#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/applications-module.h"
#include "ns3/mobility-module.h"
#include "ns3/stats-module.h"
#include "ns3/wifi-module.h"
#include "ns3/propagation-loss-model.h"

#include <iostream>
#include <vector>

NS_LOG_COMPONENT_DEFINE ("PerimeterEstimation");

using namespace ns3;

 /*void GetDistance_From(Ptr<Node> nd1, Ptr<Node> nd2){
       Ptr<MobilityModel> model1=nd1->GetObject<MobilityModel>();
       Ptr<MobilityModel> model2=nd2->GetObject<MobilityModel>();
       double_t dist=model1->GetDistanceFrom(model2);
       NS_LOG_UNCOND("Rss"<<dist);
}*/

       void GetRssVal(Ptr<PropagationLossModel> model, Ptr<WaypointMobilityModel> wp1, Ptr<WaypointMobilityModel> wp2){

              double tx=+20;
              double rss = model->CalcRxPower(tx, wp1, wp2);
              NS_LOG_UNCOND("Rss2"<<rss);
       }

       int main(int argc, char *argv[]){
       // void rsscalc();

      // void GetDistance_From(Ptr<Node>, Ptr<Node>);
              void GetRssVal(Ptr<PropagationLossModel>, Ptr<WaypointMobilityModel>, Ptr<WaypointMobilityModel>);

              bool verbose = false;
       // /double rss;
              std::string phyMode ("DsssRate1Mbps");

              CommandLine cmd;
              cmd.Parse (argc, argv);

              Config::SetDefault ("ns3::WifiRemoteStationManager::FragmentationThreshold", StringValue ("2200"));
              Config::SetDefault ("ns3::WifiRemoteStationManager::RtsCtsThreshold", StringValue ("2200"));
              Config::SetDefault ("ns3::WifiRemoteStationManager::NonUnicastMode", StringValue (phyMode));

              NodeContainer nc;
              nc.Create(5);

              WifiHelper wifi;
              if (verbose)
              {
                     wifi.EnableLogComponents ();  
              }

              YansWifiPhyHelper wifiPhy =  YansWifiPhyHelper::Default ();
              wifiPhy.Set ("RxGain", DoubleValue (-10) ); 
              wifiPhy.SetPcapDataLinkType (YansWifiPhyHelper::DLT_IEEE802_11_RADIO); 

              YansWifiChannelHelper wifiChannel;
              wifiChannel.SetPropagationDelay ("ns3::ConstantSpeedPropagationDelayModel");
              wifiChannel.AddPropagationLoss ("ns3::RangePropagationLossModel");
              wifiPhy.SetChannel (wifiChannel.Create ());

              NqosWifiMacHelper wifiMac = NqosWifiMacHelper::Default ();
              wifi.SetStandard (WIFI_PHY_STANDARD_80211b);
              wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager",
                     "DataMode",StringValue (phyMode),
                     "ControlMode",StringValue (phyMode));

              wifiMac.SetType ("ns3::AdhocWifiMac");
              NetDeviceContainer devices = wifi.Install (wifiPhy, wifiMac, nc);

              std::vector<MobilityHelper> mobility;
              mobility.resize(4);
              for(int i=0;i<4;i++){
                     mobility[i].SetMobilityModel("ns3::WaypointMobilityModel");
                     mobility[i].Install(nc.Get(i));
              }

              Ptr <RangePropagationLossModel> rangemodel = CreateObject <RangePropagationLossModel> ();

              Ptr<WaypointMobilityModel> qw1 = DynamicCast<WaypointMobilityModel>( nc.Get(0)->GetObject<MobilityModel>());

              uint32_t waypointCount=100;
              Waypoint wpt1 (Seconds (0.0), Vector (0.0, 0.0, 0.0));
              int x=0,y=0;
              for ( uint32_t iw = 0; iw < waypointCount; ++iw )  {
                     wpt1.time += Seconds (1.0);
                     wpt1.position= Vector(x++,y,0);
                     qw1->AddWaypoint(wpt1);


              }

              Ptr<WaypointMobilityModel> qw2 = DynamicCast<WaypointMobilityModel>( nc.Get(1)->GetObject<MobilityModel>());

              Waypoint wpt2 (Seconds (0.0), Vector (0.0, 0.0, 0.0));
              x=0,y=0;
              for ( uint32_t iw = 0; iw < waypointCount; ++iw )
              {
                     wpt2.time += Seconds (1.0);
                     wpt2.position= Vector(x--,y,0);
                     qw2->AddWaypoint(wpt2);
              }

              Ptr<WaypointMobilityModel> qw3 = DynamicCast<WaypointMobilityModel>( nc.Get(2)->GetObject<MobilityModel>());


              Waypoint wpt3 (Seconds (0.0), Vector (0.0, 0.0, 0.0));
              x=0,y=0;
              for ( uint32_t iw = 0; iw < waypointCount; ++iw )
              {
                     wpt3.time += Seconds (1.0);
                     wpt3.position= Vector(x,y--,0);
                     qw3->AddWaypoint(wpt3);
              }

              Ptr<WaypointMobilityModel> qw4 = DynamicCast<WaypointMobilityModel>( nc.Get(3)->GetObject<MobilityModel>());

              Waypoint wpt4 (Seconds (0.0), Vector (0.0, 0.0, 0.0));
              x=0,y=0;
              for ( uint32_t iw = 0; iw < waypointCount; ++iw )
              {
                     wpt4.time += Seconds (1.0);
                     wpt4.position= Vector(x,y++,0);
                     qw4->AddWaypoint(wpt4);
              }

       /*// To get the distance from a node to another node

       Simulator::Schedule(Seconds(6), &GetDistance_From, nc.Get(0), nc.Get(1));*/

       /*To get rss value between 2 nodes*/
          //    for(int i=0;i<50;i+=5)
             //        Simulator::Schedule(Seconds(i), &GetRssVal,rangemodel, qw1, qw2);

              Simulator::Stop (Seconds (200));
              Simulator::Run ();
              Simulator::Destroy ();
              return 0;
       }
