
import byucc.jhdl.apps.Viewers.cvt.cvtFrame;
import byucc.jhdl.apps.Stimulator.Stimulator;
import byucc.jhdl.base.CellInterface;
import byucc.jhdl.base.HWSystem;
import byucc.jhdl.base.Node;
import byucc.jhdl.base.TestBench;
import byucc.jhdl.base.SimulatorCallback;
import byucc.jhdl.base.Wire;
import byucc.jhdl.Logic.Logic;
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

/** This is a basic test of the HitCounter circuit.  This TestBench
 * simply creates an instance of the HitCounter design within CVT and
 * also creates a GraphCanvas linked to it to give a custom
 * visualization of the functionality of the circuit.
 * @author Anthony L. Slade */
public class TestHitCounter extends Logic
  implements TestBench, SimulatorCallback {

  /** Reads in values from the command line to set the parameters of
   * the HitCounter to be tested.  Also creates a GraphCanvas view of
   * the HitCounter output. */
  public static void main( String[] args ) {
    if ( 3 != args.length )
      showUsage(1);
    int hitValue=0, width=0, countWidth=0;
    // parse user input
    try {
      hitValue = Integer.parseInt( args[0] );
      width = Integer.parseInt( args[1] );
      countWidth = Integer.parseInt( args[2] );
    } catch ( NumberFormatException nfe ) {
      showUsage(1);
    }
    // build the TestBench and the design circuit
    TestHitCounter thc
      = new TestHitCounter( new HWSystem(),
			    hitValue,
			    width,
			    countWidth );
    // put the design in a CVT frame
    new cvtFrame(thc);
    // build a custom view of the HitCounter output
    GraphCanvas gc = thc.createGraphView();
    JLabel l1 = new JLabel("HitCounter Test"),
      l2 = new JLabel("HitCounter Test");
    JPanel panel = new JPanel(new BorderLayout());
    panel.add(gc,BorderLayout.CENTER);
    panel.add(l1,BorderLayout.NORTH);
    panel.add(l2,BorderLayout.SOUTH);
    JFrame graphFrame = new JFrame("Test HitCounter");
    graphFrame.getContentPane().add(panel);
    graphFrame.setLocation(250,250);
    graphFrame.pack(); graphFrame.show();
  }

  /** Prints out the usage for the user to learn what the command line
   * should be
   * @param exitValue the return exit value for when the program
   * exits */
  public static void showUsage(int exitValue) {
    System.err.println( "TestHitCounter usage:" );
    System.err.println( "  java TestHitCounter <target_value> "
			+"<wire_width> <counter_width>" );
    System.exit( exitValue );
  }

  /** Builds a TestHitCounter TestBench
   * @param hitValue the constant value to be embedded in the
   * HitCounter equals comparator
   * @param width the width of the input wire
   * @param countWidth the width of the HitCounter output wire */
  public TestHitCounter( Node parent,
			 int hitValue, int width, int countWidth ) {
    super( parent,"TestHitCounter" );
    new HitCounter( this,
		    hitValue,
		    input = wire(width,"input"),
		    restart = wire(1,"restart"),
		    count = wire(countWidth,"count"),
		    hit = wire(1,"hit") );
    Stimulator stim = new Stimulator( this );
    stim.addWire(input);
    stim.addWire(restart);
  }

  // SimulatorCallback interface methods
  /** Resets the values of the GraphCanvas */
  public void simulatorReset() {
    graph.resetValues();
    graph.repaint();
    hitDetected = false;
  }
  /** Updates the GraphCanvas if new hits have been detected */
  public void simulatorUpdate(int cycle, int step) {
    if ( hitDetected ) {
      graph.updateValue(0,count.get(this));
      hitDetected = false;
      // every so often on long simulation runs, update graph
      if ( 0 == cycle%UPDATE_FREQUENCY )
	graph.repaint();
    }
    hitDetected = hit.getB(this);
  }
  /** Simply tells the GraphCanvas to repaint */
  public void simulatorRefresh(int cycle, int step) {
    graph.repaint();
  }

  /** Creates a new GraphCanvas linked with this TestBench */
  GraphCanvas createGraphView() {
    graph = new GraphCanvas( new String[] {"input"},
			     new int[] {0},
			     new Color[] {Color.blue},
			     "Number of hits");
    getSystem().addSimulatorCallback(this);
    return graph;
  }

  // The input and output wires of the system
  protected Wire input, restart, count, hit;

  /** Used to visualize the operation of the HitCounter design */
  private GraphCanvas graph;

  /** Tells the simulatorUpdate method that the next cycle it needs to
   * grab the count value */
  private boolean hitDetected;

  /** The maximum number of cycles between updates to the graph */
  private static final int UPDATE_FREQUENCY = 40;

} // end class TestHitCounter
