package brn.swans.route.metric;

import java.util.List;

import jist.swans.net.NetAddress;
import jist.swans.radio.RadioInterface;

public interface RouteMetricInterface {

  public static class NoLinkExistsException extends Exception {
    private static final long serialVersionUID = 1L;

    public NoLinkExistsException(String message, Throwable cause) {
      super(message, cause);
    }

    public NoLinkExistsException(String message) {
      super(message);
    }

    public NoLinkExistsException(Throwable cause) {
      super(cause);
    }
  }

  public static class NoRouteExistsException extends Exception {
    private static final long serialVersionUID = 1L;
    public NoRouteExistsException(String message, Throwable cause) {
      super(message, cause);
    }

    public NoRouteExistsException(String message) {
      super(message);
    }

    public NoRouteExistsException(Throwable cause) {
      super(cause);
    }
  }

//  /** forward only route request which came from a link with a better metric of this */
//  final static int MAX_LINK_METRIC_FOR_RREQ_FORWARDING = 5000;
//
//  /** constant for an non-existing link */
//  final static int INVALID_ROUTE_METRIC = -1;
//
//  final static int NB_MIN_METRIC = 5000;
//
//  final static int MAX_ROUTE_METRIC_FOR_TX = 1016;

  interface EventListener {
    /**
     * Called when a new link is added or updated in the link table.
     */
    void onUpdate(Object from, Object to, int old_metric, int metric);
  }

  /**
   * Add the given listener to the queue of listeners to be notified on changes.
   *
   * @param listener the listener to add.
   */
  void addEventListener(EventListener listener);


  /**
   * Get the neighbors of node addr.
   *
   * @param addr the node to consider
   * @return the neighbors of node addr
   */
  List /*Object*/ getNeighbors(NetAddress addr);

  /**
   * Get the metric of link addrSrc addrDst
   *
   * @param addrSrc the start point of the link
   * @param addrDst the end point of the link
   * @return the links metric
   * @throws NoLinkExistsException 
   */
  int getLinkMetric(NetAddress addrSrc, NetAddress addrDst) throws NoLinkExistsException;

  /**
   * Get the additional cookie associated with this link. this is metric 
   * specific.
   *
   * @param addrSrc the start point of the link
   * @param addrDst the end point of the link
   * @return the links metric info object
   */
  LinkTable.LinkData getLink(NetAddress addrSrc, NetAddress addrDst);

  /**
   * Update the given links
   *
   * @param a
   * @param b
   * @param metric
   * @param permanent
   * @return true if successful, false otherwise
   */
  boolean updateBothLinks(Object a, Object b, int metric, boolean permanent);

  /**
   * Get a route from addrSrc to addrDst
   *
   * @param addrSrc
   * @param addrDst
   * @return route from addrSrc to addrDst
   * @throws NoRouteExistsException 
   */
  List queryRoute(NetAddress addrSrc, NetAddress addrDst, int maxLinkMetric, int maxLinkEtx) throws NoRouteExistsException;

  List queryRoute(NetAddress addrSrc, NetAddress addrDst, int maxLinkMetric, int maxLinkEtx, boolean fromCache) throws NoRouteExistsException;

  /**
   * Get the metric of the given route.
   *
   * @param route
   * @param maxLinkMetric
   * @return the metric of the given route.
   * @throws NoLinkExistsException 
   * @throws NoRouteExistsException 
   */
  int getRouteMetric(List route, int maxLinkMetric, int maxLinkEtx) 
    throws NoRouteExistsException, NoLinkExistsException;

  /**
   * Get the home channel of node <code>nb</code>
   *
   * @param nb the node to query for
   * @return the home channel or RadioInterface.RFChannel.INVALID_ROUTE_METRIC, if not known
   */
  RadioInterface.RFChannel getHomeChannel(NetAddress nb);

  /**
   * Returns my own home channel.
   *
   * @return my home channel or RadioInterface.RFChannel.INVALID_ROUTE_METRIC, if not known
   */
  RadioInterface.RFChannel getHomeChannel();

  /**
   * Returns an array of available channels.
   *
   * @return array of available channels.
   */
  RadioInterface.RFChannel[] getChannels();


  ArpTableInterface getArpTable();


  void removeLink(NetAddress addr1, NetAddress addr2);

  /**
   * @deprecated use {@link RouteMetricInterface#queryRoute(NetAddress, NetAddress, int, int)}
   * TODO remove
   */
  List queryRoute(NetAddress src, NetAddress dst, int csMinMetric);


  /**
   * @deprecated use {@link RouteMetricInterface#getRouteMetric(List, int, int)}
   * TODO remove
   */
  int getRouteMetric(List route, int invalidRouteMetric);


  /**
   * @deprecated use {@link RouteMetricInterface#getLinkMetric(NetAddress, NetAddress)}
   * TODO remove
   */
  int getLinkMetricOld(NetAddress prev, NetAddress curr);
}
