/* An Emin2 network
 * Added scenarios (31 Jan 98)
 * Added 3d (27 April 98)
 */
package emin;

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


import vrml.external.field.*;
import vrml.external.Node;
import vrml.external.Browser;
import vrml.external.exception.*;




/**
 * Stores a message
 */
class Message extends Object {
  public int dest;
  public int size;
  public Message(int d, int s) {
    dest = d;
    size = s;
  }
}

/**
 * The different types of command
 */
interface Cmd_types {
  public final int IDLE_C=0;
  public final int SEND_C=1;
  public final int RECV_C=2;   // Send, receive commands
  public final int READ_C=3;
  public final int READ_R=4;	  // Read command, response
  public final int WRITE_C=5;  // Write command
  public final int TST_SET_C=6;// Read-modify-write command
  public final int PROC_C=7;   // Local processing command
  public final int USER_C=8;   // User defined command
  public final int USER_R=9;   // User defined command
  public final String[] wstate = {"idle","send","recv","read","read_r",
  "write","write_r","tst_set","proc","user","user_r"};
}

/**
 * Stores a command
 */
class Cmd_buf {
  int cmd, src, pno, addr, size;
  int[] data;
  Cmd_buf() {}
  Cmd_buf( int cmdi, int srci, int pnoi, int addri, int sizei, 
	   int[] datai ) {
    cmd = cmdi;    src = srci;     pno = pnoi;    addr = addri;
    size = sizei;    data = datai;
  }	
}


/**
 * Interface to memory
 */
interface Mem_if {
  void Mem_fn(int i,Cmd_buf c);
}

/**
 * Interface to workload from model
 */
interface To_workload {
  /** Initialises workload
   * @ param m Reference to the model
   * @ param mf Place holder for extensable memory function.
   */
  void init_workload( To_model m, Mem_if mf);
  /** Starts workload
    * @ param pnum Index of processor
    * @ param nprocs Total number of processors
    */
  void do_workload(int pnum, int nprocs);
}

/**
 * Interface to model from workload
 */
interface To_model {
  void do_cmd(int cmd, int pno, int addr, int size, int[] data);
  //void do_mem_cmd(int cmd, int pno, int addr, int size, Object data);
  //double get_time(int pnum);
  //int  read_mem(int pnum, int a);
  //void write_mem(int pnum, int a, int val);
  //int get_int_param(int index, String name);
}


/**
 * This class implements a workload for generating ubenchmarks.
 * @version     1.0
 * @author      Fred Howell
 */
class UBenchWorkload implements To_workload, Cmd_types {
  int workload = 0;
  int num_msg = 1;
  To_model model=null;
  Mem_if mem=null;
  public UBenchWorkload(int wl, int n) { workload = wl;
    num_msg = n; }
  public void init_workload(To_model m, Mem_if mf) { model = m; mem = mf; }
  public void do_workload(int pnum, int nprocs) {
    int[] databuf = new int[256];

    if (workload == 0) { // bcast
      if (pnum==0) {
	for (int i=0; i<num_msg; i++) {
	  for (int dest = 0; dest < nprocs; dest ++) {
	    model.do_cmd(READ_C, dest, 16, 1, databuf);
	  }
	}
      }
    } else if (workload==1) { // gather
      for (int i=0; i<num_msg; i++) {
	model.do_cmd(READ_C, 0, 16, 1, databuf);
      }
    } else if (workload==2) { // all to all
      for (int i=0; i<num_msg; i++) {
	for (int dest = 0; dest < nprocs; dest ++) {
	  model.do_cmd(READ_C, dest, 16, 1, databuf);
	}
      }
    } else if (workload==3) { // random (10%)
      for (int i=0; i<num_msg; i++) {
	int proc = (int)Math.rint(Math.random() * 90.0);
	int comm = (int)Math.rint(Math.random() * 10.0);
	double dprocs = nprocs-1.0;
	int dest = (int)Math.rint(Math.random() * dprocs);
	model.do_cmd(PROC_C, dest, 16, proc, databuf);
	model.do_cmd(READ_C, dest, 16, comm, databuf);
      }
    } else if (workload==4) { // random (50%)
      for (int i=0; i<num_msg; i++) {
	int proc = (int)Math.rint(Math.random() * 50.0);
	int comm = (int)Math.rint(Math.random() * 50.0);
	double dprocs = nprocs-1.0;
	int dest = (int)Math.rint(Math.random() * dprocs);
	model.do_cmd(PROC_C, dest, 16, proc, databuf);
	model.do_cmd(READ_C, dest, 16, comm, databuf);
      }
    } else if (workload==5) { // random (90%)
      for (int i=0; i<num_msg; i++) {
	int proc = (int)Math.rint(Math.random() * 10.0);
	int comm = (int)Math.rint(Math.random() * 90.0);
	double dprocs = nprocs-1.0;
	int dest = (int)Math.rint(Math.random() * dprocs);
	model.do_cmd(PROC_C, dest, 16, proc, databuf);
	model.do_cmd(READ_C, dest, 16, comm, databuf);
      }
    } else if (workload==6) { // read local
      for (int i=0; i<num_msg; i++) {
	int dest = pnum;
	model.do_cmd(READ_C,dest , 16, 1, databuf);
      }
    } else if (workload==7) { // read neighbour
      for (int i=0; i<num_msg; i++) {
	int dest = (pnum + 1) % nprocs;
	model.do_cmd(READ_C, dest , 16, 1, databuf);
      }
    } else if (workload==8) { // read random location.
      for (int i=0; i<num_msg; i++) {
	int dest = rrand(nprocs);
	model.do_cmd(READ_C, dest , 16, 1, databuf);
      }
    }



    // for (int addr = 0; addr < 10; addr ++) {
    //  model.do_cmd(READ_C, pnum, addr, 1, databuf);
    // }
  }

  int rrand( int max ) {    /* Return int from 0..max-1 */
    int r =  (int)Math.rint(Math.random() * (max-1));
    return r;
  }
  
}


/**
 * This class creates a simulated processor which generates traffic
 * on its bus. <P>
 * @see         eduni.simjava.Sim_entity
 * @version     1.0
 * @version     1.1 - connects to vrml version in cpu.wrl
 * @author      Fred Howell
 */
class PNode extends Sim_entity implements Cmd_types, To_model {
  private Sim_port network;
  private Sim_port networkin;
  private int pnum;
  private int nprocs;
  private int state;

