/* 
 *	Copyright (c) 1997-98 
 *	NorthEast Parallel Architectures Center, Syracuse University. 
 * All Rights Reserved. Permission to use, copy, modify, and distribute this
 * software and its documentation for educational, research and non-profit
 * purposes, without fee, and without a written agreement is hereby granted,
 * provided that the above copyright notice and this paragraph appear in all
 * copies. Permission to incorporate this software into commercial products may
 * be obtained by contacting the NorthEast Parallel Architectures Center. 
 *
 * The software program and documentation are supplied "as is",
 * without any accompanying services from NPAC. NPAC does not
 * warrant that the operation of the program will be uninterrupted or
 * error-free. The end-user understands that the program was developed for
 * research purposes and is advised not to rely exclusively on the program for
 * any reason.
 *
 */

package cis600.client;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*; 
import java.util.Vector;
import org.omg.CosNaming.*;
import cis600.util.*;
/**
 * Histogram, Pie-chart & Probability Distribution Functions in a single
 * frame. The probability distribution Function is plotted in ranges.
 * 
 * @version     0.5 20 April 1998
 * @author      Shrideep Pallickara
 *
 */

public class Histogram extends java.applet.Applet implements Runnable{

  /** Variables we are gonna use during the double-buffering */
  private Image buf;                         
  private Graphics gBuf;
  /* End of variables used during double buffering */
  
  /** Picking up the width and height from the HTML page */
  int xsize=400,ysize=800;

  /** Self-explanatory variable names, the helper variable is used during 
    the plotting of the pie-chart, in the TransientBuffer() routine */
  int currSample, prevSample, helper=0;

  int basesize=0;
  
  /**Vector which keeps track of the samples */
  Vector plotInfo;

  /**Vector which keeps track of the distribution */
  Vector distributionInfo;
  int plotTracker=0;

  double scale=1; 
  
  /** The thread which controls the repaint() */
  Thread scroller;
  
  /**Timeslice allocated to the thread */
  int timeout = 250;
  int count, MaxCount=151; 

  /** This is our random number generator */
  cis600.util.RandomGen _randomizer;
  int numberOfRanges=0;

  boolean isApplication=false;
  /** To be used to display revelant textual information */
  private Font  lbl = new Font("Helvetica", Font.BOLD, 10);

  /** The Null constructor for the class */
  public Histogram() {
  }

  /**
   *  The init() method is being used both by the applet and application
   *  capabilities of the program. Depending on how its being used viz. applet
   *  OR application capability of the program 
   *
   */

  public void init() { 
    if (!isApplication) {
      xsize=getSize().width; 
      ysize=getSize().height;
      buf = createImage(xsize,ysize);
      gBuf = buf.getGraphics();
    } 
    getRandomizerHandle();
    setBackground(Color.white);
    plotInfo=new Vector();
    distributionInfo = new Vector();
    numberOfRanges = ysize/50;
    for ( int i=0; i< numberOfRanges; i++)
      distributionInfo.addElement(new Integer(0));
    for (int i=0; i <xsize; i++)
      randomize();
  } 
  

  private void getRandomizerHandle() {
    try {
      /* Initialize the ORB.*/
      org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(this, null);
      
      /* Get a reference to the Naming Service */
      org.omg.CORBA.Object nameServiceObj = 
	orb.resolve_initial_references("NameService");
      /* Check to see if the operation involving getting a reference to the NameService was successful */
      if (nameServiceObj == null) {
	System.out.println("Name Service Object = null");
	return;
      }
      
      org.omg.CosNaming.NamingContext nameService =
	org.omg.CosNaming.NamingContextHelper.narrow(nameServiceObj);
      
      if (nameService == null) {
	System.out.println("nameService = null");
	return;
      }
      
      NameComponent[] collabName = 
      { new NameComponent("Utilities", "Randomizer")};     
      _randomizer= 
	cis600.util.RandomGenHelper.narrow(nameService.resolve(collabName));
      System.out.println("Received Generator Handle");
    } catch(Exception e) {
      System.out.println("Exception: " + e);
    }
  }
  

  /** 
   * Start the thread which controls, the animation of the Randomizer function
   * Called automatically within the applet but requires an explicit call in 
   * the application version of the program.
   *
   */
  
