package brn.sim.scenario.mchannel;

import brn.sim.AbstractParams;
import brn.sim.builder.*;
import brn.sim.builder.FlowBuilder.SaturatingUdpParams;
import brn.sim.builder.PathLossBuilder.DistShadowingParams;
import brn.sim.builder.TransBuilder.UdpParams;
import brn.analysis.mcexor.TestConstants;

import java.io.IOException;
import java.util.Hashtable;

import jist.swans.Constants;
import jist.swans.misc.Util;
import jist.swans.net.NetAddress;

public class McExORParams extends AbstractParams {
  private static final long serialVersionUID = 1L;

  public final static int SEED = 101;

  public FlowBuilder.SaturatingUdpParams appParams = new FlowBuilder.SaturatingUdpParams();

  public TransBuilder.UdpParams udpParams = new TransBuilder.UdpParams();

  public static McExORParams defaultParams() {
    return defaultParams(SEED);
  }

  public static McExORParams defaultParams(int seed) {
    McExORParams params = new McExORParams();

    // set parameters
    params.endTime = 130;
    params.seed = seed;
    params.nodes = 8;
    params.assertion = true;

    params.dumpRadio = null;//"multi-channel.tr";

    params.dumpFieldNam = null;//"field_multi-channel.nam";
    params.dumpNetNam = null;//"net_multi-channel.nam";
    params.dumpMacNam = null;//"mac_multi-channel.nam";
    params.dumpRadioNam = null;//"radio_multi-channel.nam";

    params.dumpMacGantt = null;//"mac.gantt";
    params.dumpRadioChannelGantt = null;//"radio_ch.gantt";
    params.dumpRadioModeGantt = null;//"radio_mode.gantt";

    params.handlerRadioTimeBar = true;
    params.handlerMacTimeBar = true;
    params.handlerRadio = true;
    params.handlerLinkQuality = true;

    params.dumpNet = false;
    params.dumpMac = false;

    DistShadowingParams pathLoss = new DistShadowingParams();
    pathLoss.exponent = 2.7;
    pathLoss.stdDeviation = 4.;
    pathLoss.coherenceTime = 100000000; // in msec

    FieldBuilder.FieldParams field = new FieldBuilder.FieldParams();
    field.fieldX = 400;
    field.fieldY = 50;
    field.pathloss = pathLoss;
    field.fading = new FadingBuilder.RayleighParams();
    field.spatial_mode = Constants.SPATIAL_LINEAR;
    field.channelPattern = Constants.CHANNEL_PATTERN_ROUNDROBIN;
    field.channelNumber = 1;
    params.field = field;

    RadioBuilder.NoiseParams radio = new RadioBuilder.NoiseAdditiveParams();

    //RadioBuilder.NoiseParams radio = new RadioBuilder.NoiseAdditiveBitLevelParams();
    radio.fieldX = field.fieldX;
    radio.fieldY = field.fieldY;
    radio.placement = Constants.PLACEMENT_GRID;
    radio.placementOpts = "8x1";
    radio.useAnnos = true;
    radio.min_connectivity_betweenNodes = 0;
    radio.connectivity_use_sensing = false;
    radio.num_repetitions = 1;
    radio.threshold = 0.0;

    params.node.radio = radio;

    MacBuilder.MCExORParams mac = new MacBuilder.MCExORParams();
    mac.channelNumber = field.channelNumber;
    mac.useAnnos = radio.useAnnos;
    mac.useBitRateAnnos = false;
    params.node.mac = mac;

    // MCExOR stuff
    mac.useCompression = true;
    mac.usePreferencedAck = false;
    mac.useAppSeqNumbers = false;
    mac.delayChannelSwitch = brn.swans.Constants.DEFAULT_DELAY_CHANNEL_SWITCH;
    mac.refNoiseFactor = 1;
    mac.updatePrioOnNoiseDetection = true;
    mac.useVariableAckSize = true;
    mac.useNAVinAcks = true;
    mac.useNAVinData = true;
    mac.useRtsCts = false;
    mac.useNAVinRtsCts = false;
    mac.useVariableCtsSize = false;
    mac.useCtsCompression = false;
    mac.candidateSetSize = 3; //TODO ????
    mac.useRtsCtsFeedback = false;

    mac.constantDataBitRate = Constants.BANDWIDTH_1Mbps;
    mac.constantCtrlBitRate = Constants.BANDWIDTH_1Mbps;
    mac.rca = Constants.RCA_CONSTANT_RATE;

    mac.testRun = false;

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

    RouteBuilder.MCExORParams route = new RouteBuilder.MCExORParams();
    route.protocol = Constants.NET_PROTOCOL_MCEXOR;
    route.forwarding = brn.swans.Constants.FORWARDING_MCEXOR;
    route.discovery = brn.swans.Constants.DISCOVERY_PROACTIVE;
    route.floodintOffset = 100000;
    route.floodingPeriod = 10000;
    route.floodingMax = -1;
    route.candidateSetSize = mac.candidateSetSize;
    route.testRun = mac.testRun;
    route.testRunOpts = null;
    route.useRtsCts = mac.useRtsCts;
    params.node.route = route;

    // ETX
    MetricBuilder.EtxParams metric = new MetricBuilder.EtxParams();
    metric.probes = new int[] { Constants.BANDWIDTH_1Mbps, 50 };
    metric.period = 1000;
    metric.tau = 100000;
    metric.globalLinkTable = true;
    metric.numberOfChannels = field.channelNumber;
    route.metric = metric;

    // ETT
/*
    MetricBuilder.EttParams metric2 = new MetricBuilder.EttParams();
    metric2.probes = new int[] { Constants.BANDWIDTH_1Mbps, 100 };
    metric2.period = 1000;
    metric2.tau = 100000;
    metric2.globalLinkTable = true;
    metric2.numberOfChannels = field.channelNumber;
    route.metric = metric2;
*/
    params.appParams.flowId     = 0;
    params.appParams.clientAddr = new NetAddress(1);
    params.appParams.serverAddr = new NetAddress(params.nodes);
    params.appParams.start      = 100000;
    params.appParams.end        = 110000;
    params.appParams.maxNumberOfPackets = 1;

    params.gui = true;

    return params;
  }

