#
#
#
#

import sys
from jarray import array, zeros
from java.lang import *
from java.util import *

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

from org.apache.commons.math.stat.descriptive import DescriptiveStatistics

from brn.sim import *
from brn.sim.data import *
from brn.sim.builder import *
import brn.swans.Constants

from brn.distsim.ormapper.util import *

true = 1
false = 0

NONE = DataManager.LEVEL_OFF
LESS = DataManager.LEVEL_IMPORTANT
BASIC = DataManager.LEVEL_BASIC
MORE = DataManager.LEVEL_ADDITIONAL
ALL = DataManager.LEVEL_ALL

ROUTING_DSR = 1
ROUTING_EXOR = 2
ROUTING_TDICOR = 3


def sum(seq):
    def add(x,y): return x+y
    return reduce(add, seq, 0)

def mean(seq):
    if (len(seq) <= 0):
        return 0
    return sum(seq) / len(seq)

def sumLine(line, default):
  if line != None:
    return sum(line.getY())
  return default

def meanLine(line, default):
  if line != None:
    return mean(line.getY())
  return default

def lenLine(line, default):
  if line != None:
    return len(line.getY())
  return default

def lineFillGaps(line, sampleLen, fillValue):
  newLine = Line(line.getTitle())
  x = line.getXInternal()
  y = line.getYInternal()
  lastX = x[0];
  toleranceLen = 1.1 * sampleLen
  for i in range(0, len(x)):
    while lastX + toleranceLen < x[i]:
      lastX += sampleLen
      newLine.add(lastX, fillValue);
    newLine.add(x[i], y[i]);
    lastX = x[i]
  return newLine

class TimeThroughput(Object):
  def __init__(self, time, throughput, title):
    self.time = time
    self.throughput = throughput
    self.title = title

def lineConvert(line, sampleLen, fillValue):
  x = line.getXInternal()
  y = line.getYInternal()
  newLine = ArrayList(len(x))

  lastX = x[0];
  toleranceLen = 1.1 * sampleLen
  for i in range(0, len(x)):
    while lastX + toleranceLen < x[i]:
      lastX += sampleLen
      point = TimeThroughput(lastX, fillValue, line.getTitle())
      newLine.add(point);
    point = TimeThroughput(x[i], y[i], line.getTitle())
    newLine.add(point);
    lastX = x[i]
  return newLine

def aggregate(line, level):
  newLine = ArrayList(len(line))
  for outerIdx in range (0, len(line)/level):
    o = line.get(outerIdx*level)
    point = TimeThroughput(o.dist, o.throughput, o.title)
    count = 1
    for innerIdx in range(1, level):
      if outerIdx*level + innerIdx >= len(line):
        break;
      o = line.get(outerIdx*level + innerIdx)
      point.throughput += o.throughput
      count += 1
    point.throughput = point.throughput / count
    newLine.add(point)
  return newLine

class DelayStats(Object):
  def __init__(self, simid, min, percentile05,
       mean, percentile95, max, stddev):
    self.simid = simid
    if (False == Double.isNaN(min)):
      self.min = min
    if (False == Double.isNaN(percentile05)):
      self.percentile05 = percentile05
    if (False == Double.isNaN(mean)):
      self.mean = mean
    if (False == Double.isNaN(percentile95)):
      self.percentile95 = percentile95
    if (False == Double.isNaN(max)):
      self.max = max
    if (False == Double.isNaN(stddev)):
      self.stddev = stddev

class ReorderDensityStats(Object):
  def __init__(self, simid, min, percentile05,
       mean, percentile95, max, stddev):
    self.simid = simid
    if (False == Double.isNaN(min)):
      self.min = min
    if (False == Double.isNaN(percentile05)):
      self.percentile05 = percentile05
    if (False == Double.isNaN(mean)):
      self.mean = mean
    if (False == Double.isNaN(percentile95)):
      self.percentile95 = percentile95
    if (False == Double.isNaN(max)):
      self.max = max
    if (False == Double.isNaN(stddev)):
      self.stddev = stddev

class FlowResult(Object):
  def __init__(self):
    self.flowId = 0
    self.flowStats = None # FlowStats()
    self.delayStats = None # DelayStats()
    self.rdStats = None # ReorderDensityStats()

class SimulationResult(Object):
    pass