  public void start() {
    if (scroller == null) {
      scroller = new Thread(this);
      scroller.start();
    }
  }
  
  public void stop() {
    if (scroller != null) {
      scroller.stop();
      scroller = null;
    }
  }
  
  public void run() {
    try {
      Thread.currentThread().sleep(5*timeout);} 
    catch (InterruptedException e){}
    for (count=0; count <= MaxCount; ) {
      try {Thread.currentThread().sleep(timeout);} 
      catch (InterruptedException e){}
      randomize();
      repaint();
    }
  }
  

  /* Dispose off the graphics context */
  public void destroy() { gBuf.dispose(); } 
  
  public void update(Graphics g) { paint(g); } 

  /*
   * This is the fixed buffer employed in the double-buffering scheme
   * Basically its responsible, for updating the status information of 
   * the pie-chart, the histogram and PDF headers. Besides this the method
   * is responsible for drawing the pie-chart with the value of the previous
   * sample as a precursor to,  the animation to the present sample.
   *
   */

  public void paintFixedBuffer(Graphics g) {
    double fromX=-Math.PI*scale;   
    double toX=Math.PI*scale;
    double topY=xsize/2.0*scale; 
    double bottomY=-topY;
    g.setColor(Color.white);
    g.fillRect(0,0,xsize, ysize);
    g.setColor(Color.blue);
    g.setFont(lbl);
    g.drawString("PIE CHART Reverting from "+prevSample+" to "+currSample
		, 40, 10);
    g.drawString("The HISTOGRAM OF THE ARRIVING SAMPLES", 40, 2*(ysize/3)+40);
    /*g.drawString("The PROBABILITY DISTRIBUTION FUNCTION", 
      40, 2*(ysize/3)+40); */
    g.drawLine(0,ysize-1, xsize, ysize-1);
    g.drawLine(0,ysize, 0, ysize-ysize*(3/4));
    for (int i=1; i<15; i++) {
      g.setColor(Color.darkGray);
      g.fillArc(25, 25+i, 300,120, 0, prevSample);
      g.setColor(Color.gray);
      g.fillArc(25, 25+i, 300,120, prevSample, 360-prevSample);
    }
    g.setColor(Color.lightGray);
    g.fillArc(25, 25, 300,120, 0, prevSample);
    g.setColor(Color.black);
    g.fillArc(25, 25, 300,120, prevSample, 360-prevSample);
  }

  /*
   * This method is reponsible for the 3D animation of the pie-chart, reverting
   * to the new value of the sample.
   * This method is called approx. Math.abs(currentSample-prevSample)
   * This method reduces/increases the value of the pir-chart plot-angle by
   * a single degree, to simulate animation.
   *
   */

  
  public void paintTransientBuffer(Graphics g) {
    if (currSample > prevSample) {
      helper++;
      if ((prevSample-helper )!=360) {
	g.setColor(Color.darkGray);
	for (int i=1; i<15; i++) 
	  g.fillArc(25, 25+i, 300,120, 0, prevSample+helper);
	g.setColor(Color.lightGray);
	g.fillArc(25, 25, 300,120, 0, prevSample+helper);
      }
    } 
    
    if (currSample < prevSample){
      helper++;
      if ((prevSample-helper )!=0) {
	for (int i=1; i<15; i++) {
	  g.setColor(Color.gray);
	  g.fillArc(25, 25+i, 300,120, 
		    prevSample-helper, 360-prevSample+helper);
	}
	g.setColor(Color.black);
	g.fillArc(25, 25, 300,120, prevSample-helper, 360-prevSample+helper);
	for (int i=1; i<15; i++) {
	  g.setColor(Color.darkGray);
	  g.fillArc(25, 25+i, 300,120, 0, prevSample-helper);
	}
	g.setColor(Color.lightGray);
	g.fillArc(25, 25, 300,120, 0, prevSample-helper);
      }
    } 
  }

  /**
   * This method plots the histogram of all the previous samples, and the 
   * current sample. 
   */
  
  public void paintHistogram(Graphics g) {
    g.setColor(Color.black);
    int temp_size;
    for (int i=0; i < plotInfo.size(); i++) {
      temp_size=(int)((Integer)plotInfo.elementAt(i)).intValue();
      g.drawLine(i,(ysize*2)/3,i,(2*ysize/3-temp_size/2));
    }
  }

