package brn.sim.handler;

import jist.swans.misc.Event;
import jist.swans.misc.MessageAnno;
import jist.swans.net.AbstractNet;
import jist.swans.net.NetMessage;
import jist.swans.radio.RadioInterface;
import brn.sim.data.javis.DequeueTraceEvent;
import brn.sim.data.javis.EnqueueTraceEvent;
import brn.sim.data.javis.HopTraceEvent;
import brn.sim.data.javis.LinkDropTraceEvent;
import brn.sim.data.javis.MarkTraceEvent;
import brn.sim.data.javis.ReceiveTraceEvent;
import brn.sim.data.javis.Trace;

/**
 * Captures node positions as well as all NET events.
 *
 * @author kurth
 */
public class JavisNetEventHandler extends JavisFieldEventHandler {

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

  protected EnqueueTraceEvent enqueueTraceEvent   = new EnqueueTraceEvent();
  protected DequeueTraceEvent dequeueTraceEvent   = new DequeueTraceEvent();
  protected HopTraceEvent hopTraceEvent           = new HopTraceEvent();
  protected ReceiveTraceEvent receiveTraceEvent   = new ReceiveTraceEvent();
  protected LinkDropTraceEvent linkDropTraceEvent = new LinkDropTraceEvent();
  protected MarkTraceEvent channelTraceEvent         = new MarkTraceEvent();

  // ////////////////////////////////////////////////
  // initialization
  //

  public JavisNetEventHandler(Trace trace) {
    super(trace);
  }

  public void registerHandlers() {
    super.registerHandlers();
    Event.addHandler(AbstractNet.EnqueueEvent.class, new EnqueueHandler());
    Event.addHandler(AbstractNet.DequeueEvent.class, new DequeueHandler());
    Event.addHandler(AbstractNet.SendToMacEvent.class, new SendToMacHandler());
    Event.addHandler(AbstractNet.SendToMacFinishEvent.class, new SendToMacFinishHandler());
    Event.addHandler(AbstractNet.RecvFromMacEvent.class, new RecvFromMacHandler());
    Event.addHandler(AbstractNet.LinkDropEvent.class, new LinkDropHandler());
  }

  // ////////////////////////////////////////////////
  // event handlers
  //

  protected class EnqueueHandler implements Event.Handler {
    public void handle(Event event) {
      AbstractNet.EnqueueEvent ev = (AbstractNet.EnqueueEvent) event;
      NetMessage.Ip msg = (NetMessage.Ip) ev.data;

      enqueueTraceEvent.set(ev.time, ev.localAddr.getId(), ev.nextHop.getId(),
          msg.getProtocol(), msg.getSize(), msg.getId(), ev.queue.size());
      handleTrace(enqueueTraceEvent);
    }
  }

  protected class DequeueHandler implements Event.Handler {
    public void handle(Event event) {
      AbstractNet.DequeueEvent ev = (AbstractNet.DequeueEvent) event;
      NetMessage.Ip msg = (NetMessage.Ip) ev.data;

      dequeueTraceEvent.set(ev.time, ev.localAddr.getId(), ev.nextHop.getId(),
          msg.getProtocol(), msg.getSize(), msg.getId(), ev.queue.size());
      handleTrace(dequeueTraceEvent);
    }
  }

  protected class SendToMacHandler implements Event.Handler {
    public void handle(Event event) {
      AbstractNet.SendToMacEvent ev = (AbstractNet.SendToMacEvent) event;
      NetMessage.Ip msg = (NetMessage.Ip) ev.data;

      if (ev.anno != null) {
        RadioInterface.RFChannel rfChannel
            = (RadioInterface.RFChannel) ev.anno.get(MessageAnno.ANNO_MAC_RF_CHANNEL);

        if (null != rfChannel) {
          channelTraceEvent.set(ev.time, TRACE_CHANNEL_EVENT_NAME,
                ev.localAddr.getId(), rfChannel.getChannel(), MarkTraceEvent.SHAPE_CIRCLE, false);
          handleTrace(channelTraceEvent);
        }
      }

      hopTraceEvent.set(ev.time, ev.localAddr.getId(), ev.nextHop.getId(),
          msg.getProtocol(), msg.getSize(), msg.getId());
      handleTrace(hopTraceEvent);
    }
  }

  protected class SendToMacFinishHandler implements Event.Handler {
    public void handle(Event event) {
      AbstractNet.SendToMacFinishEvent ev = (AbstractNet.SendToMacFinishEvent) event;

      /*
      NetMessage.Ip msg = null;

      if (ev.data instanceof NetMessage.Ip) {
        msg = (NetMessage.Ip) ev.data;
      } else if (ev.data instanceof MacMessage.Management) {
        MacMessage.Management macMsg = (MacMessage.Management)ev.data;
        msg = (NetMessage.Ip) ev.data;
      } else {
        throw new IllegalArgumentException("Wrong type.");
      }
      */
      if (ev.anno != null) {
        RadioInterface.RFChannel rfChannel
                = (RadioInterface.RFChannel) ev.anno.get(MessageAnno.ANNO_MAC_RF_CHANNEL);

        if (null != rfChannel) {
          channelTraceEvent.set(ev.time, TRACE_CHANNEL_EVENT_NAME,
                ev.localAddr.getId(), rfChannel.getChannel(), MarkTraceEvent.SHAPE_CIRCLE, true);
          handleTrace(channelTraceEvent);
        }
      }
    }
  }

  protected class RecvFromMacHandler implements Event.Handler {
    public void handle(Event event) {
      AbstractNet.RecvFromMacEvent ev = (AbstractNet.RecvFromMacEvent) event;
      NetMessage.Ip msg = (NetMessage.Ip) ev.data;

      receiveTraceEvent.set(ev.time, msg.getSrc().getId(), ev.localAddr.getId(),
          msg.getProtocol(), msg.getSize(), msg.getId());
      handleTrace(receiveTraceEvent);
    }
  }

  protected class LinkDropHandler implements Event.Handler {
    public void handle(Event event) {
      AbstractNet.LinkDropEvent ev = (AbstractNet.LinkDropEvent) event;
      NetMessage.Ip msg = (NetMessage.Ip) ev.data;

      long src = ev.incoming ? ev.nextHop.getId()   : ev.localAddr.getId();
      long dst = ev.incoming ? ev.localAddr.getId() : ev.nextHop.getId();
      linkDropTraceEvent.set(ev.time, src, dst,
          msg.getProtocol(), msg.getSize(), msg.getId());
      handleTrace(linkDropTraceEvent);
    }
  }
}