# TODO use placement-pathloss without shadowing
class TdicorParams:
  def __init__(self, params=None):
    if None==params:
      self.params = None
      self.defaultParams()
    else:
      self.params=params

  # Constructs default parameters
  # @return: TdicorParams
  def defaultParams(self):
    params = AbstractParams()
    # field
    params.field.fieldX = 2000
    params.field.fieldY = 2000
    params.field.spatial_mode = Constants.SPATIAL_HIER
    # mobility
    #params.field.mobility = Constants.MOBILITY_BOUNDLESS_SIM_AREA
    # vMin:vMax:aMin:aMax:deltaT:maxAngularChange[:vStart:angStart]
    #params.field.mobilityOpts = "1:1:0:0:.5:0:1:0"
    # pathloss
    #params.field.pathloss = PathLossBuilder.FreeSpaceParams()
    params.field.pathloss = PathLossBuilder.LogDistanceParams()
    params.field.pathloss.exponent = 2.7
    # time-invariant shadowing
    shadow = PathLossBuilder.ShadowingParams()
    shadow.pathloss = params.field.pathloss
    shadow.stdDeviation = 4.
    shadow.exponential = false # JistAPI.END !!
    shadow.symmetricShadowing = true
    shadow.coherenceTime = 0 # JistAPI.END #(long)(2.5 * Constants.SECOND)
    params.field.pathloss = shadow
    #params.field.fading = FadingBuilder.NoneParams()
    params.field.fading = FadingBuilder.PunnooseRicianParams()
    params.field.fading.maxVelocity = 2.
    params.field.fading.K = 0
    # propagaion delay
    #params.field.propDelay = Constants.PROPAGATION_DELAY_FIXED
    params.field.propDelayFixed = Constants.PROPAGATION
    params.field.propDelay = Constants.PROPAGATION_DELAY_DIST_NORMAL
    params.field.propDelayStdDev = 250.

    # node params
    params.node = None
    params.nodeNumber[0] = 12
    params.nodeParams[0] = self.getNodeParams(NodeBuilder.TrafficParams(), params.field)

    # trans
    params.nodeParams[0].trans = TransBuilder.UdpParams()
    flowParams = params.nodeParams[0].traffic.flowParams
    params.nodeParams[0].traffic = TrafficBuilder.RadialParams()
    params.nodeParams[0].traffic.flowParams = flowParams
    params.nodeParams[0].traffic.startAngle = .75 * Math.PI

    params.nodeParams[0].traffic.flowParams.start = 80000
    params.nodeParams[0].traffic.flowParams.end = 90000
    params.nodeParams[0].traffic.flowParams.maxOutstandingPackets = 180

    # general setup
    params.endTime = 130
    params.seed = 2
    params.assertion = true

    self.params = params
    return self

  # Default parameters with traditional 802.11 MAC and BRN DSR
  # @return: TdicorParams
  def unicastParams(self):
    self.defaultParams()
    params = self.params
    paramsOld = params.nodeParams[0].clone()

    params.nodeParams[0].mac = MacBuilder.M802_11Params()
    params.nodeParams[0].mac.useAnnos = paramsOld.mac.useAnnos
    params.nodeParams[0].mac.useBitRateAnnos = paramsOld.mac.useBitRateAnnos
    params.nodeParams[0].mac.rateSelection = paramsOld.mac.rateSelection
    params.nodeParams[0].mac.messageQueue = paramsOld.mac.messageQueue
    params.nodeParams[0].mac.messageQueueCapacity = paramsOld.mac.messageQueueCapacity
    params.nodeParams[0].mac.nav = paramsOld.mac.nav
    params.nodeParams[0].mac.thresholdRts = 3000
    #params.nodeParams[0].mac.macType = paramsOld.mac.macType

    params.nodeParams[0].net = NetBuilder.IpNotifyParams()
    params.nodeParams[0].net.protocolMapper = paramsOld.net.protocolMapper

    params.nodeParams[0].route = RouteBuilder.BrnDsrParams()
    params.nodeParams[0].route.protocol = paramsOld.route.protocol
    params.nodeParams[0].route.discovery = paramsOld.route.discovery
    params.nodeParams[0].route.floodintOffset = paramsOld.route.floodintOffset
    params.nodeParams[0].route.floodingPeriod = paramsOld.route.floodingPeriod
    params.nodeParams[0].route.floodingMax = paramsOld.route.floodingMax
    params.nodeParams[0].route.metric = paramsOld.route.metric
    params.nodeParams[0].route.forwarding = brn.swans.Constants.FORWARDING_UNICAST

    return self

  def aodvParams(self):
    self.unicastParams()
    params = self.params

    params.handlerLinkQuality = false

    params.nodeParams[0].radio.useAnnos = false

    params.nodeParams[0].mac.useAnnos = false

    params.nodeParams[0].net.protocolMapper = array([ \
        Constants.NET_PROTOCOL_UDP, \
        Constants.NET_PROTOCOL_LINK_PROBE, \
        Constants.NET_PROTOCOL_AODV, \
        Constants.NET_PROTOCOL_FLOODING \
      ], 'i')

    params.nodeParams[0].route = RouteBuilder.AodvParams()
    params.nodeParams[0].route.protocol = Constants.NET_PROTOCOL_AODV
    params.nodeParams[0].route.aodvHelloInterval = 20
    params.nodeParams[0].route.aodvStats = true

    params.nodeParams[0].traffic.flowParams.useAnnos = false

    return self

  def getNodeParams(self, nodeParams, field):
    # radio
    nodeParams.radio = RadioBuilder.NoiseAdditiveBerParams()
    #nodeParams.radio = RadioBuilder.NoiseAdditiveParams()
    # use shorter cw
    nodeParams.radio.radioType = Constants.MAC_802_11g_PURE
    nodeParams.radio.fieldX = field.fieldX
    nodeParams.radio.fieldY = field.fieldY
    nodeParams.radio.useAnnos = true
    nodeParams.radio.diversityCombiner = brn.swans.Constants.RADIO_DIVERSITY_STBC
    #nodeParams.radio.recvCorruptPackets = false

    # 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
    nodeParams.radio.placement = Constants.PLACEMENT_RANDOM
    nodeParams.radio.threshold = .8
    nodeParams.radio.min_connectivity_betweenNodes = 2
    nodeParams.radio.connectivityBitRate = Constants.BANDWIDTH_6Mbps
    #nodeParams.radio.pathlossPlacement = field.pathLoss.clone()

    # mac
    nodeParams.mac = MacBuilder.M802_11TxDivParams()
    #nodeParams.mac.macType = nodeParams.radio.radioType
    nodeParams.mac.useAnnos = nodeParams.radio.useAnnos
    nodeParams.mac.nav = brn.swans.Constants.MAC_NAV_SHORTENING
    nodeParams.mac.thresholdRts = 500
    nodeParams.mac.messageQueue = brn.swans.Constants.NET_QUEUE_ITERABLE
    nodeParams.mac.messageQueueCapacity = 200
    # mac rate selection
    nodeParams.mac.useBitRateAnnos = true
    nodeParams.mac.rateSelection = RateBuilder.ConstantParams()
    nodeParams.mac.rateSelection.dataBitrate = Constants.BANDWIDTH_6Mbps
    nodeParams.mac.rateSelection.controlBitrate = Constants.BANDWIDTH_6Mbps

    # net
    nodeParams.net = NetBuilder.TxDORParams()
    nodeParams.net.protocolMapper = array([ \
        Constants.NET_PROTOCOL_LINK_PROBE, \
        Constants.NET_PROTOCOL_MCEXOR, \
        Constants.NET_PROTOCOL_FLOODING, \
        Constants.NET_PROTOCOL_UDP, \
        Constants.NET_PROTOCOL_TCP, \
        Constants.NET_PROTOCOL_ARP \
      ], 'i')

    # route
    nodeParams.route = RouteBuilder.TxDORParams()
    nodeParams.route.protocol = Constants.NET_PROTOCOL_MCEXOR
    nodeParams.route.forwarding = brn.swans.Constants.FORWARDING_TXDOR
    nodeParams.route.discovery = brn.swans.Constants.DISCOVERY_PROACTIVE
    nodeParams.route.floodintOffset = 50000
    nodeParams.route.floodingPeriod = 10000
    nodeParams.route.floodingMax = 0
    # route metric
    nodeParams.route.metric = MetricBuilder.EtxParams()
    nodeParams.route.metric.useFastLinkTable = true
    nodeParams.route.metric.period = 1000
    nodeParams.route.metric.tau = 60000 # use not shorter than 30 to keep routes stable
    nodeParams.route.metric.probes = array([Constants.BANDWIDTH_6Mbps, 20], 'i')
    nodeParams.route.metric.numberOfChannels = Constants.CHANNEL_NUMBER_DEFAULT
    nodeParams.route.metric.globalLinkTable = true

    return nodeParams

  def setSnrRadio(self):
    params = self.params

    # radio
    params.nodeParams[0].radio = RadioBuilder.NoiseAdditiveTxDivParams()
    #nodeParams.radio = RadioBuilder.NoiseAdditiveParams()
    # use shorter cw
    params.nodeParams[0].radio.radioType = Constants.MAC_802_11g_PURE
    params.nodeParams[0].radio.fieldX = params.field.fieldX
    params.nodeParams[0].radio.fieldY = params.field.fieldY
    params.nodeParams[0].radio.useAnnos = true

    return self

  def setMetricAndBitRate(self, useEtx, minLinkMetric, dataRate, controlRate):
    params = self.params

    params.nodeParams[0].radio.connectivityBitRate = dataRate

    params.nodeParams[0].mac.rateSelection.dataBitrate = dataRate
    params.nodeParams[0].mac.rateSelection.controlBitrate = controlRate

    params.nodeParams[0].route.minLinkMetric = minLinkMetric # us

    metricOld = params.nodeParams[0].route.metric
    if true == useEtx:
      params.nodeParams[0].route.metric = MetricBuilder.EtxParams()
    else:
      params.nodeParams[0].route.metric = MetricBuilder.EttParams()
    params.nodeParams[0].route.metric.bitRate = dataRate
    params.nodeParams[0].route.metric.useFastLinkTable = true
    params.nodeParams[0].route.metric.period = metricOld.period
    params.nodeParams[0].route.metric.tau = metricOld.tau # use not shorter than 30 to keep routes stable
    params.nodeParams[0].route.metric.probes = metricOld.probes
    params.nodeParams[0].route.metric.numberOfChannels = metricOld.numberOfChannels
    params.nodeParams[0].route.metric.globalLinkTable = metricOld.globalLinkTable
    if (dataRate == controlRate):
      params.nodeParams[0].route.metric.probes = array([dataRate, 1480], 'i')
    else:
      params.nodeParams[0].route.metric.probes = array([controlRate, 1480, dataRate, 1480], 'i')

    return self

  # Set parameters for batch execution with distsim.
  # @return: the parameters to adopt
  def setParamsBatch(self):
    params = self.params

    params.handlerRadioLevel = DataManager.LEVEL_OFF # too big
    params.handlerRadioDivLevel = DataManager.LEVEL_BASIC # too big, to slow
    params.handlerMacLevel = DataManager.LEVEL_BASIC
    params.handlerNetLevel = DataManager.LEVEL_BASIC
    params.handlerRouteLevel = DataManager.LEVEL_BASIC
    params.handlerFlowLevel = DataManager.LEVEL_ALL
    params.handlerForwardGraphLevel = DataManager.LEVEL_ALL
    params.handlerLinkQualityLevel = DataManager.LEVEL_OFF # too big
    params.handlerLinkTableLevel = DataManager.LEVEL_ALL
    params.handlerRadioTimeBarLevel = DataManager.LEVEL_OFF  # too big
    params.handlerMacTimeBarLevel = DataManager.LEVEL_OFF  # too big
    params.handlerNetTimeBarLevel = DataManager.LEVEL_OFF  # too big

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

    return self.params

  # Set parameters for local test execution.
  # @return: the parameters to adopt
  def setParamsTest(self):
    params = self.params

    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.handlerRadioLevel = DataManager.LEVEL_OFF
    params.handlerRadioDivLevel = DataManager.LEVEL_BASIC
    params.handlerMacLevel = DataManager.LEVEL_ALL
    params.handlerNetLevel = DataManager.LEVEL_BASIC
    params.handlerRouteLevel = DataManager.LEVEL_ALL
    params.handlerFlowLevel = DataManager.LEVEL_ALL
    params.handlerForwardGraphLevel = DataManager.LEVEL_ALL
    params.handlerLinkQualityLevel = DataManager.LEVEL_OFF
    params.handlerLinkTableLevel = DataManager.LEVEL_ALL
    params.handlerRadioTimeBarLevel = DataManager.LEVEL_OFF
    params.handlerMacTimeBarLevel = DataManager.LEVEL_OFF
    params.handlerNetTimeBarLevel = DataManager.LEVEL_OFF

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

    return self.params