  To_workload workload;

  double 
    cmd_hold_time,
    send_hold_time,
    recv_hold_time,
    read_hold_time,
    write_hold_time,
    process_cycle_time,
    user_hold_time;

  double  
    cmd_hold_time_pw,
    send_hold_time_pw,
    recv_hold_time_pw,
    read_hold_time_pw,
    write_hold_time_pw,
    user_hold_time_pw;


  Emin2 app;

  /**
   * Creates a processor node object, with a given workload.
   * @param pnum     The processor index.
   * @param nprocs   The total number of processors.
   * @param speed    The processor speed (in MHz).
   */
  public PNode(String name, Emin2 app, int x, int y, int pnum, int nprocs, 
	      int cmdsi, int cmdpwi, To_workload wl) {
    super(name,"node",x,y);
    this.app = app;
    network = new Sim_port("out", "port", Anim_port.BOTTOM, 12); 
    networkin = new Sim_port("in", "port", Anim_port.BOTTOM, 12); 
    add_port(network);
    add_port(networkin);
    this.pnum   = pnum;
    this.nprocs = nprocs;
    this.cmd_hold_time  = cmdsi;
    this.cmd_hold_time_pw  = cmdpwi;
    workload = wl;
    if (wl != null) wl.init_workload(this, null);

    add_param(new Anim_param( "State", Anim_param.STATE, 
			      new Param_type("node_state",wstate) ));
    reset_times();
  }

  // Connect to VRML node.
  Node mynode = null;
  EventInSFInt32 set_state = null;
  boolean error = true;
  void connect3d() {
    // app.pause(1000);
    mynode = app.getNode(get_name());
    if (mynode!=null) {
	set_state = (EventInSFInt32) app.getEventIn(mynode, "set_state");
 	if (set_state==null) {
		error = true; 
		System.out.println("connect3d failed to set state");
	} else error=false;
    } else {
	System.out.println("connect3d failed "+get_name());
    }
  }
  void update3d(int i) {
    if (!error) {
	set_state.setValue(i);
	// System.out.println("Trying to set value to "+i);

    }
  }

 void reset_times() {
    send_hold_time =
    recv_hold_time =
    read_hold_time =
    write_hold_time =
    process_cycle_time =
    user_hold_time = 0.0;
    send_hold_time_pw =
    recv_hold_time_pw =
    read_hold_time_pw =
    write_hold_time_pw =
    user_hold_time_pw = 0.0;
  }
  void set_nstate( int cmd) {
    state = cmd;
    if (app.show_msg) sim_trace(1,"P "+ wstate[state]);
    update3d(cmd);
  }

  /** Call the workload to do the biz
   */
  public void body() {
    connect3d();
    if (workload!=null)
      workload.do_workload( pnum, nprocs );
  }

  void send(Cmd_buf b) {
    sim_hold( send_hold_time + send_hold_time_pw * b.size ); 
    sim_schedule(network, 0.0, SEND_C, b );
  }

  void recv(Cmd_buf b) {
    Sim_event ev = new Sim_event();
    sim_hold( recv_hold_time + recv_hold_time_pw * b.size ); 
    sim_wait_for(new Sim_type_p(SEND_C), ev);
    b = (Cmd_buf)ev.get_data();
  }

  void read(Cmd_buf b) {
    Sim_event ev = new Sim_event();
    sim_hold( read_hold_time + read_hold_time_pw * b.size ); 
    sim_schedule(network, 0.0, READ_C, b );
    set_nstate(READ_R);
    sim_wait_for(new Sim_type_p(READ_R), ev);
    b = (Cmd_buf)ev.get_data();
  }

  void tst_set(Cmd_buf b) {
    Sim_event ev = new Sim_event();

    sim_hold( read_hold_time + read_hold_time_pw * b.size ); 
    set_nstate(READ_R);
    sim_schedule(network, 0.0, TST_SET_C, b );
    sim_wait_for(new Sim_type_p(READ_R), ev);
    b = (Cmd_buf)ev.get_data();
  }

  void write(Cmd_buf b) {
    sim_hold( write_hold_time + write_hold_time_pw * b.size ); 
    sim_schedule(network, 0.0, WRITE_C, b );
  }

  void process(int s) {
    sim_hold( process_cycle_time * s ); 
  }

  void user(Cmd_buf b) {
    Sim_event ev = new Sim_event();
    sim_hold( user_hold_time + user_hold_time_pw * b.size ); 
    sim_schedule(network, 0.0, USER_C, b );
    set_nstate(USER_R);
    sim_wait_for(new Sim_type_p(USER_R), ev);
    b = (Cmd_buf)ev.get_data();
  }

  public void do_cmd(int cmd, int pno, int addr, int size, int[] data) {
    Cmd_buf b = new Cmd_buf(cmd,pnum,pno,addr,size,data);
    set_nstate(cmd);
    sim_hold( cmd_hold_time + cmd_hold_time_pw * size ); 
    if (cmd == SEND_C)		send(b);
    if (cmd == RECV_C)		recv(b);
    if (cmd == READ_C)		read(b);
    if (cmd == TST_SET_C)	tst_set(b);
    if (cmd == WRITE_C)		write(b);
    if (cmd == PROC_C)		process(b.size);
    if (cmd == USER_C)		user(b);
    set_nstate(IDLE_C);
  }
}


/**
 * This class creates a simulated processor which generates traffic
 * on its bus. <P>
 * @see         eduni.simjava.Sim_entity
 * @version     1.0
 * @author      Fred Howell
 */
 
class Processor extends Sim_entity {
  private Sim_port out;
  private int pnum;
  private int nprocs;
  private int nmsgs;
  private int workload;
  private double speed;

  /**
   * Creates a processor object, with a given workload.
   * @param pnum     The processor index.
   * @param nprocs   The total number of processors.
   * @param speed    The processor speed (in MHz).
   */
  public Processor(String name, int x, int y, int pnum, int nprocs, 
		   int nmsgs, int workload, double speed) {
    super(name,"processor",x,y);
    out = new Sim_port("out", "port", Anim_port.BOTTOM, 30); add_port(out);
    this.pnum   = pnum;
    this.nprocs = nprocs;
    this.nmsgs  = nmsgs;
    this.workload  = workload;
    this.speed  = speed;
  }

