#include "ns3/core-module.h"
#include "ns3/csma-module.h"
#include "ns3/wifi-module.h"
#include "ns3/mobility-module.h"
#include "ns3/network-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-helper.h"
#include "ns3/application-container.h"
#include "ns3/packet-sink-helper.h"
#include "ns3/on-off-helper.h"
#include "ns3/random-variable-stream.h"
#include "ns3/wifi-mode.h"

#include "iostream"
#include "string"
using namespace ns3;
using namespace std;

NS_LOG_COMPONENT_DEFINE ("Test1");


int main (int argc,char *argv[])
{
	Packet::EnableChecking();
	Packet::EnablePrinting();	
	uint32_t nVoipSta = 2;
	uint32_t nFtpSta = 6;
	uint32_t nLiveStreamingSta = 1;  //&VoD
	uint32_t nVideoSta = 1;
	uint32_t nSta = nVoipSta + nFtpSta + nLiveStreamingSta + nVideoSta;
	uint32_t nVoipSer = 2;
	uint32_t nFtpSer = 6;
	uint32_t nLiveStreamingSer = 1;  //&VoD
	uint32_t nVideoSer = 1;
	uint32_t nCsma = nVoipSer + nFtpSer + nLiveStreamingSer + nVideoSer;
	bool verbose = true;
	if(verbose)
	{
		//LogComponentEnable("ApWifiMac", LOG_LEVEL_ALL);
		//LogComponentEnable("OnOffApplication", LOG_LEVEL_INFO);
	}	
	Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (1460));
	//create nodes
	NodeContainer p2pNode;
	p2pNode.Create (2);

	NodeContainer wifiApNode;
	wifiApNode = p2pNode.Get(0);
	NodeContainer wifiStaNode;
	wifiStaNode.Create (nSta);

	NodeContainer csmaNode;
	csmaNode.Add(p2pNode.Get(1));
	csmaNode.Create (nCsma);

	//create & setup wifi channel
	YansWifiChannelHelper channel = YansWifiChannelHelper::Default();
	YansWifiPhyHelper phy = YansWifiPhyHelper::Default();
	phy.SetChannel(channel.Create());

	//install wire devices
	PointToPointHelper pointToPoint;
        pointToPoint.SetDeviceAttribute("DataRate", StringValue("100Mbps"));
        pointToPoint.SetChannelAttribute("Delay", StringValue("2ms"));
	
	NetDeviceContainer p2pDevice;
	p2pDevice = pointToPoint.Install (p2pNode);

	CsmaHelper csma;
	csma.SetChannelAttribute ("DataRate", StringValue("100Mbps"));
	csma.SetChannelAttribute ("Delay", TimeValue(NanoSeconds (6560)));
	//csma.SetDeviceAttribute ("Mtu", UintegerValue(1508));

	NetDeviceContainer csmaDevice;
	csmaDevice = csma.Install (csmaNode);

	//install wireless devices
	WifiHelper wifi = WifiHelper::Default();
	wifi.SetRemoteStationManager("ns3::AarfWifiManager");
	//wifi.SetStandard(WIFI_PHY_STANDARD_80211a );

	QosWifiMacHelper mac =QosWifiMacHelper::Default();
	
	Ssid ssid = Ssid("ns-3-ssid");
	mac.SetType("ns3::StaWifiMac","Ssid",SsidValue(ssid),"ActiveProbing",BooleanValue(true));
	
	NetDeviceContainer staDevices;
	staDevices = wifi.Install(phy, mac, wifiStaNode);

	mac.SetType("ns3::ApWifiMac","Ssid",SsidValue(ssid));

	NetDeviceContainer apDevices;
	apDevices = wifi.Install(phy, mac , wifiApNode);

	//setting mobility model
	MobilityHelper mobility;
	mobility.SetPositionAllocator("ns3::GridPositionAllocator",
					"MinX", DoubleValue (0.0),
					"MinY", DoubleValue (0.0),
					"DeltaX", DoubleValue (5.0),
					"DeltaY", DoubleValue (10.0),
					"GridWidth", UintegerValue (3),
					"LayoutType", StringValue ("RowFirst"));
	//mobility.SetMobilityModel("ns3::RandomWalk2dMobilityModel", "Bounds", RectangleValue (Rectangle (-50, 50, -50, 50)));
	mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
	mobility.Install(wifiStaNode);

	mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
	mobility.Install(wifiApNode);
	
	InternetStackHelper stack;
	stack.Install(csmaNode);
	stack.Install(wifiApNode);
	stack.Install(wifiStaNode);

	Ipv4AddressHelper address;
	address.SetBase("10.1.1.0","255.255.255.0");
	Ipv4InterfaceContainer p2pInterface;
	p2pInterface = address.Assign (p2pDevice);

	address.SetBase("10.1.2.0", "255.255.255.0");
	Ipv4InterfaceContainer wifiInterfaces;
	wifiInterfaces = address.Assign(staDevices);
	Ipv4InterfaceContainer wifiApInterfaces;
	wifiApInterfaces = address.Assign(apDevices);

	address.SetBase("10.1.3.0","255.255.255.0");
	Ipv4InterfaceContainer csmaInterface;
	csmaInterface = address.Assign (csmaDevice);

	//live streaming receiver
	Address remoteAddress1 = InetSocketAddress(wifiInterfaces.GetAddress(1),2000);
	PacketSinkHelper receiver1("ns3::TcpSocketFactory", remoteAddress1);
	ApplicationContainer receiverapp1 = receiver1.Install(wifiStaNode.Get(1));
	receiverapp1.Start(Seconds(1.0));
	receiverapp1.Stop(Seconds(50.0));

	//live streaming sender
	OnOffHelper sender1("ns3::TcpSocketFactory", remoteAddress1);
	sender1.SetConstantRate(DataRate("1Mbps"), 1460);
	sender1.SetAttribute("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=0.5]"));
	sender1.SetAttribute("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0.1]"));
	ApplicationContainer senderapp1 = sender1.Install(csmaNode.Get(1));
	senderapp1.Start(Seconds(1.0));
	senderapp1.Stop(Seconds(50.0));
	

	//voip receiver
	Address remoteAddress2 = InetSocketAddress(wifiInterfaces.GetAddress(0), 4000);
	PacketSinkHelper receiver2("ns3::UdpSocketFactory", remoteAddress2);
	ApplicationContainer receiverapp2 = receiver2.Install(wifiStaNode.Get(0));
	receiverapp2.Start(Seconds(10.0));
	receiverapp2.Stop(Seconds(50.2));

	Address remoteAddress7 = InetSocketAddress(wifiInterfaces.GetAddress(6), 7777);
	PacketSinkHelper receiver7("ns3::UdpSocketFactory", remoteAddress2);
	ApplicationContainer receiverapp7 = receiver7.Install(wifiStaNode.Get(6));
	receiverapp7.Start(Seconds(25.0));
	receiverapp7.Stop(Seconds(50.2));
	
	//voip sender
	OnOffHelper sender2("ns3::UdpSocketFactory", remoteAddress2);
	sender2.SetConstantRate(DataRate("65.625Kbps"), 208);
	//sender2.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1.0]"));
	//sender2.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVarialbe[Constant=0.0]"));
	ApplicationContainer senderapp2 = sender2.Install(csmaNode.Get(2));
	senderapp2.Start(Seconds(10.0));
	senderapp2.Stop(Seconds(50.2));

	OnOffHelper sender9("ns3::UdpSocketFactory", remoteAddress7);
	sender9.SetConstantRate(DataRate("65.625Kbps"), 208);
	//sender2.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1.0]"));
	//sender2.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVarialbe[Constant=0.0]"));
	ApplicationContainer senderapp9 = sender9.Install(csmaNode.Get(7));
	senderapp9.Start(Seconds(25.0));
	senderapp9.Stop(Seconds(50.2));
        
	//ftp receiver
	Address remoteAddress3 = InetSocketAddress(wifiInterfaces.GetAddress(2),6000);
	PacketSinkHelper receiver3("ns3::TcpSocketFactory", remoteAddress3);
	ApplicationContainer receiverapp3 = receiver3.Install(wifiStaNode.Get(2));
	receiverapp3.Start(Seconds(1.0));
	receiverapp3.Stop(Seconds(50.0));

	Address remoteAddress5 = InetSocketAddress(wifiInterfaces.GetAddress(4),10000);
	PacketSinkHelper receiver5("ns3::TcpSocketFactory", remoteAddress5);
	ApplicationContainer receiverapp5 = receiver5.Install(wifiStaNode.Get(4));
	receiverapp5.Start(Seconds(25.0));
	receiverapp5.Stop(Seconds(50.0));

	Address remoteAddress6 = InetSocketAddress(wifiInterfaces.GetAddress(5),6666);
	PacketSinkHelper receiver6("ns3::TcpSocketFactory", remoteAddress6);
	ApplicationContainer receiverapp6 = receiver6.Install(wifiStaNode.Get(5));
	receiverapp6.Start(Seconds(35.0));
	receiverapp6.Stop(Seconds(50.0));

	Address remoteAddress8 = InetSocketAddress(wifiInterfaces.GetAddress(6),8888);
	PacketSinkHelper receiver8("ns3::TcpSocketFactory", remoteAddress8);
	ApplicationContainer receiverapp8 = receiver8.Install(wifiStaNode.Get(6));
	receiverapp8.Start(Seconds(25.0));
	receiverapp8.Stop(Seconds(50.0));

	Address remoteAddress9 = InetSocketAddress(wifiInterfaces.GetAddress(7),9999);
	PacketSinkHelper receiver9("ns3::TcpSocketFactory", remoteAddress9);
	ApplicationContainer receiverapp9 = receiver9.Install(wifiStaNode.Get(7));
	receiverapp9.Start(Seconds(30.0));
	receiverapp9.Stop(Seconds(50.0));

	Address remoteAddress10 = InetSocketAddress(wifiInterfaces.GetAddress(8),9910);
	PacketSinkHelper receiver10("ns3::TcpSocketFactory", remoteAddress10);
	ApplicationContainer receiverapp10 = receiver10.Install(wifiStaNode.Get(8));
	receiverapp10.Start(Seconds(35.0));
	receiverapp10.Stop(Seconds(50.0));
	

	//ftp sender
	OnOffHelper sender3("ns3::TcpSocketFactory", remoteAddress3);
	sender3.SetConstantRate(DataRate("30Mbps"), 1460); 
	//sender3.SetAttribute("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]"));
	//sender3.SetAttribute("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]"));
	ApplicationContainer senderapp3 = sender3.Install(csmaNode.Get(3));
	senderapp3.Start(Seconds(1.0));
	senderapp3.Stop(Seconds(50.0));

	OnOffHelper sender7("ns3::TcpSocketFactory", remoteAddress5);
	sender7.SetConstantRate(DataRate("50Mbps"), 1460); 
	ApplicationContainer senderapp7 = sender7.Install(csmaNode.Get(5));
	senderapp7.Start(Seconds(25.0));
	senderapp7.Stop(Seconds(50.0));
	
	OnOffHelper sender8("ns3::TcpSocketFactory", remoteAddress6);
	sender8.SetConstantRate(DataRate("40Mbps"), 1460); 
	ApplicationContainer senderapp8 = sender8.Install(csmaNode.Get(6));
	senderapp8.Start(Seconds(35.0));
	senderapp8.Stop(Seconds(50.0));

	OnOffHelper sender10("ns3::TcpSocketFactory", remoteAddress8);
	sender10.SetConstantRate(DataRate("50Mbps"), 1460); 
	ApplicationContainer senderapp10 = sender10.Install(csmaNode.Get(8));
	senderapp10.Start(Seconds(25.0));
	senderapp10.Stop(Seconds(50.0));

	OnOffHelper sender11("ns3::TcpSocketFactory", remoteAddress9);
	sender11.SetConstantRate(DataRate("50Mbps"), 1460); 
	ApplicationContainer senderapp11 = sender11.Install(csmaNode.Get(9));
	senderapp11.Start(Seconds(30.0));
	senderapp11.Stop(Seconds(50.0));

	OnOffHelper sender12("ns3::TcpSocketFactory", remoteAddress10);
	sender12.SetConstantRate(DataRate("50Mbps"), 1460); 
	ApplicationContainer senderapp12 = sender12.Install(csmaNode.Get(10));
	senderapp12.Start(Seconds(35.0));
	senderapp12.Stop(Seconds(50.0));
	

	//video receiver
	Address remoteAddress4 = InetSocketAddress(wifiInterfaces.GetAddress(3), 8000);
	PacketSinkHelper receiver4("ns3::UdpSocketFactory", remoteAddress4);
	ApplicationContainer receiverapp4 = receiver4.Install(wifiStaNode.Get(3));
	receiverapp4.Start(Seconds(1.0));
	receiverapp4.Stop(Seconds(50.0));
	
	//video sender
	OnOffHelper sender4("ns3::UdpSocketFactory", remoteAddress4);
	sender4.SetConstantRate(DataRate("65.625Kbps"), 208);
	ApplicationContainer senderapp4 = sender4.Install(csmaNode.Get(4));
	senderapp4.Start(Seconds(1.0));
	senderapp4.Stop(Seconds(50.0));
	OnOffHelper sender5("ns3::UdpSocketFactory", remoteAddress4);
	sender5.SetConstantRate(DataRate("0.25Mbps"), 650);
	ApplicationContainer senderapp5 = sender5.Install(csmaNode.Get(4));
	senderapp5.Start(Seconds(1.0));
	senderapp5.Stop(Seconds(50.0));
	OnOffHelper sender6("ns3::UdpSocketFactory", remoteAddress4);
	sender6.SetConstantRate(DataRate("0.5Mbps"), 1460);
	ApplicationContainer senderapp6 = sender6.Install(csmaNode.Get(4));
	senderapp6.Start(Seconds(1.0));
	senderapp6.Stop(Seconds(50.0));
        
	

	Ipv4GlobalRoutingHelper::PopulateRoutingTables();
	Simulator::Stop(Seconds(55.0));
	pointToPoint.EnablePcapAll("P2p_mytest1");
	//csma.EnablePcapAll("Csma_mytest1");
	phy.EnablePcapAll("Wifi_mytest1");
	Simulator::Run();
	Simulator::Destroy();
	return 0;
	
}
