/**
  * Web Site Hits Count Graph Generator
  * @author Robert J Morton <robmorton@clara.net>
  * @version 26 April 2000 */

import java.applet.*;                                      //all the gubbins to make the applet work
import java.awt.*;                                         //for graphics operations (GUI)
import java.net.*;                                         //for downloading data from the remote server
import java.io.*;                                          //for stream handling for the above


public class hc extends Applet implements Runnable {
   AppletContext ac;                                       //get details of HTML document this applet is running in
   String cb;                                              //code base URL - where this applet's class file came from
   URL url;                                                //url of current HTML file 
   InputStream I;                                          //input stream for downloading index or current HTML file
   int L = 0;                                              //length of the remote item being loaded
   int l = 0;                                              //number of bytes of the above successfully downloaded
   byte B[];                                               //gigantic byte array to hold the downloaded index data
   int w;                                                  //weeks counter used on horizontal axis of graph
   Thread TH;                                              //reference for a separate Internet Data Transfer thread
   int lp = 1, LP = 1;                                     //indicates current and previous download phases
   String E;                                               //for Exception during downloading + method where it occurred
   int X = 30;                                             //horizontal bias from left edge of applet to start of x-axis
   int Y = 125;                                            //vertical bias from top edge of applet to start of y-axis
   int n = 25;                                             //off-set from start mark of year to start of its name eg 1999
   Color bg1 = new Color(210, 210, 210);                   //main background colour
   Color bg2 = new Color(208, 176, 176);                   //graph background colour ideally with a 24-bit system
   Color bg3 = new Color(128, 128, 128);                   //graticule colour

   String year[] = {"1998", "1999", "2000", "2001", "2002", "2003", "2004"};  //year name
   int weeks[]   = {  52,     52,     52,     52,     52,     52,    52  };   //weeks in year
   String hits[] = {"00", "10", "20", "30", "40", "50"};                      //hits scale

   public void init() {
      bg1 = getBackground();
      setBackground(bg1);
      ac = getAppletContext();                             //get details of HTML document this applet is running in
      cb = getCodeBase().toString();                       //URL (less file name) from where this applet came
      if(!cb.endsWith("/")) {                              //workaround re Hotjava re Microsoft intranet machine names
         int x = cb.lastIndexOf('/');                      //where getCodeBase() wrongly seems to return the
         if(x != -1) cb = cb.substring(0, x + 1);          //document base (cira Nov 1999)
      }
      TH = new Thread(this);                               //create a thread for downloading data from server
      setBackground(bg1);                                  //set the applet's background colour
   }


   public void paint(Graphics g) { 
      g.setColor(bg1); g.fillRect(0, 0, 450, 150);         //clear the graph panel
      g.setColor(bg2); g.fillRect(X, Y-100, 364, 100);     //clear the graph area

      g.setColor(Color.black);
      w = 0;
      for(int i = 0; i < weeks.length; i++) {              //for each year shown
         g.drawString(year[i], X + 13 + w, Y + 20);        //year number
         g.drawLine(X + w, Y + 5, X + w, Y + 10);          //year boundary mark
         g.setColor(bg3);
         g.drawLine(X + w, Y, X + w, Y - 100);             //annotation mark
         w += weeks[i];                                    //accumulated number of weeks
         g.setColor(Color.black);
      }
      g.setColor(bg3);
      g.drawLine(X + w, Y, X + w, Y - 100);                //annotation mark
      g.setColor(Color.black);
      g.drawLine(X + w, Y + 5, X + w, Y + 10);             //final year boundary mark
      g.drawLine(X, Y + 5, X + w, Y + 5);                  //horizontal axis

      int z = 0;
      for(int i = 0; i < hits.length; i++) {               //for each 10-hit graduation
         g.drawString(hits[i], X - n, Y + 5 - z);          //annotation
         g.drawLine(X - 10, Y - z, X - 5, Y - z);          //annotation mark
         g.setColor(bg3);
         g.drawLine(X, Y - z, X + w, Y - z);               //annotation mark
         z += 20;                                          //accumulated number of hits
         g.setColor(Color.black);
      }
      g.drawLine(X - 5, Y, X - 5, Y - 100);                //vertical axis
      g.drawString("Hits per week:", X - n, Y - 110);
      g.drawString("Year:", X - n, Y + 20);

      update(g);                                           //paint/repaint the graph bars
   }


