package brn.sim.handler;

import jist.swans.misc.Event;
import jist.swans.misc.MessageAnno;
import jist.swans.trans.AbstractTrans;
import brn.sim.DataManager;
import brn.sim.DataManager.DataContributor;
import brn.sim.data.AbstractDiagramData;
import brn.sim.data.DiagramData;


/**
 * Handler for transport related data collection
 *
 * @author kurth
 */
public class StatsTransHandler extends DataContributor {

  //////////////////////////////////////////////////
  // data classes
  //

  protected class NodeData {
    protected int id;
    private String category;

    public NodeData(int id) {
      this.id = id;
      this.category = CATEGORY_NODE + Integer.toString(id);
    }

    private DiagramData arrivedPacketsPerFlow = null;
    protected DiagramData getArrivedPacketsPerFlow() {
      // Mac Discard counter
      if (null == arrivedPacketsPerFlow) {
        arrivedPacketsPerFlow = new DiagramData(
            new String[] {category, CATEGORY_TRANS, "arrived packets per flow"},
            "packet", "(id)", "flow", "id", AbstractDiagramData.MARK);
        addData(arrivedPacketsPerFlow, DataManager.LEVEL_ADDITIONAL);
      }

      return arrivedPacketsPerFlow;
    }
  }


  //////////////////////////////////////////////////
  // data members
  //

  private static final String ID = "StatsTransHandler";

  private static final String CATEGORY_TRANS = "Trans";
  private static final String CATEGORY_NODE = "Node ";

  private NodeData[] nodeData;

  protected double sampleLen;


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

  public StatsTransHandler(double sampleLen) {
    this.sampleLen = sampleLen;
    this.nodeData = new NodeData[20];
  }


  //////////////////////////////////////////////////
  // access
  //

//  public static String getCategory(String id) {
//    return "Trans " + id;
//  }

  public String getId() {
    return ID;
  }

  protected NodeData getNodeData(int id) {
    try {
      if (null == nodeData[id])
        nodeData[id] = new NodeData(id);
    }
    catch (ArrayIndexOutOfBoundsException e) {
      if (id > 50000)
        throw new RuntimeException("id to large");
      NodeData[] tmp = new NodeData[id + 100];
      System.arraycopy(nodeData, 0, tmp, 0, nodeData.length);
      nodeData = tmp;
      return getNodeData(id);
    }
    return nodeData[id];
  }


  //////////////////////////////////////////////////
  // event handling
  //

  /* (non-Javadoc)
   * @see brn.sim.DataManager.DataContributor#registerHandlers()
   */
  @Override
  public void registerHandlers() {
    super.registerHandlers();
    registerTransHandlers();
  }

  private void registerTransHandlers() {
    Event.addHandler(AbstractTrans.SegmentArrivedEvent.class, new Event.Handler() {
      public void handle(Event event) {
        AbstractTrans.SegmentArrivedEvent ev = (AbstractTrans.SegmentArrivedEvent) event;

        int flow = -1;
        int packet = -1;
        if (null != ev.anno) {
          Integer flowId = (Integer) ev.anno.get(MessageAnno.ANNO_RTG_FLOWID);
          Integer packetId = (Integer) ev.anno.get(MessageAnno.ANNO_RTG_PACKETID);
          if (null != flowId && null != packetId) {
            flow = flowId.intValue();
            packet = packetId.intValue();
          }
        }
//        if (-1 == flow || -1 == packet) {
//          if (ev.data instanceof AnnotatedMessage) {
//            AnnotatedMessage msg = (AnnotatedMessage) ev.data;
//            flow = msg.flowId;
//            packet = msg.packetId;
//          }
//        }
        if (-1 == flow || -1 == packet)
          return;

        getNodeData(ev.nodeId).getArrivedPacketsPerFlow().addNextPoint(packet,flow);
      }
    });
  }

}
