package brn.sim.scenario.txdor;

import java.io.IOException;

import jist.runtime.JistAPI;
import jist.swans.Constants;
import jist.swans.misc.Util;
import brn.sim.DeprecatedBasicParams;
import brn.sim.builder.FlowBuilder;
import brn.sim.builder.FadingBuilder;
import brn.sim.builder.FieldBuilder;
import brn.sim.builder.MacBuilder;
import brn.sim.builder.MetricBuilder;
import brn.sim.builder.NetBuilder;
import brn.sim.builder.RadioBuilder;
import brn.sim.builder.RateBuilder;
import brn.sim.builder.RouteBuilder;
import brn.sim.builder.TrafficBuilder;
import brn.sim.builder.FieldBuilder.FieldParams;
import brn.sim.builder.MetricBuilder.EtxParams;
import brn.sim.builder.PathLossBuilder.LogDistanceParams;
import brn.sim.builder.PathLossBuilder.ShadowingParams;
import brn.sim.builder.RadioBuilder.NoiseParams;
import brn.sim.builder.RateBuilder.ConstantParams;

/**
 * @deprecated
 * 
 * @author kurth
 */
public class TxDOrParams extends DeprecatedBasicParams {
  private static final long serialVersionUID = 1L;

  /**
   * Creates default parameters for TxDOR simulation.
   *
   * @return default parameters for TxDOR simulation.
   */
  public static TxDOrParams defaultParams(TxDOrParams params) {
    // set parameters
    params.endTime = 130;
    params.seed = 2;
    params.nodes = 12;
    params.assertion = true;

    LogDistanceParams lossExp = new LogDistanceParams();
    lossExp.exponent = 2.7;

    // time-invariant shadowing
    ShadowingParams pathLoss = new ShadowingParams();
    pathLoss.pathloss = lossExp;
    pathLoss.stdDeviation = 4.;
    pathLoss.exponential = false;
    pathLoss.symmetricShadowing = true; 
    pathLoss.coherenceTime = JistAPI.END;//0 * Constants.SECOND;

    FadingBuilder.PunnooseRicianParams fading = new FadingBuilder.PunnooseRicianParams();
    fading.maxVelocity = 1.5;
    fading.K = 0;

    FieldBuilder.FieldParams field = new FieldBuilder.FieldParams();
    field.spatial_mode = Constants.SPATIAL_LINEAR; // TODO HIER
    field.fieldX = 2000;
    field.fieldY = 2000;
    field.pathloss = pathLoss;
    field.fading = fading;
//    field.propDelay = Constants.PROPAGATION_DELAY_FIXED;
//    field.propDelayFixed = Constants.PROPAGATION;
    field.propDelay = Constants.PROPAGATION_DELAY_DIST_NORMAL;
    field.propDelayStdDev = 250.;
    params.field = field;

    RadioBuilder.NoiseParams radio = new RadioBuilder.NoiseAdditiveTxDivParams();
    radio.fieldX = field.fieldX;
    radio.fieldY = field.fieldY;
    radio.useAnnos = true;
    // use shorter cw
    radio.radioType = Constants.MAC_802_11g_PURE; //Constants.MAC_802_11bg;
    params.node.radio = radio;

    // Random placement with connectivity constraint 2 links with > 80% PDR
    // use data bitrate and always stddev 4/coherence time 0 to generate
    // the same placement across all seeds
    radio.placement = Constants.PLACEMENT_RANDOM;
    radio.threshold = .8;
    radio.min_connectivity_betweenNodes = 2;
    radio.connectivityBitRate = Constants.BANDWIDTH_6Mbps;
    ShadowingParams pathlossPlacement = null;
    try {
      pathlossPlacement = (ShadowingParams) pathLoss.clone();
    } catch (CloneNotSupportedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    radio.pathlossPlacement = pathlossPlacement;

    RateBuilder.ConstantParams rateSelection = new RateBuilder.ConstantParams();
    rateSelection.dataBitrate = Constants.BANDWIDTH_6Mbps;
    rateSelection.controlBitrate = Constants.BANDWIDTH_6Mbps;

    MacBuilder.M802_11Params mac = new MacBuilder.M802_11TxDivParams();
    mac.useAnnos = radio.useAnnos;
    mac.useBitRateAnnos = true;
    mac.rateSelection = rateSelection;
    mac.nav = brn.swans.Constants.MAC_NAV_SHORTENING;
    mac.messageQueue = brn.swans.Constants.NET_QUEUE_ITERABLE;
    mac.messageQueueCapacity = 200;
//    mac.macType = Constants.MAC_802_11g_PURE;
    mac.thresholdRts = 500;
    params.node.mac = mac;

    NetBuilder.IpParams net = new NetBuilder.TxDORParams();
    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.TxDORParams route = new RouteBuilder.TxDORParams();
    route.protocol = Constants.NET_PROTOCOL_MCEXOR;
    route.forwarding = brn.swans.Constants.FORWARDING_TXDOR;
    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.useFastLinkTable = true;
    metric.period = 1000;
    metric.tau = 60000; // use not shorter than 30 to keep routes stable
    metric.probes = new int[] {Constants.BANDWIDTH_6Mbps, 20};
    metric.numberOfChannels = Constants.CHANNEL_NUMBER_DEFAULT;
    metric.globalLinkTable = true;
    route.metric = metric;

    TrafficBuilder.RadialParams trafficParams = new TrafficBuilder.RadialParams();
    trafficParams.flowParams = params.trafficParams.flowParams;
    trafficParams.startAngle = .75 * Math.PI;
    params.trafficParams = trafficParams;

    ((FlowBuilder.SaturatingUdpParams)params.trafficParams.flowParams).start = 80000;
    ((FlowBuilder.SaturatingUdpParams)params.trafficParams.flowParams).end = 90000;
    ((FlowBuilder.CaUdpParams)params.trafficParams.flowParams).maxOutstandingPackets = 180;
    return params;
  }

  public static TxDOrParams radioBerParams(TxDOrParams params) {
    
    RadioBuilder.NoiseParams radioOld = (NoiseParams) params.node.radio;
    
    FieldParams field = (FieldParams) params.field;
    field.propDelay = Constants.PROPAGATION_DELAY_DIST;
    field.propDelayStdDev = 250.;

    RadioBuilder.NoiseParams radio = new RadioBuilder.NoiseAdditiveBerParams();
    radio.fieldX = radioOld.fieldX;
    radio.fieldY = radioOld.fieldY;
    radio.useAnnos = radioOld.useAnnos;
    // use shorter cw
    radio.radioType = radioOld.radioType;
    radio.placement = radioOld.placement;
    radio.placementOpts = radioOld.placementOpts;
    radio.seed = radioOld.seed;
    radio.min_connectivity_betweenNodes = radioOld.min_connectivity_betweenNodes;
    radio.connectivity_use_sensing = radioOld.connectivity_use_sensing;
    radio.num_repetitions = radioOld.num_repetitions;
    radio.threshold = radioOld.threshold;
    radio.connectivityBitRate = radioOld.connectivityBitRate;
//    radio.pathlossPlacement = radioOld.pathlossPlacement;
    radio.pathlossPlacement = null;
    radio.startMobility = radioOld.startMobility;
    params.node.radio = radio;
    
    return params;
  }
  
  /**
   * TODO set cache timeout (cand + linkT) to 500/450 ms
   */
  protected static TxDOrParams unicastParams(TxDOrParams params) {
    defaultParams(params);

    MacBuilder.M802_11Params oldMac = (MacBuilder.M802_11Params) params.node.mac;
    NetBuilder.IpParams oldNet = (NetBuilder.IpParams) params.node.net;
    RouteBuilder.BrnDsrParams oldRoute = (RouteBuilder.BrnDsrParams)params.node.route;

    MacBuilder.M802_11Params mac = new MacBuilder.M802_11Params();
    mac.useAnnos = oldMac.useAnnos;
    mac.useBitRateAnnos = oldMac.useBitRateAnnos;
    mac.rateSelection = oldMac.rateSelection;
    mac.messageQueue = oldMac.messageQueue;
    mac.messageQueueCapacity = oldMac.messageQueueCapacity;
    mac.nav = oldMac.nav;
    mac.thresholdRts = 3000;
//    mac.macType = oldMac.macType;
    params.node.mac = mac;

    NetBuilder.IpParams net = new NetBuilder.IpNotifyParams();
    net.protocolMapper = oldNet.protocolMapper;
    params.node.net = net;

    RouteBuilder.BrnDsrParams route = new RouteBuilder.BrnDsrParams();
    route.protocol = oldRoute.protocol;
    route.discovery = oldRoute.discovery;
    route.floodintOffset = oldRoute.floodintOffset;
    route.floodingPeriod = oldRoute.floodingPeriod;
    route.floodingMax = oldRoute.floodingMax;
    route.metric = oldRoute.metric;
    route.forwarding = brn.swans.Constants.FORWARDING_UNICAST;
    params.node.route = route;

    return params;
  }

  protected static TxDOrParams aodvParams(TxDOrParams params) {
    defaultParams(params);

    params.handlerLinkQuality = false;

    RadioBuilder.NoiseParams radio = (RadioBuilder.NoiseParams) params.node.radio;
    radio.useAnnos = false;

    MacBuilder.M802_11Params mac = (MacBuilder.M802_11Params) params.node.mac;
    mac.useAnnos = false;

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

    RouteBuilder.AodvParams route = new RouteBuilder.AodvParams();
    route.protocol = Constants.NET_PROTOCOL_AODV;
    route.aodvHelloInterval = 20;
    route.aodvStats = true;
    params.node.route = route;

    ((FlowBuilder.SaturatingUdpParams)params.trafficParams.flowParams).useAnnos = false;

    return params;
  }

  public void setMetricAndBitRate(boolean useEtx, int minLinkMetric /*us/etx*/,
      int dataRate, int controlRate) {
    TxDOrParams params = this;

    RadioBuilder.NoiseParams radio = (RadioBuilder.NoiseParams) params.node.radio;
    radio.connectivityBitRate = dataRate;

    MacBuilder.M802_11Params mac = (MacBuilder.M802_11Params) params.node.mac;
    RateBuilder.ConstantParams rate = (ConstantParams) mac.rateSelection;
    rate.dataBitrate = dataRate;
    rate.controlBitrate = controlRate;

    RouteBuilder.BrnDsrParams route = (RouteBuilder.BrnDsrParams) params.node.route;
    route.minLinkMetric = minLinkMetric /* us */;

    MetricBuilder.EtxParams metricOld = (EtxParams) route.metric;
    MetricBuilder.EtxParams metric;
    if (useEtx)
      metric = new MetricBuilder.EtxParams();
    else
      metric = new MetricBuilder.EttParams();
    metric.bitRate = dataRate;
    metric.useFastLinkTable = true;
    metric.period = metricOld.period;
    metric.tau = metricOld.tau; // use not shorter than 30 to keep routes stable
    metric.probes = metricOld.probes;
    metric.numberOfChannels = metricOld.numberOfChannels;
    metric.globalLinkTable = metricOld.globalLinkTable;
    if (dataRate == controlRate)
      metric.probes = new int[] {dataRate, 1480};
    else
      metric.probes = new int[] {controlRate, 1480, dataRate, 1480};
    route.metric = metric;
  }

  /**
   * Set parameters for batch execution with distsim.
   *
   * @return the parameters to adopt
   */
  public TxDOrParams setParamsBatch() {
    TxDOrParams params = this;

    params.handlerRadio = false; // too big
    params.handlerRadioEx = false; // too big, to slow
    params.handlerMac = true;
    params.handlerNet = true;
    params.handlerRoute = true;
    params.handlerFlow = true;
    params.handlerForwardGraph = true;
    params.handlerLinkQuality = false; // too big
    params.handlerLinkTable = true;
    params.handlerRadioTimeBar = false;  // too big
    params.handlerMacTimeBar = false;  // too big
    params.handlerNetTimeBar = false;  // too big

    params.dumpRadio = null;//"txdor.tr";
    params.dumpMac = false;
    params.dumpNet = false;
    params.dumpFieldNam = null;//"txdor-field.nam";
    params.dumpRadioNam = null;//"txdor-radio.nam";
    params.dumpMacNam = null;//"txdor-mac.nam";
    params.dumpNetNam = null;//"txdor-net.nam";

    return params;
  }

  /**
   * Set parameters for local test execution.
   *
   * @return the parameters to adopt
   */
  public TxDOrParams setParamsTest() {
    TxDOrParams params = this;

    params.db = true;
    params.dbRes = "jdbc:mysql://localhost:3306/simulation";
    params.dbDef = "jdbc:mysql://localhost:3306/simulation";
    params.file = false;
    params.directory = "/tmp/sim";

    params.handlerRadio = false;
    params.handlerRadioEx = false;
    params.handlerMac = true;
    params.handlerNet = true;
    params.handlerRoute = true;
    params.handlerFlow = true;
    params.handlerForwardGraph = true;
    params.handlerLinkQuality = false;
    params.handlerLinkTable = true;
    params.handlerRadioTimeBar = false;  // too big
    params.handlerMacTimeBar = false;  // too big
    params.handlerNetTimeBar = false;  // too big

    params.dumpRadio = null;//"txdor.tr";
    params.dumpMac = false;
    params.dumpNet = false;
    params.dumpFieldNam = null;//"txdor-field.nam";
    params.dumpRadioNam = null;//"txdor-radio.nam";
    params.dumpMacNam = null; //"txdor-mac.nam";
    params.dumpNetNam = null;  //"txdor-net.nam";

    return params;
  }

  public static void main(String[] args) throws IOException {
    TxDOrParams params = defaultParams(new TxDOrParams()).setParamsTest();
//    TxDOrParams params = aodvParams();
//    TxDOrParams params = unicastParams();


    // and out
    Util.writeObject("res/config/TxDOrParams.xml", params);
  }

}
