/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation;
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Author: Vikas Pushkar (Adapted from third.cc)
 */


#include <cstdint>
#include <iostream>

#include "../build/ns3/animation-interface.h"
#include "../build/ns3/application-container.h"
#include "../build/ns3/basic-energy-source.h"
#include "../build/ns3/boolean.h"
#include "../build/ns3/command-line.h"
#include "../build/ns3/double.h"
#include "../build/ns3/internet-stack-helper.h"
#include "../build/ns3/ipv4-address.h"
#include "../build/ns3/ipv4-address-helper.h"
#include "../build/ns3/ipv4-global-routing-helper.h"
#include "../build/ns3/ipv4-interface-container.h"
#include "../build/ns3/log.h"
#include "../build/ns3/mobility-helper.h"
#include "../build/ns3/net-device-container.h"
#include "../build/ns3/node.h"
#include "../build/ns3/node-container.h"
#include "../build/ns3/nstime.h"
#include "../build/ns3/object.h"
#include "../build/ns3/point-to-point-helper.h"
#include "../build/ns3/ptr.h"
#include "../build/ns3/simple-device-energy-model.h"
#include "../build/ns3/simulator.h"
#include "../build/ns3/ssid.h"
#include "../build/ns3/string.h"
#include "../build/ns3/udp-echo-helper.h"
#include "../build/ns3/uinteger.h"
#include "../build/ns3/wifi-helper.h"
#include "../build/ns3/wifi-mac-helper.h"
#include "../build/ns3/wifi-phy-standard.h"
#include "../build/ns3/yans-wifi-helper.h"

using namespace ns3;
int flag=0;

NS_LOG_COMPONENT_DEFINE ("80211af");
//LogComponentEnable("80211af", LogLevel(LOG_LEVEL_DEBUG));