  public static McExORParams defaultPure80211g(int seed) {
    McExORParams params = defaultParams(seed);

    params.handlerMac = false;

    int dataRate = Constants.BANDWIDTH_24Mbps;
    int ctrlRate = Constants.BANDWIDTH_6Mbps;

    /**
     * Field size x = 400 for bitrate 6-24Mbps
     */
    Builder.Params routeParams = ((RouteBuilder.MCExORParams)params.node.route).metric;

    if (routeParams instanceof MetricBuilder.EtxParams) {
      ((MetricBuilder.EtxParams)(routeParams)).probes = new int[] {
          dataRate, 50
      };
    } else if (routeParams instanceof MetricBuilder.EttParams) {
      ((MetricBuilder.EttParams)(routeParams)).probes = new int[] {
          dataRate, 100
      };
    }

    int fieldX = 400;
    int fieldY = 50;

    ((FieldBuilder.FieldParams)params.field).fieldX = fieldX;
    ((FieldBuilder.FieldParams)params.field).fieldY = fieldY;
    ((RadioBuilder.NoiseParams)params.node.radio).fieldX = fieldX;
    ((RadioBuilder.NoiseParams)params.node.radio).fieldY = fieldY;

    ((RadioBuilder.NoiseParams)params.node.radio).radioType = Constants.MAC_802_11g_PURE;

    ((MacBuilder.MCExORParams)params.node.mac).constantDataBitRate = dataRate;
    ((MacBuilder.MCExORParams)params.node.mac).constantCtrlBitRate = ctrlRate;

    params.endTime = 95;

    return params;
  }

  public static McExORParams withRtsCts(int seed) {
    McExORParams params = defaultParams();

    boolean useRtsCts = true;

    params.seed = seed;
    ((MacBuilder.MCExORParams)params.node.mac).useRtsCts = useRtsCts;
    ((MacBuilder.MCExORParams)params.node.mac).useNAVinRtsCts = true;
    ((MacBuilder.MCExORParams)params.node.mac).useVariableCtsSize = false;

    ((MacBuilder.MCExORParams)params.node.mac).useCompression = false;
    ((MacBuilder.MCExORParams)params.node.mac).useCtsCompression = false;

    ((RouteBuilder.MCExORParams)params.node.route).useRtsCts = useRtsCts;

    params.appParams.maxNumberOfPackets = 1;

    return params;
  }

  public static McExORParams withRtsCtsAndMultiChannel(int seed, int nrChannels) {
    McExORParams params = defaultParams();

    boolean useRtsCts = true;

    params.seed = seed;
    ((MacBuilder.MCExORParams)params.node.mac).useRtsCts = useRtsCts;
    ((MacBuilder.MCExORParams)params.node.mac).useNAVinRtsCts = true;
    ((MacBuilder.MCExORParams)params.node.mac).useVariableCtsSize = false;

    ((MacBuilder.MCExORParams)params.node.mac).useCompression = false;
    ((MacBuilder.MCExORParams)params.node.mac).useCtsCompression = false;

    ((RouteBuilder.MCExORParams)params.node.route).useRtsCts = useRtsCts;

    ((FieldBuilder.FieldParams)params.field).channelNumber = nrChannels;

    ((MacBuilder.MCExORParams)params.node.mac).channelNumber = nrChannels;

    Builder.Params routeParams = ((RouteBuilder.MCExORParams)params.node.route).metric;

    if (routeParams instanceof MetricBuilder.EtxParams) {
      ((MetricBuilder.EtxParams)(routeParams)).numberOfChannels = nrChannels;
    } else if (routeParams instanceof MetricBuilder.EttParams) {
      ((MetricBuilder.EttParams)(routeParams)).numberOfChannels = nrChannels;
    }

    params.appParams.maxNumberOfPackets = 25;

    return params;
  }

