package test.sim.scenario;

import jist.swans.Constants;
import jist.swans.Node;
import jist.swans.misc.MessageAnno;
import jist.swans.net.NetAddress;
import jist.swans.net.NetIp;
import jist.swans.trans.TransUdp;
import brn.sim.AbstractDriver;
import brn.sim.AbstractParams;
import brn.sim.DeprecatedBasicParams;
import brn.sim.builder.BuilderException;
import brn.sim.builder.FieldBuilder;
import brn.sim.builder.MacBuilder;
import brn.sim.builder.MetricBuilder;
import brn.sim.builder.NetBuilder;
import brn.sim.builder.PathLossBuilder;
import brn.sim.builder.RadioBuilder;
import brn.sim.builder.RouteBuilder;
import brn.swans.app.UdpApplication;


public class Mac802_11eTest extends AbstractDriver {
  /** logger for mac events. */

  protected void setupApplication(AbstractParams opts, int nodeId, Node node) throws BuilderException {
    super.setupApplication(opts, nodeId, node);

//    DsrParams params = (DsrParams)opts;

    int txRate = 500;
    int txRate2 = 500;
    long start = 80 * Constants.SECOND;
    long end = start + 5 * Constants.SECOND + 500 * Constants.MILLI_SECOND;
    long start2 = end;
    long end2 = start2 + 5 * Constants.SECOND + 500 * Constants.MILLI_SECOND;
    final int txPort = 9000;
    final int txPort2 = 9001;

    final NetIp net = (NetIp)node.getNet();

//    if (2 == nodeId) {
//      final NetAddress receiver = new NetAddress(3);
//
//      JistAPI.sleep(start);
//
//      JistAPI.runAt(new Runnable() {
//        public void run() {
//          UdpMessage udp = new UdpMessage(txPort, txPort, new MessageBytes("as"));
//          Ip msg = new Ip(udp , net.getAddress(), receiver, Constants.NET_PROTOCOL_UDP,
//              Constants.NET_PRIORITY_D_BESTEFFORT, Constants.TTL_DEFAULT);
//          MessageAnno anno = new MessageAnno();
//          List lstCandidates = new ArrayList(3);
//          lstCandidates.add(new MacAddress(3));
//          lstCandidates.add(new MacAddress(4));
//          anno.put(MacTxDOR.ANNO_CANDIDATES, lstCandidates);
//          net.send(msg , 1, MacAddress.NULL, anno);
//        }
//      }, start);
//    }
//    else {
//      NetAddress receiver = null;
//
//      TransUdp udp = new TransUdp();
//      UdpApplication app = new UdpApplication(txPort, receiver, start, end, txRate, null);
//
//      udp.setNetEntity(net.getProxy());
//      net.setProtocolHandler(Constants.NET_PROTOCOL_UDP, udp.getProxy());
//      app.setUdpEntity(udp.getProxy());
//
//      node.addTransport(udp);
//      node.addApplication(app);
//
//      app.getProxy().run();
//    }


    TransUdp udp = new TransUdp();
    MessageAnno anno = new MessageAnno();
    // TODO set flow id
    anno.put(MessageAnno.ANNO_RTG_FLOWID, new Integer(0));
    UdpApplication app11 = null;
    UdpApplication app12 = null;
    UdpApplication app2 = null;
    if (1 == nodeId) {
      app11 = new UdpApplication(net.getAddress(), txPort,
          new NetAddress(opts.nodes), txPort, start, end, txRate, Constants.NET_PRIORITY_D_CONTROLLEDLOAD,
          "asdf".getBytes(), anno);
      app12 = new UdpApplication(net.getAddress(), txPort + 1,
          new NetAddress(opts.nodes), txPort, start, end, txRate, Constants.NET_PRIORITY_D_VIDEO, 
          "asdfkfdjngkjngjkadnfkljf nkjabfkdjnfkjgbndfdkgndagkndakdgndakgn".getBytes(), anno);
      //app.setMaxNumberOfPackets(50);
    } else {
      app11 = new UdpApplication(net.getAddress(), txPort, start, end);
      app12 = new UdpApplication(net.getAddress(), txPort + 1, start, end);
    }

    if (2 == nodeId) {
      app2 = new UdpApplication(net.getAddress(), txPort,
          new NetAddress(opts.nodes), txPort2, start2, end2, txRate2, Constants.NET_PRIORITY_D_VIDEO,
          "asdf".getBytes(), anno);
    } else {
      app2 = new UdpApplication(net.getAddress(), txPort2, start2, end2);
    }

    udp.setNetEntity(net.getProxy());
    net.setProtocolHandler(Constants.NET_PROTOCOL_UDP, udp.getProxy());
    app11.setUdpEntity(udp.getProxy());
    app12.setUdpEntity(udp.getProxy());
    app2.setUdpEntity(udp.getProxy());

    node.addTransport(udp);
    node.addApplication(app11);
    node.addApplication(app12);
    node.addApplication(app2);

    app11.getProxy().run();
    app12.getProxy().run();
    app2.getProxy().run();
  }