   public void update(Graphics g) {
      g.setColor(Color.blue);                              //set trace colour to blue
      if(lp == 3) {                                        //provided hit count data download completed
         int h = 0;                                        //number of hits for a given week
         w = X;                                            //initial x-bias for week number
         int W = 0;                                        //number of weeks for which there is valid data
         int H = 0;                                        //hits total accumulator
         for(int i = 0; i < L; i++) {
            if((h = (int)B[i]) > 0) {                      //aviod displaying zero values before start date
               g.drawLine(w, Y, w, Y - (h << 1));          //display it as a vertical bar on the chart
               H += h;                                     //add this week's hits to the total
               W++;                                        //increment the number of weeks for which there is valid data
            }
            w++;                                           //increment the week number
         }
         g.setColor(Color.black);
         g.drawString("Total to Date " + H, 105, 15);
         g.drawString("Weekly Average " + (H / W)), 230, 15);
      }
   }


   public void start() { TH.start(); }                     //resume execution of Internet data transfer thread 

   public void run() {                                     //MANAGE INTERNET DATA TRANSFERS ON A SEPARATE THREAD
      while(TH.isAlive()) {                                //while this thread exists
         switch(lp) {                                      //THE 2 DOWNLOADING PHASES
            case 1: fileConnect(); break;                  //connect to index resource on server
            case 2: fileLoad(); break;                     //manage the downloading of its content
         }
         if(lp != LP) {                                    //if loading of hits data has finished
            LP = lp;                                       //latch the current load state
            repaint();                                     //display the bars
         }
         try {
            Thread.currentThread().sleep(250);             //sleep to allow other things to take place
         } catch (InterruptedException e) {}               //catch interrupt from GUI or browser
      }
   }

   public void stop() { TH.stop(); }                       //freeze execution of thread while away from host HTML page

   public void destroy() {                                 //called after stop() before applet is removed from memory
      if(TH != null) {                                     //if the Internet data transfer thread object still exists
         TH.stop();                                        //stop it running
         TH = null;                                        //and jettison its object into limbo
      }
   }


   void fileConnect() {                                    //CONNECT TO THE HITS DATA FILE ON THE SERVER
      try {
         url = new URL(cb + "hc.dat");                     //form the url of the hits data file
         URLConnection u = url.openConnection();           //open a connection to the remote file
         L = u.getContentLength();                         //length of the remote file (bytes)
         l = 0;                                            //number of bytes so far successfully downloaded
         I = u.getInputStream();                           //create an input stream object to access the file
         B = new byte[L];                                  //create the gigantic buffer for the data
         lp = 2;                                           //advance to the index loading phase
      } catch(Exception e) {
         lp = 0;                                           //set unrecoverable error status
         E = "fileConnect() " + e;                         //note the exception and where it occurred
      } 
   }


   void fileLoad() {                                       //DOWNLOAD THE HITS DATA
      int k;                                               //current byte being read()
      try {                                                //if read() hasn't hit the current end of input stream
         while(l < L && (k = I.read()) != -1)              //and the entire file has not yet been downloaded
            B[l++] = (byte)k;                              //add its new byte to the array big byte array
         if(l >= L) {                                      //if the whole of the index has now been downloaded
            I.close();                                     //close the URL Connection's input stream
            lp = 3;                                        //indicate file loading completed successfully
         }
      } catch(Exception e) { 
         lp = 0;                                           //set error condition
         E = "fileLoad() " + e + L + " " + l;              //note the exception and where it occurred
      }
   }

}


/*  Robert J Morton, the author of this program, 
    is a poor but Right Honourable Fellow of the
    Ancient and Noble Order of the Long-term Unemployed.

    Offers of work please to: robmorton@clara.net  */