#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 - n), port2));  
		source.SetAttribute ("MaxBytes", UintegerValue (param::maxBytes));
		ApplicationContainer sourceApps = source.Install (csmaNodes1.Get (param::nCsma));
		sourceApps.Start (Seconds (1.0));
		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 == 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.114));
		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.114));
		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 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 - 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));

	  }

	  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 - 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));

		  n++;
	  }

	  if(count == 3){
		  uint16_t port = param::portNumber1 + n;

		  BulkSendHelper source ("ns3::TcpSocketFactory",
                         InetSocketAddress (csmaInterfaces1.GetAddress (param::nCsma - n), port));  
		  source.SetAttribute ("MaxBytes", UintegerValue (param::maxBytes));
		  ApplicationContainer sourceApps = source.Install (csmaNodes1.Get (param::nCsma));
		  sourceApps.Start (Seconds (1.153));
		  sourceApps.Stop (Seconds (param::stopTime));


		  PacketSinkHelper sink ("ns3::TcpSocketFactory",
                         InetSocketAddress (Ipv4Address::GetAny (), port));
		  ApplicationContainer sinkApps = sink.Install (csmaNodes1.Get (param::nCsma - n));
		  sinkApps.Start (Seconds (param::startTime));
		  sinkApps.Stop (Seconds (param::stopTime));

	  }

	  if(count == 3){
		  
		  uint16_t port = param::portNumber2 + n;

		  BulkSendHelper source ("ns3::TcpSocketFactory",
                         InetSocketAddress (csmaInterfaces2.GetAddress (param::nCsma - n), port));  
		  source.SetAttribute ("MaxBytes", UintegerValue (param::maxBytes));
		  ApplicationContainer sourceApps = source.Install (csmaNodes2.Get (param::nCsma));
		  sourceApps.Start (Seconds (1.146));
		  sourceApps.Stop (Seconds (param::stopTime));


		  PacketSinkHelper sink ("ns3::TcpSocketFactory",
                         InetSocketAddress (Ipv4Address::GetAny (), port));
		  ApplicationContainer sinkApps = sink.Install (csmaNodes2.Get (param::nCsma - n));
		  sinkApps.Start (Seconds (param::startTime));
		  sinkApps.Stop (Seconds (param::stopTime));

		  n++;
	  }

	  count = count++;
  }
 
 
  Ipv4GlobalRoutingHelper::PopulateRoutingTables ();

  Simulator::Stop (Seconds (param::stopTime + 2));

  pointToPoint.EnablePcapAll ("p4p 10");
  csma1.EnablePcap ("p4p 10", csmaDevices1.Get (1), true);
  csma2.EnablePcap ("p4p 10", csmaDevices2.Get (1), true);
  Simulator::Run ();
  Simulator::Destroy ();
  return 0;
}
