/**
 * Read web server data and analyse
 * hourly access patterns.
 * 
 * @author David J. Barnes and Michael Kolling, modified Albin Morelle
 * @version 2001.12.31, modified 2003.9, 2006.10
 */
public class LogAnalyzer {
    // Where to calculate the hourly access counts.
    private int[] hourCounts;
    // Use a LogfileReader to access the data.
    private LogfileReader reader;

    /**
     * Create an object to analyze hourly web accesses,
     * the data file being weblog.txt
     */
    public LogAnalyzer() { 
        this("weblog.txt") ;
    }

    /**
     * Create an object to analyze hourly web accesses.
     * @param name of the log file
     */
    public LogAnalyzer(String LogFileName) { 
        // Create the array object to hold the hourly
        // access counts.
        hourCounts = new int[24];
        // Create the reader to obtain the data.
        reader = new LogfileReader(LogFileName);
    }

    /**
     * Analyze the hourly access data from the log file.
     */
    public void analyzeHourlyData() {
        while(reader.hasMoreEntries()) {
            LogEntry entry = reader.nextEntry();
            int hour = entry.getHour();
            hourCounts[hour]++;
        }
    }

    /**
     * Print the hourly counts.
     * These should have been set with a prior
     * call to analyzeHourlyData.
     */
    public void printHourlyCounts() {
        System.out.println("Hr: Count");
        for(int hour = 0; hour < hourCounts.length; hour++) {
            System.out.println(hour + ": " + hourCounts[hour]);
        }
    }
    
    /**
     * Print the lines of data read by the LogfileReader
     */
    public void printData() {
        reader.printData();
    }
    
    /**
     * @return number of accesses reported by the log file
     */
    public int numberOfAccesses() {
        int s = 0 ;
        for (int i = 0; i < hourCounts.length; i++)
            s += hourCounts[i] ;
        return s ;
    }
    
    /**
     * @return busiest hour
     */
    public int busiestHour()  {
        int bh = 0 ;
        for (int i = 1; i < hourCounts.length; i++)
            if (hourCounts[i] > hourCounts[bh]) bh = i ;
        return bh ;
    }
    
    /**
     * @return quiest hour
     */
    public int quiestHour() {
        int qh = 0 ;
        while ( (qh < hourCounts.length) && (hourCounts[qh] == 0) ) qh++;
        if (hourCounts[qh] != 0)
            for (int i = qh + 1; i < hourCounts.length; i++)
                if ( (hourCounts[i] > 0) && 
                     (hourCounts[i] < hourCounts[qh]) 
                   ) qh = i ;
        return qh ;
    }

    /**
     * @return busiest two-hour period
     */
    public int busiestTwoHours() {
        int timeOfMaxCount = 0 ;
        int maxCount = hourCounts[0] + hourCounts[1] ;
        for (int i = 2; i < hourCounts.length-1; i++) {
            int currentCount = hourCounts[i] + hourCounts[i+1] ;
            if (currentCount > maxCount) {
                maxCount = currentCount ;
                timeOfMaxCount = i ;
            }
        }
        return timeOfMaxCount ;
    }

    /**
     * @return hours sorted by decreasing counts
     */
    public int[] rankHours() {
        int[] sortedHours = new int[hourCounts.length] ;
        int nbeq ; // number of values equals to the current value
        int nbgt ; // number of values greater than the current value
        for (int h = 0; h < sortedHours.length; h++) {
            nbeq = 0 ;
            nbgt = 0 ;
            for (int i = 0; i < hourCounts.length; i++) {
                if ( (i < h) && (hourCounts[i] == hourCounts[h]) ) nbeq++ ;
                if ( hourCounts[i] > hourCounts[h]  ) nbgt++ ;
            }
            sortedHours[nbgt + nbeq] = h ;
        }
        return sortedHours ;
    }
    
     /**
     * @return hour-count couples sorted by decreasing counts
     */
    public HourCount[] rankHours2() {
        HourCount[] hc = new HourCount[hourCounts.length];
        int h ;
        // Initialize tab hc
        for (h = 0; h < hc.length; h++) {
            hc[h] = new HourCount(h, hourCounts[h]);
        }
        // Sort tab hc with a Bubble sort
        for (int i = 0; i < hc.length; i++) {
            for (h = hc.length - 1; h > i; h--) {
                if ( hc[h].getCount() > hc[h-1].getCount() ) {
                    // Exchange hc[h] and hc[h-1]
                    HourCount x = hc[h];
                    hc[h] = hc[h-1];
                    hc[h-1] = x;
                }
            }
        }
        return hc ;
    }
        
} // end class LogAnalyzer