  /**
   * Sends a message to the given processor.
   * @param  dest    The destination processor index.
   * @param  hold_time    The time this processor is delayed.
   */
  void send(int dest, double hold_time) {
    sim_schedule(out, 0.0, 1, new Message(dest, 4));
    if (Emin2.show_msg) sim_trace(1, "S out "+dest);   
    sim_hold(hold_time);		 
  }

  /**
   * Generates the messages.
   */
  public void body() {
    int i;

    double delay = 1.0;
    
    if (workload == 0) { // 1 to all
      if (pnum==1) {
	for(i=0; i<nmsgs; i++) {
	  send(i % nprocs,delay);
	}    
      }
    } else if (workload==1) { // all to 1
      for(i=0; i<nmsgs; i++) {
	send(1,delay);
      }    
    } else if (workload==2) { // all to all
      for(i=0; i<nmsgs; i++) {
	send((i+pnum) % nprocs,delay);
      }    
    } else { // random 
      Random rdest = new Random();
      double spacing = 
	(workload==3) ? 10.0 : 
	(workload==4) ? 1.0 : 0.0;
      Sim_normal_obj rdelay = new Sim_normal_obj("Delay Object", 
						 spacing, spacing/2, pnum);
      for(i=0; i<nmsgs; i++) {
	send(rdest.nextInt() % nprocs, rdelay.sample());
      }    
    } 
  }
}

/** Component of multistage networks
 */
class Sw extends Sim_entity implements Cmd_types {
  private int swsize;		// Size of local switch
  private int msize;		// Size of overall switch (total # of I/O ports)
  private int nstages;		// Number off stages
  private int sx, sy;		// switch index
  Sim_port inp[];
  Sim_port outp[];
  double hold_time, hold_time_pw;

  Param_type sw_param;
  Emin2 app;

  /** Build a sw
   */
  public Sw(String name, Emin2 app, int x, int y,
     int sz, int msz, int nstg, int sxi, int syi, 
     double ht, double htpw) {
    super(name,"sw",x,y);
    this.app = app;
    swsize = sz;
    msize = msz;
    nstages = nstg;
    sx = sxi;
    sy = syi;
    hold_time = ht;
    hold_time_pw = htpw;

    inp  = new Sim_port[swsize];
    outp = new Sim_port[swsize];
    for (int i=0; i<swsize; i++) {
      inp[i] = new Sim_port( "inp"+i,"port", Anim_port.TOP, 
			     i*(24/(sz-1))); 
      add_port(inp[i]);
      outp[i] = new Sim_port( "outp"+i,"port", Anim_port.BOTTOM, 
			      i*(24/(sz-1))); 
      add_port(outp[i]);      
    }
    String[] swstate = {"idle","busy"};
    sw_param = new Param_type("swstate", swstate);
    add_param(new Anim_param( "State", Anim_param.STATE, sw_param ));
  }


  // Connect to VRML node.
  Node mynode = null;
  EventInMFInt32 connections = null;
  EventInSFTime glowTime = null;
  boolean error = true;
  void connect3d() {
    // app.pause(1000);
    mynode = app.getNode(get_name());
    if (mynode!=null) {
	connections = (EventInMFInt32) app.getEventIn(mynode, "connections");
 	if (connections==null) {
		error = true; 
		System.out.println("connect3d failed to set state");
	} else error=false;
	glowTime = (EventInSFTime) app.getEventIn(mynode, "glowTime");
    } else {
	System.out.println("connect3d failed "+get_name());
    }
  }
  void update3d(int f, int t) {
    if (!error) {
	if ((f < 4) && (t<4))
		connections.set1Value(f,t);
	// System.out.println("Trying to set value "+f+" to "+t);
	glowTime.setValue(app.getVrmlTime().getValue());
    }
  }


  int ilog2( int i ){
    int l = 0;
    for (l=0; ((i>>=1) !=0); l++) ;
    return l;
  }

  // Return source port #
  int getsrcport(Sim_event ev) {
    int found=-1;
    for (int i=0; i<swsize; i++) {
	if (ev.from_port(inp[i])) { found = i; }
    }
    return found;   
  }
 
  // Determine output port index given msg
  int route( int glob_dest, boolean to_mem ) {
    int local_dest = 0;
    if (to_mem) glob_dest += msize/2;	// Procs from 0..msize/2, then mems
    System.out.println("Routing: "+glob_dest+" "+to_mem);
    int mask = swsize-1;
    int lgswsize = ilog2(swsize);
    for (int s=nstages-1; s>=0; s--) {
      if (s==sx) local_dest = glob_dest & mask;
      glob_dest >>= lgswsize;
    }
    System.out.println("Routing: "+local_dest);
    update3d(last_src,local_dest); 
    return local_dest;
  }

  void mem_cmd(Cmd_buf b) {
    // sim_trace(1,"C Mem cmd "+b.pno);
    sim_schedule(outp[route(b.pno,true)], 
		 hold_time + hold_time_pw*b.size,
		 b.cmd,b );
    sim_schedule(get_id(), hold_time + hold_time_pw*b.size, 
		 123, b );
  }

  void proc_cmd(Cmd_buf b) {
    // sim_trace(1,"C Proc cmd "+b.pno);
    sim_schedule(outp[route(b.pno,false)], 
		 hold_time + hold_time_pw*b.size,
		 b.cmd, b ); 
    sim_schedule(get_id(), hold_time + hold_time_pw*b.size, 
		 123, b );
  }

  void error_cmd() {
    sim_trace(1,"C Error - sw received RECV cmd\n");
  }
  
  private int last_src = -1;

  public void body() {
    connect3d();
    Sim_event ev = new Sim_event();
    int numreqs = 0;
    while (true) {
      Cmd_buf b = new Cmd_buf(); 
      sim_get_next(ev);
      if (ev.type()==123) {numreqs--;} else {
	b = (Cmd_buf)ev.get_data();
	numreqs++;

	last_src = getsrcport(ev);

	if (b.cmd==SEND_C || b.cmd==READ_R || b.cmd==USER_R)
	  proc_cmd(b);
      
	if (b.cmd==READ_C || b.cmd==WRITE_C || 
	    b.cmd==TST_SET_C || b.cmd==USER_C) 
	  mem_cmd(b);
	
	if (b.cmd==RECV_C || b.cmd==PROC_C)
	  error_cmd();
      }
	if (app.show_msg) {
        if (numreqs==0) sim_trace(1, "P idle");
        else  sim_trace(1, "P busy");
	}
   
    }
  }
};