  public static McExORParams defaultParamsOnPyramid() {
    McExORParams params = defaultParams();

    /** we are on a grid ... */
    ((RadioBuilder.NoiseParams)params.node.radio).min_connectivity_betweenNodes = 0;
    ((RadioBuilder.NoiseParams)params.node.radio).connectivity_use_sensing = false;
    ((RadioBuilder.NoiseParams)params.node.radio).num_repetitions = 1;
    ((RadioBuilder.NoiseParams)params.node.radio).threshold = 0.0;

    ((RadioBuilder.NoiseParams)params.node.radio).placement = Constants.PLACEMENT_PYRAMID;
    ((RadioBuilder.NoiseParams)params.node.radio).placementOpts = "10x6x1";

    params.endTime = 100;
    params.nodes = 14;
    params.appParams.clientAddr = new NetAddress(1);
    params.appParams.serverAddr = new NetAddress(params.nodes);

    int fieldX = 500;
    int fieldY = 500;

    ((FieldBuilder.FieldParams)params.field).fieldX = fieldX;
    ((FieldBuilder.FieldParams)params.field).fieldY = fieldY;
    ((RadioBuilder.NoiseParams)params.node.radio).fieldX = fieldX;
    ((RadioBuilder.NoiseParams)params.node.radio).fieldY = fieldY;

    return params;
  }

  public static McExORParams defaultParamsOnGrid() {
    McExORParams params = defaultParams();

    /** we are on a grid ... */
    ((RadioBuilder.NoiseParams)params.node.radio).min_connectivity_betweenNodes = 0;
    ((RadioBuilder.NoiseParams)params.node.radio).connectivity_use_sensing = false;
    ((RadioBuilder.NoiseParams)params.node.radio).num_repetitions = 1;
    ((RadioBuilder.NoiseParams)params.node.radio).threshold = 0.0;

    ((RadioBuilder.NoiseParams)params.node.radio).placement = Constants.PLACEMENT_GRID;
    ((RadioBuilder.NoiseParams)params.node.radio).placementOpts = "4x2";

    params.endTime = 100;
    params.nodes = 8;
    params.appParams.clientAddr = new NetAddress(1);
    params.appParams.serverAddr = new NetAddress(params.nodes);

    int fieldX = 500;
    int fieldY = 100;

    ((FieldBuilder.FieldParams)params.field).fieldX = fieldX;
    ((FieldBuilder.FieldParams)params.field).fieldY = fieldY;
    ((RadioBuilder.NoiseParams)params.node.radio).fieldX = fieldX;
    ((RadioBuilder.NoiseParams)params.node.radio).fieldY = fieldY;

    return params;
  }

  public static McExORParams withMultiChannel(int nrChannels) {
    McExORParams params = defaultParams();
    ((FieldBuilder.FieldParams)params.field).channelNumber = nrChannels;

    ((MacBuilder.MCExORParams)params.node.mac).channelNumber = nrChannels;

    Builder.Params routeParams = ((RouteBuilder.MCExORParams)params.node.route).metric;

    if (routeParams instanceof MetricBuilder.EtxParams) {
      ((MetricBuilder.EtxParams)(routeParams)).numberOfChannels = nrChannels;
    } else if (routeParams instanceof MetricBuilder.EttParams) {
      ((MetricBuilder.EttParams)(routeParams)).numberOfChannels = nrChannels;
    }

    return params;
  }

  public static McExORParams withMultiChannelMaxThroughput(int nrChannels) {
    McExORParams params = withMultiChannel(nrChannels);

    params.appParams.maxNumberOfPackets = Integer.MAX_VALUE;

    return params;
  }

  public static McExORParams withMultiChannelMaxThroughput2(int nrChannels) {
    McExORParams params = withMultiChannel(nrChannels);

    params.appParams.maxNumberOfPackets = Integer.MAX_VALUE;

    ((RadioBuilder.NoiseParams)params.node.radio).placement = Constants.PLACEMENT_GRID;
    ((RadioBuilder.NoiseParams)params.node.radio).placementOpts = "20x1";

    params.nodes = 20;
    params.appParams.clientAddr = new NetAddress(1);
    params.appParams.serverAddr = new NetAddress(params.nodes);

    int fieldX = 1500;
    int fieldY = 500;

    ((FieldBuilder.FieldParams)params.field).fieldX = fieldX;
    ((FieldBuilder.FieldParams)params.field).fieldY = fieldY;
    ((RadioBuilder.NoiseParams)params.node.radio).fieldX = fieldX;
    ((RadioBuilder.NoiseParams)params.node.radio).fieldY = fieldY;

    return params;
  }

