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 brn.sim import *
from brn.sim.data import *
from brn.sim.builder import *
import brn.swans.Constants as BrnConstants

from click.sim.builder import *

from test import TestDriver

true = 1
false = 0

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


class RtpTest(TestDriver):
    def __init__(self):
        pass

    def envParams(self):
        params = AbstractParams()

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

        # field
        params.field.fieldX = int(400)
        params.field.fieldY = int(400)
        params.field.spatial_mode = Constants.SPATIAL_HIER
        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 = 12
        #params.field.fading.traceFile = "../brn.jist/res/fading/rice_table.txt"
        #params.field.fading = FadingBuilder.RicianParams()
        #params.field.fading.K = 6

        return params


    def getJistNode(self, field, nodeParams):
        nodeParams.radio = RadioBuilder.NoiseAdditiveBerParams()
        nodeParams.radio.useAnnos = true
        nodeParams.radio.fieldX = field.fieldX
        nodeParams.radio.fieldY = field.fieldY
        #nodeParams.radio.placement = Constants.PLACEMENT_GRID
        #nodeParams.radio.placementOpts = "5x5"
        nodeParams.radio.placement = Constants.PLACEMENT_MANUAL
        nodeParams.radio.placementOpts = '282.494x210.4106: 86.2946x143.4466: 339.5293x17.039: 338.7066x130.8133: 221.6256x203.7057: 373.549x7.149: 112.6844x204.7621: 50.3338x2.0888: 71.4796x22.6795: 143.5478x179.6795: 307.5611x78.9896: 207.6851x49.8872: 296.736x236.8324: 209.0097x125.0367: 156.7916x210.9243: 60.1111x324.7711: 201.9642x193.8886: 99.2346x297.8131: 166.7675x343.3851: 114.7103x26.3367: 220.79x241.3338: 82.523x247.172: 263.299x326.1139: 321.3202x342.5137: 27.8487x170.7655: 134.8403x186.3928: 348.8375x69.289: 258.2174x99.6261: 341.7331x387.1084: 210.2313x154.4704: 357.3141x175.8907: 362.7455x268.9009: 344.0876x395.9033: 308.1311x246.5946: 11.4928x235.7724: 127.8575x362.1642: 208.1073x300.6962: 203.2921x341.8668: 140.1606x114.1046: 150.101x253.4018: 307.9187x351.2549: 88.591x63.1429: 20.7658x291.1235: 190.1405x54.8507: 32.5602x368.3264: 151.6639x29.2485: 91.0515x19.8032: 339.9184x59.5464: 352.4038x134.7987: 195.7055x114.442'

        # 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 = RateBuilder.ConstantParams()
        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_MCEXOR, \
            Constants.NET_PROTOCOL_FLOODING, \
            Constants.NET_PROTOCOL_ARP \
          ], 'i')

        # route
        nodeParams.route = RouteBuilder.BrnDsrParams()
        nodeParams.route.protocol = Constants.NET_PROTOCOL_MCEXOR
        nodeParams.route.forwarding = BrnConstants.FORWARDING_UNICAST
        nodeParams.route.discovery = BrnConstants.DISCOVERY_REACTIVE
        nodeParams.route.bitrateFromLinkTable = false
        nodeParams.route.minLinkMetric = 50 * Constants.MILLI_SECOND

        nodeParams.route.metric = MetricBuilder.EttParams()
        nodeParams.route.metric.probes = array( [
                Constants.BANDWIDTH_6Mbps, 1500
          ] , 'i')
        nodeParams.route.metric.period = 1000
        nodeParams.route.metric.tau = 30000
        nodeParams.route.metric.globalLinkTable = false

        return nodeParams


    def getClickNode(self, field, nodeParams):
        nodeParams.radio = RadioBuilder.NoiseAdditiveBerParams()
        nodeParams.radio.useAnnos = true
        nodeParams.radio.fieldX = field.fieldX
        nodeParams.radio.fieldY = field.fieldY
        #nodeParams.radio.placement = Constants.PLACEMENT_GRID
        #nodeParams.radio.placementOpts = "15x1"
        nodeParams.radio.placement = Constants.PLACEMENT_MANUAL
        nodeParams.radio.placementOpts = '282.494x210.4106: 86.2946x143.4466: 339.5293x17.039: 338.7066x130.8133: 221.6256x203.7057: 373.549x7.149: 112.6844x204.7621: 50.3338x2.0888: 71.4796x22.6795: 143.5478x179.6795: 307.5611x78.9896: 207.6851x49.8872: 296.736x236.8324: 209.0097x125.0367: 156.7916x210.9243: 60.1111x324.7711: 201.9642x193.8886: 99.2346x297.8131: 166.7675x343.3851: 114.7103x26.3367: 220.79x241.3338: 82.523x247.172: 263.299x326.1139: 321.3202x342.5137: 27.8487x170.7655: 134.8403x186.3928: 348.8375x69.289: 258.2174x99.6261: 341.7331x387.1084: 210.2313x154.4704: 357.3141x175.8907: 362.7455x268.9009: 344.0876x395.9033: 308.1311x246.5946: 11.4928x235.7724: 127.8575x362.1642: 208.1073x300.6962: 203.2921x341.8668: 140.1606x114.1046: 150.101x253.4018: 307.9187x351.2549: 88.591x63.1429: 20.7658x291.1235: 190.1405x54.8507: 32.5602x368.3264: 151.6639x29.2485: 91.0515x19.8032: 339.9184x59.5464: 352.4038x134.7987: 195.7055x114.442'

        #nodeParams.radio.placement = Constants.PLACEMENT_RANDOM
        #nodeParams.radio.min_connectivity_betweenNodes = 1
        # TODO connectivity simulation does not consider rx noise figure,
        # so use a higher bit rate here
        #nodeParams.radio.connectivityBitRate = Constants.BANDWIDTH_36Mbps
        #nodeParams.radio.threshold = .8
        #nodeParams.radio.connectivity_use_sensing = false
        #nodeParams.radio.seed = 42

        # mac
        nodeParams.mac = ClickBuilder.MacParams()
        nodeParams.mac.useAnnos = nodeParams.radio.useAnnos
        nodeParams.mac.useBitRateAnnos = false
        nodeParams.mac.macPromisc = true
        nodeParams.mac.rateSelection = RateBuilder.ConstantParams()
        nodeParams.mac.rateSelection.dataBitrate = Constants.BANDWIDTH_6Mbps
        nodeParams.mac.rateSelection.controlBitrate = Constants.BANDWIDTH_6Mbps

        # net
        nodeParams.net = ClickBuilder.NetParams()
        nodeParams.net.protocolMapper = array([
            Constants.NET_PROTOCOL_LINK_PROBE,
            Constants.NET_PROTOCOL_UDP,
            Constants.NET_PROTOCOL_TCP,
            Constants.NET_PROTOCOL_DSR,
            Constants.NET_PROTOCOL_FLOODING,
            Constants.NET_PROTOCOL_ARP
          ], 'i')
        nodeParams.net.clickfile = "res/click/meshnode.click"
        #nodeParams.net.clickGui = true

        # route is in click!
        nodeParams.route = None

        return nodeParams


    def getParams(self):
        params = self.envParams()

        nodeParams =  NodeBuilder.TrafficParams()
        nodeParams.traffic = TrafficBuilder.RadialGatewayParams()
        nodeParams.trans   = TransBuilder.UdpParams()

        params.nodeNumber = array( [50], 'i')
        #params.nodeParams = array([self.getJistNode(params.field, nodeParams)],
        #                           NodeBuilder.NodeParams)
        params.nodeParams = array([self.getClickNode(params.field, nodeParams)],
                                  NodeBuilder.NodeParams)

        flowParams = RtpFlowBuilder.RtpFlowParams()
        flowParams.duration = 10000

        params.nodeParams[0].traffic.flowParams    = flowParams
        params.nodeParams[0].traffic.useHalfCircle = false
        params.nodeParams[0].traffic.flows         = 1
        params.nodeParams[0].traffic.startOffset   = 500

        return params


    def runLocal(self):
        params = self.getParams()

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

        # keep flows shorter than 10 s when using time bar!
        params.handlerRadioTimeBarLevel = NONE
        params.handlerMacTimeBarLevel = NONE
        params.handlerNetTimeBarLevel = NONE

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

        #params.dumpRadioNam = 'radio.nam';
        #params.dumpRadio = 'radio.tr';
        #params.dumpMac = true
        params.dumpNet = true;

        params.db = True

        self.run(params)

    def runTest(self, version):
      if "1" == version:
        params = self.getParams()
      else:
        print "version " + version + " unknown"
        return

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

      # keep flows shorter than 10 s when using time bar!
      params.handlerRadioTimeBarLevel = NONE
      params.handlerMacTimeBarLevel = NONE
      params.handlerNetTimeBarLevel = NONE

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

      params.db = False

      self.run(params)

    def getSimulationSuite(self, version):
        params = self.getParams()

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

        # keep flows shorter than 10 s when using time bar!
        params.handlerRadioTimeBarLevel = NONE
        params.handlerMacTimeBarLevel = NONE
        params.handlerNetTimeBarLevel = NONE

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

        params.db = True

        list = ArrayList()
        list.add(params)
        return list

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

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