/**
 * Multistage network
 */
class Mstage extends Sim_entity implements Cmd_types {
  Sw [][] switches;

  // External ports
  Sim_port []procsin;
  Sim_port []memsin;
  Sim_port []procsout;
  Sim_port []memsout;

  Sim_port []to_switches;
  Sim_port []from_switches;
  int maxreqs;
  int nstages;
  int swperstage;
  double bus_hold_time, bus_hold_time_pw;
  double idle_time;
  int nports;

  Emin2 app;

  public Mstage(String name, Emin2 app, int x, int y, double st, double pw, int np, int swsize, int totalwidth)  
  { 
    super(name,"mstage",x,y);
    this.app = app;
    set_invisible(true); // Don't display this entity.
    bus_hold_time = st;
    bus_hold_time_pw = pw;
    nports = np;
    procsin = new Sim_port[nports];
    memsin  = new Sim_port[nports];
    procsout = new Sim_port[nports];
    memsout  = new Sim_port[nports];
    for (int i=0; i<nports; i++) {
      procsin[i] = new Sim_port( "procsin"+i, "port", Anim_port.TOP, i*(170/(nports-1)) );
      add_port(procsin[i]);
      memsin[i] = new Sim_port( "memsin"+i, "port", Anim_port.BOTTOM, i*(170/(nports-1)) ); 
      add_port(memsin[i]);      
      procsout[i] = new Sim_port( "procsout"+i, "port", Anim_port.TOP, i*(170/(nports-1)) );
      add_port(procsout[i]);
      memsout[i] = new Sim_port( "memsout"+i, "port", Anim_port.BOTTOM, i*(170/(nports-1)) ); 
      add_port(memsout[i]);      
    }

    swperstage = np*2 / swsize;
    // Work out how many stages are needed
    nstages = 1;
    int conns = np*2;
    if (swperstage>1) 
      while ( (conns /= swsize)>1 )
	nstages ++;

    // sim_trace(1, "C "+nstages+" stages ");

    switches = new Sw[nstages][swperstage];

    int swwidth = (totalwidth - 32) / swperstage;

    to_switches = new Sim_port[np*2];
    from_switches = new Sim_port[np*2];
    for (int si=0; si<np*2; si++) {
      to_switches[si] = new Sim_port( "tosw"+si,"port", Anim_port.TOP, si*(170/(nports-1))   ); 
      add_port(to_switches[si]);
      from_switches[si] = new Sim_port( "fromsw"+si, "port", Anim_port.BOTTOM, si*(170/(nports-1)) ); 
      add_port(from_switches[si]);
    }

    // Make sub switches
    int sx,sy;
    for (sx=0; sx<nstages; sx++) {
      for (sy=0; sy<swperstage; sy++) {
	switches[sx][sy] = new Sw("sw"+sx+"_"+sy, app,
				60 + sy * swwidth,
				120 + sx * 70,
				swsize, np*2, nstages, sx,sy,st,pw);
      }
    }

    // Join sub switches
    for (sx=-1; sx<nstages; sx++) {
      int destinp = 0;
      int destsw  = 0;
      for (sy=0; sy<swperstage; sy++) {
	for (int k=0; k<swsize; k++) {
	  int sp = sy*swsize+k;
	  int sxp1 = sx+1;
	  if (sx==-1) {
	    Sim_system.link_ports(name, "tosw"+sp, 
				  "sw"+sxp1+"_"+sy, "inp"+k);
	  } else if (sx==nstages-1)
	    Sim_system.link_ports( "sw"+sx+"_"+sy, "outp"+k, 
				   name, "fromsw"+sp);
	  else
	    Sim_system.link_ports( "sw"+sx+"_"+sy, "outp"+k, 
				   "sw"+sxp1+"_"+destsw, "inp"+destinp);

	  destsw = (destsw + 1);
	  if (destsw >= swperstage) { 
	    destsw = 0; destinp = (destinp + 1) % swsize;
	  }
	}
      }
    }
  }

  int get_max_reqs() { return maxreqs; }

// tdiag stuff here
//  void wr_bars(FILE *fp) {
//   fprintf(fp,"%s %s\n", get_name(), "msstate");
//  for (int x=0; x<nstages; x++) {
//    for (int y=0; y<swperstage; y++) {
//fprintf(fp,"%s %s\n", switches[x][y]->get_name() , "swstate");
//    }
//  }
//}

  void mem_cmd(Cmd_buf b,boolean internal) {
    // sim_trace(1,"C Mem cmd  "+b.pno+" "+internal);
    sim_schedule(internal ? memsout[b.pno] : to_switches[b.src + nports], 
		 0.0, b.cmd, b );
  }
  void proc_cmd(Cmd_buf b,boolean internal) {
    // sim_trace(1,"C Proc cmd "+b.pno+" "+internal);
    sim_schedule(internal ? procsout[b.pno] : to_switches[b.src], 
		 0.0, b.cmd, b );
  }

  void error_cmd() {
    sim_trace(1,"C Error - xbar received RECV cmd\n");
  }

  // Return true if from one of the internal switches.
  boolean is_internal(Sim_event ev) {
    boolean found = false;
    for (int i=0; i<nports*2; i++) 
      if (ev.from_port(from_switches[i])) found = true;
    return found;
  }

  public void body() {
    Sim_event ev=new Sim_event();
    int numreqs = 0;
    maxreqs = 0;
    while (true) {
      Cmd_buf b = new Cmd_buf(); 
      sim_get_next(ev);
      b=(Cmd_buf)ev.get_data();

      boolean internal = is_internal(ev);
      if (internal) numreqs--; else numreqs++;
      if (numreqs > maxreqs) maxreqs = numreqs;

      if (b.cmd==SEND_C || b.cmd==READ_R || b.cmd==USER_R)
	proc_cmd(b,internal);
      
      if (b.cmd==READ_C || b.cmd==WRITE_C || 
	  b.cmd==TST_SET_C || b.cmd==USER_C) 
	mem_cmd(b,internal);
      
      if (b.cmd==RECV_C || b.cmd==PROC_C)
	error_cmd();

      if (Emin2.show_msg) sim_trace(1, "P "+ numreqs);
    }
  }
};