  public static McExORParams maxThroughputParams() {
    McExORParams params = defaultParams();

    params.appParams.maxNumberOfPackets = Integer.MAX_VALUE;

    ((RadioBuilder.NoiseParams)params.node.radio).placement = Constants.PLACEMENT_GRID;
    ((RadioBuilder.NoiseParams)params.node.radio).placementOpts = "20x1";

    params.nodes = 20;
    params.appParams.clientAddr = new NetAddress(1);
    params.appParams.serverAddr = new NetAddress(params.nodes);

    int fieldX = 1500;
    int fieldY = 500;

    ((FieldBuilder.FieldParams)params.field).fieldX = fieldX;
    ((FieldBuilder.FieldParams)params.field).fieldY = fieldY;
    ((RadioBuilder.NoiseParams)params.node.radio).fieldX = fieldX;
    ((RadioBuilder.NoiseParams)params.node.radio).fieldY = fieldY;

    return params;
  }

  public static FadingBuilder.FadingParams getFadingParams(Integer fading, int i) {
    switch (fading.intValue()) {
    case Constants.FADING_NONE:
      return new FadingBuilder.NoneParams();
    case Constants.FADING_RICIAN: {
      FadingBuilder.RicianParams params = new FadingBuilder.RicianParams();
      params.K = i;
    }
    case Constants.FADING_RAYLEIGH:
      return new FadingBuilder.RayleighParams();
    }
    return new FadingBuilder.NoneParams();
  }
  
  public static McExORParams evalCandidateSetSelection(Integer seed, Integer key, Integer idx,
                                                       Integer exponent, Integer stdDeviation,
                                                       Integer coherenceTime, Integer fading) {
    McExORParams params = defaultParams();
    params.seed = seed.intValue();
    params.appParams.maxNumberOfPackets = Integer.MAX_VALUE;

    boolean testRun = true;
    Integer[] testRunOptNode1 = new Integer[]{
        TestConstants.ROUTE_DONT_FORWARD_PACKETS,
        key,
        idx
    };

    Hashtable testRunOpts = new Hashtable();
    testRunOpts.put(new Integer(1), testRunOptNode1);

    /**
     * Exponent for pathloss formula.
     * from NS2.manual:
     * Environment:
     * Outdoor      Free space          2
     *              Shadowed urban area 2.7 to 5
     * In building  Line-of-sight       1.6 to 1.8
     *              Obstructed          4 to 6
     */
    final double[] exp_values = {1.6, 2.7, 6};
    ((PathLossBuilder.DistShadowingParams)
        ((FieldBuilder.FieldParams)params.field).pathloss).exponent = exp_values[exponent.intValue()]; // 1.6, 2, 2.7, 4, 5, 6

    /**
     * Standard deviation for log-normal shadow fading.
     * from NS2.manual:
     * Environment            sigma (dB)
     * Outdoor                4 to 12
     * Office, hard partition 7
     * Office, soft partition 9.6
     * Factory, line-of-sight 3 to 6
     * Factory, obstructed    6.8
     */
    final double[] stdDev_values = {4, 6.8, 12};
    ((PathLossBuilder.DistShadowingParams)
        ((FieldBuilder.FieldParams)params.field).pathloss).stdDeviation = stdDev_values[stdDeviation.intValue()]; // 3, 6.8, 9.6, 12

    final long[] coh_values = {Constants.SECOND / 10, Constants.SECOND, 5*Constants.SECOND};
    ((PathLossBuilder.DistShadowingParams)
        ((FieldBuilder.FieldParams)params.field).pathloss).coherenceTime = coh_values[coherenceTime.intValue()]; // Constants.SECOND - 30*Constants.SECOND
    ((FieldBuilder.FieldParams)params.field).fading = getFadingParams(fading, 4);
//    ((FieldBuilder.FieldParams)params.field).fadingRicianFactor = 4; //    K-factor is between, say, 4 and 12 dB


    ((MacBuilder.MCExORParams)params.node.mac).testRun = testRun;

    ((RouteBuilder.MCExORParams)params.node.route).testRun = testRun;
    ((RouteBuilder.MCExORParams)params.node.route).testRunOpts = testRunOpts;

    /** we are on a grid ... */
    ((RadioBuilder.NoiseParams)params.node.radio).min_connectivity_betweenNodes = 0;
    ((RadioBuilder.NoiseParams)params.node.radio).connectivity_use_sensing = false;
    ((RadioBuilder.NoiseParams)params.node.radio).num_repetitions = 1;
    ((RadioBuilder.NoiseParams)params.node.radio).threshold = 0.0;


    return params;
  }

  public static McExORParams evalCandidateSetSelectionOnGrid(Integer seed, Integer key, Integer idx,
                                                       Integer exponent, Integer stdDeviation,
                                                       Integer coherenceTime, Integer fading) {
    McExORParams params = evalCandidateSetSelection(seed, key, idx,
        exponent, stdDeviation, coherenceTime, fading);

    ((RadioBuilder.NoiseParams)params.node.radio).placement = Constants.PLACEMENT_GRID;
    ((RadioBuilder.NoiseParams)params.node.radio).placementOpts = "4x2";

    params.appParams.clientAddr = new NetAddress(1);
    params.appParams.serverAddr = new NetAddress(params.nodes);

    int fieldX = 500;
    int fieldY = 100;

    ((FieldBuilder.FieldParams)params.field).fieldX = fieldX;
    ((FieldBuilder.FieldParams)params.field).fieldY = fieldY;
    ((RadioBuilder.NoiseParams)params.node.radio).fieldX = fieldX;
    ((RadioBuilder.NoiseParams)params.node.radio).fieldY = fieldY;

    return params;
  }

