package jist.swans.route;

import java.util.List;

import jist.swans.Node;
import jist.swans.misc.Event;
import jist.swans.misc.Message;
import jist.swans.misc.MessageAnno;
import jist.swans.misc.MessageEvent;
import jist.swans.net.NetAddress;

/**
 * Base class for all route classes, encapsulates common functions like
 * stats generations etc.
 *
 * @author kurth
 */
public abstract class AbstractRoute {

  // ////////////////////////////////////////////////
  // Events
  //

  public static class PacketForwardedEvent extends MessageEvent {
    public NetAddress lastIp;
    public NetAddress localAddr;

    public PacketForwardedEvent() { super(false); }
    public PacketForwardedEvent(int nodeId) { super(nodeId); }

    public void handle(Message msg, MessageAnno anno, NetAddress lastIp,
        NetAddress localAddr) {
      this.lastIp = lastIp;
      this.localAddr = localAddr;
      super.handle(msg, anno);
    }
  }

  public static class DuplicateEvent extends PacketForwardedEvent {
    public DuplicateEvent() { super(); }
    public DuplicateEvent(int nodeId) { super(nodeId); }
  }

  public static class CandSelectedEvent extends MessageEvent {
    public List candidates;
    public int packetId;

    public CandSelectedEvent() { super(false); }
    public CandSelectedEvent(int nodeId) { super(nodeId); }

    public void handle(int packetId, List candidates, Message data, MessageAnno anno) {
      this.candidates = candidates;
      this.packetId = packetId;
      super.handle(data, anno);
    }
  }

  public static class CandMetricEvent extends Event {
    public List candidates;
    public int metricToSrc;
    public int metricToDst;

    public void handle(int nodeId, List candidates, int metricToSrc, int metricToDst) {
      this.candidates = candidates;
      this.metricToSrc = metricToSrc;
      this.metricToDst = metricToDst;
      super.handle(nodeId);
    }
  }

  public static class DiscardEvent extends MessageEvent {
    public DiscardEvent() { super(false); }
    public DiscardEvent(int nodeId) { super(nodeId); }
  }

  public static class RetryEvent extends MessageEvent {
    public int tryCount;
    public boolean passiveRetry;

    public RetryEvent() { super(false); }
    public RetryEvent(int nodeId) { super(nodeId); }

    public void handle(Message data, MessageAnno anno, int tryCount, boolean passiveRetry) {
      this.tryCount = tryCount;
      this.passiveRetry = passiveRetry;
      super.handle(data, anno);
    }
  }

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

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

  protected Node node;

  protected PacketForwardedEvent packetForwardedEvent;

  protected DuplicateEvent duplicateEvent;

  protected CandSelectedEvent candSelectedEvent;

  protected DiscardEvent discardEvent;
  
  protected RetryEvent retryEvent;

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

  public AbstractRoute() {
    packetForwardedEvent = new PacketForwardedEvent();
    duplicateEvent = new DuplicateEvent();
    candSelectedEvent = new CandSelectedEvent();
    discardEvent = new DiscardEvent();
    retryEvent = new RetryEvent();
  }
  
  // ////////////////////////////////////////////////
  // accessors
  //

  public abstract RouteInterface getRouteProxy();

  public Node getNode() {
    return node;
  }

  public void setNode(Node node) {
    this.node = node;

    packetForwardedEvent = new PacketForwardedEvent(node.getNodeId());
    duplicateEvent = new DuplicateEvent(node.getNodeId());
    candSelectedEvent = new CandSelectedEvent(node.getNodeId());
    discardEvent = new DiscardEvent(node.getNodeId());
    retryEvent = new RetryEvent(node.getNodeId());
  }


}