/** Bus is a general purpose bus with N connections
 */
class Bus extends Sim_entity implements Cmd_types {
  private Sim_port procsin[];
  private Sim_port memsin[];
  private Sim_port procsout[];
  private Sim_port memsout[];

  private int nports;
  double bus_hold_time, bus_hold_time_pw;
 
  // State 
  //  bus_param state;

  private static final int IDLE = 0;
  private static final int BUSY = 1;

  private int state;
  Param_type bus_param;

  double idle_time;

  /** Bus constructor
   * @param nports Number of procs/mems
   * @param st  Startup time (ns)
   * @param pw  Time per word (ns)
   */
  public Bus( String name, int x, int y, int nports, double st, double pw) {
    super(name,"bus",x,y);
    this.nports = nports;
    this.bus_hold_time = st;
    this.bus_hold_time_pw = pw;

    procsin = new Sim_port[nports];
    memsin = new Sim_port[nports];
    procsout = new Sim_port[nports];
    memsout = new Sim_port[nports];

    for (int i=0; i<nports; i++) {
      procsin[i] = new Sim_port( "procsin"+i, "port", Anim_port.TOP, i*(170/(nports-1)) ); 
      add_port(procsin[i]);
      procsout[i] = new Sim_port( "procsout"+i, "port", Anim_port.TOP, i*(170/(nports-1)) ); 
      add_port(procsout[i]);
      memsin[i] = new Sim_port( "memsin"+i, "port", Anim_port.BOTTOM, i*(170/(nports-1)) ); 
      add_port(memsin[i]);      
      memsout[i] = new Sim_port( "memsout"+i, "port", Anim_port.BOTTOM, i*(170/(nports-1)) ); 
      add_port(memsout[i]);      
    }

    state = IDLE;
    String[] bstate = {"idle","busy"};
    bus_param = new Param_type("bstate", bstate);
    add_param(new Anim_param( "BState", Anim_param.STATE, bus_param ));
  }

  void mem_cmd(Cmd_buf b) {
    // sim_trace(1,"C Mem cmd "+b.pno);
    sim_schedule(memsout[b.pno], 0.0, b.cmd, b );
    sim_hold(bus_hold_time+b.size*bus_hold_time_pw);
    if (Emin2.show_msg) sim_trace(1, "S memsout"+b.pno+" "+b.addr);    
  }
 
  void proc_cmd(Cmd_buf b) {
    // sim_trace(1,"C Proc cmd "+b.pno);
    sim_schedule(procsout[b.pno], 0.0, b.cmd, b );
    sim_hold(bus_hold_time+b.size*bus_hold_time_pw);
    if (Emin2.show_msg) sim_trace(1, "S procsout"+b.pno+" "+b.addr);    
  }
 
  void error_cmd() {
    sim_trace(1,"C Error - bus received RECV cmd");
  }
 

  /** Bus behaviour
   * Initially only one transaction on bus at a time.
   */
  public void body() {
    Sim_event ev = new Sim_event();
    idle_time = 0.0;
    while (true) {
      Cmd_buf b = new Cmd_buf(); 
      double t = Sim_system.sim_clock();
      state = IDLE; dump_state();
      sim_get_next(ev);
      idle_time += Sim_system.sim_clock() - t;

      state = BUSY; dump_state();

      b = (Cmd_buf)ev.get_data();

      if (b.cmd==SEND_C || b.cmd==READ_R || b.cmd==USER_R)
	proc_cmd(b);
      
      if (b.cmd==READ_C || b.cmd==WRITE_C || 
	  b.cmd==TST_SET_C || b.cmd==USER_C) 
	mem_cmd(b);
	
      if (b.cmd==RECV_C || b.cmd==PROC_C)
	error_cmd();
    }
  }

  public void dump_state() {
    if(state == IDLE) sim_trace(1, "P idle");
    if(state == BUSY) sim_trace(1, "P busy");
  }
}

/** Memory component.
 */
class Memory extends Sim_entity implements Cmd_types {
  int index;
  int length;
  int []data;
 
  // Links
  Sim_port in, out;
 
  // Params
  double mem_hold_time, mem_hold_time_pw;
 
  // State
  //  mem_param state;
  int state;
  Param_type mem_param;
  void set_state(boolean idle, int cmd) {
    if (idle) state = 0;
    else state = (cmd == READ_C) ? 1 :
      (cmd == TST_SET_C) ? 2 :
      (cmd == USER_C) ? 3 :
      (cmd == WRITE_C) ? 4 : 5;
    if (Emin2.show_msg) sim_trace(1,"P "+ mem_param.getVals()[state]);
    update3d(state);
  }
 
  // Stats
  double idle_time;

  Emin2 app;

  public Memory(String name, Emin2 app, int x, int y, 
	 int index_i, int length_i, double mht, double mhtpw)
  {
    super(name,"memory",x,y);
    this.app = app;
    index = index_i;
    length = length_i;
    mem_hold_time = mht;
    mem_hold_time_pw = mhtpw;
    in = new Sim_port("in", "port", Anim_port.TOP, 12); add_port(in);
    out = new Sim_port("out", "port", Anim_port.TOP, 12); add_port(out);
    data = new int[length];
    String[] mstate = {"idle","read","tst_set","user","write","unknown"};
    mem_param = new Param_type("mstate", mstate);
    add_param(new Anim_param( "State", Anim_param.STATE, mem_param ));
    idle_time = 0.0;
  }

  // Connect to VRML node.
  Node mynode = null;
  EventInSFInt32 set_state = null;
  boolean error = true;
  void connect3d() {
    // app.pause(1000);
    mynode = app.getNode(get_name());
    if (mynode!=null) {
	set_state = (EventInSFInt32) app.getEventIn(mynode, "set_state");
 	if (set_state==null) {
		error = true; 
		System.out.println("connect3d failed to set state");
	} else error=false;
    } else {
	System.out.println("connect3d failed "+get_name());
    }
  }
  void update3d(int i) {
    if (!error) {
	set_state.setValue(i);
	System.out.println("Trying to set value to "+i);

    }
  }




  void check_addr(int a) {
    if (!((a >=0) && (a < length)))
      System.out.println("Memory out of bounds error :"+a);
  }
 
  int read_ll(int a) { 
    check_addr(a);
    return data[a]; 
  }
   void write_ll(int a, int v) { 
    check_addr(a);
    data[a] = v; 
  }
 