  public static McExORParams evalCandidateSetSelectionRtsCts(Integer seed, Integer key, Integer idx,
                                                       Integer exponent, Integer stdDeviation,
                                                       Integer coherenceTime, Integer fading) {
    McExORParams params = evalCandidateSetSelection(seed, key, idx, exponent, stdDeviation, coherenceTime, fading);

    boolean useRtsCts = true;

    ((MacBuilder.MCExORParams)params.node.mac).useRtsCts = useRtsCts;
    ((MacBuilder.MCExORParams)params.node.mac).useNAVinRtsCts = true;
    ((MacBuilder.MCExORParams)params.node.mac).useVariableCtsSize = false;

    ((MacBuilder.MCExORParams)params.node.mac).useCompression = false;
    ((MacBuilder.MCExORParams)params.node.mac).useCtsCompression = false;

    ((RouteBuilder.MCExORParams)params.node.route).useRtsCts = useRtsCts;

    params.appParams.maxNumberOfPackets = 2;

    return params;
  }

  public static McExORParams evalCandidateSetSelectionBitRateMChannel(Integer seed, Integer key, Integer idx,
                                                       Integer exponent, Integer stdDeviation,
                                                       Integer coherenceTime, Integer fading,
                                                       Integer dRate, Integer cRate) {

    McExORParams params = evalCandidateSetSelectionBitRate(seed, key, idx,
                                                       exponent, stdDeviation,
                                                       coherenceTime, fading,
                                                       dRate, cRate);
    boolean testRun = true;
    params.appParams.maxNumberOfPackets = 15;

    params.handlerNet         = true;
    params.handlerFlow        = true;
    params.handlerForwardGraph= true;
    params.handlerLinkQuality = true;
    params.handlerLinkTable   = true;
    params.handlerRadio       = true;
    params.handlerRoute       = true;
    params.handlerRadioTimeBar = true;
    params.handlerMacTimeBar   = true;

    Integer[] testRunOptNode1 = new Integer[]{
        //TestConstants.ROUTE_DONT_FORWARD_PACKETS,
        key,
        idx
    };

    Integer[] testRunOptNode3_5_7 = new Integer[]{
        //TestConstants.ROUTE_DONT_FORWARD_PACKETS,
        new Integer(-2),
        new Integer(6)
    };

    Integer[] testRunOptNode8 = new Integer[]{
        TestConstants.ROUTE_DONT_FORWARD_PACKETS,
        //key,
        //idx
    };

    Hashtable testRunOpts = new Hashtable();
    testRunOpts.put(new Integer(1), testRunOptNode1);
    testRunOpts.put(new Integer(3), testRunOptNode3_5_7);
    testRunOpts.put(new Integer(5), testRunOptNode3_5_7);
    testRunOpts.put(new Integer(7), testRunOptNode3_5_7);
    testRunOpts.put(new Integer(8), testRunOptNode8);


    ((MacBuilder.MCExORParams)params.node.mac).testRun = testRun;

    ((RouteBuilder.MCExORParams)params.node.route).testRun = testRun;
    ((RouteBuilder.MCExORParams)params.node.route).testRunOpts = testRunOpts;

    int nrChannels = 2;
    ((FieldBuilder.FieldParams)params.field).channelNumber = nrChannels;
    ((MacBuilder.MCExORParams)params.node.mac).channelNumber = nrChannels;

    Builder.Params routeParams = ((RouteBuilder.MCExORParams)params.node.route).metric;

    if (routeParams instanceof MetricBuilder.EtxParams) {
      ((MetricBuilder.EtxParams)(routeParams)).numberOfChannels = nrChannels;
    } else if (routeParams instanceof MetricBuilder.EttParams) {
      ((MetricBuilder.EttParams)(routeParams)).numberOfChannels = nrChannels;
    }

    return params;
  }

