package brn.sim.handler;

import brn.sim.DataManager;
import brn.sim.data.TimeBar;
import brn.swans.mac.MacMcExORMessage;
import jist.swans.misc.Event;
import jist.swans.misc.MessageAnno;
import jist.swans.mac.AbstractMac;
import jist.swans.mac.MacDcfMessage;
import jist.swans.mac.Mac802_11Message;
import jist.swans.radio.RadioInterface;
import jist.swans.Constants;

public class TimeBarMacPacketHandler extends DataManager.DataContributor {

  // ////////////////////////////////////////////////
  // constants
  //

  private static final String ID = "TimeBarMacPacketHandler";

  // ////////////////////////////////////////////////
  // locals
  //

  private TimeBar timeBar;

  // ////////////////////////////////////////////////
  // initialization
  //
  public TimeBarMacPacketHandler() {
    timeBar = new TimeBar(new String[] {"Global", "Mac", "Packet Timebar"});
  }

  public void registerHandlers() {

    // ////////////////////////////////////////////////
    // SendEvent
    //
    Event.addHandler(AbstractMac.SendEvent.class, new Event.Handler() {
      public void handle(Event event) {
        AbstractMac.SendEvent ev = (AbstractMac.SendEvent) event;

        boolean isAck = (ev.getData() instanceof MacMcExORMessage.Ack
            || ev.getData() instanceof MacDcfMessage.Ack);
        boolean isRts = (ev.getData() instanceof MacMcExORMessage.Rts
            || ev.getData() instanceof Mac802_11Message.Rts);
        boolean isCts = (ev.getData() instanceof MacMcExORMessage.Cts
            || ev.getData() instanceof Mac802_11Message.Cts);

        String text = "";
        if (isAck)
          text = "A";
        if (isRts)
          text = "RTS";
        if (isCts)
          text = "CTS";

        if (ev.getData() instanceof MacMcExORMessage)
          text = text + ((MacMcExORMessage)ev.getData()).getId();

        text = text + "/" + (ev.retry ? "1" : "0");
        if (ev.anno != null) {
          RadioInterface.RFChannel txChannel
                  = (RadioInterface.RFChannel)ev.anno.get(MessageAnno.ANNO_MAC_RF_CHANNEL);
          if (txChannel != null)
            text = text + "(" + txChannel.getChannel() + ")";
        }
        text = text + "/" + ev.phyBitRate / Constants.BANDWIDTH_1Mbps + "M";

        byte barcolor = TimeBar.COLOR_GREEN; // DATA
        if (isAck)
          barcolor = TimeBar.COLOR_DARK_GREEN; // ACK
        if (isRts)
          barcolor = TimeBar.COLOR_MAGENTA; // RTS
        if (isCts)
          barcolor = TimeBar.COLOR_CYAN; // CTS

        timeBar.add(ev.nodeId, ev.time, ev.time + ev.duration, barcolor, text);
      }
    });

    // ////////////////////////////////////////////////
    // ReceiveEvent
    //
    Event.addHandler(AbstractMac.ReceiveEvent.class, new Event.Handler() {
      public void handle(Event event) {
        AbstractMac.ReceiveEvent ev = (AbstractMac.ReceiveEvent) event;

        boolean isAck = (ev.getData() instanceof MacMcExORMessage.Ack
            || ev.getData() instanceof MacDcfMessage.Ack);
        boolean isRts = (ev.getData() instanceof MacMcExORMessage.Rts
            || ev.getData() instanceof Mac802_11Message.Rts);
        boolean isCts = (ev.getData() instanceof MacMcExORMessage.Cts
            || ev.getData() instanceof Mac802_11Message.Cts);

        String text = "";
        if (isAck)
          text = "A";
        if (isRts)
          text = "RTS";
        if (isCts)
          text = "CTS";

        if (ev.getData() instanceof MacMcExORMessage)
          text = text + ((MacMcExORMessage)ev.getData()).getId();

        if (ev.anno != null) {
          RadioInterface.RFChannel txChannel
                  = (RadioInterface.RFChannel)ev.anno.get(MessageAnno.ANNO_MAC_RF_CHANNEL);
          if (txChannel != null)
            text = text + "(" + txChannel.getChannel() + ")";

          Integer phyBitRate = ((Integer)ev.anno.get(MessageAnno.ANNO_MAC_BITRATE));
          if (phyBitRate != null)
            text = text + "/" + phyBitRate.intValue() / Constants.BANDWIDTH_1Mbps + "M";
        }
        byte barcolor = TimeBar.COLOR_YELLOW; // DATA + ACK
        if (isRts)
          barcolor = TimeBar.COLOR_DARK_MAGENTA; // RTS
        if (isCts)
          barcolor = TimeBar.COLOR_DARK_CYAN; // CTS
        if (ev.forwarder)
          barcolor = TimeBar.COLOR_DARK_RED; // DATA packet next forwarder

        timeBar.add(ev.nodeId, ev.realStart - ev.duration, ev.realStart, barcolor, text);
      }
    });

    // ////////////////////////////////////////////////
    // ReceiveForeignEvent
    //
    Event.addHandler(AbstractMac.ReceiveForeignEvent.class, new Event.Handler() {
      public void handle(Event event) {
        AbstractMac.ReceiveForeignEvent ev = (AbstractMac.ReceiveForeignEvent) event;

        boolean isAck = (ev.getData() instanceof MacMcExORMessage.Ack
            || ev.getData() instanceof MacDcfMessage.Ack);
        boolean isRts = (ev.getData() instanceof MacMcExORMessage.Rts
            || ev.getData() instanceof Mac802_11Message.Rts);
        boolean isCts = (ev.getData() instanceof MacMcExORMessage.Cts
            || ev.getData() instanceof Mac802_11Message.Cts);

        String text = "F";
        if (isAck)
          text = "FA";
        if (isRts)
          text = "FRTS";
        if (isCts)
          text = "FCTS";

        if (ev.getData() instanceof MacMcExORMessage)
          text = text + ((MacMcExORMessage)ev.getData()).getId();

        if (ev.anno != null) {
          RadioInterface.RFChannel txChannel
                  = (RadioInterface.RFChannel)ev.anno.get(MessageAnno.ANNO_MAC_RF_CHANNEL);
          if (txChannel != null)
            text = text + "(" + txChannel.getChannel() + ")";
          Integer phyBitRate = ((Integer)ev.anno.get(MessageAnno.ANNO_MAC_BITRATE));
          if (phyBitRate != null)
            text = text + "/" + phyBitRate.intValue() / Constants.BANDWIDTH_1Mbps + "M";
        }
        byte barcolor = TimeBar.COLOR_DARK_YELLOW; // DATA + ACK
        if (isRts || isCts)
          barcolor = TimeBar.COLOR_DARK_MAGENTA; // RTS+CTS

        timeBar.add(ev.nodeId, ev.time - ev.duration, ev.time, barcolor, text);
      }
    });

    // ////////////////////////////////////////////////
    // NavChangedEvent
    //
    Event.addHandler(AbstractMac.NavChangedEvent.class, new Event.Handler() {
      public void handle(Event event) {
        AbstractMac.NavChangedEvent ev = (AbstractMac.NavChangedEvent) event;

        if (ev.navValue > 0) {
          timeBar.add(ev.nodeId, ev.time, ev.navValue,
              TimeBar.COLOR_DARK_GRAY, "" + ev.initiator != null ?
                  "" + ev.initiator.getId() : "");
        }
      }
    });

/*
    Event.addHandler(AbstractMac.BackoffEvent.class, new Event.Handler() {
      public void handle(Event event) {
        AbstractMac.BackoffEvent ev = (AbstractMac.BackoffEvent) event;

        if (ev.waitedBo > 0) {
          timeBar.add(ev.nodeId, ev.time, ev.time + ev.waitedBo,
              TimeBar.COLOR_DARK_CYAN, "B");
        }
      }
    });
*/
  }


  // ////////////////////////////////////////////////
  // implementation
  //

  /**
   * @return the radioTimeBar
   */
  public TimeBar getTimeBar() {
    return timeBar;
  }

  /*
   * (non-Javadoc)
   * @see brn.sim.DataManager.DataContributor#getId()
   */
  public String getId() {
    return TimeBarMacPacketHandler.ID;
  }

  /* (non-Javadoc)
   * @see brn.sim.DataManager.DataContributor#setDataManager(brn.sim.DataManager)
   */
  public void setDataManager(DataManager manager) {
    super.setDataManager(manager);
    manager.addData(this, timeBar);
  }
}
