package test.rate;

import java.util.ArrayList;

import org.apache.log4j.Logger;

import jist.runtime.JistAPI;
import jist.runtime.JistAPI.Continuation;
import jist.swans.mac.MacAddress;
import jist.swans.mac.MacInterface;
import jist.swans.misc.Message;
import jist.swans.misc.MessageAnno;
import jist.swans.misc.Util;
import jist.swans.net.MessageQueue;
import jist.swans.net.NetAddress;
import jist.swans.net.NetInterface;
import jist.swans.net.NetMessage.Ip;

public class BitrateTestNet implements NetInterface {

  // Logger
  public static final Logger log = Logger.getLogger(BitrateTestNet.class); 
  
  // entity hookup
  /** self-referencing proxy entity. */
  protected NetInterface self;

  /** local network address. */
  protected NetAddress localAddr;
  
  /** mac interface */
  protected MacInterface mac;
  
  /** outgoing packet queue. */
  protected MessageQueue q;
  
  /** MacAddress of receiver */
  protected MacAddress recvMac;
  
  /** whether link layer is busy. */
  protected boolean busy;
  
  /** time last message was sent */
  private long timeSent;

  /** @return Self-referencing proxy entity*/
  NetInterface getProxy() {
    return self;
  }
  
  /** A list of handlers to call in certain events. */
  ArrayList netHandlers = null; 
  
  /** Constructor
   * 
   * @param addr Address of this net interface
   * @param mac MAC interface reference
   * @param recvMac MAC address of the receiver of all packets sent from this STA
   */
  public BitrateTestNet(NetAddress addr, MacInterface mac, MacAddress recvMac) {
    // proxy entity
    this.self = (NetInterface) JistAPI.proxy(new NetInterface.Dlg(this),
        NetInterface.class);
    // Net address
    this.localAddr = addr;
    // MAC interface
    this.mac = mac;
    // Receiver MAC address
    this.recvMac = recvMac;
    // Init handler list
    netHandlers = new ArrayList();
  }
  
  public NetAddress getAddress() throws Continuation {
    return localAddr;
  }

  /** {@inheritDoc} */
  public void receive(Message msg, MacAddress lastHop, byte macId,
      boolean promiscuous, MessageAnno anno) {
    // get the message from the MAC layer
    for (int i=0; i < netHandlers.size(); i++)
      ((NetHandler) netHandlers.get(i)).onReceive();
  }

  /** {@inheritDoc} */
  public void send(Message msg, NetAddress dst, short protocol, byte priority, 
      byte ttl, MessageAnno anno) {
    for (int i=0; i < netHandlers.size(); i++)
      ((NetHandler) netHandlers.get(i)).onSend();
    
    timeSent = JistAPI.getTime();
//    log.debug(Util.getTimeDotted() + " -  send  - msg: " 
//        + msg.toString().trim() + ", dest: " + recvMac);
    // Hand message down to MAC layer
    mac.send(msg, recvMac, null);

  }

  /** {@inheritDoc} */
  public void send(Ip msg, int interfaceId, MacAddress nextHop, MessageAnno anno) {
    // TODO Auto-generated method stub

  }

  /** {@inheritDoc} */
  public void endSend(Message msg, int netid, MessageAnno anno) {
    for (int i=0; i < netHandlers.size(); i++)
      ((NetHandler) netHandlers.get(i)).onEndSend();
    
    long t = JistAPI.getTime();
//    log.debug(Util.getTimeDotted() + " - endSnd - msg: " + msg.toString().trim() 
//        + ", netId: " + netid + ", dur: " + (t - timeSent));

  }

  /** Add a handler to the list */
  public void addNetHandler(NetHandler handler) {
    netHandlers.add(handler);
  }
  
  public static interface NetHandler {
    
    public void onReceive();
    
    public void onSend();
    
    public void onEndSend();
  }

}