  public static McExORParams evalCandidateSetSelectionBitRate(Integer seed, Integer key, Integer idx,
                                                       Integer exponent, Integer stdDeviation,
                                                       Integer coherenceTime, Integer fading,
                                                       Integer dRate, Integer cRate) {
    McExORParams params = evalCandidateSetSelection(seed, key, idx, exponent, stdDeviation, coherenceTime, fading);

    //params.endTime = 101;

    params.handlerMac = false;
    params.handlerNet = false;
    params.handlerFlow = false;
    params.handlerForwardGraph = false;
    params.handlerLinkQuality = false;
    params.handlerLinkTable = false;
    params.handlerRadio = false;
    params.handlerRoute = false;
    params.handlerRadioTimeBar = true;
    params.handlerMacTimeBar = true;

    final int[] rate_values = {
        Constants.BANDWIDTH_6Mbps, Constants.BANDWIDTH_9Mbps,  Constants.BANDWIDTH_12Mbps,
        Constants.BANDWIDTH_18Mbps, Constants.BANDWIDTH_24Mbps, Constants.BANDWIDTH_36Mbps,
        Constants.BANDWIDTH_48Mbps, Constants.BANDWIDTH_54Mbps
    };

    int dataRate = rate_values[dRate.intValue()];
    int ctrlRate = rate_values[cRate.intValue()];

    /**
     * Field size x = 400 for bitrate 6-24Mbps
     */
    Builder.Params routeParams = ((RouteBuilder.MCExORParams)params.node.route).metric;

    if (routeParams instanceof MetricBuilder.EtxParams) {
      ((MetricBuilder.EtxParams)(routeParams)).probes = new int[] {
          dataRate, 50
      };
    } else if (routeParams instanceof MetricBuilder.EttParams) {
      ((MetricBuilder.EttParams)(routeParams)).probes = new int[] {
          Constants.BANDWIDTH_6Mbps, 100,
          Constants.BANDWIDTH_18Mbps, 100,
          Constants.BANDWIDTH_54Mbps, 100
      };
      ((MetricBuilder.EttParams)(routeParams)).period = 5000;
    }

    int fieldX = 300;
    int fieldY = 50;

    ((FieldBuilder.FieldParams)params.field).fieldX = fieldX;
    ((FieldBuilder.FieldParams)params.field).fieldY = fieldY;
    ((RadioBuilder.NoiseParams)params.node.radio).fieldX = fieldX;
    ((RadioBuilder.NoiseParams)params.node.radio).fieldY = fieldY;

    ((RadioBuilder.NoiseParams)params.node.radio).radioType = Constants.MAC_802_11g_PURE;

    ((MacBuilder.MCExORParams)params.node.mac).constantDataBitRate = dataRate;
    ((MacBuilder.MCExORParams)params.node.mac).constantCtrlBitRate = ctrlRate;

    return params;
  }

  public static McExORParams evalCandidateSetSelectionBitRateRtsCtsMChannel(Integer seed, Integer key, Integer idx,
                                                       Integer key2, Integer idx2,
                                                       Integer exponent, Integer stdDeviation,
                                                       Integer coherenceTime, Integer fading,
                                                       Integer dRate, Integer cRate) {
    McExORParams params = evalCandidateSetSelectionBitRateRtsCts(seed, key, idx,
                                                       key2, idx2,
                                                       exponent, stdDeviation,
                                                       coherenceTime, fading,
                                                       dRate, cRate);

    boolean testRun = true;
    params.appParams.maxNumberOfPackets = 15;

    Integer[] testRunOptNode1 = new Integer[]{
        //TestConstants.ROUTE_DONT_FORWARD_PACKETS,
        key,
        idx
    };

    Integer[] testRunOptNode3_5_7 = new Integer[]{
        //TestConstants.ROUTE_DONT_FORWARD_PACKETS,
        new Integer(-2),
        new Integer(6)
    };

    Integer[] testRunOptNode8 = new Integer[]{
        TestConstants.ROUTE_DONT_FORWARD_PACKETS,
        //key,
        //idx
    };

    Hashtable testRunOpts = new Hashtable();
    testRunOpts.put(new Integer(1), testRunOptNode1);
    testRunOpts.put(new Integer(3), testRunOptNode3_5_7);
    testRunOpts.put(new Integer(5), testRunOptNode3_5_7);
    testRunOpts.put(new Integer(7), testRunOptNode3_5_7);
    testRunOpts.put(new Integer(8), testRunOptNode8);


    ((MacBuilder.MCExORParams)params.node.mac).testRun = testRun;

    ((RouteBuilder.MCExORParams)params.node.route).testRun = testRun;
    ((RouteBuilder.MCExORParams)params.node.route).testRunOpts = testRunOpts;

    int nrChannels = 2;
    ((FieldBuilder.FieldParams)params.field).channelNumber = nrChannels;
    ((MacBuilder.MCExORParams)params.node.mac).channelNumber = nrChannels;

    Builder.Params routeParams = ((RouteBuilder.MCExORParams)params.node.route).metric;

    if (routeParams instanceof MetricBuilder.EtxParams) {
      ((MetricBuilder.EtxParams)(routeParams)).numberOfChannels = nrChannels;
    } else if (routeParams instanceof MetricBuilder.EttParams) {
      ((MetricBuilder.EttParams)(routeParams)).numberOfChannels = nrChannels;
    }

    return params;
  }