# TDiCOR simulation
# @author: kurth
class SimTdicor(AbstractDriver):
  def __init__(self):
    pass

  #---------------------------------------------------------------------------
  # Setup Parameter
  #---------------------------------------------------------------------------

  def getParamsUdp(self, nodes, seed, routing, csSize, bitrate, \
     fadVelo = 2., fadK = 0, shadStd = 0, flows = 1, \
      promiscStorePackets = true, noCandSets = 1, scaleRemainingHops = true):
    if routing == ROUTING_DSR:
      p = TdicorParams().unicastParams()
      Util.assertion(1 == csSize)
    elif routing == ROUTING_TDICOR:
      p = TdicorParams().defaultParams()
      Util.assertion(1 != csSize)
    else: #routing == ROUTING_EXOR:
      # TODO
      Util.assertion(1 != csSize)
      raise Exception("not implemented")

    params = p.params
    params.seed = seed
    params.nodeNumber[0] = nodes

    params.field.fieldX = 2000
    params.field.fieldY = 2000

    params.field.pathloss.stdDeviation = shadStd
    params.field.pathloss.coherenceTime = 1000 * Constants.MILLI_SECOND
    params.field.pathloss.symmetricShadowing = true
    params.field.pathloss.exponential = true
    params.field.fading.maxVelocity = fadVelo
    params.field.fading.K = fadK

    params.nodeParams[0].radio.fieldX = params.field.fieldX
    params.nodeParams[0].radio.fieldY = params.field.fieldY
    params.nodeParams[0].radio.placement = Constants.PLACEMENT_RANDOM
    params.nodeParams[0].radio.threshold = .8
    params.nodeParams[0].radio.min_connectivity_betweenNodes = 2

    params.nodeParams[0].mac.thresholdRts = 3000
    if ROUTING_TDICOR == routing:
      params.nodeParams[0].mac.thresholdRts = 500
      params.nodeParams[0].mac.promiscStorePackets = promiscStorePackets

    # 50000 for DSR/ETT, 500 for TDiCOR
    # TODO ETX bounds for DSR/ETT
    minLinkMetric = 50 * Constants.MILLI_SECOND
    if ROUTING_TDICOR == routing:
      minLinkMetric = 500
    p.setMetricAndBitRate(false, minLinkMetric, bitrate, Constants.BANDWIDTH_6Mbps)

    Util.assertion(params.nodeParams[0].route.metric.globalLinkTable == true)

    if ROUTING_TDICOR == routing:
      params.nodeParams[0].route.candidateSetSize = csSize
      params.nodeParams[0].route.candidateSelection = brn.swans.Constants.TXDOR_CSSEL_ETT
      params.nodeParams[0].route.noCandSets = noCandSets
      params.nodeParams[0].route.scaleRemainingHops = scaleRemainingHops

    # TODO time offset for start?
    params.nodeParams[0].traffic.startAngle = 0 # RadialParams
    params.nodeParams[0].traffic.flows = flows

    return p

  def getParamsCbr(self, nodes, seed, stdDev, csSize, bitrate, routing, flows, \
      packetSize, txRate, rtsTh, gateway, bidirectional, \
      promiscStorePackets = true, noCandSets = 1, scaleRemainingHops = true):
    p = getParams(nodes, seed, stdDev, csSize, bitrate, routing, flows, \
      promiscStorePackets, noCandSets, scaleRemainingHops)
    params = p.params

    params.nodeParams[0].mac.thresholdRts = rtsTh

    udpParams = CbrUdpParams()
    udpParams.start = 80000;
    udpParams.end = 100000;
    udpParams.udpPayloadLen = packetSize;
    udpParams.udpTxRate = txRate;

    if gateway:
      params.nodeParams[0].traffic = RadialGatewayParams()
      params.nodeParams[0].traffic.flowParams = udpParams
      params.nodeParams[0].traffic.flows = flows
      params.nodeParams[0].traffic.useHalfCircle = false
      params.nodeParams[0].traffic.startOffset = 10000 / flows
      params.nodeParams[0].traffic.twoWay = bidirectional
    else:
      params.nodeParams[0].traffic = RandomParams()
      params.nodeParams[0].traffic.flowParams = udpParams
      params.nodeParams[0].traffic.seed = seed
      params.nodeParams[0].traffic.flows = flows
      params.nodeParams[0].traffic.startOffset = 10000 / flows
      params.nodeParams[0].traffic.twoWay = bidirectional

    return p


  def getParamsTcp(self, nodes, seed, stdDev, csSize, bitrate, routing, flows, \
      promiscStorePackets = true, noCandSets = 1, scaleRemainingHops = true):
    p = getParams(nodes, seed, stdDev, csSize, bitrate, routing, flows, \
      promiscStorePackets, noCandSets, scaleRemainingHops)
    params = p.params

    # TODO time offset for start?
    tcpParams = TcpParams()
    tcpParams.start = 80000
    tcpParams.tcpBytes = tcpParams.tcpMSS * 1000

    params.nodeParams[0].trans = TransBuilder.TcpParams()

    # RadialParams
    params.nodeParams[0].traffic.startAngle = 0;
    params.nodeParams[0].traffic.flows = flows;
    params.nodeParams[0].traffic.flowParams = tcpParams;

    return p


  #---------------------------------------------------------------------------
  # Scenario Definitions: Single Flow
  #---------------------------------------------------------------------------

  # Benchmark TDiCOR vs. DSR at 6/12 Mbps, promiscStorePackets and noCandSets
  def getSimulationSuiteSingleFlow33(self):
    list = ArrayList()

    for nodes in [25,50,100,200]:
      for seed in range(1,11):
        for stdDev in [4,8,12]:
          for bitrate in [Constants.BANDWIDTH_6Mbps, Constants.BANDWIDTH_12Mbps]:
            for routing in [ROUTING_DSR,ROUTING_TDICOR]: #ROUTING_EXOR,
              if (ROUTING_DSR == routing):
                list.add(self.getParams(nodes, seed, stdDev, 1, bitrate, \
                                     routing).setParamsBatch())
              else:
                for csSize in [2,3,4]:
                  for promiscStorePackets in [false,true]:
                    for noCandSets in [1,2]:
                      for scaleRemainingHops in [false,true]:
                        list.add(self.getParams(nodes, seed, stdDev, csSize, bitrate, \
                          routing, promiscStorePackets, noCandSets, \
                          scaleRemainingHops).setParamsBatch())
    return list


  # Benchmark TDiCOR vs. DSR at 6/12/24/ Mbps
  def getSimulationSuiteSingleFlow34(self):
    list = ArrayList()

    for nodes in [25,50,100]:
      for seed in range(1,11):
        for stdDev in [4,8,12]:
          for bitrate in [Constants.BANDWIDTH_6Mbps, Constants.BANDWIDTH_12Mbps]:
            for routing in [ROUTING_DSR,ROUTING_EXOR,ROUTING_TDICOR]:
              if (ROUTING_DSR == routing):
                list.add(self.getParams(nodes, seed, routing, 1, bitrate, \
                  shadStd=stdDev).setParamsBatch())
              else:
                for csSize in [2,3,4]:
                  list.add(self.getParams(nodes, seed, routing, csSize, bitrate, \
                    shadStd=stdDev).setParamsBatch())
    return list

  # Benchmark TDiCOR vs. DSR at 6/12/24/ Mbps with rayleigh fading only
  def getSimulationSuiteSingleFlow35(self):
    list = ArrayList()

    for nodes in [25,50,100]:
      for seed in range(1,11):
        for fadK in [0, 3, 6]:
          for bitrate in [Constants.BANDWIDTH_6Mbps, Constants.BANDWIDTH_12Mbps]:
            for routing in [ROUTING_DSR,ROUTING_TDICOR]: # TODO ROUTING_EXOR,
              if (ROUTING_DSR == routing):
                list.add(self.getParamsUdp(nodes, seed, routing, 1, bitrate, \
                  fadK=fadK).setParamsBatch())
              else:
                for csSize in [2,3,4]:
                  list.add(self.getParamsUdp(nodes, seed, routing, csSize, bitrate, \
                    fadK=fadK).setParamsBatch())
    return list

  def evalSimulationResultsSingleFlow34(self, dbUrl, dbUser, dbPasswd, driver, version, \
                              dbResUrl, dbResUser, dbResPasswd):
    # get the simulation ids
    loader = DbBinaryLoader(dbUrl, dbUser, dbPasswd)
    lstIds = loader.loadSimulationIds(driver, version)
    saver = DBSaver(dbResUrl, dbResUser, dbResPasswd, dbResUrl, dbResUser, dbResPasswd)
    results = LinkedList()
    if (None == lstIds or lstIds.size() <= 0):
      raise Exception("no simulations found for driver " + driver + \
                      " and version " + version)

    for simulationId in lstIds:
      result = SimulationResult()
      result.simid = simulationId
      result.driver = driver
      result.version = version
      print "Load simulation " + str(simulationId) + " from database"

      try:
        # read configuration
        params = self.load(loader, result.simid, "Global, Config")
        result.seed = params.seed
        result.nodes = sum(params.nodeNumber)
        result.pathlossExp = params.field.pathloss.pathloss.exponent
        result.fadingK = params.field.fading.K
        result.fadingVelo = params.field.fading.maxVelocity
        result.shadowStdDev = params.field.pathloss.stdDeviation
        #result.placement = params.nodeParams[0].radio.radios[0].placementOpts
        #result.pattern = result.placement.split(',')[0]
        #result.spacing = result.placement.split(',')[2]
        #result.txAnt =  len(params.nodeParams[0].radio.radios)
        result.divComb = params.nodeParams[0].radio.diversityCombiner
        result.csSize = 1
        result.csSelection = -1
        result.routing = "DSR"
        if isinstance(params.nodeParams[0].route, RouteBuilder.TxDORParams):
          result.routing = "TDiCOR"
          result.csSize = params.nodeParams[0].route.candidateSetSize
          result.csSelection = params.nodeParams[0].route.candidateSelection
        result.useRts = (params.nodeParams[0].mac.thresholdRts < 1000)
        result.dataRate = params.nodeParams[0].mac.rateSelection.dataBitrate
        result.controlRate = params.nodeParams[0].mac.rateSelection.controlBitrate
        #result.dataTxDiv = false ? 1 : 0
        #result.ignoreRtsCtsNav = false ? 1 : 0
        #result.useAckCancelation = false ? 1 : 0
        #result.promiscStorePackets = false ? 1 : 0
        #if isinstance(params.nodeParams[0].mac, MacBuilder.M802_11TxDivParam)s:
          #result.dataTxDiv = ((MacBuilder.M802_11TxDivParams)params.node.mac).useDataTxDiv ? 1 : 0
          #result.ignoreRtsCtsNav = ((MacBuilder.M802_11TxDivParams)params.node.mac).ignoreRtsCtsNav ? 1 : 0
          #result.useAckCancelation = ((MacBuilder.M802_11TxDivParams)params.node.mac).useAckCancelation ? 1 : 0
          #result.promiscStorePackets = ((MacBuilder.M802_11TxDivParams)params.node.mac).promiscStorePackets ? 1 : 0
        if isinstance(params.nodeParams[0].route.metric, MetricBuilder.EttParams):
          result.metric = "ETT"
        elif isinstance( params.nodeParams[0].route.metric, MetricBuilder.EtxParams):
          result.metric = "ETX"
        else:
          result.metric =  params.nodeParams[0].route.metric.getClass().getSimpleName()
        result.flows = params.nodeParams[0].traffic.flows
        if isinstance(params.nodeParams[0].traffic.flowParams, FlowBuilder.CbrUdpParams):
          result.packetSize = params.nodeParams[0].traffic.flowParams.udpPayloadLen
        if isinstance(params.nodeParams[0].traffic, TrafficBuilder.RadialGatewayParams):
          result.gateway = 1
          result.twoWay = params.nodeParams[0].traffic.twoWay
        else:
          result.gateway = 0
          result.twoWay = params.nodeParams[0].traffic.twoWay
        sampleLen = params.sampleLen

        # radio txdiv delay spread
        data = self.load(loader, result.simid, "Global, Radio, txdiv delay spread (avg)", false)
        result.radAvgDelaySpread = meanLine(data, 0.)

        # radio txdiv power delta
        data = self.load(loader, result.simid, "Global, Radio, txdiv power delta (avg)", false)
        result.radAvgPowerDelta = meanLine(data, 0.)

        data = self.load(loader, result.simid, "Global, Radio, txdiv occurance (avg)", false)
        result.radTxDivCount = sumLine(data, 0.) * sampleLen

        # TODO radio utilization, x, y

        # mac stats
        data = self.load(loader, result.simid, "Global, Mac, Stats", true)
        result.macStats = data.getProperties()

        # mac drops
        data = self.load(loader, result.simid, "Global, Mac, discard vs time", false)
        result.macDrops = lenLine(data, 0)

        # mac dups
        data = self.load(loader, result.simid, "Global, Mac, duplicate (hist)", false)
        result.macDuplicates = sumLine(data, 0.)

        # mac backoff
        data = self.load(loader, result.simid, "Global, Mac, backoff (cuml)")
        result.macBackoffCuml = sum(data.getY())

        # mac short retries
        data = self.load(loader, result.simid, "Global, Mac, short retries (hist)", false)
        result.macShortRetries = sumLine(data, 0.)

        # mac long retries
        data = self.load(loader, result.simid, "Global, Mac, long retries (hist)", false)
        result.macLongRetries = sumLine(data, 0.)

        # mac ack cancelation
        data = self.load(loader, result.simid, "Global, Mac, ack cancelation (hist)", false)
        result.macCanceledAcks = sumLine(data, 0.)

        # mac send immediate
        data = self.load(loader, result.simid, "Global, Mac, send immediate (hist)", false)
        result.macSendImmediate = sumLine(data, 0.)

        # net drops
        data = self.load(loader, result.simid, "Global, Net, drop (hist)", false)
        result.netDrops = sumLine(data, 0.)

        # routing duplicates
        data = self.load(loader, result.simid, "Global, Routing, duplicate (hist)", false)
        result.rtgDuplicate = sumLine(data, 0.)

        # routing drops
        data = self.load(loader, result.simid, "Global, Routing, discard vs time", false)
        result.rtgDrops = lenLine(data, 0)

        # TODO routing number of hops, routing drops

        # flows
        flow = -1
        flowName = "All Flows, "
        result.throughput = ArrayList()
        result.flowStats  = ArrayList()
        #seri = None
        while True:
          if -1 > flow:
            flowName = "Flow " + str(flow) + ", "
          flowName += "Application, "

          # flow stats
          data = self.load(loader, result.simid, flowName + "Flow stats", false)
          if None == data:
            break
          flowResult = FlowResult()
          flowResult.flowId = flow
          flowResult.flowStats = data.getProperties()
          result.flowStats.add(flowResult)

          if 0 > flow:
            result.avgThroughput = flowResult.flowStats.getAvgThroughput()
            result.avgDelay = flowResult.flowStats.getAvgDelay()
            result.sendPackets = flowResult.flowStats.getSendPackets()
            result.recvPackets = flowResult.flowStats.getRecvPackets()
            result.avgHopCount = flowResult.flowStats.getAvgHopCount()
            result.flowEnd = flowResult.flowStats.getEnd()

          # flow delay statistics
          stats = DescriptiveStatistics.newInstance()
          data = self.load(loader, result.simid, flowName + "packet delay", true)
          ydata = data.getY()
          for j in range(0, len(ydata)):
            stats.addValue(ydata[j] - ydata[j-1])

          flowResult.delayStats = DelayStats(result.simid, \
                stats.getMin(), \
                stats.getPercentile(5.), \
                stats.getMean(), \
                stats.getPercentile(95.), \
                stats.getMax(), \
                stats.getStandardDeviation())

          # flow reorder statistics
          stats = DescriptiveStatistics.newInstance()
          data = self.load(loader, result.simid, flowName + "packet arrival vs time", true)
          ydata = data.getY()
          for j in range(0, len(ydata)):
            stats.addValue(ydata[j])
          sortedY = stats.getSortedValues()
          stats.clear()
          for j in range(0, len(sortedY)):
            stats.addValue(ydata[j] - sortedY[j])

          flowResult.rdStats = ReorderDensityStats(result.simid, \
                stats.getMin(), \
                stats.getPercentile(5.), \
                stats.getMean(), \
                stats.getPercentile(95.), \
                stats.getMax(), \
                stats.getStandardDeviation())
          #saver.save(rdStats, entity, false)

          # flow throughput
          data = self.load(loader, result.simid, flowName + "throughput (avg'd)")
          line = data.getLine()
          distThroughput = lineConvert(line, sampleLen, .0)
          #distThroughput = aggregate(distThroughput, 20)
          for obj in distThroughput:
            obj.title = flowName
            obj.simid = result.simid
            #obj.borderdist = str(borderDist)
          result.throughput.addAll(distThroughput)
          #line.setTitle(flowName)
          #if None == seri:
            #seri = XplotSerializer(data.getTitle(), data.getXLabel(), data.getYLabel())
            #seri.addLine(line,"green")
          #else:
            #seri.addLine(line,"yellow")

        #seri.saveToFile("flows-" + str(result.simid) + ".xpl")
        #seri = None
        results.add(result)
      except Exception, inst:
          print "Skip simulation " + str(simulationId) + " (" + inst.getMessage() + ")"
          continue
      #except:
      #    print "Unexpected error:", sys.exc_info()[0]
      #    continue

    for result in results:
      if result.routing == "TDiCOR":
        result.avgThroughputRatio = -1.
        result.avgNonRtsThroughputRatio = -1.
        result.avgDelayRatio = -1.
        result.avgNonRtsDelayRatio = -1.

        for other in results:
          if (other.seed == result.seed
              and other.nodes == result.nodes
              and other.shadowStdDev == result.shadowStdDev
              and other.fadingK == result.fadingK
              and other.fadingVelo == result.fadingVelo
              and other.useRts == result.useRts
              and other.routing == "DSR"
              and other.dataRate == result.dataRate
              and other.controlRate == result.controlRate
              and other.gateway == result.gateway
              and other.flows == result.flows):
            print "asfdasdf "
            result.avgThroughputRatio = result.avgThroughput / other.avgThroughput
            if (Double.isNaN(result.avgThroughputRatio)):
              result.avgThroughputRatio = .0
            other.avgThroughputRatio = 1.
            result.avgDelayRatio = result.avgDelay / other.avgDelay
            if (Double.isNaN(result.avgDelayRatio)):
              result.avgDelayRatio = .0
            other.avgDelayRatio = 1.
            break

        for other in results:
          if (other.seed == result.seed
              and other.nodes == result.nodes
              and other.shadowStdDev == result.shadowStdDev
              and other.fadingK == result.fadingK
              and other.fadingVelo == result.fadingVelo
              and other.useRts == 0
              and other.routing == "DSR"
              and other.dataRate == result.dataRate
              and other.controlRate == result.controlRate
              and other.gateway == result.gateway
              and other.flows == result.flows):
            result.avgNonRtsThroughputRatio = result.avgThroughput / other.avgThroughput
            if (Double.isNaN(result.avgNonRtsThroughputRatio)):
              result.avgNonRtsThroughputRatio = .0
            other.avgNonRtsThroughputRatio = 1.
            result.avgNonRtsDelayRatio = result.avgDelay / other.avgDelay
            if (Double.isNaN(result.avgNonRtsDelayRatio)):
              result.avgNonRtsDelayRatio = .0
            other.avgNonRtsDelayRatio = 1.
            break

    print "Writing #" + str(len(results)) + " results"
    for result in results:
      print "Writing result " + str(result.simid) + " to database"
      saver.save(result, driver + "-" + version, false)
    saver.finalize()


  #---------------------------------------------------------------------------
  # Scenario Definitions:  Simulations with multiple saturating TDiCOR or
  # DSR flows, arranged circularly.
  #---------------------------------------------------------------------------

  # Benchmark TDiCOR vs. DSR at 6/12 Mbps, multi-flow
  def getSimulationSuiteMultiFlow101(self):
    list = ArrayList()

    for nodes in [25,50,100]:
      for seed in range(1,11):
        for stdDev in [4,8,12]:
          for bitrate in [Constants.BANDWIDTH_6Mbps, Constants.BANDWIDTH_12Mbps, Constants.BANDWIDTH_24Mbps]:
            for flows in [1,2,3,4]:
              for routing in [ROUTING_DSR,ROUTING_EXOR,ROUTING_TDICOR]:
                if (ROUTING_DSR == routing):
                  list.add(self.getParams(nodes, seed, stdDev, 1, bitrate, \
                                     routing,flows).setParamsBatch())
                else:
                  for csSize in [2,3,4]:
                    list.add(self.getParams(nodes, seed, stdDev, csSize, bitrate, \
                                     routing,flows).setParamsBatch())
    return list

  def evalSimulationResultsMultiFlow101(self, dbUrl, dbUser, dbPasswd, driver, version, \
                              dbResUrl, dbResUser, dbResPasswd):
    pass

  #---------------------------------------------------------------------------
  # Scenario Definitions: Simulations with multiple non-saturating TDiCOR or
  # DSR flows, arranged randomly.
  #---------------------------------------------------------------------------

  # Benchmark TDiCOR vs. DSR at 6/12 Mbps, multi-flow,
  # traffic model RadialGateway, 2 packet sizes, higher data rate
  def getSimulationSuiteMultiFlowCbr207(self):
    list = ArrayList()

    # TODO random Gateway traffic
    for nodes in [100]:
      for seed in range(1,11):
        for stdDev in [4,8,12]:
          for bitrate in [Constants.BANDWIDTH_6Mbps, Constants.BANDWIDTH_12Mbps, Constants.BANDWIDTH_24Mbps]:
            for flows in [2,3,4,5,6]:
              for packetSize in [160,536,1480]:
                for routing in [ROUTING_DSR,ROUTING_EXOR,ROUTING_TDICOR]:
                  gateway = true
                  bidirectional = true
                  # Parameters like G.711 with 20ms packetization and 160 byte
                  txRate = 50 * 160 / packetSize;
                  if (ROUTING_DSR == routing):
                    rtsThreshold = 3000
                    list.add(self.getParamsCbr(nodes, seed, stdDev, 1, bitrate, \
                      routing, flows, packetSize, txRate, rtsThreshold, \
                      gateway, bidirectional).setParamsBatch())
                  else:
                    rtsThreshold = 100
                    for csSize in [2,3,4]:
                      list.add(self.getParamsCbr(nodes, seed, stdDev, csSize, bitrate, \
                        routing, flows, packetSize, txRate, rtsThreshold, \
                        gateway, bidirectional).setParamsBatch())
    return list

  def evalSimulationResultsMultiFlowCbr207(self, dbUrl, dbUser, dbPasswd, driver, version, \
                              dbResUrl, dbResUser, dbResPasswd):
    pass

  #---------------------------------------------------------------------------
  # Scenario Definitions: multiple TDiCOR TCP flows
  #---------------------------------------------------------------------------

  # Benchmark TDiCOR vs. DSR at 6/12 Mbps, multi-flow
  def getSimulationSuiteMultiFlowTcp301(self):
    list = ArrayList()

    # TODO random Gateway traffic
    for nodes in [200]:
      for seed in range(1,21):
        for stdDev in [4,8,12]:
          for bitrate in [Constants.BANDWIDTH_6Mbps, Constants.BANDWIDTH_12Mbps]:
            for flows in [1,2,3]:
              for routing in [ROUTING_DSR,ROUTING_EXOR,ROUTING_TDICOR]:
                if (ROUTING_DSR == routing):
                  list.add(self.getParamsTcp(nodes, seed, stdDev, 1, bitrate, \
                    routing, flows).setParamsBatch())
                else:
                  for csSize in [2,3,4]:
                    list.add(self.getParamsTcp(nodes, seed, stdDev, csSize, bitrate, \
                      routing, flows).setParamsBatch())
    return list

  def evalSimulationResultsMultiFlowTcp301(self, dbUrl, dbUser, dbPasswd, driver, version, \
                              dbResUrl, dbResUser, dbResPasswd):
    pass

  #---------------------------------------------------------------------------
  # Misc
  #---------------------------------------------------------------------------

  def getSimulationSuite(self, version):
    if ("SingleFlow33" == version):
      return self.getSimulationSuiteSingleFlow33()
    if ("SingleFlow34" == version):
      return self.getSimulationSuiteSingleFlow34()
    if ("SingleFlow35.2" == version):
      return self.getSimulationSuiteSingleFlow35()
    if ("MultiFlow101" == version):
      return self.getSimulationSuiteMultiFlow101()
    if ("MultiFlowCbr207" == version):
      return self.getSimulationSuiteMultiFlowCbr207()
    if ("MultiFlowTcp301" == version):
      return self.getSimulationSuiteMultiFlowTcp301()
    raise Exception("No simulations for version " + str(version))

  def evalSimulationResults(self, dbUrl, dbUser, dbPasswd, driver, version, \
                            dbResUrl, dbResUser, dbResPasswd):
    if ("SingleFlow35.2" == version):
      self.evalSimulationResultsSingleFlow34(dbUrl, dbUser, dbPasswd, driver, version, \
                            dbResUrl, dbResUser, dbResPasswd)
      return
    raise Exception("No evaluator for version " + str(version))


  def load(self, loader, simulationId, configPath, error=true):
    ret = loader.load(simulationId, configPath)
    if (None == ret and error):
      raise Exception("Object with path \"" + configPath + \
                      "\" not found for id " + str(simulationId))
    return ret

  def runLocal(self):
    nodes = 50
    seed = 2
    shadStd = 0
    csSize = 3
    bitrate = Constants.BANDWIDTH_6Mbps
    routing = ROUTING_TDICOR

    params = self.getParamsUdp(nodes, seed, routing, csSize, bitrate,
        fadVelo = 2., fadK = 0, shadStd = shadStd, flows = 1,
        promiscStorePackets = true, noCandSets = 1, scaleRemainingHops = true)
    params.params.nodeParams[0].route.candidateSelection = brn.swans.Constants.TXDOR_CSSEL_EAX
    params.setMetricAndBitRate(true, 500, Constants.BANDWIDTH_6Mbps, Constants.BANDWIDTH_6Mbps)

    params = params.setParamsTest()
    params.db = False

    level = NONE
    params.handlerFieldLevel = level
    params.handlerRadioLevel = MORE
    params.handlerRadioDivLevel = level
    params.handlerMacLevel = ALL
    params.handlerRateLevel = level
    params.handlerNetLevel = level
    params.handlerRouteLevel= MORE
    params.handlerTransLevel = level
    params.handlerFlowLevel = ALL
    params.handlerRadioTimeBarLevel = BASIC
    params.handlerMacTimeBarLevel = level
    params.handlerNetTimeBarLevel = level
    params.handlerForwardGraphLevel = BASIC
    params.handlerLinkTableLevel = BASIC
    params.handlerLinkQualityLevel = BASIC

    self.run(params)

  def runFile(self, fileName):
    params = TdicorParams(Util.readObject(fileName))
    self.run(params.setParamsTest())


#---------------
# main
#---------------

if (1 < len(sys.argv)):
  driver = SimTdicor()
  driver.run(array(sys.argv[1:], String))