  void read(Cmd_buf b, int src) {
    for (int i=0; i<b.size; i++) { b.data[i] = data[i+b.addr]; }
    b.cmd = READ_R;
    b.pno = b.src;
    b.src = index;
    sim_schedule(out, 0.0, READ_R, b);
  }
 
  void tst_set(Cmd_buf b, int src) {
    // Just tst_set *one* integer
    if (data[b.addr] != b.data[0]) {
      sim_trace(1,"Tst-set to "+ b.data[0] );
      data[b.addr] = b.data[0];
    } else  {
      sim_trace(1,"Tst-set returns 0" );
      b.data[0] = 0;
    }
    b.cmd = READ_R;
    b.pno = b.src;
    b.src = index;
    sim_schedule(out, 0.0, READ_R, b);
  }
 
  void write(Cmd_buf b) {
    if ((b.data != null) && (b.addr >=0) && (b.addr+b.size-1 < length)) {
      if (Emin2.show_msg) sim_trace(1,"Writing "+b.data[0]+" to "+ b.addr);
      for (int i=0; i<b.size; i++) {
	data[i+b.addr] = b.data[i];
      }
    }
  }
  

  void hold(int size) {
    sim_hold( mem_hold_time + mem_hold_time_pw * size );
  }
 
  public void do_cmd(int cmd, int pno, int addr, int size, int[] cdata) {
    Cmd_buf b = new Cmd_buf(cmd,index,pno,addr,size,cdata);
    if (cmd == USER_R) {
      sim_schedule(out, 0.0, USER_R, b );
    } else {
      sim_trace(1, "Only handles USER cmds");
    }
  }
 
  public void body() {
    connect3d();
    /* Respond to requests */
    Cmd_buf b;
    double t;
    Sim_event ev = new Sim_event();
    while (true) {
      int type,src;
      t = Sim_system.sim_clock();
 
      set_state(true,0); 
      sim_get_next(ev); 
      b = (Cmd_buf)ev.get_data();
      type = ev.type();
      src = ev.scheduled_by();
      idle_time += Sim_system.sim_clock() - t;
 
      set_state(false,type); 
 
      sim_hold( mem_hold_time + mem_hold_time_pw * b.size ); 
 
      if (type == READ_C)               read(b,src); 
      else if (type == WRITE_C)         write(b);
      else if (type == TST_SET_C)       tst_set(b,src);
      // else if (type == USER_C)          (*mf)(index,b);      
      else sim_trace(1,"Received unknown command:"+type);
    }
  }
 
  void report() {
    double total_time = Sim_system.sim_clock();
    double utilisation = 100.0*(total_time - idle_time)/total_time;
    sim_trace(1, "C RESULTS utilisation  "+utilisation);
  }

}
 
/** Very basic layout class for positioning graphs.
 * Just stores a vector of points + uses this to position
 * components.
 */
class BasicLayout implements LayoutManager {
  Vector p = new Vector(); 
  Vector d = new Vector(); 

  public  BasicLayout()  { }
  public void addLayoutComponent(String  name,  Component  comp) { }
  public void removeLayoutComponent(Component  comp){ }

  /** Set xp coords of component */
  public void setPos(int x, int y,int w, int h) { 
    p.addElement(new Point(x,y)); 
    d.addElement(new Dimension(w,h));
  }

  public  void layoutContainer(Container parent) {
    System.out.println("Laying out container");
    for (int i=0; i<parent.getComponentCount(); i++) {
      Component c = parent.getComponent(i);
      Point pp = (Point)p.elementAt(i);
      Dimension dd = (Dimension)d.elementAt(i);
      c.setBounds(pp.x, pp.y, dd.width, dd.height);
    }
  }
  public Dimension minimumLayoutSize(Container  parent) {
    return (new Dimension(60,60));
  }
  public Dimension preferredLayoutSize(Container  parent) {
    return (new Dimension(100,100));
  }
}


/** Emin2 class
 * Constructs cluster simulation
 */
