/**
 * A work farm example, with integrated results graph
 */

package workfarm;

import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import eduni.simanim.*;
import eduni.simjava.*;
import eduni.simdiag.*;


/** The Graph test applet.
 * @author Fred Howell
 * @see Anim_applet
 */
public class GraphTest extends Anim_applet implements ItemListener {
  Panel inputs,outputs;
  Label msgLabel, maxLabel, sinkLabel, srcLabel, numWorkLabel, showMsgLabel;
  TextField msgField, maxField, sinkField, srcField;
  Choice numWorkChoice;
  Checkbox showMsgBox;
  static public boolean show_msg = true;

  /** Experiment input parameter
   */
  int curr_njobs = -1; // Not initialised
  int min_njobs = -1; // Not initialised
  int max_njobs = -1; // Not initialised

  /** Output Graph Window 
   */
  GraphWindow gw;
  GraphDiagram gd;

  // Generate graph
  
  /** Initialise the gui inputs
   */
  public void anim_init() {
    int i;
    inputs = new Panel();
    outputs = new Panel();
    GridBagLayout gb = new GridBagLayout();
    GridBagConstraints c = new GridBagConstraints();
    outputs.setLayout(gb);
    inputs.setLayout(new GridLayout(0,2));

    msgLabel = new Label("Min number of jobs:", Label.RIGHT);
    inputs.add(msgLabel);
    msgField = new TextField("5",3);
    inputs.add(msgField);

    maxLabel = new Label("Max number of jobs:", Label.RIGHT);
    inputs.add(maxLabel);
    maxField = new TextField("10",3);
    inputs.add(maxField);
    
 
    numWorkLabel = new Label("Number of workers:", Label.RIGHT);
    inputs.add(numWorkLabel);
    numWorkChoice = new Choice();
    for(i=1; i<=5; i++) numWorkChoice.addItem(" "+i+" ");
    numWorkChoice.select(2);
    numWorkChoice.addItemListener(this);;
    inputs.add(numWorkChoice);

    showMsgLabel = new Label("Show messages:", Label.RIGHT);
    inputs.add(showMsgLabel);
    showMsgBox = new Checkbox("");
    showMsgBox.setState(true);
    inputs.add(showMsgBox);

    srcLabel = new Label("Farmer delay between jobs (mean):", Label.RIGHT);
    inputs.add(srcLabel);
    srcField = new TextField("0.4",5);
    inputs.add(srcField);

    sinkLabel = new Label("Worker processing delay (mean):", Label.RIGHT);
    inputs.add(sinkLabel);
    sinkField = new TextField("1.0",5);
    inputs.add(sinkField);

    /* Place inputs and timing diagram into gridbag */
    c.fill = GridBagConstraints.BOTH;
    c.gridwidth = GridBagConstraints.REMAINDER;
    c.weighty = 1.0;
    outputs.add(inputs); gb.setConstraints(inputs,c);


    /* Add a graph window */
    GraphWindow gw = new GraphWindow();
    gd = gw.getDiag();
    gw.start();
 
    // Add a trace saver
    trace_out.addTraceListener( new TraceSaver("tracefile") );

 
    /* add all to the top level gridbag layout */
    this.add("North", outputs); //layout.setConstraints(outputs, gbc); 
  }

  Farmer giles;
  Bucket sink;

  /** Extract results from a simulation run,
   * send to the graph window.
   */
  public void anim_completed() {
    // Extract results...
    double total_time = sink.get_result();

    // Hopefully Farmer etc is still alive.
    gd.handleGraph( new GraphData(this, "Total time", (double) curr_njobs, total_time) );
    gd.handleGraph( new GraphDisplay(this) );

    // More?
    if (curr_njobs < max_njobs) {
      curr_njobs++;
      run();
    } else {
      System.out.println("Done!!");
      curr_njobs = -1;
    }
  }

  /** Setup the animation
   */
  public void anim_layout() {
    int i, num_workers;
    double src_hold, sink_hold;

    System.out.println("Laying out simulation");
    min_njobs = Integer.parseInt(msgField.getText());
    max_njobs = Integer.parseInt(maxField.getText());
    num_workers = numWorkChoice.getSelectedIndex()+1;
    src_hold = Double.valueOf(srcField.getText()).doubleValue();
    sink_hold = Double.valueOf(sinkField.getText()).doubleValue();
    show_msg = showMsgBox.getState();

    // Deal with loop stuff
    if (curr_njobs==-1) {
      curr_njobs = min_njobs; // Minimum
      gd.handleGraph( new GraphClearObject(this) );
      gd.handleGraph( new GraphSetAxes(this,"Messages","Time") );
      gd.handleGraph( new GraphSetScale(this,0,(double)max_njobs,
					0.0,src_hold*(double)max_njobs) );
      gd.handleGraph( new GraphDisplay(this) );
    } 

    System.out.println("Currently "+curr_njobs+"messages");

    // Add entities
    giles = new Farmer("Farmer", curr_njobs, src_hold, 20, 20);
    Sim_system.add(giles);
    Sim_system.add(new Bucket("Bucket_1", 90+70*num_workers, 20, Anim_port.LEFT));
    sink = new Bucket("Bucket_2", 20, 160, Anim_port.RIGHT);
    Sim_system.add(sink);
    for(i=1; i<=num_workers; i++) {
      Sim_system.add(new Wrouter("Wrouter_"+i, 20+70*i, 20));
      Sim_system.add(new Worker("Worker_"+i, sink_hold, 20+70*i, 90));
      Sim_system.add(new Rrouter("Rrouter_"+i, 20+70*i, 160));
    }

    // Link entities
    Sim_system.link_ports("Farmer", "first", "Wrouter_1", "in");
    Sim_system.link_ports("Wrouter_"+num_workers, "next", "Bucket_1", "in");
    Sim_system.link_ports("Rrouter_1", "out", "Bucket_2", "in");
    for(i=1; i<=num_workers; i++) {
      if(i!=num_workers)
        Sim_system.link_ports("Wrouter_"+i, "next", "Wrouter_"+(i+1), "in");
      Sim_system.link_ports("Wrouter_"+i, "worker", "Worker_"+i, "in");
      Sim_system.link_ports("Worker_"+i, "out", "Rrouter_"+i, "in1");
      if(i!=1)
        Sim_system.link_ports("Rrouter_"+i, "out", "Rrouter_"+(i-1), "in2");
    }
  }

  // do a layout if they change the number of workers
  public void itemStateChanged(ItemEvent e) {
    Object source = e.getSource();
    if (source == numWorkChoice)
        anim_relayout();
  }
}