  public static void main(String[] args) {
    Mac802_11eTest test = new Mac802_11eTest();

    if (args.length < 1) {
      test.showUsage();
      return;
    }

    try {
    DeprecatedBasicParams params = new DeprecatedBasicParams();

    // set parameters
    params.endTime = 100;
    params.seed = 0;
    params.nodes = 3;
    params.assertion = true;
    params.handlerRadio = true;
    params.handlerRadioEx = true;
    params.handlerRadioTimeBar = true;
    params.handlerTXOP = true;
    params.dumpRadio = "dsr.tr";
    params.dumpFieldNam = "dsr.nam";
    params.dumpNet = true;
    params.seed = 2;
    params.handlerMacTimeBar = true;

    FieldBuilder.FieldParams field = new FieldBuilder.FieldParams();
    field.fieldX = 300;
    field.fieldY = 100;
    field.pathloss = new PathLossBuilder.FreeSpaceParams();
//    field.exponent = 2.7;
//    field.stdDeviation = 4.;
    field.spatial_mode = Constants.SPATIAL_LINEAR;
    params.field = field;

    RadioBuilder.NoiseParams radio = new RadioBuilder.NoiseAdditiveParams();
    radio.fieldX = field.fieldX;
    radio.fieldY = field.fieldY;
    radio.placement = Constants.PLACEMENT_POISSON;
    radio.placementOpts = "0.5x0.5x30x18";
    radio.useAnnos = true;
    params.node.radio = radio;

    MacBuilder.M802_11eParams mac = new MacBuilder.M802_11eParams();
    mac.useAnnos = radio.useAnnos;
    mac.useBitRateAnnos = false;
    params.node.mac = mac;

    NetBuilder.IpParams net = new NetBuilder.IpParams();
    net.protocolMapper = new int[] { Constants.NET_PROTOCOL_UDP,
        Constants.NET_PROTOCOL_LINK_PROBE, Constants.NET_PROTOCOL_MCEXOR,
        Constants.NET_PROTOCOL_FLOODING };
    params.node.net = net;

    RouteBuilder.BrnDsrParams route = new RouteBuilder.BrnDsrParams();
    route.protocol = Constants.NET_PROTOCOL_MCEXOR;
    route.forwarding = brn.swans.Constants.FORWARDING_UNICAST;
    route.discovery = brn.swans.Constants.DISCOVERY_PROACTIVE;
    route.floodintOffset = 50000;
    route.floodingPeriod = 10000;
    route.floodingMax = 0;
    params.node.route = route;

    MetricBuilder.EtxParams metric = new MetricBuilder.EtxParams();
//    metric.rates = new int[] { 22 };
    metric.probes = new int[] { Constants.BANDWIDTH_DEFAULT, 1000 };
    metric.period = 1000;
    metric.tau = 30000;
    metric.globalLinkTable = true;
    route.metric = metric;

    test.run(params);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

}
