package brn.sim.handler;

import java.util.Arrays;
import java.util.List;

import jist.runtime.JistAPI;
import jist.swans.misc.Event;
import jist.swans.net.AbstractNet;
import jist.swans.net.NetMessage;
import jist.swans.net.QueuedMessage;
import brn.sim.DataManager;
import brn.sim.DataManager.DataContributor;
import brn.sim.data.TimeBar;
import brn.swans.net.NetTxDOR.IterableMessageQueue;

public class TimeBarNetQueueHandler extends DataContributor {

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

  private static final String ID = "TimeBarNetQueueHandler";


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

  private TimeBar netQueueTimeBar;

//  private TimeBar.Entry[] currentEntries;

  private long[] startTimes;

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

  public TimeBarNetQueueHandler() {
    netQueueTimeBar = new TimeBar(new String[] {"Global", "Net", "Queue Timebar"});
//    currentEntries = new TimeBar.Entry[20];
    startTimes = new long[20];
    Arrays.fill(startTimes, JistAPI.END);
  }

  private String getPacketId(NetMessage.Ip msg) {
    return msg.getSrc().getId() + "/" + msg.getId() + "/" + msg.getTTL();
  }

  public void registerHandlers() {
    Event.addHandler(AbstractNet.EnqueueEvent.class, new Event.Handler() {
      public void handle(Event event) {
        AbstractNet.EnqueueEvent ev = (AbstractNet.EnqueueEvent) event;
        String detail = "";

        try {
          if (startTimes[ev.nodeId] != JistAPI.END
              && 1000 < ev.time - startTimes[ev.nodeId]) {

            if (ev.queue instanceof IterableMessageQueue) {
              IterableMessageQueue q = (IterableMessageQueue) ev.queue;
              for (int pri = 0; pri < 3; pri++) {
                List packets = q.getQueue(pri);
                for (int i = 0; i < packets.size(); i++) {
                  QueuedMessage qmsg = (QueuedMessage) packets.get(i);
                  detail += getPacketId((NetMessage.Ip) qmsg.getPayload()) + " ";
                }
              }
            } else
              startTimes[ev.nodeId] = JistAPI.END;
            
              detail = "" + ev.queue.size();
              String text = getPacketId((NetMessage.Ip) ev.data);
              netQueueTimeBar.add(new TimeBar.Entry(ev.nodeId, startTimes[ev.nodeId],
                  ev.time, TimeBar.COLOR_GREEN, text, detail));
          }
        } catch(ArrayIndexOutOfBoundsException e) {
          long[] tmp = new long[ev.nodeId+20];
          System.arraycopy(startTimes, 0, tmp, 0, startTimes.length);
          startTimes = tmp;
          handle(event);
          return;
        } catch(ClassCastException e) {
          netQueueTimeBar.add(new TimeBar.Entry(ev.nodeId, startTimes[ev.nodeId],
              ev.time, TimeBar.COLOR_GREEN, "INVALID", detail));
        } catch(NullPointerException e) {
           netQueueTimeBar.add(new TimeBar.Entry(ev.nodeId, startTimes[ev.nodeId],
              ev.time, TimeBar.COLOR_GREEN, "INVALID", detail));
        }

        startTimes[ev.nodeId] = ev.time;
      }
    });

    Event.addHandler(AbstractNet.DequeueEvent.class, new Event.Handler() {
      public void handle(Event event) {
        AbstractNet.DequeueEvent ev = (AbstractNet.DequeueEvent) event;

        try {
          if (startTimes[ev.nodeId] != JistAPI.END
              && 1000 < ev.time - startTimes[ev.nodeId]) {

            String text = getPacketId((NetMessage.Ip) ev.data);
            String detail = "";

            if (ev.queue instanceof IterableMessageQueue) {
              IterableMessageQueue q = (IterableMessageQueue) ev.queue;
              for (int pri = 0; pri < 3; pri++) {
                List packets = q.getQueue(pri);
                for (int i = 0; i < packets.size(); i++) {
                  QueuedMessage qmsg = (QueuedMessage) packets.get(i);
                  detail += getPacketId((NetMessage.Ip) qmsg.getPayload()) + " ";
                }
              }
            } else
              detail = "" + ev.queue.size();

            netQueueTimeBar.add(new TimeBar.Entry(ev.nodeId, startTimes[ev.nodeId],
                  ev.time, TimeBar.COLOR_YELLOW, text, detail));
          }
        } catch(ArrayIndexOutOfBoundsException e) {
          long[] tmp = new long[ev.nodeId+20];
          System.arraycopy(startTimes, 0, tmp, 0, startTimes.length);
          startTimes = tmp;
          handle(event);
          return;
        }

        if (ev.queue == null ||  ev.queue.isEmpty())
          startTimes[ev.nodeId] = JistAPI.END;
        else
          startTimes[ev.nodeId] = ev.time;
      }
    });
  }


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

  /**
   * @return the radioTimeBar
   */
  public TimeBar getNetQueueTimeBar() {
    return netQueueTimeBar;
  }

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

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

}
