package csc454.net;
import java.awt.*;
import java.util.*;

public class station extends Canvas implements Runnable {
  //time for 64 byte contention packet to tansmit in ms
  protected static double conTime_ = .512; 
  //time for a regular packet to transmit in ms
  protected static double packetTransTime_ = 1.024; 
  protected static double maxPackets = 10;
  protected double normRate_; //Normailzation rate
  protected static int stationWidth_;
  protected static Color borderColor_ = Color.black;
  protected static Color stringColor_ = Color.black;
  protected static Color idleColor_ = Color.yellow;
  protected static Color seizedColor_ = Color.green;
  protected static Color contentionColor_ = Color.red;
  protected static Color backoffColor_ = Color.gray;
  private static Font nameFont_=new Font("Helvetica",Font.BOLD,6);
  protected time t_;
  protected double totTime=0;
  protected queue q_;    // reference to station queue
  protected net n_;    // reference to the net
  protected TextArea txt_;  // where to print messages
  protected int num_;  //station number
  protected int state_=-1;//set station to idle
  protected int cnt_=0; //number messages processed by station
  protected int collisions_=0; //number collisions
  protected int lost_=0; //number lost messages
  protected boolean terminate_=false;
public station(queue q, TextArea txt, int num, net n, double normRate,
                 int stationWidth) {
    stationWidth_=stationWidth;
    normRate_=normRate;
    q_=q; 
    n_=n;
    txt_ = txt;
    num_=num;
    resize( stationWidth_, stationWidth_ );
  }

  public void paint( Graphics g ){
    if (state_==-1) {
      g.setFont(nameFont_);
      g.setColor( borderColor_);
      g.drawOval(10,10,(stationWidth_-10),(stationWidth_-10));
      state_=0;
    }
    switch (state_) {
    case 0: 
      g.setColor(idleColor_);
      g.fillOval(11,11,(stationWidth_-12),(stationWidth_-12));
      g.setColor( stringColor_);
      g.drawString("Idle",17,40);
       break;
    case 1: 
      g.setColor(seizedColor_);
      g.fillOval(11,11,stationWidth_-12,stationWidth_-12);
      g.setColor( stringColor_);
      g.drawString("Seize",17,40);
      break;
    case 2: 
      g.setColor(contentionColor_);
      g.fillOval(11,11,stationWidth_-12,stationWidth_-12);
      g.setColor( stringColor_);
      g.drawString("Cont.",17,40);
      break;
    case 3: 
      g.setColor(backoffColor_);
      g.fillOval(11,11,stationWidth_-12,stationWidth_-12);
      g.setColor( stringColor_);
      g.drawString("Backoff",17,40);
    }
    g.setColor( stringColor_);
    g.drawString("Server"+num_,10,10);
  }

  public void begin (time t) {
    t_=t;
  }

  public void terminate() {
    terminate_=true;
}

  public  void run() { 
    state_=0;
    repaint();
    for(;!terminate_;) {
      try {                     // simulate service
        if (q_.dequeue()) {           //wait for a successful dequeue
          double startCont=t_.elapsed();
          int attempt=1;
          while(attempt <=5 & attempt != 0) {
            if (n_.contend(num_)) {//wait till you can contend
              state_=2;
              repaint();
              long delay = (long)(conTime_ * normRate_);
              Thread.currentThread().sleep(delay);
              if (n_.seize(num_)==1) {
                cnt_++;
                txt_.appendText("Message "+cnt_+
                                "being transmitted by station " + num_+
                                " after "+((t_.elapsed()-startCont)/1000.0)+
                                " seconds of contention and " + attempt + 
                                " attempts\n");
                state_=1;
                repaint();
                delay = (long)(packetTransTime_ * 
                               (1+(int)(10*Math.random())) * normRate_);
                Thread.currentThread().sleep(delay);
                n_.free(num_);
                attempt=0;
              }
              else {
                state_=3;
                repaint();
                collisions_++;
                attempt++;
                long backoff = (long)(conTime_* normRate_ * 
                                      attempt * attempt * Math.random());
                Thread.currentThread().sleep(backoff);
              }
            }
          }
          if (attempt>5) {
            lost_++;
            txt_.appendText("Message lost after "+(attempt-1) + "attempts and " +
                            ((t_.elapsed()-startCont)/1000.0)+ 
                            " seconds of contention\n");
          }
        }
      }
      catch (InterruptedException e) { return; }
      state_=0;
      repaint();
    }
    double avgTime=totTime/(double)cnt_;
    txt_.appendText("station " + num_ + "...\n"+
                    "\tprocessed "+ cnt_+" Messages\n"+
                    "\tLost"+lost_+" Messages\n"+
                    "\tDetected "+collisions_ +" Collisions\n"+
                    "\tAverage Contention time was " + avgTime + "\n"+
                    "\tin " + t_.elapsed()+ " time units\n");
  }
}