  public static McExORParams evalCandidateSetSelectionBitRateRtsCts(Integer seed, Integer key, Integer idx,
                                                       Integer key2, Integer idx2,
                                                       Integer exponent, Integer stdDeviation,
                                                       Integer coherenceTime, Integer fading,
                                                       Integer dRate, Integer cRate) {
    McExORParams params = evalCandidateSetSelectionBitRate(seed, key, idx, exponent, stdDeviation,
        coherenceTime, fading, dRate, cRate);

    //params.endTime = 120;
    //params.appParams.start      = 199000;

    // use bitrate-selection algorithm
    //((MacBuilder.MCExORParams)params.node.mac).rca = Constants.RCA_OR_RBAR_MIN_SAFE_NB;
    ((MacBuilder.MCExORParams)params.node.mac).rca = Constants.RCA_OR_RBAR_MIN_RATE;

//    ((FieldBuilder.FieldParams)params.field).fading = Constants.FADING_NONE;

    params.appParams.maxNumberOfPackets = 3;

    boolean testRun = true;

    Integer[] testRunOptNode1 = new Integer[]{
        //TestConstants.ROUTE_DONT_FORWARD_PACKETS,
        key,
        idx
    };

    Integer[] testRunOptNode3_5_7 = new Integer[]{
        TestConstants.ROUTE_DONT_FORWARD_PACKETS,
        new Integer(-2),
        new Integer(6)
    };

    Integer[] testRunOptNode8 = new Integer[]{
        TestConstants.ROUTE_DONT_FORWARD_PACKETS,
        //key,
        //idx
    };

    Hashtable testRunOpts = new Hashtable();
    testRunOpts.put(new Integer(1), testRunOptNode1);
    testRunOpts.put(new Integer(3), testRunOptNode3_5_7);
    testRunOpts.put(new Integer(5), testRunOptNode3_5_7);
    testRunOpts.put(new Integer(7), testRunOptNode3_5_7);
    testRunOpts.put(new Integer(8), testRunOptNode8);


    ((MacBuilder.MCExORParams)params.node.mac).testRun = testRun;

    ((RouteBuilder.MCExORParams)params.node.route).testRun = testRun;
    ((RouteBuilder.MCExORParams)params.node.route).testRunOpts = testRunOpts;
    //params.endTime = 99;


    Integer[] testRunOpts2Node1 = new Integer[]{
        TestConstants.ROUTE_DONT_FORWARD_PACKETS,
        key2,
        idx2
    };

    Hashtable testRunOpts2 = new Hashtable();
    testRunOpts2.put(new Integer(1), testRunOpts2Node1);

    ((RouteBuilder.MCExORParams)params.node.route).testRunOpts2 = testRunOpts2;

    params.handlerNet         = true;
    params.handlerFlow        = true;
    params.handlerForwardGraph= true;
    params.handlerLinkQuality = true;
    params.handlerLinkTable   = true;
    params.handlerRadio       = true;
    params.handlerRoute       = true;
    params.handlerRadioTimeBar = true;
    params.handlerMacTimeBar   = true;

    int fieldX = 300;
    int fieldY = 50;

    ((FieldBuilder.FieldParams)params.field).fieldX = fieldX;
    ((FieldBuilder.FieldParams)params.field).fieldY = fieldY;
    ((RadioBuilder.NoiseParams)params.node.radio).fieldX = fieldX;
    ((RadioBuilder.NoiseParams)params.node.radio).fieldY = fieldY;

    // ------------
    // RTS/CTS
    boolean useRtsCts = true;

    ((MacBuilder.MCExORParams)params.node.mac).useRtsCts = useRtsCts;
    ((MacBuilder.MCExORParams)params.node.mac).useNAVinRtsCts = true;
    ((MacBuilder.MCExORParams)params.node.mac).useVariableCtsSize = false;

    ((MacBuilder.MCExORParams)params.node.mac).useCompression = true;
    ((MacBuilder.MCExORParams)params.node.mac).useCtsCompression = false;
    ((MacBuilder.MCExORParams)params.node.mac).useRtsCtsFeedback = false;

    ((RouteBuilder.MCExORParams)params.node.route).useRtsCts = useRtsCts;

    return params;
  }

  public static McExORParams maxThroughputUnicastParams() {
    McExORParams params = defaultParams();
    params.appParams.maxNumberOfPackets = Integer.MAX_VALUE;

    ((RouteBuilder.MCExORParams)params.node.route).candidateSetSize = 1;
    ((MacBuilder.MCExORParams)params.node.mac).candidateSetSize = 1;

    //params.nodes = 16;
    //params.appParams.serverAddr = params.nodes;
    //((RadioBuilder.NoiseParams)params.node.radio).placementOpts = "8x2";

    return params;
  }

  public static McExORParams randomPlacementParams() {
    McExORParams params = defaultParams();

    /** we are on a grid ... */
    ((RadioBuilder.NoiseParams)params.node.radio).min_connectivity_betweenNodes = 0;
    ((RadioBuilder.NoiseParams)params.node.radio).connectivity_use_sensing = false;
    ((RadioBuilder.NoiseParams)params.node.radio).num_repetitions = 1;
    ((RadioBuilder.NoiseParams)params.node.radio).threshold = 0.0;

    RadioBuilder.NoiseParams noiseParams = (RadioBuilder.NoiseParams)params.node.radio;
    noiseParams.placement = Constants.PLACEMENT_RANDOM;

    params.nodes = 8;

    int fieldX = 500;
    int fieldY = 500;

    ((FieldBuilder.FieldParams)params.field).fieldX = fieldX;
    ((FieldBuilder.FieldParams)params.field).fieldY = fieldY;
    ((RadioBuilder.NoiseParams)params.node.radio).fieldX = fieldX;
    ((RadioBuilder.NoiseParams)params.node.radio).fieldY = fieldY;

    return params;
  }