int 
main (int argc, char *argv[])
{
  int nWifi = 300;
  CommandLine cmd;
  cmd.AddValue ("nWifi", "Number of wifi STA devices", nWifi);


  cmd.Parse (argc,argv);
  NodeContainer allNodes;
  NodeContainer wifiStaNodes;
  wifiStaNodes.Create (nWifi);
  allNodes.Add (wifiStaNodes);
  NodeContainer wifiApNode ;
  wifiApNode.Create (1);
  allNodes.Add (wifiApNode);

  NodeContainer p2pNodes;
  p2pNodes.Add (wifiApNode);
  p2pNodes.Create(1);
  allNodes.Add (p2pNodes.Get (1));

  PointToPointHelper pointToPoint;
  pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
  pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));

  NetDeviceContainer p2pDevices;
  p2pDevices = pointToPoint.Install (p2pNodes);

  MobilityHelper mobility;
  mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
  mobility.Install (wifiStaNodes);
  mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
  mobility.Install (wifiApNode);

  int lines=3, DeltaX=25, DeltaY=200;
    for(int count=0; count<lines; count++)
    {
  	for(int i=0; i<int((nWifi)/lines); i++)
  	{
  	  AnimationInterface::SetConstantPosition (wifiStaNodes.Get(i+int(nWifi*count/lines)),(i+1)*DeltaX,count*DeltaY, 1);
  	}
    std::cout<<(count+1)*nWifi/lines<<" geophones have been displayed \n";
  }

  AnimationInterface::SetConstantPosition (wifiApNode.Get(0),(nWifi/lines-1)*DeltaX/2, (lines-1)*DeltaY/2, 3);
  AnimationInterface::SetConstantPosition (p2pNodes.Get(1),(nWifi/lines-1)*DeltaX/2  , (lines-1)*DeltaY+100, 0);

  YansWifiChannelHelper channel = YansWifiChannelHelper::Default ();
  YansWifiPhyHelper phy = YansWifiPhyHelper::Default ();

  channel.AddPropagationLoss("ns3::TwoRayGroundPropagationLossModel","Frequency",DoubleValue(300e+06));//,"SystemLoss",DoubleValue(50));
  //channel.SetPropagationDelay ("ns3::ConstantSpeedPropagationDelayModel");
  phy.SetChannel (channel.Create ());
  phy.Set("TxPowerStart",DoubleValue(16.02));
  phy.Set("TxPowerEnd",DoubleValue(16.02));
  phy.Set("TxPowerLevels", UintegerValue(1));
  phy.Set("TxGain",DoubleValue(80));
  phy.Set("RxGain",DoubleValue(-3));
  phy.Set("EnergyDetectionThreshold",DoubleValue(-88));

  WifiHelper wifi;
  wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager","DefaultTxPowerLevel", UintegerValue (30));//,"DataMode", StringValue("VhtMcs9"), "ControlMode", StringValue("VhtMcs0"));

  //Ptr<WifiPhy> phy1;
  //phy1->DefineChannelNumber (34, WIFI_PHY_STANDARD_80211af, 300, 10);
  wifi.SetStandard (WIFI_PHY_STANDARD_80211ac);

  WifiMacHelper mac;
  Ssid ssid = Ssid ("ns-3-ssid");

  NetDeviceContainer staDevices;
  mac.SetType ("ns3::StaWifiMac","Ssid", SsidValue (ssid),"ActiveProbing", BooleanValue (false));
  staDevices = wifi.Install (phy, mac, wifiStaNodes);

  NetDeviceContainer apDevices;
  mac.SetType ("ns3::ApWifiMac","Ssid", SsidValue (ssid));
  apDevices = wifi.Install (phy, mac, wifiApNode);

  Ptr<BasicEnergySource> energySource = CreateObject<BasicEnergySource>();
  Ptr<SimpleDeviceEnergyModel> energyModel = CreateObject<SimpleDeviceEnergyModel>();

  energySource->SetInitialEnergy (100);
  energyModel->SetEnergySource (energySource);
  energySource->AppendDeviceEnergyModel (energyModel);
  energyModel->SetCurrentA (20);

  // aggregate energy source to node
  wifiApNode.Get (0)->AggregateObject (energySource);

  // Install internet stack

  InternetStackHelper stack;
  stack.Install (allNodes);

  // Install Ipv4 addresses

  Ipv4AddressHelper address;
  address.SetBase ("10.1.0.0", "255.255.192.0");
  Ipv4InterfaceContainer p2pInterfaces;
  p2pInterfaces = address.Assign (p2pDevices);
  address.SetBase ("10.2.0.0", "255.255.192.0");
  Ipv4InterfaceContainer staInterfaces;
  staInterfaces = address.Assign (staDevices);
  Ipv4InterfaceContainer apInterface;
  apInterface = address.Assign (apDevices);

  // Install applications

  UdpEchoServerHelper echoServer (9);
  ApplicationContainer serverApps = echoServer.Install (p2pNodes.Get (1));
  serverApps.Start (Seconds (1.0));
  serverApps.Stop (Seconds (5.0));
  UdpEchoClientHelper echoClient (p2pInterfaces.GetAddress (1), 9);
  echoClient.SetAttribute ("MaxPackets", UintegerValue (10));
  echoClient.SetAttribute ("Interval", TimeValue (Seconds (2.5)));
  echoClient.SetAttribute ("PacketSize", UintegerValue (1024));
  ApplicationContainer clientApps = echoClient.Install (wifiStaNodes);
  clientApps.Start (Seconds (2.0));
  clientApps.Stop (Seconds (5.0));

  Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
  Simulator::Stop (Seconds (15.0));

  AnimationInterface anim ("wireless-sample.xml"); // Mandatory
  for (uint32_t i = 0; i < wifiStaNodes.GetN (); ++i)
    {
      anim.UpdateNodeDescription (wifiStaNodes.Get (i), "G"); // Optional
      anim.UpdateNodeColor (wifiStaNodes.Get (i), 255, 0, 0); // Optional
    }
  for (uint32_t i = 0; i < wifiApNode.GetN (); ++i)
    {
      anim.UpdateNodeDescription (wifiApNode.Get (i), "WGN"); // Optional
      anim.UpdateNodeColor (wifiApNode.Get (i), 0, 255, 0); // Optional
    }
    anim.UpdateNodeDescription (p2pNodes.Get (1), "Data Center"); // Optional
    anim.UpdateNodeColor (p2pNodes.Get (1), 0, 0, 255); // Optional
  std::cout<<"Program executed! \n";
  anim.EnablePacketMetadata (); // Optional
  //anim.EnableIpv4RouteTracking ("routingtable-wireless.xml", Seconds (0), Seconds (5), Seconds (0.25)); //Optional
 // anim.EnableWifiMacCounters (Seconds (0), Seconds (10)); //Optional
  // anim.EnableWifiPhyCounters (Seconds (0), Seconds (10)); //Optional
  Simulator::Run ();
  Simulator::Destroy ();
  return 0;
}
