########################################################################################################################
# Copyright (c) 2015, University of Osnabrueck                                                                         #
#   All rights reserved.                                                                                               #
#                                                                                                                      #
#   Redistribution and use in source and binary forms, with or without modification, are permitted provided that the   #
#   following conditions are met:                                                                                      #
#                                                                                                                      #
#   1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following#
#       disclaimer.                                                                                                    #
#                                                                                                                      #
#   2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the       #
#       following disclaimer in the documentation and/or other materials provided with the distribution.               #
#                                                                                                                      #
#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, #
#   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE  #
#   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, #
#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR    #
#   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  #
#   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE   #
#   USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                           #
########################################################################################################################


from ns.applications import *
from ns.core import *
from ns.internet import *
from ns.network import *
import ns.point_to_point
from ns.wifi import *
from ns.mobility import *
from ns.olsr import *
import sys
import numpy as np

PROBETIME = 4.0

"""
This script offers an example of how to use the RaLaNSPropagationLossModel.
A WiFi-node is placed at "transmitter". Then a second WiFi-node is placed once on every position of a grid defined by
"borders" and "stepwidth". At every position, one UDP-packet is sent between the WiFi-nodes. The received power for
each packet is logged using the YansWifiChannel logging component. This script is called by the ralanstest-script
"""

def SetPosition(node, position):
    mobility = node.GetObject(MobilityModel.GetTypeId())
    mobility.SetPosition(position)


def SendPacket(socket):
    socket.Send(Packet(1024))


def main(argv):
    #LogComponentEnable("UdpEchoClientApplication", ns.core.LOG_LEVEL_INFO)
    #LogComponentEnable("UdpEchoServerApplication", ns.core.LOG_LEVEL_INFO)
    LogComponentEnable("YansWifiChannel", LOG_LEVEL_DEBUG);
    LogComponentEnable("RaLaNSPropagationLossModel", ns.core.LOG_LEVEL_INFO);

    cmd = CommandLine()
    cmd.transmitter = "[0, 0, 1]"
    cmd.AddValue("transmitter", "Where to place the transmitter (e.g: [0,0,1])")
    cmd.borders = "[-100, -100, 100, 100]"
    cmd.AddValue("borders", "Borders of scanning area in python style: [left, bottom, right, top]")
    cmd.stepwidth = 1
    cmd.AddValue("stepwidth", "Stepwidth of probe as a float")
    cmd.threshold = 20.0
    cmd.AddValue("threshold", "the maximal distance for calculating")
    cmd.interpolate = True
    cmd.AddValue("interpolate", "Choose whether to interpolate or not")
    cmd.mapFile = "/home/joris/workspace/bake/source/ns-3.22/coverage/small_street_flat_trPOINTrecAREA0.08.txt"
    cmd.AddValue("mapFile", "Set filepath")
    cmd.nosignal = -3076.53
    cmd.AddValue("nosignal", "Set no signal value")
    cmd.badnum = 0
    cmd.AddValue("badnum", "Set the badNum value, to exclude max. badNum no signal values")
    cmd.listinterpolationnum = 2
    cmd.AddValue("listinterpolationnum", "Set the listInterpolationNum value, to set the number of interpolation points\
            for the list calculation")
    cmd.Parse(argv)

    PROBETIME = 4.0
    transmitter = eval(cmd.transmitter)
    stepwidth = float(cmd.stepwidth)
    borders = eval(cmd.borders)
    threshold = float(cmd.threshold)
    mapFile = cmd.mapFile
    interpolate = bool(cmd.interpolate)
    nosignal = float(cmd.nosignal)
    badnum = int(cmd.badnum)
    listinterpolationnum = int(cmd.listinterpolationnum)
    traceName = "trace"


    wifiStaNodes = NodeContainer()
    wifiStaNodes.Create(1)
    probeNode = NodeContainer()
    probeNode.Create(1)

    #INITIALIZATION OF THE PropagationLossModel
    channel = YansWifiChannelHelper()
    channel.AddPropagationLoss("ns3::RaLaNSPropagationLossModel", 
                                  "mapFile",
                                  StringValue(mapFile), 
                                  "interpolate", BooleanValue(interpolate),
                                  "noSignal", DoubleValue(nosignal),
                                  "badNum", IntegerValue(badnum),
                                  "listInterpolationNum", IntegerValue(listinterpolationnum),
                                  "threshold", DoubleValue(threshold))
    channel.SetPropagationDelay("ns3::ConstantSpeedPropagationDelayModel")
    phy = YansWifiPhyHelper().Default()
    phy.SetChannel(channel.Create());

    wifiHelper = WifiHelper();
    wifiHelper.SetStandard(WIFI_PHY_STANDARD_80211b);

    wifiHelper.SetRemoteStationManager("ns3::ConstantRateWifiManager",
                                       "DataMode", StringValue("DsssRate1Mbps"),
                                       "ControlMode", StringValue("DsssRate1Mbps"))

    macHelper = NqosWifiMacHelper.Default()

    macHelper.SetType("ns3::AdhocWifiMac")
    staDevices = wifiHelper.Install(phy, macHelper, wifiStaNodes)
    probeDevice = wifiHelper.Install(phy, macHelper, probeNode)


    listPositionAllocator = ListPositionAllocator()
    listPositionAllocator.Add(Vector(transmitter[0], transmitter[1], transmitter[2]))
    listPositionAllocator.Add(Vector(1000, 0, 0))  #some initial position for the probe
    mobility = MobilityHelper()
    mobility.SetPositionAllocator(listPositionAllocator)
    mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel")
    mobility.Install(wifiStaNodes)
    mobility.Install(probeNode)

    stack = InternetStackHelper()
    stack.Install(wifiStaNodes)
    stack.Install(probeNode)

    address = Ipv4AddressHelper()
    address.SetBase(Ipv4Address("10.1.1.0"), Ipv4Mask("255.255.255.0"))
    staInterfaces = address.Assign(staDevices)
    probeInterface = address.Assign(probeDevice)

    tid = TypeId.LookupByName("ns3::UdpSocketFactory")
    recvSink = Socket.CreateSocket(probeNode.Get(0), tid)
    localAddress = InetSocketAddress(Ipv4Address.GetAny(), 80)
    recvSink.Bind(localAddress)

    source = Socket.CreateSocket(wifiStaNodes.Get(0), tid);
    remote = InetSocketAddress(Ipv4Address("255.255.255.255"), 80);
    source.SetAllowBroadcast(True)
    source.Connect(remote)

    Simulator.Schedule(Seconds(40.0 - PROBETIME / 2.0), SetPosition, probeNode.Get(0),
                       Vector(borders[0], borders[1], 0))
    simtime = 40.0  #give some time for building up routing tables
    print borders
    for x in np.arange(borders[0], borders[2], stepwidth):
        for y in np.arange(borders[1], borders[3], stepwidth):
            Simulator.Schedule(Seconds(simtime), SetPosition, probeNode.Get(0), Vector(x, y, transmitter[2]))
            simtime += PROBETIME * 1.0 / 2
            Simulator.Schedule(Seconds(simtime), SendPacket, source)
            simtime += PROBETIME * 1.0 / 2
    print "Simtime=", simtime

    phy.EnablePcapAll("traces/spnesimulation/" + traceName)
    phy.EnableAsciiAll("traces/spnesimulation/" + traceName)
    print "Transmitter= ",transmitter
    print "start simulation"
    Simulator.Stop(Seconds(simtime))
    Simulator.Run()
    Simulator.Destroy()
    print "simulation finished"



if __name__ == '__main__':
    sys.exit(main(sys.argv))