  public static McExORParams evalMultiChannelCandidateSetSelection(Integer seed, Integer key, Integer idx,
                                                       Integer exponent, Integer stdDeviation,
                                                       Integer coherenceTime, Integer fading) {
    System.out.println("called with "+ seed + ", " + key + ", " + idx);
    McExORParams params = defaultParams();
    params.seed = seed.intValue();
    params.appParams.maxNumberOfPackets = 2; //Integer.MAX_VALUE;

    //params.nodes = 14;
    //params.appParams.clientAddr = 1;
    //params.appParams.serverAddr = params.nodes;

    boolean testRun = true;
    Integer[] testRunOptsNode1 = new Integer[]{
        //TestConstants.ROUTE_DONT_FORWARD_PACKETS, // forward packets
        key,
        idx
    };

    Hashtable testRunOpts = new Hashtable();
    testRunOpts.put(new Integer(1), testRunOptsNode1);

    /**
     * Exponent for pathloss formula.
     * from NS2.manual:
     * Environment:
     * Outdoor      Free space          2
     *              Shadowed urban area 2.7 to 5
     * In building  Line-of-sight       1.6 to 1.8
     *              Obstructed          4 to 6
     */
    final double[] exp_values = {1.6, 2.7, 6};
    ((PathLossBuilder.DistShadowingParams)
        ((FieldBuilder.FieldParams)params.field).pathloss).exponent = exp_values[exponent.intValue()]; // 1.6, 2, 2.7, 4, 5, 6

    /**
     * Standard deviation for log-normal shadow fading.
     * from NS2.manual:
     * Environment            sigma (dB)
     * Outdoor                4 to 12
     * Office, hard partition 7
     * Office, soft partition 9.6
     * Factory, line-of-sight 3 to 6
     * Factory, obstructed    6.8
     */
    final double[] stdDev_values = {3, 6.8, 12};
    ((PathLossBuilder.DistShadowingParams)
        ((FieldBuilder.FieldParams)params.field).pathloss).stdDeviation = stdDev_values[stdDeviation.intValue()]; // 3, 6.8, 9.6, 12

    final long[] coh_values = {Constants.SECOND / 10, Constants.SECOND, 5*Constants.SECOND};
    ((PathLossBuilder.DistShadowingParams)
        ((FieldBuilder.FieldParams)params.field).pathloss).coherenceTime = coh_values[coherenceTime.intValue()]; // Constants.SECOND - 30*Constants.SECOND
    ((FieldBuilder.FieldParams)params.field).fading = getFadingParams(fading, 4);


    ((MacBuilder.MCExORParams)params.node.mac).testRun = testRun;

    ((RouteBuilder.MCExORParams)params.node.route).testRun = testRun;
    ((RouteBuilder.MCExORParams)params.node.route).testRunOpts = testRunOpts;

    /** we are on a grid ... */
    ((RadioBuilder.NoiseParams)params.node.radio).min_connectivity_betweenNodes = 0;
    ((RadioBuilder.NoiseParams)params.node.radio).connectivity_use_sensing = false;
    ((RadioBuilder.NoiseParams)params.node.radio).num_repetitions = 1;
    ((RadioBuilder.NoiseParams)params.node.radio).threshold = 0.0;


    int nrChannels = 2;
    ((FieldBuilder.FieldParams)params.field).channelNumber = nrChannels;
    ((MacBuilder.MCExORParams)params.node.mac).channelNumber = nrChannels;

    Builder.Params routeParams = ((RouteBuilder.MCExORParams)params.node.route).metric;

    if (routeParams instanceof MetricBuilder.EtxParams) {
      ((MetricBuilder.EtxParams)(routeParams)).numberOfChannels = nrChannels;
    } else if (routeParams instanceof MetricBuilder.EttParams) {
      ((MetricBuilder.EttParams)(routeParams)).numberOfChannels = nrChannels;
    }

    return params;
  }

  public static void main(String[] args) throws IOException {
    McExORParams params = defaultParams();

    // and out
    Util.writeObject("../brn-jist-common/res/config/McExORParams_ng_mch2.xml", params);
  }

  /* (non-Javadoc)
   * @see brn.sim.AbstractParams#clone()
   */
  public Object clone() throws CloneNotSupportedException {
    McExORParams ret = (McExORParams) super.clone();
    if (null != appParams) ret.appParams = (SaturatingUdpParams) appParams.clone();
    if (null != udpParams) ret.udpParams = (UdpParams) udpParams.clone();
    return ret;
  }
}
