package jist.swans.misc;

import java.util.HashMap;

import jist.runtime.JistAPI;

/**
 * Message annotation class. On send, the net layer creates the annotation and
 * gives them down the network stack. After the physical layer has transmitted
 * the packet, the annotations are given back up the stack.
 * On receive, the physical layer creates the packet annotation and gives them
 * up.
 *
 * @author kurth
 */
public class MessageAnno extends HashMap implements JistAPI.Timeless, Cloneable {
  private static final long serialVersionUID = 1L;

  //////////////////////////////////////////////////
  // Annotations - FIELD
  //

  //////////////////////////////////////////////////
  // Annotations - RADIO
  //

  /** Annotation for received signal power (in mW) Double */
  public static final Integer ANNO_RADIO_SIGNAL_POWER = new Integer(101);
  /** Annotation for noise level at receiver */
  public static final Integer ANNO_RADIO_NOISE_LEVEL  = new Integer(102);
  /** Annotation for reception status */
  public static final Integer ANNO_RADIO_RECV_STATUS  = new Integer(103);
  /** interference power level */
  public static final Integer ANNO_RADIO_INTF_POWER   = new Integer(104);
  /** SNR of the received packet (linear scale, not dB!) Double */
  public static final Integer ANNO_RADIO_PACKET_SNR   = new Integer(105);
  /** PER of the received packet */
  public static final Integer ANNO_RADIO_PACKET_PER   = new Integer(106);
  /** bit errors of the received packet by start of chunk in bits*/
  public static final Integer ANNO_RADIO_PACKET_BER   = new Integer(107); // SortedMap<Long, BitErrorMask>
  /** position (Integer) at which the packet is truncated, or null if it isn't */
  public static final Integer ANNO_RADIO_PACKET_TRUNCATED = new Integer(108);
  /** unique message id */
  public static final Integer ANNO_MSG_ID             = new Integer(109);

  //////////////////////////////////////////////////
  // Annotations - MAC
  //

  /** Annotation indicating a successful transmission */
  public static final Integer ANNO_MAC_SUCCESS      = new Integer(201);  // Boolean
  /** Annotation indicating the number of retries during transmission */
  public static final Integer ANNO_MAC_RETRIES      = new Integer(202);  // Byte
  /** Annotation for the transmitted/received bitrate */
  public static final Integer ANNO_MAC_BITRATE      = new Integer(203);  // Integer
  /** Annotation for the channel to use / used */
  public static final Integer ANNO_MAC_RF_CHANNEL   = new Integer(204);
  /** contains the list of candidates (both rx/tx) */
  public static final Integer ANNO_MAC_CANDIDATES   = new Integer(205); // List<MacAddress>
  /** contains the index of the local node within the (received ) candidate set */
  public static final Object ANNO_MAC_CAND_IDX      = new Integer(206);

  // status
  public static final Integer ANNO_MAC_FORWARD_PREF = new Integer(207);
  public static final Integer ANNO_MAC_RECV_ACKS    = new Integer(208);
  public static final Integer ANNO_MAC_COOKIE       = new Integer(209);


  /** Annotation for the transmitted/received bitrate */
  public static final Integer ANNO_MAC_DURATION     = new Integer(210);  // Integer
  public static final Integer ANNO_MAC_RECV_TIME    = new Integer(211);  // Long

  /** source address of the contained ip packet */
  public static final Integer ANNO_MAC_NETSRC       = new Integer(212); // NetAddress
  /** id of the contained ip packet */
  public static final Integer ANNO_MAC_NETID        = new Integer(213); // Short
  /** ttl of the contained ip packet */
  public static final Integer ANNO_MAC_NETTTL       = new Integer(214); // Byte
  /** source address of a mac packet */
  public static final Integer ANNO_MAC_SOURCE       = new Integer(215); // MacAddress
  /** mac sequence number annotation */
  public static final Integer ANNO_MAC_SEQNO        = new Integer(216); // Short
  /** mac retry bit annotation */
  public static final Integer ANNO_MAC_RETRY        = new Integer(217); // Boolean
  /** index of the final destination within the candidate set, or -1 */
  public static final Integer ANNO_MAC_FINALDST_IDX = new Integer(218); // Byte

