#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/csma-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/applications-module.h"
#include "ns3/ipv4-global-routing-helper.h"

using namespace ns3;

namespace param{
	const int nCsma = 5;
	const int startTime = 0;
	const int stopTime = 30;
	const int maxBytes = 100000;
	const int maxCount = 4;
	const int portNumber1 = 50000;
	const int portNumber2 = 60000;
}

int 
main (int argc, char *argv[])
{
  bool verbose = true;
  
  int count = 0;
  int n = 0;

  NodeContainer p2pNodes;
  p2pNodes.Create (2);

  NodeContainer csmaNodes1;
  csmaNodes1.Add (p2pNodes.Get (1));
  csmaNodes1.Create (param::nCsma);

  NodeContainer csmaNodes2;
  csmaNodes2.Add (p2pNodes.Get (0));
  csmaNodes2.Create (param::nCsma);


  PointToPointHelper pointToPoint;
  pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("10Mbps"));
  pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));

  NetDeviceContainer p2pDevices;
  p2pDevices = pointToPoint.Install (p2pNodes);


  CsmaHelper csma1;
  csma1.SetChannelAttribute ("DataRate", StringValue ("100Mbps"));
  csma1.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560)));
  
  CsmaHelper csma2;
  csma2.SetChannelAttribute ("DataRate", StringValue ("100Mbps"));
  csma2.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560)));


  NetDeviceContainer csmaDevices1;
  csmaDevices1 = csma1.Install (csmaNodes1);

  NetDeviceContainer csmaDevices2;
  csmaDevices2 = csma2.Install (csmaNodes2);


  InternetStackHelper stack;
  stack.Install (csmaNodes2);
  stack.Install (csmaNodes1);


  Ipv4AddressHelper address;
  address.SetBase ("10.1.1.0", "255.255.255.0");
  Ipv4InterfaceContainer p2pInterfaces;
  p2pInterfaces = address.Assign (p2pDevices);

  address.SetBase ("10.1.2.0", "255.255.255.0");
  Ipv4InterfaceContainer csmaInterfaces1;
  csmaInterfaces1 = address.Assign (csmaDevices1);

  address.SetBase ("10.1.3.0", "255.255.255.0");
  Ipv4InterfaceContainer csmaInterfaces2;
  csmaInterfaces2 = address.Assign (csmaDevices2);

  
  while(count != param::maxCount){
	  
	   if(count == 0){
		    uint16_t port2 = param::portNumber2 + n;

			BulkSendHelper source ("ns3::TcpSocketFactory",
			               InetSocketAddress (csmaInterfaces2.GetAddress (param::nCsma), port2));  
			source.SetAttribute ("MaxBytes", UintegerValue (param::maxBytes));
			ApplicationContainer sourceApps = source.Install (csmaNodes1.Get (param::nCsma));
			sourceApps.Start (Seconds (1.000));
			sourceApps.Stop (Seconds (param::stopTime));
		   
		   
			PacketSinkHelper sink ("ns3::TcpSocketFactory",
                           InetSocketAddress (Ipv4Address::GetAny (), port2));
		    ApplicationContainer sinkApps = sink.Install (csmaNodes2.Get (param::nCsma));
		    sinkApps.Start (Seconds (param::startTime));
		    sinkApps.Stop (Seconds (param::stopTime));

			n++;
	  }

	  if(count == 1){
		    uint16_t port1 = param::portNumber1 + n;

			BulkSendHelper source ("ns3::TcpSocketFactory",
			               InetSocketAddress (csmaInterfaces1.GetAddress (param::nCsma - n), port1));  
			source.SetAttribute ("MaxBytes", UintegerValue (param::maxBytes));
			ApplicationContainer sourceApps = source.Install (csmaNodes1.Get (param::nCsma));
			sourceApps.Start (Seconds (1.085));
			sourceApps.Stop (Seconds (param::stopTime));
		   
		   
			PacketSinkHelper sink ("ns3::TcpSocketFactory",
                           InetSocketAddress (Ipv4Address::GetAny (), port1));
		    ApplicationContainer sinkApps = sink.Install (csmaNodes1.Get (param::nCsma - n));
		    sinkApps.Start (Seconds (param::startTime));
		    sinkApps.Stop (Seconds (param::stopTime));

			
	  }

	  if(count == 1){
		    uint16_t port2 = param::portNumber2 + n;		  
		 
		  
			BulkSendHelper source ("ns3::TcpSocketFactory",
			               InetSocketAddress (csmaInterfaces2.GetAddress (param::nCsma - n), port2));  
			source.SetAttribute ("MaxBytes", UintegerValue (param::maxBytes));
			ApplicationContainer sourceApps = source.Install (csmaNodes2.Get (param::nCsma));
			sourceApps.Start (Seconds (1.085));
			sourceApps.Stop (Seconds (param::stopTime));
		  
			PacketSinkHelper sink ("ns3::TcpSocketFactory",
                           InetSocketAddress (Ipv4Address::GetAny (), port2));
		    ApplicationContainer sinkApps = sink.Install (csmaNodes2.Get (param::nCsma - n));
		    sinkApps.Start (Seconds (param::startTime));
		    sinkApps.Stop (Seconds (param::stopTime));
		  
		    n++;
	  }
	  
	  if(count == 2){
		    uint16_t port1 = param::portNumber1 + n;		  
		 
		  
			BulkSendHelper source ("ns3::TcpSocketFactory",
			               InetSocketAddress (csmaInterfaces1.GetAddress (param::nCsma - n), port1));  
			source.SetAttribute ("MaxBytes", UintegerValue (param::maxBytes));
			ApplicationContainer sourceApps = source.Install (csmaNodes1.Get (param::nCsma));
			sourceApps.Start (Seconds (1.127));
			sourceApps.Stop (Seconds (param::stopTime));
		  
			PacketSinkHelper sink ("ns3::TcpSocketFactory",
                           InetSocketAddress (Ipv4Address::GetAny (), port1));
		    ApplicationContainer sinkApps = sink.Install (csmaNodes1.Get (param::nCsma - n));
		    sinkApps.Start (Seconds (param::startTime));
		    sinkApps.Stop (Seconds (param::stopTime));
		  
		    
	  }

	  if(count == 2){
		    uint16_t port2 = param::portNumber2 + n;		  
		 
		  
			BulkSendHelper source ("ns3::TcpSocketFactory",
			               InetSocketAddress (csmaInterfaces2.GetAddress (param::nCsma - n), port2));  
			source.SetAttribute ("MaxBytes", UintegerValue (param::maxBytes));
			ApplicationContainer sourceApps = source.Install (csmaNodes2.Get (param::nCsma));
			sourceApps.Start (Seconds (1.127));
			sourceApps.Stop (Seconds (param::stopTime));
		  
			PacketSinkHelper sink ("ns3::TcpSocketFactory",
                           InetSocketAddress (Ipv4Address::GetAny (), port2));
		    ApplicationContainer sinkApps = sink.Install (csmaNodes2.Get (param::nCsma - n));
		    sinkApps.Start (Seconds (param::startTime));
		    sinkApps.Stop (Seconds (param::stopTime));
		  
		    n++;
	  }

	  if(count == 2){
		    uint16_t port2 = param::portNumber2 + n;		  
		 
		  
			BulkSendHelper source ("ns3::TcpSocketFactory",
			               InetSocketAddress (csmaInterfaces2.GetAddress (param::nCsma - n), port2));  
			source.SetAttribute ("MaxBytes", UintegerValue (param::maxBytes));
			ApplicationContainer sourceApps = source.Install (csmaNodes1.Get (param::nCsma - 1));
			sourceApps.Start (Seconds (1.127));
			sourceApps.Stop (Seconds (param::stopTime));
		  
			PacketSinkHelper sink ("ns3::TcpSocketFactory",
                           InetSocketAddress (Ipv4Address::GetAny (), port2));
		    ApplicationContainer sinkApps = sink.Install (csmaNodes2.Get (param::nCsma - n));
		    sinkApps.Start (Seconds (param::startTime));
		    sinkApps.Stop (Seconds (param::stopTime));
		  
		    
	  }

	  if(count == 2){
		    uint16_t port1 = param::portNumber1 + n;		  
		 
		  
			BulkSendHelper source ("ns3::TcpSocketFactory",
			               InetSocketAddress (csmaInterfaces1.GetAddress (param::nCsma - n), port1));  
			source.SetAttribute ("MaxBytes", UintegerValue (param::maxBytes));
			ApplicationContainer sourceApps = source.Install (csmaNodes2.Get (param::nCsma - 1));
			sourceApps.Start (Seconds (1.127));
			sourceApps.Stop (Seconds (param::stopTime));
		  
			PacketSinkHelper sink ("ns3::TcpSocketFactory",
                           InetSocketAddress (Ipv4Address::GetAny (), port1));
		    ApplicationContainer sinkApps = sink.Install (csmaNodes1.Get (param::nCsma - n));
		    sinkApps.Start (Seconds (param::startTime));
		    sinkApps.Stop (Seconds (param::stopTime));
		  
		    n++;
	  }
	  
	  if(count == 3){
		    uint16_t port1 = param::portNumber1 + n;		  
		 
		  
			BulkSendHelper source ("ns3::TcpSocketFactory",
			               InetSocketAddress (csmaInterfaces1.GetAddress (param::nCsma - n), port1));  
			source.SetAttribute ("MaxBytes", UintegerValue (param::maxBytes));
			ApplicationContainer sourceApps = source.Install (csmaNodes1.Get (param::nCsma));
			sourceApps.Start (Seconds (1.141));
			sourceApps.Stop (Seconds (param::stopTime));
		  
			PacketSinkHelper sink ("ns3::TcpSocketFactory",
                           InetSocketAddress (Ipv4Address::GetAny (), port1));
		    ApplicationContainer sinkApps = sink.Install (csmaNodes1.Get (param::nCsma - n));
		    sinkApps.Start (Seconds (param::startTime));
		    sinkApps.Stop (Seconds (param::stopTime));
		  
		    
	  }

	  if(count == 3){
		    uint16_t port2 = param::portNumber2 + n;		  
		 
		  
			BulkSendHelper source ("ns3::TcpSocketFactory",
			               InetSocketAddress (csmaInterfaces2.GetAddress (param::nCsma - n), port2));  
			source.SetAttribute ("MaxBytes", UintegerValue (param::maxBytes));
			ApplicationContainer sourceApps = source.Install (csmaNodes2.Get (param::nCsma));
			sourceApps.Start (Seconds (1.139));
			sourceApps.Stop (Seconds (param::stopTime));
		  
			PacketSinkHelper sink ("ns3::TcpSocketFactory",
                           InetSocketAddress (Ipv4Address::GetAny (), port2));
		    ApplicationContainer sinkApps = sink.Install (csmaNodes2.Get (param::nCsma - n));
		    sinkApps.Start (Seconds (param::startTime));
		    sinkApps.Stop (Seconds (param::stopTime));
		  
		    n++;
	  }
	  
	  count++;
  }

  Ipv4GlobalRoutingHelper::PopulateRoutingTables ();

  Simulator::Stop (Seconds (param::stopTime + 2));

  pointToPoint.EnablePcapAll ("p2p 10");
  csma1.EnablePcap ("p2p 10", csmaDevices1.Get (1), true);
  csma2.EnablePcap ("p2p 10", csmaDevices2.Get (1), true);
  Simulator::Run ();
  Simulator::Destroy ();
  return 0;
}
