using namespace ns3 ;

NS_LOG_COMPONENT_DEFINE("Project");

ns3::Time timeout = ns3::Seconds (0);

int main(int argc, char *argv[])
{

	NS_LOG_INFO("Create Nodes");
	NodeContainer csmanode;
	csmanode.Create(4);

	NodeContainer OFSwitch;
	OFSwitch.Create(1);

	NS_LOG_INFO("Build Topology");
	CsmaHelper csma;
	csma.SetChannelAttribute ("DataRate", DataRateValue (5000000));
	csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2)));

	NetDeviceContainer csmaNetDevices, csmaNetDevices1, csmaNetDevices2, link;
	NetDeviceContainer switchDevice;

	//connect node0 to node1
	link = csma.Install(NodeContainer(csmanode.Get(0),csmanode.Get(1)));
	csmaNetDevices.Add(link.Get(0));
	csmaNetDevices.Add(link.Get(1));

	//connect node1 to OFSwitch
	link = csma.Install(NodeContainer(csmanode.Get(1),OFSwitch.Get(0)));
	csmaNetDevices1.Add(link.Get(0));
	switchDevice.Add(link.Get(1));

	//connect OFSwitch to node2
	link = csma.Install(NodeContainer(OFSwitch.Get(0),csmanode.Get(2)));
	switchDevice.Add(link.Get(0));
	csmaNetDevices1.Add(link.Get(1));

	//connect node2 to node3
	link = csma.Install(NodeContainer(csmanode.Get(2),csmanode.Get(3)));
	csmaNetDevices2.Add(link.Get(0));
	csmaNetDevices2.Add(link.Get(1));

	
	//Create Switch net device, which will do packet switching

	Ptr<Node> switchNode = OFSwitch.Get (0);
	BridgeHelper bridge;
	bridge.Install (switchNode, switchDevice);

	//Add Internet stack to terminals
	 InternetStackHelper internet;
	 internet.Install(csmanode);

	 Ipv4AddressHelper address;
	 address.SetBase ("10.1.1.0", "255.255.255.0");
	 address.Assign (csmaNetDevices);

	 address.SetBase ("10.1.2.0", "255.255.255.0");
	 address.Assign (csmaNetDevices1);

	 address.SetBase ("10.1.3.0", "255.255.255.0");
	 address.Assign (csmaNetDevices2);

	 Ipv4GlobalRoutingHelper::PopulateRoutingTables ();

	 //Print IP address of Nodes
	 for (int i=0; i<4; i++)
	   {
	      Ptr<Node> n = csmanode.Get (i);
	      Ptr<Ipv4> ipv4 = n->GetObject<Ipv4> ();
	      Ipv4InterfaceAddress ipv4_int_addr = ipv4->GetAddress (1, 0);
	      Ipv4Address ip_addr = ipv4_int_addr.GetLocal ();
	      NS_LOG_INFO ("Node: " << i << " IP Address: "<< ip_addr);
	   }
	
	 Ptr<Node> n = csmanode.Get (0);
	 Ptr<Ipv4> ipv4 = n->GetObject<Ipv4> ();
	 Ipv4InterfaceAddress ipv4_int_addr = ipv4->GetAddress (1, 0);
	 Ipv4Address ip_addr = ipv4_int_addr.GetLocal ();

	 Ptr<OutputStreamWrapper> routintable = Create<OutputStreamWrapper>("routingtable",std::ios::out);
	 Ipv4GlobalRoutingHelper ipv4global;
	 ipv4global.PrintRoutingTableAllAt(Seconds(10.0), routintable);



	 OnOffHelper onoff("ns3::UdpSocketFactory",Address(InetSocketAddress(ip_addr,1024)));
	 onoff.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]"));
	 onoff.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]"));
	 onoff.SetAttribute ("DataRate", DataRateValue (DataRate (6000)));

	 ApplicationContainer apps = onoff.Install(csmanode.Get(3));
	 apps.Start(Seconds(1.0));
	 apps.Stop(Seconds(20.0));


	 PacketSinkHelper sink ("ns3::UdpSocketFactory", Address (InetSocketAddress (Ipv4Address::GetAny(), 1024)));
	 apps = sink.Install(csmanode.Get(0));
	 apps.Start(Seconds(0.0));
	 apps.Stop(Seconds(22.0));


	  AsciiTraceHelper ascii;
	  Ptr<OutputStreamWrapper> stream = ascii.CreateFileStream ("MobilityWlans.tr");
	  csma.EnableAsciiAll (stream);
	  csma.EnablePcapAll ("MobilityWlans", false);



	 NS_LOG_INFO ("Run Simulation.");
	 Simulator::Run ();
	 Simulator::Destroy ();
	 NS_LOG_INFO ("Done.");

}

















