package test.rate;

import java.util.ArrayList;
import java.util.Iterator;

import org.apache.log4j.Logger;

import jist.runtime.JistAPI;
import jist.swans.mac.Mac802_11;
import jist.swans.mac.Mac802_11Message;
import jist.swans.mac.MacDcfMessage;
import jist.swans.misc.Message;
import jist.swans.misc.MessageAnno;
import jist.swans.misc.Util;
import jist.swans.phy.PhyMessage;
import jist.swans.radio.RadioInterface;

public class BitrateTestRadioField implements RadioInterface {
  
  /** logger for radio/field events. */
  public static final Logger log = Logger.getLogger(BitrateTestRadioField.class);
  
  /** Connected MAC entities */
  Mac802_11[] macs;
  
  /** self-referencing proxy entity */
  RadioInterface self;
  
  /** @return Self-referencing proxy entity*/
  RadioInterface getProxy() {
    return self;
  }
  
  private int[] pktCtr;
  
  private int[] ackCtr;
  
  private int dropPackets;
  
  private int dropAcks;
  
  public BitrateTestRadioField(int dropThisNrOfPackets, int dropThisNrOfAcks) {
    dropPackets = dropThisNrOfPackets;
    dropAcks = dropThisNrOfAcks;
    this.self = (RadioInterface)JistAPI.proxy(new RadioInterface.Dlg(this), 
        RadioInterface.class);
  }

  public void setMacs(ArrayList macs) {
    this.macs = new Mac802_11[macs.size()];
    Iterator it = macs.iterator();
    int i=0;
    while(it.hasNext())
      this.macs[i++] = (Mac802_11)it.next();
    pktCtr = new int[macs.size()];
    ackCtr = new int[macs.size()];
  }
  
  public void endReceive(Message msg, Double power, RFChannel rfChannel, Object event) {
    // TODO Auto-generated method stub

  }

  public void endTransmit() {
    // TODO Auto-generated method stub
//    System.out.println("t: " + JistAPI.getTime() + " - Transmission completed.");
  }

  public void receive(Message msg, Double power, Long duration) {
    // TODO Auto-generated method stub

  }

  public void setSleepMode(boolean sleep) {
    // TODO Auto-generated method stub

  }

  public double getNoise_mW() throws JistAPI.Continuation {
    return 0;  //To change body of implemented methods use File | Settings | File Templates.
  }

  public void setChannel(RFChannel channel, long delay) {
    //To change body of implemented methods use File | Settings | File Templates.
  }

  public void endSetChannel(RFChannel channel) {
    //To change body of implemented methods use File | Settings | File Templates.
  }

  public RFChannel getChannel() throws JistAPI.Continuation {
    return null;  //To change body of implemented methods use File | Settings | File Templates.
  }

  public void transmit(Message msg, long delay, long duration, MessageAnno anno) {

    MacDcfMessage macMsg = (MacDcfMessage) ((PhyMessage)msg).getPayload();
//    log.debug(Util.getTimeDotted() + ": delay=" + delay + " dur=" + duration);
//    log.debug(Util.getTimeDotted() + ": before rx-tx");
    String msgType = "unk. type";
    switch(macMsg.getType()) {
      case MacDcfMessage.TYPE_DATA: msgType = "DATA"; break;
      case Mac802_11Message.TYPE_RTS:  msgType = "RTS"; break;
      case Mac802_11Message.TYPE_CTS:  msgType = "CTS"; break;
      case MacDcfMessage.TYPE_ACK:  msgType = "ACK"; break;
    }
    
    JistAPI.sleep(delay);
//    log.debug(Util.getTimeDotted() + ": " + msgType + " to " + macMsg.getDst()
//        + ": after rx-tx");
    JistAPI.sleep(duration);
//    log.debug(Util.getTimeDotted() + ": after tx");
    
    // forward message to other MAC layer
    
    //System.out.println("t: " + JistAPI.getTime() + " - Forwarding to MAC.");
//    for(int i=0; i<20; i++)
//      System.out.println(Boolean.toString(Constants.random.nextBoolean()));
//    if(Constants.random.nextBoolean()) {
//      System.out.println("??? SUCCESSFUL TRANSMISSION!");

    for (int i = macs.length -1 ; i >= 0; --i)
      if (macMsg.getDst().equals(macs[i].getAddress())) {
        if (macMsg.getType() == MacDcfMessage.TYPE_DATA) {
          if (++pktCtr[i] > dropPackets) macs[i].receive(msg, anno);
          else {
            log.debug(Util.getTimeDotted() + " DROPPING PACKET to rid:" + macs[i].getAddress().getId());
//            pktCtr[i]++;
          }
        } else if (macMsg.getType() == MacDcfMessage.TYPE_ACK) {
          if (++ackCtr[i] > dropAcks) macs[i].receive(msg, anno);
          else {
            log.debug(Util.getTimeDotted() + " DROPPING ACK to rid:" + macs[i].getAddress().getId());
//            ackCtr[i]++;
          }
        } else {
          /*if (++ackCtr[i] > dropAcks) */
          macs[i].receive(msg, anno);
//          else {
//            log.debug(Util.getTimeDotted() + " DROPPING ACK to rid:" + macs[i].radioInfo.getId());
////            ackCtr[i]++;
//          }
        }
        break;
      }


    // schedule end of transmission
    self.endTransmit();

  }

  public void transmit(Message msg, MessageAnno anno, long predelay,
      long duration, long postdelay) {
    // TODO Auto-generated method stub
    
  }

}