  /** 
   * This method plots the Probability Distribution Function of the Values
   * generated by the Random Number generator. A flat probability distribution
   * indicates the efficiency of the Random Number generator. 
   * The PDF is plotted for 40 ranges of the values generated by the 
   * Randomizer.
   *
   */
  
  public void plotDistribution(Graphics g) {
    int value;
    int plotting;
    plotting = distributionInfo.size();
    Color[] col = new Color[plotting];
    int l=135,m=165,n=250;
    for (int i=0; i <plotting; i++)
      col[i]= new Color( l+ 5*i, m -6*i, n -13*i);
    
    for (int i=0; i <plotting/2; i++) {
      g.setColor(col[i]);
      value = ((Integer)distributionInfo.elementAt(i)).intValue();
      for (int j=0; j < 35; j ++) {
	g.drawLine(35*i+j, ysize,
	           35*i+j,(ysize-value));
      }
    }
    
    for (int i=plotting/2; i < plotting;i++) {
       g.setColor(col[i]);
      value = ((Integer)distributionInfo.elementAt(i)).intValue();
	for (int j=0; j < 35; j ++) {
	   g.drawLine(35*(plotting-i)+j, ysize,
	        	   35*(plotting-i)+j,(ysize-value));
      }
    }      
  }
  
  /**
   * Paints the Fixed Buffer first, then the pie-chart histogram and PDF in 
   * that order.
   *
   */

  public void paint(Graphics g) {
    if (isApplication && buf==null) {
      buf = createImage(xsize, ysize);
      gBuf = buf.getGraphics();
    }
    float f = (((Integer)plotInfo.lastElement()).floatValue()/(ysize/2))*360;
    currSample = (int) f;
    helper = 0;
    paintFixedBuffer(gBuf);
    paintHistogram(gBuf);
    /* plotDistribution(gBuf); */
    if (prevSample!=currSample) {
      for ( int i=0; i < Math.abs(prevSample-currSample-1) ; i++) {
	paintTransientBuffer(gBuf);
	g.drawImage(buf,0,0,this); 
      }
    }
    prevSample=currSample;
  }

  /**
   * This method is invoked by the thread responsible for the animation 
   */
  public void randomize() {
    if (plotTracker >xsize) {
      plotInfo.removeElementAt(0);
      plotTracker--;
    }
    int temp = _randomizer.nextInt((ysize/2-1));
    plotInfo.addElement(new Integer(temp));
    temp = (int)(temp/50);
    int temp2 = ((Integer)distributionInfo.elementAt(temp)).intValue();
    temp2++;
    distributionInfo.setElementAt(new Integer(temp2), temp);
			
    plotTracker++;
  }
  
  public static void
    main(String args[]) {
      Histogram _randomizer = new Histogram();
      _randomizer.isApplication =true;
      _randomizer.init();
      RandomizerFrame _frame = new RandomizerFrame(_randomizer);
      
  }
}

/**
 * This class enables the program to function as an application too.
 */

class RandomizerFrame extends Frame implements WindowListener {
  Histogram _randomizer;
  
  public RandomizerFrame(Histogram _randomizer) {
    this._randomizer = _randomizer;
    setTitle("Randomizer Distribution Function");
    add(_randomizer);
    addWindowListener(this);
    pack();
    setSize(_randomizer.xsize, _randomizer.ysize);
    show();
    _randomizer.start();
  }
  
  public void windowClosed(WindowEvent event) {}
  
  public void windowDeiconified(WindowEvent event) {}
  
  public void windowIconified(WindowEvent event) {}
  
  public void windowActivated(WindowEvent event) {}
  
  public void windowDeactivated(WindowEvent event) {}
  
  public void windowOpened(WindowEvent event) {}
  
  public void 
  windowClosing(WindowEvent event) {
    System.out.println("Resources to be returned shortly .....");
    System.out.println("Killing the thread");
    _randomizer.stop();
    System.out.println("Disposing off the graphics context");
    _randomizer.destroy();
    System.out.println("Done ......");
    System.exit(0);
  }
}