package test.brn.swans.radio;

import java.util.ArrayList;
import java.util.List;

import jist.runtime.JistAPI;
import jist.swans.Constants;
import jist.swans.Node;
import jist.swans.mac.MacAddress;
import jist.swans.misc.MessageAnno;
import jist.swans.misc.MessageBytes;
import jist.swans.misc.Util;
import jist.swans.net.NetAddress;
import jist.swans.net.NetIp;
import jist.swans.net.NetMessage.Ip;
import jist.swans.trans.TransUdp;
import jist.swans.trans.TransUdp.UdpMessage;
import brn.sim.AbstractDriver;
import brn.sim.AbstractParams;
import brn.sim.builder.BuilderException;
import brn.swans.app.UdpApplication;

/**
 * Get the Link Qualities for nodes with different distances.
 *
 * @author kurth
 */
public class TxDiversityTest extends AbstractDriver {

  protected TxDiversityTest() {
  }

//  protected RadioNoise createRadio(AbstractParams opts, Field field, Placement place, int nodeId) throws Exception {
//    // radio
//    RadioNoise radio;
//    switch (opts.radioNoiseType) {
//    case Constants.RADIO_NOISE_INDEP:
//      radio = new RadioNoiseIndep(RadioFactory.createRadioInfoDefault80211g());
//      break;
//    case Constants.RADIO_NOISE_ADDITIVE:
//      radio = new RadioNoiseAdditive(RadioFactory.createRadioInfoDefault80211g());
//      break;
//    default:
//      radio = new RadioNoiseAdditiveTxDiversity(RadioFactory.createRadioInfoDefault80211g());
//    break;
//    }
//    // placement
//    Location location = place.getNextLocation();
//    field.addRadio(radio.getRadioInfo(), radio.getProxy(), location);
//    // field.startMobility(radio.getRadioInfo().getUnique().getID());
//    radio.setFieldEntity(field.getProxy());
//    radio.setUseAnnotations(opts.useAnnos);
//    return radio;
//  }
//
//  protected AbstractMac createMac(AbstractParams opts, int nodeId, RadioNoise radio) throws BuilderException {
//    switch (opts.mac) {
//    case Constants.MAC_802_11:
//    case Constants.MAC_DUMB:
//      return super.createMac(opts, nodeId, radio);
//    }
//
//    RateControlAlgorithmIF rateControl = new ConstantRate(Constants.BANDWIDTH_1Mbps);
//
//    MacTxDOR mac = new MacTxDOR(new MacAddress(nodeId), radio.getRadioInfo(),
//        opts.useRawMac, null);
//    mac.setRadioEntity(radio.getProxy());
//    mac.setUseAnnotations(opts.useAnnos);
//    mac.setUseBitRateAnnotations(opts.useBitRateAnnos);
//    mac.setPromiscuous(opts.macPromisc);
//    mac.setRateControlAlgorithm(rateControl);
//    radio.setMacEntity(mac.getProxy());
//    return mac;
//  }
//
//  protected AbstractNet createNet(AbstractParams opts, Mapper protMap,
//      PacketLoss inLoss, PacketLoss outLoss, int nodeId, AbstractMac mac,
//      MessageQueue messageQueue) throws Exception {
//    AbstractNet net;
//    if (opts.net == Constants.NET_IPV4) {
//      final NetAddress address = new NetAddress(nodeId);
//      net = new NetIp(address, protMap, inLoss, outLoss/* , ipStats */);
//      // TODO
//      // net.setPromiscuous(opts.netPromisc);
//      Util.assertion(false == opts.netPromisc);
//
//      // node entity hookup
//      byte intId = ((NetIp) net).addInterface(mac.getProxy(), messageQueue);
//      if (mac instanceof Mac802_11)
//        ((Mac802_11) mac).setNetEntity(net.getProxy(), intId);
//      else if (mac instanceof MacTxDOR)
//        ((MacTxDOR) mac).setNetEntity(net.getProxy(), intId);
//    } else {
//      throw new RuntimeException("Invalid network layer!");
//    }
//    return net;
//  }

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

    long start = 20 * Constants.SECOND;
    long end = 20 * Constants.SECOND + 500 * Constants.MILLI_SECOND;
    final int txPort = 9000;

    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(MessageAnno.ANNO_MAC_CANDIDATES, lstCandidates);
          net.send(msg , 1, MacAddress.NULL, anno);
        }
      }, start);
    }
    else {
      TransUdp udp = new TransUdp();
      UdpApplication app = new UdpApplication(net.getAddress(), txPort, start, end);

      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();
    }

//    NetAddress receiver = null;
//    if (2 == nodeId)
//      receiver = new NetAddress(3);
//
//      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();
  }

  public static void main(String[] args) throws Exception {
    TxDiversityTest test = new TxDiversityTest();

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

    try {
      final AbstractParams options = (AbstractParams) (Util.readObject(args[0]));
      test.run(options);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

}
