/**
 * 
 */
package brn.sim.handler;

import org.apache.log4j.Logger;

import jist.swans.field.AbstractField;
import jist.swans.misc.Event;
import jist.swans.misc.Location;
import brn.sim.DataManager;
import brn.sim.DataManager.DataContributor;
import brn.sim.data.AbstractDiagramData;
import brn.sim.data.DiagramData;

/**
 * @author ofriedri
 */
public class StatsFieldHandler extends DataContributor {

  private static final Logger log = Logger.getLogger(StatsFieldHandler.class);
  
  private static final String ID = "StatsRateHandler";

  /** Data captured per node */
  private NodeData[] nodeData;

  private int referenceNodeId;
  
  private Location refNodeLoc;

  public StatsFieldHandler(int nodes) {
    this.nodeData = new NodeData[nodes + 1];
    this.referenceNodeId = 1;
    this.refNodeLoc = new Location.Location2D(0, 50);
    if (log.isDebugEnabled())
      log.debug("Created StatsFieldHandler");
  }

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

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

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

        getNodeData(ev.nodeId).getDistanceToRefNode().addNextTimePoint(ev.time,
            ev.loc.distance(refNodeLoc));
      }
    });
  }

  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];
  }

  /**
   * Class encapsulating simulation data on a per node basis
   */
  public class NodeData {
    protected DiagramData distanceToRefNode = null;

    protected int id;

    private String category;

    public NodeData(int id) {
      this.id = id;
      this.category = "Node " + id;
    }

    public DiagramData getDistanceToRefNode() {
      if (distanceToRefNode == null) {
        distanceToRefNode = new DiagramData(new String[] { category, "Field",
            "distance to " + referenceNodeId }, "time", "ms", "distance", "m",
            AbstractDiagramData.MARK);
        addData(distanceToRefNode, DataManager.LEVEL_BASIC);
      }
      return distanceToRefNode;
    }

  }
}
