package test.rate;

import java.util.Hashtable;

import org.apache.log4j.Logger;

import jist.runtime.JistAPI;
import jist.swans.Constants;
import jist.swans.mac.MacAddress;
import jist.swans.misc.Message;
import jist.swans.misc.MessageAnno;
import jist.swans.misc.Util;
import jist.swans.net.NetAddress;
import jist.swans.net.NetInterface;
import jist.swans.net.NetMessage;
import jist.swans.route.AbstractRoute;
import jist.swans.route.RouteInterface;

/**
 * A dumb routing class with a simple mapping of net addresses to the mac
 * address. This circumvents the necessity of sending packets to find routes.
 * 
 * @author Oliver Friedrich
 *
 */
public class RouteDumb extends AbstractRoute implements RouteInterface
{
  /** logger */
  public static final Logger log = Logger.getLogger(RouteDumb.class);
  
  /** routing proxy */
  RouteInterface self;
  
  /** network entity */
  NetInterface netEntity;
  
  /** network address */
  NetAddress localAddr;
  
  /** netaddress -> macaddress map */
  Hashtable netMacTable;
  
  public RouteDumb(NetAddress localAddr) {
    this.localAddr = localAddr;
    netMacTable = new Hashtable();
    self = (RouteInterface)JistAPI.proxy(new RouteInterface.Dlg(this),
        RouteInterface.class);
  }
  
  //////////////////////////////////////////////////
  // entity hookup
  //

  /**
   * Sets the interface to the network layer.
   *
   * @param netEntity the interface to the network layer
   */
  public void setNetEntity(NetInterface netEntity)
  {
    this.netEntity = netEntity;
  }

  /**
   * Gets the proxy interface for this object.
   *
   * @return the proxy <code>RouteInterface.Dsr</code> interface for this object
   */
  public RouteInterface getRouteProxy()
  {
    return self;
  }
  
  /////////////////////////////////////////////////
  // convenience functions
  //
  
  public Hashtable getNetMacTable()
  {
    return netMacTable;
  }
  
  public void setNetMacTable(Hashtable ht)
  {
    netMacTable = ht;
  }
  
  public void setNetAddressMacAddressEntry(NetAddress net, MacAddress mac)
  {
    netMacTable.put(net, mac);
  }
  
  public MacAddress getMacAddressFromNetAddress(NetAddress net)
  {
    Object o = netMacTable.get(net);
    if (o == null)
      throw new RuntimeException("MacAddress unknown for NetAddress " + net);
    return (MacAddress)o;
  }

  /////////////////////////////////////////////////
  // message functions
  //
  
  public void peek(NetMessage msg, MacAddress lastHop, MessageAnno anno)
  {
    log("peek");
  }

  public void send(NetMessage msg, MessageAnno anno)
  {
    log("send");
    NetMessage.Ip ipmsg = (NetMessage.Ip) msg;
    netEntity.send(ipmsg, Constants.NET_INTERFACE_DEFAULT, 
        getMacAddressFromNetAddress(ipmsg.getDst()), anno);
  }

  public void receive(Message msg, NetAddress src, MacAddress lastHop, byte macId, NetAddress dst, byte priority, byte ttl, MessageAnno anno)
  {
    log("receive");
    NetMessage.Ip msgIn = (NetMessage.Ip) msg;
    // Now go through some strange contortions to get this message received by
    // the proper protocol handler
    NetMessage.Ip newIp = new NetMessage.Ip(msgIn.getPayload(), src, dst,
      msgIn.getProtocol(), priority, ttl);        

    netEntity.receive(newIp, lastHop, macId, false, null);

  }

  void log(String msg) {
    if (log.isDebugEnabled())
      log.debug(Util.getTimeDotted() + ": " + msg);
  }
}
