# sim-lq.py
#
# perform only link probing and calculate link qualities
# (see TestLinkQuality)
#
# uses multiple radios and diversity
#
# gruenau1 1001:12
# gruenau2 2001:16
# amsel 4001:3 fink 4011:3 star 4021:3 rabe 4031:3
# brn-suse093-3 301:2 brn-suse093-4 401:3 brn-suse093-5 501:3 brn-suse093-6 601:3 brn-suse093-7 701:3
# chi 3001:2 blur 3101:2 laptop-tutor1 3501:2 mku 3301:2
# beta 3402:1 gorillaz 3201:2
# mk 3601:2
#
# madrid.informatik.hu-berlin.de 2
# bern.informatik.hu-berlin.de 2
# amsel star fink rabe
# gruenau
import sys
from math import ceil
from jarray import array, zeros
from java.lang import *
from java.util import *
from java.io import StringReader

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

from brn.sim import *
from brn.sim.data import *
from brn.sim.builder import *
from brn.sim.handler import LinkQualityHandler
import brn.swans.Constants as BrnConstants

from brn.distsim.ormapper.util import *

true = 1
false = 0

ROUTING_DSR = 1
ROUTING_EXOR = 2
ROUTING_TDICOR = 3

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

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 getBorderDist(flowName, pattern):
  try:
    flowId = int(flowName.split(' ')[1])
    nodesX = int(pattern.split('x')[0])
    nodesY = int(pattern.split('x')[1])
    row = (flowId-1) / nodesX
    column = (flowId-1) % nodesX
    return min(min(row, nodesY-row-1), min(column, nodesX-column-1))
  except ValueError:
    return -1