  public static final Integer ANNO_MAC_OPT_CANDS    = new Integer(219);

  public static final Integer ANNO_MAC_RTS_CANDIDATES = new Integer(220);
  /** forwarder of the frame */
  public static final Integer ANNO_MAC_FORWARDER = new Integer(221); // Set<MacAddress>

  //////////////////////////////////////////////////
  // Annotations - NET
  //

  /** arrival time at net layer */
  public static final Integer ANNO_NET_ARRIVAL = new Integer(301); // Long
  /** start of the service time at the net layer */
  public static final Integer ANNO_NET_SERVICE = new Integer(302); // Long

  //////////////////////////////////////////////////
  // Annotations - ROUTE
  //

  /** identification of the current flow, transported in the dsr id option field */
  public static final Integer ANNO_RTG_FLOWID = new Integer(501); // Integer
  /** identification of the current packet with the flow */
  public static final Integer ANNO_RTG_PACKETID = new Integer(502); // Integer
  /** hop count, routing meta information */
  public static final Integer ANNO_RTG_HOPCOUNT = new Integer(503); // Integer
  /** list of forwarders */
  public static final Integer ANNO_RTG_FORWARDER = new Integer(504); // List<NetAddress>
  /** the address of the last forwarding hop */
  public static final Integer ANNO_RTG_LASTHOP = new Integer(505); // NetAddress


  //////////////////////////////////////////////////
  // Annotations - TRANS
  //

  /** the tx time */
  public static final Integer ANNO_TRANS_TXTIME = new Integer(601); // Long

  //////////////////////////////////////////////////
  // Annotations - APP
  //

//  //////////////////////////////////////////////////
//  // Interface
//  //
//
//  public abstract Object get(Object key);
//
//  public abstract Object put(Object key, Object value);
//
//  public abstract Object clone();
//
//  public MessageAnno create() {
//  }
//
//  public MessageAnno create() {
//  }
//
//  //////////////////////////////////////////////////
//  // List Impl
//  //
//
//  protected static class ListImpl extends MessageAnno {
//    private List keys;
//    private List values;
//    private MessageAnno chain = null;
//
//
//    protected ListImpl() {
//      // TODO use pooling ??
//      keys = new ArrayList(20);
//      values = new ArrayList(20);
//    }
//
//    protected ListImpl(MessageAnno other) {
//      // chain message annos, make them copy-on-write
//      chain = other;
//      keys = new ArrayList(20);
//      values = new ArrayList(20);
//    }
//
//    public Object get(Object key) {
//      // Always look first into own storage
//      int index = this.keys.indexOf(key);
//      if (-1 != index)
//        return this.values.get(index);
//      if (null != this.chain)
//        return this.chain.get(key);
//      return null;
//    }
//
//    public Object put(Object key, Object value)  {
//      int index = this.keys.indexOf(key);
//      if (-1 == index) {
//        this.keys.add(key);
//        this.values.add(value);
//        if (null != this.chain)
//          return this.chain.get(key);
//        return null;
//      }
//
//      Object oldValule = this.values.get(index);
////        this.keys.add(index, key);
//      this.values.set(index, value);
//      return oldValule;
//    }
//
//    public Object clone() {
//      return new ListImpl(this);
//    }
//
//    public String toString() {
//      StringBuilder builder = new StringBuilder("MessageAnno[");
//      for (int i = 0; i < keys.size(); i++) {
//        builder.append(keys.get(i));
//        builder.append("=");
//        builder.append(values.get(i));
//        builder.append(", ");
//      }
//      builder.append("]");
//      return builder.toString();
//    }
//
//  }
//
//  //////////////////////////////////////////////////
//  // List Impl
//  //
//
//  protected static class MapImpl extends MessageAnno {
//    private Map map;
//
//    protected MapImpl() {
//      this.map = new HashMap();
//    }
//
//    protected MapImpl(Map other) {
//      this.map = new HashMap(other);
//    }
//
//    public Object clone() {
//      return super.clone();
//    }
//
//    public Object get(Object key) {
//      return map.get(key);
//    }
//
//    public Object put(Object key, Object value) {
//      return map.put(key, value);
//    }
//  }
}