public class Emin2 extends Anim_applet implements ItemListener,
MouseMotionListener, MouseListener {
  Panel inputs;
  Label msgLabel, sizeLabel, workLabel, netLabel, showMsgLabel
, traceMsgLabel;
  Label bwLabel,swLabel, latencyLabel;
  TextField msgField;
  Choice sizeChoice;
  Choice workChoice;
  Choice netChoice;
  Choice bwChoice, swChoice, latencyChoice;
  Checkbox showMsgBox, traceMsgBox;
  static public boolean show_msg = true;
  static public boolean trace_on = true;

  /* Experimenter stuff */
  Label minLabel, maxLabel;
  TextField minField, maxField;

  int scenario = 1; 
    // 1: No input buttons, no output graphs.
    // 2: Input buttons, no output graphs.
    // 3: Input buttons, no output graphs, more procs.
    // 4: No input buttons, output tdiag.
    // 5: No input buttons, output graph.
  boolean input_buttons = true;
  boolean input_range  = false;
  boolean output_tdiag = false;
  boolean output_graph = false;

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

  GraphDiagram gd1, gd2;
  GraphEqn ge; // tmp sine generator

  int swypos = 150;
  int memypos = 340;

  /** Pause thread for t millisecs */
  void pause(int t) {
    try {Thread.currentThread().sleep(t);} catch (InterruptedException e) {
	System.out.println("Rudely interrupted");
    }
  }

  // --- VRML Nodes     ---
  Browser browser=null;
  Node basegroup = null;
  boolean error=true;
  Node clock = null;
  EventOutSFTime vrmlTime = null;

  // --- Connect to VRML world ---
  public void initBrowser() { 
    System.out.println("About to connect to browser.");
    pause(1000);
    browser = Browser.getBrowser(this);
    pause(1000);
    if (browser == null) {
	System.out.println("Didn't get the browser: ");
	error = true;
    } else  {
	System.out.println("Got the browser: ");
	error = false;
    }
    // pause(1000);
    // connectClock();
  }

  public EventOutSFTime getVrmlTime() {
    try {
      clock  = browser.getNode("Clock");
      vrmlTime = (EventOutSFTime) clock.getEventOut("time");
    } catch (Exception ex) { System.out.println("get vrml time error"); }
    return vrmlTime;
  }

  public void connectClock() {
	error = false;
      try {
        clock  = browser.getNode("Clock");
	  System.out.println("Done getNode!!! ");

	  if (clock != null) {
		vrmlTime = (EventOutSFTime) clock.getEventOut("time");
	  } else {
		error=true; System.out.println("Couldn't get clock");
	  }
      }
      catch (InvalidNodeException ne) { 
	  System.out.println("Failed to get node:" + ne);   error = true; }
      catch (InvalidEventInException ee) { 
	  System.out.println("Failed to get EventIn:" + ee);  error = true; }
	catch (Exception oe) {
	  System.out.println("Some other nasty error:" + oe);  error = true; }
	System.out.println("Got the clock: ");
  }
  public Node getNode(String name) {
    Node n = null;
    if (!error) {
      try {n = browser.getNode(name); }
      catch (InvalidNodeException ne) { 
	  System.out.println("Failed to get node:" + ne);   
	  error = true; }
    }
    return n;
  }
  public EventIn getEventIn(Node n, String ename) {
    EventIn e = null;
    if (!error) {
    if (n!=null) {
	try {
 	  e = n.getEventIn(ename);
 	} catch (Exception ex) { 
	  System.out.println("Couldn't get event "+ename+":"+ex);
	}
    }}
    return e;
  }
  // --- End VRML Nodes ---




  /** Initialise the gui inputs
   */
  public void anim_init() {
    int i;

    /* Get scenario from applet html */
    String s = null;
    s = getParameter("scenario");
    if (s!=null) {
      scenario = Integer.parseInt(s);
    }
 
    System.out.println("Scenario is :"+scenario);

    int init_nprocs_sel = 2;
    inputs = new Panel();
    inputs.setLayout(new GridLayout(0,2));

    if (scenario==1) {
      init_nprocs_sel = 3;
      input_buttons = false;
    } else if (scenario==2) {
      init_nprocs_sel = 2;
    } else if (scenario==3) {
      init_nprocs_sel = 4;
    } else if (scenario==4) {
      init_nprocs_sel = 2;
      input_buttons = false;
      output_tdiag = true;
    } else if (scenario==5) {
      init_nprocs_sel = 2;
      input_buttons = false;
      input_range = true;
      output_graph = true;
      min_njobs = 1;
      max_njobs = 5;
    }

    // Accept range of input values
    if (input_range) {
      minLabel = new Label("Min number of jobs:", Label.RIGHT);
      inputs.add(minLabel);
      minField = new TextField("1",3);
      inputs.add(minField);

      maxLabel = new Label("Max number of jobs:", Label.RIGHT);
      inputs.add(maxLabel);
      maxField = new TextField("5",3);
      inputs.add(maxField);
    }

    if (input_buttons) {
    msgLabel = new Label("Messages:", Label.RIGHT);
    inputs.add(msgLabel);
    msgField = new TextField("5",3);
    inputs.add(msgField);

    sizeLabel = new Label("Number of processors:", Label.RIGHT);
    inputs.add(sizeLabel);
    sizeChoice = new Choice();
    for(i=2; i<=32; i*=2) sizeChoice.addItem(" "+i+" ");
    sizeChoice.select( init_nprocs_sel );
    sizeChoice.addItemListener(this);
    inputs.add(sizeChoice);

    swLabel = new Label("Switch size:", Label.RIGHT);
    inputs.add(swLabel);
    swChoice = new Choice();
    for(i=2; i<=32; i*=2) swChoice.addItem(" "+i+" ");
    swChoice.select(2);
    swChoice.addItemListener(this);;
    inputs.add(swChoice);

  
    bwLabel = new Label("Bus Bandwidth (Mb/sec):", Label.RIGHT);
    inputs.add(bwLabel);
    bwChoice = new Choice();
    for(i=1; i<=1024; i*=4) bwChoice.addItem(" "+i+" ");
    bwChoice.select(2);
    inputs.add(bwChoice);

    latencyLabel = new Label("Bus Latency (nsec):", Label.RIGHT);
    inputs.add(latencyLabel);
    latencyChoice = new Choice();
    for(i=1; i<=100000; i*=10) latencyChoice.addItem(" "+i+" ");
    latencyChoice.select(2);
    inputs.add(latencyChoice);
    
    workLabel = new Label("Workload:", Label.RIGHT);
    inputs.add(workLabel);
    workChoice = new Choice();
    workChoice.addItem(" One to all (broadcast) ");
    workChoice.addItem(" All to one (gather) ");
    workChoice.addItem(" All to all ");
    workChoice.addItem(" Random (10%) ");
    workChoice.addItem(" Random (50%) ");
    workChoice.addItem(" Random (100%) ");
    workChoice.addItem(" Read Local ");
    workChoice.addItem(" Read Neighbour ");
    workChoice.addItem(" Read Random ");
    workChoice.select(2);
    inputs.add(workChoice);

    netLabel = new Label("Network:", Label.RIGHT);
    inputs.add(netLabel);
    netChoice = new Choice();
    netChoice.addItem(" Bus ");
    netChoice.addItem(" Crossbar ");
    netChoice.addItem(" Multistage ");
    netChoice.select(2);
    netChoice.addItemListener(this);;
    inputs.add(netChoice);
    } // end if input_buttons.

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

    traceMsgLabel = new Label("Show trace:", Label.RIGHT);
    inputs.add(traceMsgLabel);
    traceMsgBox = new Checkbox("");
    traceMsgBox.setState(true);
    inputs.add(traceMsgBox);

    // Add a trace saver
    // trace_out.addTraceListener( new TraceSaver("tracefile") );
    BasicLayout bl = new BasicLayout();
    trace_out.setLayout(bl);

    // Add a timing diagram
    if (output_tdiag) {
      TimingDiagram td = new TimingDiagram();
      bl.setPos(20,memypos,600,300);
      trace_out.add(td);
      trace_out.addTraceListener( td );

      // Add a timing window
      //TimingWindow tw = new TimingWindow();
      //  trace_out.addTraceListener( tw.getDiag() );
      //   tw.start();
    } else if (output_graph) {
      gd1 = new GraphDiagram();
      bl.setPos(20,memypos,600,300);
      trace_out.add(gd1);    
    }
 


    // Add some graphs (removed)
    // gd1 = new GraphDiagram();
    // bl.setPos(440,200,400,100);

    // Tmp - generate a sine
    //ge = new GraphEqn();
    //ge.addGraphListener(gd1);
    //gd1.addGraphListener(gd2);

    // trace_out.add(gd1);
    //    trace_out.add(gd2);
    // trace_out.addMouseListener(this);
    //  p.addMouseMotionListener(this);

    this.add("North", inputs);
  }

  boolean addedListener = false;


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

      // Hopefully Farmer etc is still alive.
      gd1.handleGraph( new GraphData(this, "Total time", (double) curr_njobs, total_time) );
      gd1.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 num_msg, i, size;
    double bw, latency;

    initBrowser(); // Connect to VRML world.
    //ge.startRunning(); // tmp

    //Panel p = (Panel)gd1.get_diag();
    //if (!addedListener) if (p!=null) {
    //  p.addMouseListener(this);
    //  p.addMouseMotionListener(this);
    //  addedListener = true;
    //}

    System.out.println("Laying out simulation");
    // Default param values:-
    num_msg = 5;
    int logsize = 2; // 1,2,3
    int workload  = 1; 
    int network  = 3; 
    int bwi       = 2; 
    int swi       = 2; 
    int latencyi  = 2; 

    if (input_buttons) {
      num_msg = Integer.parseInt(msgField.getText());
      logsize = (sizeChoice.getSelectedIndex())+1; // 1,2,3
      workload  = (workChoice.getSelectedIndex()); 
      network  = (netChoice.getSelectedIndex())+1; 
      bwi       = (bwChoice.getSelectedIndex()); 
      swi       = (swChoice.getSelectedIndex()); 
      latencyi  = (latencyChoice.getSelectedIndex()); 
    }

    if (input_range) {
      min_njobs = Integer.parseInt(minField.getText());
      max_njobs = Integer.parseInt(maxField.getText());
    } 

    if (output_graph) {
      // Deal with loop stuff
      if (curr_njobs==-1) {
	curr_njobs = min_njobs; // Minimum
	gd1.handleGraph( new GraphClearObject(this) );
	gd1.handleGraph( new GraphSetAxes(this,"Messages","Time") );
	gd1.handleGraph( new GraphSetScale(this,0,(double)max_njobs,
					0.0,10.0*(double)max_njobs) );
	gd1.handleGraph( new GraphDisplay(this) );
      } 
      System.out.println("Currently "+curr_njobs+"messages");

      num_msg = curr_njobs;
    }

    size    = 1<<logsize;         // 2,4,8
    int swsize    = 1<<swi;         // 2,4,8
    bw      = Math.pow(4.0, bwi);        // 1,4,16
    latency = Math.pow(10.0, latencyi);  // 1,10,100

    show_msg = showMsgBox.getState();
    trace_on = traceMsgBox.getState();
    if (trace_on) { Sim_system.set_trc_level(255); }
    else {Sim_system.set_trc_level(0); }

    // Set memypos according to network.
    if (network==1) { memypos = swypos + 100; }
    if (network==2) { memypos = swypos + 100; }
    if (network==3) { memypos = swypos + 60*logsize; }

    for (int x = 0; x<size; x++) {
      UBenchWorkload wl = new UBenchWorkload(workload, num_msg);
      Sim_system.add(new PNode("Node"+x, this, 60 + x*40, 10, 
			      x, size, (int)latency, (int)(1000.0/bwi), wl));
      Sim_system.add(new Memory("Memory"+x, this, 60 + x*40, memypos, 
			      x, 1000, (int)latency, (int)(1000.0/bwi)));
    }
 
    if (network==1) {
      Sim_system.add(new Bus("Bus", (60 + size*40/2)-80, swypos,
			     size, bw, latency));

      for (int y=0; y<size; y++) {
	Sim_system.link_ports("Node"+y, "out", "Bus", "procsin"+y);
	Sim_system.link_ports("Node"+y, "in", "Bus", "procsout"+y);
	Sim_system.link_ports("Memory"+y, "out", "Bus", "memsin"+y);
	Sim_system.link_ports("Memory"+y, "in", "Bus", "memsout"+y);
      }
    } else if (network==2) {
      Sim_system.add(new Sw("Sw", this,(60 + size*40/2)-80, swypos,
			     size*2, size, 1, 0,0, latency,bw));
      for (int y=0; y<size; y++) {
	int mempos = y + size;
	Sim_system.link_ports("Node"+y, "out", "Sw", "inp"+y);
	Sim_system.link_ports("Node"+y, "in", "Sw", "outp"+y);
	Sim_system.link_ports("Memory"+y, "in", "Sw", "outp"+mempos);
	Sim_system.link_ports("Memory"+y, "out", "Sw", "inp"+mempos);
      }
    } else if (network==3) {
      Sim_system.add(new Mstage("Mstage",this,60,swypos, latency,bw,size,swsize,
				size*40 + 32));
      for (int y=0; y<size; y++) {
	Sim_system.link_ports("Node"+y, "out", "Mstage", "procsin"+y);
	Sim_system.link_ports("Node"+y, "in", "Mstage", "procsout"+y);
	Sim_system.link_ports("Memory"+y, "in", "Mstage", "memsout"+y);
	Sim_system.link_ports("Memory"+y, "out", "Mstage", "memsin"+y);
      }
    }
  }
  public void itemStateChanged(ItemEvent e) {
    anim_relayout();
  }

  /** Mouse listener code 
   */
  Component movec = null;
  Point p1 = null;
  int stx, sty;
  public void mouseDragged(MouseEvent e) {
    //int x = e.getX()-stx;
    // int y = e.getY()-sty;
    // if (movec!=null) {
    //  gd1.setLocation(new Point(x,y));
    //  System.out.println("Moving comp to "+x+","+y);
    //}
  }
  public void mouseMoved(MouseEvent e) {  }
  public void mouseClicked(MouseEvent e) { 
    gd1.setLocation(new Point(e.getX(),e.getY()));
  }
  public void mousePressed(MouseEvent e) {
    // stx = e.getX();
    // sty = e.getY(); 
    // Is it clicked on Graph???
    //p1 = gd1.getLocation();
    //movec = trace_out.getComponentAt(stx,sty);
    //System.out.println("Mouse pressed"+stx+","+sty);
  }
  public void mouseReleased(MouseEvent e) {  
    movec = null;
  }
  public void mouseEntered(MouseEvent e) {  }
  public void mouseExited(MouseEvent e) {  }
 

 
}