def lineFillGaps(line, sampleLen, fillValue):
  newLine = Line(line.getTitle())
  x = line.getXInternal()
  y = line.getYInternal()

  if len(x) <= 0:
    return newLine

  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

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

  if len(x) <= 0:
    return newLine

  lastX = start-sampleLen;
  toleranceLen = 1.1 * sampleLen
  for i in range(0, len(x)):
    while lastX + toleranceLen < x[i]:
      lastX += sampleLen
      point = DistThroughput(lastX, fillValue, line.getTitle())
      newLine.add(point);
    point = DistThroughput(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 = DistThroughput(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 DistThroughput(Object):
  def __init__(self, x, y, title):
    self.dist = x
    self.throughput = y
    self.title = title

class SimulationResult(Object):
    pass


class SimDiversityThroughput(AbstractDriver):
    def __init__(self):
        pass

    #---------------------------------------------------------------------------
    # Driver Definition
    #---------------------------------------------------------------------------

    def installHandlers(self, options):
      self.super__installHandlers(options)

      linkQualityHandler = self.getDataManager().getContributor(LinkQualityHandler.ID)

      if (None != linkQualityHandler and None != options.nodeParams[0].route):
        linkQualityHandler.setSampleLen(options.nodeParams[0].route.metric.tau / 1000)


    def setupApplication(self, params, nodeId, node):
        self.super__setupApplication(params,nodeId, node)

        if not isinstance(params.nodeParams[0], NodeBuilder.AppParams):
          return

        appParams = AppBuilder.UdpNotifyParams()
        appParams.start = 000
        appParams.end = 250000
        appParams.flowId = nodeId
        #appParams.maxOutstandingPackets = -1
        #params.nodeParams[0].flow.udpPayloadLen

        if (nodeId <= params.nodeNumber[0]):
            appParams.client = true
            appParams.clientAddr = NetAddress(nodeId)
            appParams.serverAddr = NetAddress(nodeId+params.nodeNumber[0])
        else:
            appParams.client = false
            appParams.clientAddr = NetAddress(nodeId-params.nodeNumber[0])
            appParams.serverAddr = NetAddress(nodeId)

        builder = self.getBuilderProvider().getBuilder(appParams)
        ret = builder.build(appParams, node)
        self.getBuilderProvider().addHookUp(builder, appParams, node, ret)

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

    def getDiversityReceiver(self,field, nodeParams):
          # radio
        nodeParams.radio = RadioBuilder.NoiseAdditiveBerParams()
        #nodeParams.radio = RadioBuilder.NoiseAdditiveParams()
        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 = BrnConstants.RADIO_DIVERSITY_STBC
        #nodeParams.radio.recvCorruptPackets = false
        nodeParams.radio.placement = Constants.PLACEMENT_MANUAL
        nodeParams.radio.placementOpts = "0x51"
        nodeParams.radio.startMobility = "0"
        nodeParams.radio.radioDesc = '''
          mac=802.11g
          bitrates=6,9,12,18,24,36,48,54
          basicRates=6,12,24
          thresholds=5.4,5.8,7.0,9.5,11.3,14.9,18.6,20.6
          frequencies=2400
          frequency_spacings=5
          frequency_widths=20
          number_of_channels=1
          '''

        # mac
        nodeParams.mac = MacBuilder.M802_11Params()
        #nodeParams.mac.macType = Constants.MAC_802_11g_PURE
        nodeParams.mac.useAnnos = nodeParams.radio.useAnnos
        nodeParams.mac.useBitRateAnnos = true
        nodeParams.mac.rateSelection.dataBitrate = Constants.BANDWIDTH_6Mbps
        nodeParams.mac.rateSelection.controlBitrate = Constants.BANDWIDTH_6Mbps

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

        # route
        nodeParams.route = RouteBuilder.TableParams()
        nodeParams.route.protocol = Constants.NET_PROTOCOL_ARP

        # trans
        nodeParams.trans = TransBuilder.UdpParams()

        return nodeParams


    def getDiversitySender(self,field, nodeParams):
         # second params
        nodeParams = self.getDiversityReceiver(field, nodeParams).clone()

        oldRadio = nodeParams.radio
        nodeParams.radio = RadioBuilder.DiversityReceiverParams()
        nodeParams.radio.radios = array( \
          [oldRadio, oldRadio.clone()], Builder.Params)
        nodeParams.radio.radioType = oldRadio.radioType
        nodeParams.radio.radios[0].placement = Constants.PLACEMENT_MANUAL
        nodeParams.radio.radios[0].placementOpts = "0x50"
        nodeParams.radio.radios[0].startMobility = "-1"
        nodeParams.radio.radios[1].placement = Constants.PLACEMENT_MANUAL
        nodeParams.radio.radios[1].placementOpts = "0x52"
        nodeParams.radio.radios[1].startMobility = "-1"

        return nodeParams


    def defaultParams(self):
        params = AbstractParams()

        # general setup
        params.assertion = true
        params.endTime = 250
        params.seed = 1
        params.node = None

        # field
        params.field.fieldX = 400
        params.field.fieldY = 100
        params.field.spatial_mode = Constants.SPATIAL_HIER
        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"
        #params.field.pathloss = PathLossBuilder.FreeSpaceParams()
        params.field.pathloss = PathLossBuilder.LogDistanceParams()
        params.field.pathloss.exponent = 3.5
        pathLoss = PathLossBuilder.ShadowingParams()
        pathLoss.pathloss = params.field.pathloss
        pathLoss.stdDeviation = 0.
        pathLoss.exponential = true
        pathLoss.coherenceTime = 1000 * Constants.MILLI_SECOND
        params.field.pathloss = pathLoss
        #params.field.fading = FadingBuilder.NoneParams()
        params.field.fading = FadingBuilder.PunnooseRicianParams()
        params.field.fading.maxVelocity = 2.
        params.field.fading.K = 0

        nodeParams =  NodeBuilder.AppParams();
        nodeParams.app = None
        nodeParams.trans = None

        params.nodeNumber = array( [ 1, 1], 'i')
        params.nodeParams = array( [ self.getDiversitySender(params.field, nodeParams), \
                                     self.getDiversityReceiver(params.field, nodeParams)], \
                                     NodeBuilder.NodeParams)

        return params


    def getParams(self, seed, pattern, spacing, divComb, txAnt, divCombsSender=-1, \
            power=19, unicast=False, fadingK = 0, shadowStdDev = 0):
        if 0 > divCombsSender:
          divCombsSender = divComb
        params = self.defaultParams()

        params.seed = seed
        params.field.fieldX = pattern[0] * spacing[0]
        params.field.fieldY = pattern[1] * spacing[1]
        params.field.wrapField = true
        params.field.pathloss.stdDeviation = shadowStdDev
        params.field.fading.K = fadingK
        #params.field.pathloss.exponent = 3.5
        #params.field.fading.maxVelocity = 2.

        sp = str(power)
        radioDesc = params.nodeParams[1].radio.radioDesc + "txpowers=" + \
            sp+","+sp+","+sp+","+sp+","+sp+","+sp+","+sp+","+sp

        nodes = pattern[0] * pattern[1]
        _pattern = str(pattern[0]) + "x" + str(pattern[1])
        _spacing = str(spacing[0]) + "x" + str(spacing[1])
        params.nodeNumber[0] = nodes
        radios = []

        params.nodeParams[0].radio.radioDesc = radioDesc
        for i in range(txAnt):
          radio = params.nodeParams[0].radio.radios[0].clone()
          # only first radio receives
          radio.doReceive = (0 == i);
          radio.placement = Constants.PLACEMENT_GRID
          radio.placementOpts = _pattern + ",0x"+str(i)+"," + _spacing
          radio.diversityCombiner = divCombsSender
          radio.radioDesc = radioDesc
          radios += [radio]
        params.nodeParams[0].radio.radios = array(radios, Builder.Params)

        params.nodeNumber[1] = nodes
        params.nodeParams[1].radio.placement = Constants.PLACEMENT_GRID
        params.nodeParams[1].radio.placementOpts = _pattern + ",0x.5," + _spacing
        params.nodeParams[1].radio.diversityCombiner = divComb

        if unicast==True:
          params.nodeParams[0].route.table = ""
          for node in range(1,2*nodes+1):
            params.nodeParams[0].route.table += NetAddress(node).toString() + \
              "/255.255.255.255 "+NetAddress(node).toString()+" 1\n"
          params.nodeParams[1].route.table = params.nodeParams[0].route.table

        return params

    def getParamsChain(self, seed, pattern, spacing, divComb, txAnt, power=19, \
        unicast=False, flowIdStart=0, horz=False, fadingK = 0, fadingVelo=2., \
        shadowStdDev = 0, startOffset=0):
      params = self.defaultParams()

      params.endTime = 25
      params.seed = seed
      params.field.fieldX = pattern[0] * spacing[0]
      params.field.fieldY = pattern[1] * spacing[1]
      params.field.wrapField = true
      params.field.pathloss.stdDeviation = shadowStdDev
      #params.field.pathloss.exponent = 3.5
      params.field.fading.maxVelocity = fadingVelo
      params.field.fading.K = fadingK
      params.field.mobility = Constants.MOBILITY_STATIC
      params.field.mobilityOpts = None

      nodes = pattern[0] * pattern[1]
      _pattern = str(pattern[0]) + "x" + str(pattern[1])
      _spacing = str(spacing[0]) + "x" + str(spacing[1])
      params.nodeNumber = array( [ nodes ], 'i')
      params.nodeParams = array( [ self.getDiversitySender(params.field, \
          NodeBuilder.FlowParams())], NodeBuilder.NodeParams)

      sp = str(power)
      radioDesc = params.nodeParams[1].radio.radioDesc + "txpowers=" + \
          sp+","+sp+","+sp+","+sp+","+sp+","+sp+","+sp+","+sp

      radios = []
      for i in range(txAnt):
        _start = ","+str(startOffset)+"x"+str(i+1)+","
        if horz:
          _start = ","+str(i+1)+"x"+str(startOffset)+","
        radio = params.nodeParams[0].radio.radios[0].clone()
        # only first radio receives
        radio.doReceive = (0 == i);
        radio.placement = Constants.PLACEMENT_GRID
        radio.placementOpts = _pattern + _start + _spacing
        radio.diversityCombiner = divComb
        radio.radioDesc = radioDesc
        radios += [radio]
      params.nodeParams[0].radio.radios = array(radios, Builder.Params)

      if unicast==True:
        params.nodeParams[0].route.table = ""
        for node in range(1+flowIdStart,nodes+1+flowIdStart):
          params.nodeParams[0].route.table += NetAddress(node).toString() + \
            "/255.255.255.255 "+NetAddress(node).toString()+" 1\n"

      flows = []
      idx1 = 0
      idx2 = 1
      if horz:
        idx1 = 1
        idx2 = 0
      for j in range(1,pattern[idx2]+1):
        for i in range(1,pattern[idx1]+1): # 1
          flow = FlowBuilder.SaturatingUdpParams()
          flow.flowId = i + (j-1)*pattern[idx1] + flowIdStart
          flow.start = 0
          flow.end = 20000
          flow.clientAddr = NetAddress(i + (j-1)*pattern[idx1] + flowIdStart)
          flow.serverAddr = NetAddress(i%pattern[idx1] + 1 + (j-1)*pattern[idx1] + flowIdStart)
          flows += [flow]
          #print "Flow " + str(flow.flowId) + ": " + str(i + (j-1)*pattern[idx1] + flowIdStart) + \
          #  " -> " + str(i%pattern[idx1] + 1 + (j-1)*pattern[idx1] + flowIdStart)
      params.nodeParams[0].flows = array(flows, Builder.Params)

      return params


    def getParamsCrossChain(self, seed, pattern, spacing, divComb, txAnt, \
          power=19, unicast=False, fadingK = 0, shadowStdDev = 0, startOffset=0):
      params = self.getParamsChain(seed, pattern, spacing, divComb, txAnt, power, \
          unicast, flowIdStart=0, fadingK=fadingK, shadowStdDev=shadowStdDev, startOffset=startOffset)

      params.field.fieldX = max(pattern[0] * spacing[0], pattern[1] * spacing[1])
      params.field.fieldY = params.field.fieldX

      pattern2 = [pattern[1], pattern[0]]
      spacing2 = [spacing[1], spacing[0]]
      params2 = self.getParamsChain(seed, pattern2, spacing2, divComb, txAnt, power, unicast, pattern[0], True, startOffset=startOffset)

      params.nodeNumber = array( [ params.nodeNumber[0], params2.nodeNumber[0] ], 'i')
      params.nodeParams = array( [ params.nodeParams[0], params2.nodeParams[0] ], NodeBuilder.NodeParams)

      #params.nodeParams[0].flows = None

      return params

    def getParamsSingle(self, seed, spacingX, divComb, txAnt, power=19, \
        unicast=False, fadingK = 0, fadingVelo=2., shadowStdDev = 0):
      params = self.defaultParams()

      pattern = [2,1]
      spacing = [spacingX, 1000];

      params.endTime = 25
      params.seed = seed
      params.field.fieldX = pattern[0] * spacing[0] + 1000
      params.field.fieldY = pattern[1] * spacing[1]
      params.field.wrapField = true
      params.field.pathloss.stdDeviation = shadowStdDev
      params.field.fading.maxVelocity = fadingVelo
      params.field.fading.K = fadingK
      #params.field.pathloss.exponent = 3.5
      params.field.mobility = Constants.MOBILITY_STATIC
      params.field.mobilityOpts = None

      sp = str(power)
      radioDesc = params.nodeParams[1].radio.radioDesc + "txpowers=" + \
          sp+","+sp+","+sp+","+sp+","+sp+","+sp+","+sp+","+sp

      nodes = pattern[0] * pattern[1]
      _pattern = str(pattern[0]) + "x" + str(pattern[1])
      _spacing = str(spacing[0]) + "x" + str(spacing[1])
      params.nodeNumber = array( [ nodes ], 'i')
      params.nodeParams = array( [ self.getDiversitySender(params.field, \
          NodeBuilder.FlowParams())], NodeBuilder.NodeParams)

      params.nodeParams[0].radio.radioDesc = radioDesc
      radios = []
      for i in range(txAnt):
        _start = ",0x"+str(i+1)+","
        radio = params.nodeParams[0].radio.radios[0].clone()
        # only first radio receives
        radio.doReceive = (0 == i);
        radio.placement = Constants.PLACEMENT_GRID
        radio.placementOpts = _pattern + _start + _spacing
        radio.diversityCombiner = divComb
        radio.radioDesc = radioDesc
        radios += [radio]
      params.nodeParams[0].radio.radios = array(radios, Builder.Params)

      if unicast==True:
        params.nodeParams[0].route.table = ""
        for node in range(1,nodes+1):
          params.nodeParams[0].route.table += NetAddress(node).toString() + \
            "/255.255.255.255 "+NetAddress(node).toString()+" 1\n"

      flows = []
      flow = FlowBuilder.SaturatingUdpParams()
      flow.flowId = 1
      flow.start = 0
      flow.end = 20000
      flow.clientAddr = NetAddress(1)
      flow.serverAddr = NetAddress(2)
      flows += [flow]
      params.nodeParams[0].flows = array(flows, Builder.Params)

      return params

    def getParamsChainMultihop(self, seed, pattern, spacing, divComb, txAnt, power=19, \
        unicast=False, flowIdStart=0, horz=False):
      params = self.getParamsChain(seed, pattern, spacing, divComb, txAnt, \
        power=power, unicast=unicast, flowIdStart=flowIdStart, horz=horz)

      params.nodeParams[0].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
      params.nodeParams[0].route = RouteBuilder.BrnDsrParams()
      params.nodeParams[0].route.protocol = Constants.NET_PROTOCOL_MCEXOR
      params.nodeParams[0].route.forwarding = BrnConstants.FORWARDING_UNICAST
      params.nodeParams[0].route.discovery = BrnConstants.DISCOVERY_PROACTIVE
      params.nodeParams[0].route.floodintOffset = 50000
      params.nodeParams[0].route.floodingPeriod = 10000
      params.nodeParams[0].route.floodingMax = 0
      # route metric
      params.nodeParams[0].route.metric = MetricBuilder.EtxParams()
      params.nodeParams[0].route.metric.useFastLinkTable = true
      params.nodeParams[0].route.metric.period = 400
      params.nodeParams[0].route.metric.tau = 20000 # use not shorter than 30 to keep routes stable
      params.nodeParams[0].route.metric.probes = array([Constants.BANDWIDTH_6Mbps, 1500], 'i')
      params.nodeParams[0].route.metric.numberOfChannels = Constants.CHANNEL_NUMBER_DEFAULT
      params.nodeParams[0].route.metric.globalLinkTable = true

      params.endTime = 200
      flows = []
      idx = 0
      if horz:
        idx = 1
      for i in range(1,pattern[idx]+1,pattern[idx]/2 * 3):
        params.nodeParams[0].trans = TransBuilder.TcpParams()
        flow = FlowBuilder.TcpParams() #SaturatingUdpParams()
        flow.flowId = i + flowIdStart
        flow.start = 70000
        #flow.end = 100000
        flow.tcpBytes = 1460 * 1000
        flow.clientAddr = NetAddress(i + flowIdStart)
        flow.serverAddr = NetAddress((i+pattern[idx]/2)%pattern[idx] + flowIdStart)
        flows += [flow]
      params.nodeParams[0].flows = array(flows, Builder.Params)

      return params


    def setTestParams(self, params):
        params.db = true
        params.dbRes = "jdbc:mysql://localhost:3306/simulation"
        params.dbDef = params.dbRes

        params.handlerRadioLevel = NONE
        params.handlerRadioDivLevel = ALL
        params.handlerRateLevel = NONE
        params.handlerRouteLevel = NONE
        params.handlerTransLevel = ALL
        params.handlerFlowLevel = ALL

        params.handlerRadioTimeBarLevel = NONE
        params.handlerMacTimeBarLevel = NONE
        params.handlerNetTimeBarLevel = NONE

        params.handlerLinkQualityLevel = NONE
        params.handlerForwardGraphLevel = NONE

        params.gui = true

        return params

    def setSimParams(self, params):
      params.handlerRadioDivLevel = LESS
      params.handlerMacLevel = BASIC
      params.handlerFlowLevel = LESS
      params.handlerForwardGraphLevel = BASIC
      return params

    #---------------------------------------------------------------------------
    # Scenario Definitions
    #---------------------------------------------------------------------------

    # ==========================================================================
    # 2 konkurrierende links mit unterschiedlichem spacing
    # 1 cluster vert
    # 1-5 cluter horz, variation of spacing
    # objective: determine influence of higher power on carrier sensing
    #
    def getSimulationSuite01(self):
        list = ArrayList()

        seeds = [2,3,4]
        patterns = [[1,2],[1,3],[1,4],[1,5]]
        spacings = [[100,100],[150,150],[200,200],[250,250],[300,300],\
                    [125,125],[175,175],[225,225],[275,275],[325,325]]
        divCombs = [BrnConstants.RADIO_DIVERSITY_STBC, BrnConstants.RADIO_DIVERSITY_NC, BrnConstants.RADIO_DIVERSITY_SEL_MAX]
        #txAnts = 2

        for seed in seeds:
          for pattern in patterns:
            for spacing in spacings:
              param = self.getParams(seed, pattern, spacing, BrnConstants.RADIO_DIVERSITY_NONE, 1)
              list.add(self.setSimParams(param))

              for divComb in divCombs:
                  param = self.getParams(seed, pattern, spacing, divComb, 2)
                  list.add(self.setSimParams(param))

        return list

    def evalSimulation(self, dbUrl, dbUser, dbPasswd, driver, version, \
                 dbResUrl, dbResUser, dbResPasswd, callback):
      # 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:
          timeStartLoad = System.currentTimeMillis()
          print "Load simulation " + str(simulationId) + " from database"

          try:
            result = callback(driver, version, simulationId, loader)

            timeEndLoad = System.currentTimeMillis()
            saver.save(result, driver + "-" + version, false)

            timeNow = System.currentTimeMillis()
            print "   loading : " + str(timeEndLoad-timeStartLoad) + " ms, storing: " +str(timeNow-timeEndLoad)+" ms"

            if simulationId % 25 == 0:
              print "rebuilding session"
              saver.rebuildSession()
          except Exception, inst:
              print "Skip simulation " + str(simulationId) + " (" + inst.getMessage() + ")"
              #inst.printStackTrace()
              continue
          #except:
          #    print "Unexpected error:", sys.exc_info()[0]
          #    continue

#      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.close()


    def evalSimulationResults01(self, driver, version, simulationId, loader):
      result = SimulationResult()
      result.simid = simulationId
      result.driver = driver
      result.version = version

      # 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.shadowStdDev = params.field.pathloss.stdDeviation
      result.fadingK = params.field.fading.K
      result.fadingVelo = params.field.fading.maxVelocity
      result.placement = params.nodeParams[0].radio.radios[0].placementOpts
      result.pattern = result.placement.split(',')[0]
      result.patternX = int(result.pattern.split('x')[0])
      result.patternY = int(result.pattern.split('x')[1])
      result.spacing = result.placement.split(',')[2]
      result.spacingX = int(result.spacing.split('x')[0])
      result.spacingY = int(result.spacing.split('x')[1])
      result.txAnt =  len(params.nodeParams[0].radio.radios)
      result.dataRate = params.nodeParams[0].mac.rateSelection.dataBitrate
      result.controlRate = params.nodeParams[0].mac.rateSelection.controlBitrate;
      if len(params.nodeParams) >= 2 and isinstance(params.nodeParams[1].radio,RadioBuilder.NoiseAdditiveBerParams):
        result.divComb = params.nodeParams[1].radio.diversityCombiner
      else:
        result.divComb = params.nodeParams[0].radio.radios[0].diversityCombiner
      props = Properties()
      props.load(StringReader(params.nodeParams[0].radio.radios[0].radioDesc))
      txpowers = props.getProperty('txpowers')
      if None != txpowers:
        result.txPower = txpowers.strip().split(',')[0]
      result.unicast = false
      if len(params.nodeParams[0].route.table) > 40:
        result.unicast = true
      sampleLen = params.sampleLen

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

      # radio txdiv delay spread
      data = self.load(loader, result.simid, "Global, Radio, txdiv delay spread", false)
      result.radAvgDelaySpread = 0;
      if  (data != None):
        result.radAvgDelaySpread = mean(data.getY())

      # radio txdiv delay spread
      data = self.load(loader, result.simid, "Global, Radio, txdiv power delta", false)
      result.radAvgPowerDelta = 0
      result.radTxDivCount = 0
      if (None != data):
        result.radAvgPowerDelta = mean(data.getY())
        result.radTxDivCount = len(data.getY())

      # flow parameters, TODO set flow name
      flowName = "All flows"
      result.flows = HashMap()
      data = self.load(loader, result.simid, flowName + ", Application, Flow stats")
      result.flows.put(flowName, data.getProperties())

      # throughput (DiagramData)
      result.throughput = ArrayList()

      data = self.load(loader, result.simid, flowName + \
                       ", Application, throughput (avg'd)")
      #seri = XplotSerializer(data.getTitle(), data.getXLabel(), data.getYLabel())
      line = data.getLine()
      distThroughput = lineConvert(line, sampleLen, .0)
      distThroughput = aggregate(distThroughput, 20)
      borderDist = getBorderDist(flowName, result.pattern)
      for obj in distThroughput:
        obj.title = flowName
        obj.simid = result.simid
        obj.borderdist = str(borderDist)
        obj.distthroughput = (obj.dist+2.5) * obj.throughput
      result.throughput.addAll(distThroughput)
      #line = lineFillGaps(line, sampleLen, .0)
      #line.setTitle(flowName)
      #seri.addLine(line,"green")

      try:
        flowId = 1
        while true:
          flowName = "Flow " + str(flowId)
          # flow parameters, TODO set flow name
          data = self.load(loader, result.simid, flowName + \
                           ", Application, Flow stats")
          result.flows.put(flowName, data.getProperties())

          # throughput (DiagramData)
          data = self.load(loader, result.simid, flowName + \
                             ", Application, throughput (avg'd)")
          line = data.getLine()
          distThroughput = lineConvert(line, sampleLen, .0)
          distThroughput = aggregate(distThroughput, 20)
          borderDist = getBorderDist(flowName, result.pattern)
          for obj in distThroughput:
            obj.title = flowName
            obj.simid = result.simid
            obj.borderdist = str(borderDist)
            obj.distthroughput = (obj.dist+2.5) * obj.throughput
          result.throughput.addAll(distThroughput)
          #line = lineFillGaps(line, sampleLen, .0)
          #line.setTitle(flowName)
          #seri.addLine(line,"yellow")
          flowId += 1
      except Exception, inst:
        pass

      #seri.saveToFile("flows-" + str(result.simid) + ".xpl")
      return result


    # ==========================================================================
    # 2-3 cluster vert, variation of spacing
    # 1 cluster horz
    # objective: determine influence of [power/diversity/interference] on reception
    #
    def getSimulationSuite02(self):
        list = ArrayList()

        seeds = [2,3,4]
        patterns = [[2,1],[3,1],[4,1]]
        spacings = [[100,100],[150,150],[200,200],[250,250],[300,300],\
                    [125,125],[175,175],[225,225],[275,275],[325,325]]
        divCombs = [BrnConstants.RADIO_DIVERSITY_STBC, BrnConstants.RADIO_DIVERSITY_NC, BrnConstants.RADIO_DIVERSITY_SEL_MAX]
        #txAnts = 2

        for seed in seeds:
          for pattern in patterns:
            for spacing in spacings:
              param = self.getParams(seed, pattern, spacing, BrnConstants.RADIO_DIVERSITY_NONE, 1)
              list.add(self.setSimParams(param))

              for divComb in divCombs:
                  param = self.getParams(seed, pattern, spacing, divComb, 2)
                  list.add(self.setSimParams(param))

        return list

    # ==========================================================================
    # 5 cluster vert, limited number of spacings
    # 5 cluster horz, limited number of spacings
    # close vert spacing: influence of interference on reception
    # close horz spacing: influence on carrier sensing and sender transmission rate
    # 25 clusters to mitigate border effects for middle cluster
    #
    def getSimulationSuite03(self):
        list = ArrayList()

        seeds = [2,3,4]
        patterns = [[5,5],[7,7]]
        spacings = [[100,100],[150,150],[200,200],[250,250],[300,300],\
                    [125,125],[175,175],[225,225],[275,275],[325,325]]
        divCombs = [BrnConstants.RADIO_DIVERSITY_STBC, BrnConstants.RADIO_DIVERSITY_NC, BrnConstants.RADIO_DIVERSITY_SEL_MAX]
        #txAnts = 2

        for seed in seeds:
          for pattern in patterns:
            for spacing in spacings:
              param = self.getParams(seed, pattern, spacing, BrnConstants.RADIO_DIVERSITY_NONE, 1)
              list.add(self.setSimParams(param))

              for divComb in divCombs:
                  param = self.getParams(seed, pattern, spacing, divComb, 2)
                  list.add(self.setSimParams(param))

        return list

    def getSimulationSuite04(self):
        list = ArrayList()

        seeds = [2,3,4]
        patterns = [[7,7]]
        spacings = [[100,100],[150,150],[200,200],[250,250],[300,300],\
                    [125,125],[175,175],[225,225],[275,275],[325,325]]
        divCombs = [BrnConstants.RADIO_DIVERSITY_STBC, BrnConstants.RADIO_DIVERSITY_SEL_MAX, BrnConstants.RADIO_DIVERSITY_SEL_MAX]
        divCombsSender = [BrnConstants.RADIO_DIVERSITY_STBC, BrnConstants.RADIO_DIVERSITY_SEL_MAX, BrnConstants.RADIO_DIVERSITY_SEL_MIN]
        #txAnts = 2

        for seed in seeds:
          for pattern in patterns:
            for spacing in spacings:
              param = self.getParams(seed, pattern, spacing, BrnConstants.RADIO_DIVERSITY_NONE, 1)
              list.add(self.setSimParams(param))

              for i in range(len(divCombs)):
                  param = self.getParams(seed, pattern, spacing, divComb[i], 2, divCombsSender[i])
                  list.add(self.setSimParams(param))

        return list

    def getSimulationSuite05(self):
        list = ArrayList()

        seeds = [2,3,4]
        patterns = [[6,6]]
        spacings = [[50,50],[75,75],[100,100],[150,150],[200,200],[250,250],[300,300],\
                    [125,125],[175,175],[225,225],[275,275],[325,325]]
        divCombs = [BrnConstants.RADIO_DIVERSITY_STBC]
        unicasts = [False, True]
        powerSiso = [19.0001,22]
        powerMiso2 = [16,19]
        powerMiso3 = [14.22,19]

        for seed in seeds:
          for pattern in patterns:
            for spacing in spacings:
              for unicast in unicasts:
                for power in powerSiso:
                  param = self.getParams(seed, pattern, spacing, BrnConstants.RADIO_DIVERSITY_NONE, 1, power=power, unicast=unicast)
                  list.add(self.setSimParams(param))

                for i in range(len(divCombs)):
                  for power in powerMiso2:
                    param = self.getParams(seed, pattern, spacing, divCombs[i], 2, power=power, unicast=unicast)
                    list.add(self.setSimParams(param))

                  for power in powerMiso3:
                    param = self.getParams(seed, pattern, spacing, divCombs[i], 3, power=power, unicast=unicast)
                    list.add(self.setSimParams(param))
        return list


    def getSimulationSuite06(self):
        list = ArrayList()

        seeds = [20019, 240, 29186, 131440, 22550]
        #pathlossExp = [3.5]
        #fadingVelo = [2]
        fadingKs   = [3, 6, 0, 3, 6]
        shadowStds = [0, 0, 4, 4, 4]
        # field at least 1000x1000
        patterns = [[14,14],  [10,10],    [8,8],    [7,7],    [6,6],    [6,6],    [6,6],    [6,6],    [6,6],    [6,6]]
        spacings = [[75,75],[100,100],[125,125],[150,150],[175,175],[200,200],[225,225],[250,250],[275,275],[300,300]]
        unicasts = [False, True]
        powerSiso = [19.0001,22]
        powerMiso2 = [16,19]
        powerMiso3 = [14.22,19]

        for seed in seeds:
            for pIdx in range(len(patterns)):
              for unicast in unicasts:
                for power in powerSiso:
                  param = self.getParams(seed, patterns[pIdx], spacings[pIdx], \
                      BrnConstants.RADIO_DIVERSITY_NONE, 1, power=power, unicast=unicast, \
                      fadingK=fadingKs[fadIdx], shadowStdDev=shadowStds[fadIdx])
                  list.add(self.setSimParams(param))

                for power in powerMiso2:
                  param = self.getParams(seed, patterns[pIdx], spacings[pIdx], \
                      BrnConstants.RADIO_DIVERSITY_STBC, 2, power=power, unicast=unicast, \
                      fadingK=fadingKs[fadIdx], shadowStdDev=shadowStds[fadIdx])
                  list.add(self.setSimParams(param))

                for power in powerMiso3:
                  param = self.getParams(seed, patterns[pIdx], spacings[pIdx], \
                      BrnConstants.RADIO_DIVERSITY_STBC, 3, power=power, unicast=unicast, \
                      fadingK=fadingKs[fadIdx], shadowStdDev=shadowStds[fadIdx])
                  list.add(self.setSimParams(param))
        return list

    # A chain topology with variing spacings
    # TODO vary the vertical spacing, too?
    def getSimulationSuiteChain01(self):
        list = ArrayList()

        seeds = [2,3,4,14523,534,235]
        patterns = [[20,1]]
        spacings = []
        for i in range(30,160,10):
          spacings += [[i, 1000]]
        divCombs = [BrnConstants.RADIO_DIVERSITY_STBC]
        powerSiso = [19.001,22]
        powerMiso2 = [16,19]
        powerMiso3 = [14.22,19]

        # fading k? fading velo? unicast?
        fadingVelos = [2, 8, 32]
        fadingKs   = [0, 3, 6]
        unicasts = [False, True]

        for seed in seeds:
          for pattern in patterns:
            for spacing in spacings:
              for unicast in unicasts:
                for fadingK in fadingKs:
                  for fadingVelo in fadingVelos:
                    for power in powerSiso:
                      param = self.getParamsChain(seed, pattern, spacing, BrnConstants.RADIO_DIVERSITY_NONE, \
                          1, power=power, unicast=unicast, fadingK=fadingK, fadingVelo=fadingVelo)
                      list.add(self.setSimParams(param))

                    for i in range(len(divCombs)):
                      for power in powerMiso2:
                        param = self.getParamsChain(seed, pattern, spacing, divCombs[i], \
                            2, power=power, unicast=unicast, fadingK=fadingK, fadingVelo=fadingVelo)
                        list.add(self.setSimParams(param))

                      for power in powerMiso3:
                        param = self.getParamsChain(seed, pattern, spacing, divCombs[i], \
                            3, power=power, unicast=unicast, fadingK=fadingK, fadingVelo=fadingVelo)
                        list.add(self.setSimParams(param))
        return list


    # A chain topology with variing spacings
    # TODO vary the vertical spacing, too?
    def getSimulationSuiteChain02(self):
        list = ArrayList()

        seeds = [2,3,4,14523]#,534,235]
        # fading k? fading velo?
        #pathlossExp = [3.5]
        fadingVelos = [2, 8, 32]
        fadingKs   = [-100, 6, 12] #, 3, 6, 0, 3, 6]
        shadowStds = [0, 0, 0] #, 0, 0, 4, 4, 4]
        patterns = [] #[[20,1]]
        spacings = []
        for j in range(50, 200, 25) + [700]:
          for i in range(20,110,10):
            spacings += [[i, j]]
            patterns += [[int(ceil(700./i)), int(ceil(700./j))]]
        unicasts = [False, True]
        divCombs = [BrnConstants.RADIO_DIVERSITY_STBC]
        powerSiso = [19.001]#,22]
        powerMiso2 = [16]#,19]
        #powerMiso3 = [14.22,19]

        for seed in seeds:
          for fadIdx in range(len(fadingKs)):
            for sIdx in range(len(spacings)):
            #for pattern in patterns:
              #for spacing in spacings:
              for fadingVelo in fadingVelos:
                for unicast in unicasts:
                  for power in powerSiso:
                    param = self.getParamsChain(seed, patterns[sIdx], spacings[sIdx], \
                      BrnConstants.RADIO_DIVERSITY_NONE, 1, power=power, unicast=unicast, \
                      fadingK=fadingKs[fadIdx], fadingVelo=fadingVelo, shadowStdDev=shadowStds[fadIdx])
                    list.add(self.setSimParams(param))

                  for i in range(len(divCombs)):
                    for power in powerMiso2:
                      param = self.getParamsChain(seed, patterns[sIdx], spacings[sIdx], \
                        divCombs[i], 2, power=power, unicast=unicast, \
                      fadingK=fadingKs[fadIdx], fadingVelo=fadingVelo, shadowStdDev=shadowStds[fadIdx])
                      list.add(self.setSimParams(param))

                    #for power in powerMiso3:
                    #  param = self.getParamsChain(seed, patterns[sIdx], spacings[sIdx], \
                    #    divCombs[i], 3, power=power, unicast=unicast, \
                    #  fadingK=fadingKs[fadIdx], fadingVelo=fadingVelo, shadowStdDev=shadowStds[fadIdx])
                    #list.add(self.setSimParams(param))

        return list


    # A chain topology with variing spacings
    # TODO vary the vertical spacing, too?
    def getSimulationSuiteCrossChain01(self):
      list = ArrayList()

      seeds = [2,3,4,14523,534,235]
      #pathlossExp = [3.5]
      #fadingVelo = [2]
      fadingKs   = [0] # [3, 6, 0, 3, 6]
      shadowStds = [0] #[0, 0, 4, 4, 4]
      patterns = [[20,1]]
      spacings = []
      for i in range(41,200,5):
        spacings += [[i, 500]]
      startOffsets = [0., .5]
      unicasts = [False, True]
      divCombs = [BrnConstants.RADIO_DIVERSITY_STBC]
      powerSiso = [19.001,22]
      powerMiso2 = [16,19]
      powerMiso3 = [14.22,19]

      # fading k? fading velo? unicast?

      for seed in seeds:
        for fadIdx in range(len(fadingKs)):
          for pattern in patterns:
            for spacing in spacings:
                for startOffset in startOffsets:
                  for unicast in unicasts:
                    for power in powerSiso:
                      param = self.getParamsCrossChain(seed, pattern, spacing, \
                          BrnConstants.RADIO_DIVERSITY_NONE, 1, power=power, unicast=unicast, \
                          fadingK=fadingKs[fadIdx], shadowStdDev=shadowStds[fadIdx], \
                          startOffset=startOffset*spacing[0])
                      list.add(self.setSimParams(param))

                  for i in range(len(divCombs)):
                    for power in powerMiso2:
                      param = self.getParamsCrossChain(seed, pattern, spacing, \
                          divCombs[i], 2, power=power, unicast=unicast, \
                          fadingK=fadingKs[fadIdx], shadowStdDev=shadowStds[fadIdx], \
                          startOffset=startOffset*spacing[0])
                      list.add(self.setSimParams(param))

                    for power in powerMiso3:
                      param = self.getParamsCrossChain(seed, pattern, spacing, \
                          divCombs[i], 3, power=power, unicast=unicast, \
                          fadingK=fadingKs[fadIdx], shadowStdDev=shadowStds[fadIdx], \
                          startOffset=startOffset*spacing[0])
                      list.add(self.setSimParams(param))
        return list


          # A chain topology with variing spacings
    # TODO vary the vertical spacing, too?
    def getSimulationSuiteSingle01(self):
      list = ArrayList()

      seeds = [2] #,3,4,14523,534,235]
      #pathlossExp = [3.5]
      #fadingVelo = [2]
      fadingVelos = [2, 8, 32]
      fadingKs   = [0, 3, 6] #, 3, 6, 0, 3, 6]
      shadowStds = [0, 0, 0] #, 0, 4, 4, 4]
      #patterns = [[1,1]]
      #spacings = [[1000,1000]]
      spacingXs = range(10,200,10)
      unicasts = [False, True]
      divCombs = [BrnConstants.RADIO_DIVERSITY_STBC]
      powerSiso = [19.001,22]
      powerMiso2 = [16,19]
      powerMiso3 = [14.22,19]

      for seed in seeds:
        for fadIdx in range(len(fadingKs)):
          for fadingVelo in fadingVelos:
          #for pattern in patterns:
            #for spacing in spacings:
            for spacingX in spacingXs:
              for unicast in unicasts:
                for power in powerSiso:
                  param = self.getParamsSingle(seed, spacingX, \
                      BrnConstants.RADIO_DIVERSITY_NONE, 1, power=power, unicast=unicast, \
                      fadingK=fadingKs[fadIdx], fadingVelo=fadingVelo, shadowStdDev=shadowStds[fadIdx])
                  list.add(self.setSimParams(param))

                for i in range(len(divCombs)):
                  for power in powerMiso2:
                    param = self.getParamsSingle(seed, spacingX, \
                        divCombs[i], 2, power=power, unicast=unicast, \
                        fadingK=fadingKs[fadIdx], fadingVelo=fadingVelo, shadowStdDev=shadowStds[fadIdx])
                    list.add(self.setSimParams(param))

                  for power in powerMiso3:
                    param = self.getParamsSingle(seed, spacingX, \
                        divCombs[i], 3, power=power, unicast=unicast, \
                        fadingK=fadingKs[fadIdx], fadingVelo=fadingVelo, shadowStdDev=shadowStds[fadIdx])
                    list.add(self.setSimParams(param))
        return list


    def evalSimulationResultsSingle01(self, driver, version, simulationId, loader):
      result = self.evalSimulationResults01(driver, version, simulationId, loader)

      result.sendPackets = ArrayList()
      result.recvPackets = ArrayList()

      data = self.load(loader, result.simid, "Node 1, Mac, send (cuml'd)")
      line = data.getLine()
      distThroughput = lineConvert(line, 20., .0)
      for obj in distThroughput:
        if obj.dist % 10 != 0:
          continue;
        obj.title = "Node 1"
        obj.simid = result.simid
        result.sendPackets.add(obj)

      data = self.load(loader, result.simid, "Node 2, Mac, receive (cuml'd)")
      line = data.getLine()
      distThroughput = lineConvert(line, 20., .0)
      for obj in distThroughput:
        if obj.dist % 10 != 0:
          continue;
        obj.title = "Node 2"
        obj.simid = result.simid
        result.recvPackets.add(obj)

      return result

    #---------------------------------------------------------------------------
    # Evaluation
    #---------------------------------------------------------------------------

    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):
      params = self.getParams(29186, [1, 1], [1000, 1000], \
        BrnConstants.RADIO_DIVERSITY_STBC, 2, power=16, unicast=False,
        fadingK=-100, shadowStdDev=0)
      #params = self.getParamsChain(2, [30,1], [20,1000],
      #    BrnConstants.RADIO_DIVERSITY_STBC, 1, power=19, unicast=True, fadingK=0, fadingVelo=2)
      #params = self.getParamsCrossChain(2, [11,1], [100,300],
      #    BrnConstants.RADIO_DIVERSITY_STBC, 2, power=30, unicast=True)
      #params = self.getParamsSingle(2, 110,
      #    BrnConstants.RADIO_DIVERSITY_STBC, 1, power=19, unicast=True)
      #params = self.getParamsChainMultihop(2, [40,1], [60,300], \
      #  BrnConstants.RADIO_DIVERSITY_STBC, 1, power=20, unicast=True)
      params = self.setTestParams(params)

      #params.field.fading.maxVelocity = 0
      #params.field.fading.K = 0
      #flows = [params.nodeParams[0].flows[0], params.nodeParams[0].flows[9]]
      #params.nodeParams[0].flows = array(flows, Builder.Params)
      #params.nodeParams[0].mac.thresholdRts = 500
      params.nodeParams[0].mac.rateSelection.dataBitrate = Constants.BANDWIDTH_54Mbps
      params.nodeParams[0].mac.rateSelection.controlBitrate = Constants.BANDWIDTH_54Mbps

      level = NONE
      params.handlerFieldLevel = level
      params.handlerRadioLevel = MORE
      params.handlerRadioDivLevel = LESS
      params.handlerMacLevel = ALL
      params.handlerRateLevel = level
      params.handlerNetLevel = level
      params.handlerRouteLevel= ALL
      params.handlerTransLevel = level
      params.handlerFlowLevel = ALL

      params.handlerRadioTimeBarLevel = ALL
      params.handlerMacTimeBarLevel = level
      params.handlerNetTimeBarLevel = level

      params.handlerForwardGraphLevel = level
      params.handlerLinkTableLevel = level
      params.handlerLinkQuality = level

      params.db = False
      #params.fileBinary = false
      #params.directory = "tmp"

      self.run(params)

    def runFile(self, fileName):
      params = Util.readObject(fileName);
      params.db=false

      params.handlerRadioTimeBarLevel = ALL
      params.handlerMacTimeBarLevel = ALL
      #params.handlerNetTimeBarLevel = level

      #params.handlerRadioDivLevel = LESS
      #params.handlerMacLevel = LESS
      #params.handlerFlowLevel = LESS

      self.run(params);


    def getSimulationSuite(self, version):
      if ("1" == version):
        return self.getSimulationSuite01()
      if ("2" == version):
        return self.getSimulationSuite02()
      if ("3" == version):
        return self.getSimulationSuite03()
      if ("4" == version):
        return self.getSimulationSuite04()
      if ("5.7" == version):
        return self.getSimulationSuite05()
      if ("6.4" == version):
        return self.getSimulationSuite06()
      if ("Chain01.20" == version):
        return self.getSimulationSuiteChain01()
      if ("Chain02.13" == version):
        return self.getSimulationSuiteChain02()
      if ("CrossChain01.5" == version):
        return self.getSimulationSuiteCrossChain01()
      if ("Single01.4" == version):
        return self.getSimulationSuiteSingle01()
      raise Exception("No simulations for version " + version)

    def evalSimulationResults(self, dbUrl, dbUser, dbPasswd, driver, version, \
                              dbResUrl, dbResUser, dbResPasswd):
      driver = driver.replace('\\', '/')
      if ("1" == version):
        self.evalSimulation(dbUrl, dbUser, dbPasswd, driver, version, \
            dbResUrl, dbResUser, dbResPasswd, self.evalSimulationResults01)
        return
      if ("2" == version):
        self.evalSimulation(dbUrl, dbUser, dbPasswd, driver, version, \
            dbResUrl, dbResUser, dbResPasswd, self.evalSimulationResults01)
        return
      if ("3" == version):
        self.evalSimulation(dbUrl, dbUser, dbPasswd, driver, version, \
            dbResUrl, dbResUser, dbResPasswd, self.evalSimulationResults01)
        return
      if ("4" == version):
        self.evalSimulation(dbUrl, dbUser, dbPasswd, driver, version, \
            dbResUrl, dbResUser, dbResPasswd, self.evalSimulationResults01)
        return
      if ("5.7" == version):
        self.evalSimulation(dbUrl, dbUser, dbPasswd, driver, version, \
            dbResUrl, dbResUser, dbResPasswd, self.evalSimulationResults01)
        return
      if ("6.4" == version):
        self.evalSimulation(dbUrl, dbUser, dbPasswd, driver, version, \
            dbResUrl, dbResUser, dbResPasswd, self.evalSimulationResults01)
        return
      if ("Chain01.20" == version):
        self.evalSimulation(dbUrl, dbUser, dbPasswd, driver, version, \
            dbResUrl, dbResUser, dbResPasswd, self.evalSimulationResults01)
        return
      if ("Chain02.13" == version):
        self.evalSimulation(dbUrl, dbUser, dbPasswd, driver, version, \
            dbResUrl, dbResUser, dbResPasswd, self.evalSimulationResults01)
        return
      if ("CrossChain01.4" == version):
        self.evalSimulation(dbUrl, dbUser, dbPasswd, driver, version, \
            dbResUrl, dbResUser, dbResPasswd, self.evalSimulationResults01)
        return
      if ("Single01.4" == version):
        self.evalSimulation(dbUrl, dbUser, dbPasswd, driver, version, \
            dbResUrl, dbResUser, dbResPasswd, self.evalSimulationResultsSingle01)
        return
      raise Exception("No evaluator for version " + str(version))


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

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

# -----------------------------------------------------------------------------
# populates the detailed dist throughput table
evalDistThroughputSql = '''
create table div06_1_distthroughput
select
a.primary_key,
driver,
version,

b.simid,
nodes,
placement,
spacing,
spacingX,
spacingY,
pattern,
patternX,
patternY,
dataRate,
controlRate,
pathlossExp,
shadowStdDev,
fadingK,
fadingVelo,
txAnt,
divComb,
seed,
txPower,
title as flowName,
dist,
borderdist,
unicast,
throughput,
distthroughput
FROM DistThroughput AS a, SimulationResult AS b, SimulationResult$$throughput AS c
WHERE a.primary_key = c.elm and c.uid = b.primary_key and b.version=5
'''

# -----------------------------------------------------------------------------
# populates the detailed dist throughput table
evalDistThroughputSql = '''
create table eval.eval_single01_1
select
a.primary_key,
driver,
version,

b.simid,
nodes,
placement,
spacing,
spacingX,
spacingY,
pattern,
patternX,
patternY,
dataRate,
controlRate,
pathlossExp,
shadowStdDev,
fadingK,
fadingVelo,
txAnt,
divComb,
seed,
txPower,
a.title as flowName,
a.dist,
unicast,
a.throughput as flowThroughput,
e.throughput as flowRecvPacketsCuml,
g.throughput as flowSendPacketsCuml
FROM DistThroughput AS a, SimulationResult AS b, SimulationResult$$throughput AS c,
SimulationResult$$recvPackets d, DistThroughput AS e,
SimulationResult$$sendPackets f, DistThroughput AS g
WHERE a.primary_key = c.elm and c.uid = b.primary_key
  and e.primary_key = d.elm and d.uid = b.primary_key
  and g.primary_key = f.elm and f.uid = b.primary_key
  and b.version='Single01.1'
'''

# -----------------------------------------------------------------------------
# create table considering all simulations and mac and flow stats (only all flows)
evalSimulationSql = '''
create table eval.eval_chain01_9_mac
select
driver,
version,

b.simid,
nodes,
placement,
spacing,
spacingX,
spacingY,
pattern,
patternX,
patternY,
dataRate,
controlRate,
pathlossExp,
shadowStdDev,
fadingK,
fadingVelo,
txAnt,
divComb,
seed,
txPower,
unicast,

e.value              as flowName,
start                as flowStart,
end               as flowEnd,
sendPackets       as flowSendPackets,
recvPackets       as flowRecvPackets,
recvPackets / sendPackets as flowRecvRatio,
(broadcastSend+unicastSend) / sendPackets as flowSendPacketToFrameRatio,
avgThroughput/1024     as flowAvgThroughput,
minDelay          as flowMinDelay,
maxDelay          as flowMaxDelay,
avgDelay          as flowAvgDelay,
unicastSend          as macUnicastSend,
unicastRecv          as macUnicastRecv,
unicastRecv / unicastSend as macUnicastRecvRatio,
broadcastSend        as macBroadcastSend,
broadcastRecv        as macBroadcastRecv,
broadcastRecv / broadcastSend as macBroadcastRecvRatio,
ackSend              as macAckSend,
ackRecv              as macAckRecv,
ackRecv / ackSend    as macAckRecvRatio,
radTxDivCount,
radAvgDelaySpread,
radAvgPowerDelta
FROM SimulationResult AS b, brn_sim_data_MacStats AS d, java_lang_String AS e, brn_sim_data_FlowStats AS f, SimulationResult$$flows AS g
WHERE d.primary_key = b.macStats
and e.primary_key = g.key_0 and f.primary_key = g.elm and g.uid = b.primary_key and e.value = 'All flows'
and b.version='Chain01.9'
'''



# -----------------------------------------------------------------------------
# create table considering all flows
evalFlowSql = '''
create table eval.eval_chain01_9_flows
select
driver,
version,

d.simid,
nodes,
placement,
spacing,
spacingX,
spacingY,
pattern,
patternX,
patternY,
dataRate,
controlRate,
pathlossExp,
shadowStdDev,
fadingK,
fadingVelo,
txAnt,
divComb,
seed,
txPower,
unicast,

a.value                   as flowName,
b.sendPackets             as flowSendPackets,
b.sendPackets/spacingX/spacingY             as flowSendPacketsNorm,
b.recvPackets             as flowRecvPackets,
b.recvPackets/spacingX/spacingY             as flowRecvPacketsNorm,
b.recvPackets / b.sendPackets as flowRecvRatio,
b.start                   as flowStart,
b.end                     as flowEnd,
b.avgThroughput/1024      as flowAvgThroughput,
b.avgThroughput/1024/spacingX/spacingY      as flowAvgThroughputNorm,
b.minDelay                as flowMinDelay,
b.maxDelay                as flowMaxDelay,
b.avgDelay                as flowAvgDelay

from java_lang_String a, brn_sim_data_FlowStats b, SimulationResult$$flows c, SimulationResult d where
a.primary_key = c.key_0 and b.primary_key = c.elm and c.uid = d.primary_key
and d.version='Chain01.9'
'''