#include "ns3/aodv-module.h"
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/internet-module.h"
#include "ns3/mobility-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/wifi-module.h"
#include "ns3/v4ping-helper.h"
#include "ns3/netanim-module.h"
#include "ns3/applications-module.h"
#include "ns3/flow-monitor-helper.h"
#include "ns3/gnuplot.h"
#include "ns3/flow-monitor-module.h"
#include "ns3/nstime.h"
#include "ns3/simulator.h"
#include "ns3/stats-module.h"
#include <iostream>
#include <cmath>
#include <fstream>
#include <string>
#include <cassert>

using namespace ns3;
using namespace std;

uint32_t size = 7;				// Pocet uzlu
double dist = 50;			  	// Vzdalenost mezi uzly v metrech
double range = 60;				//dosah radia (uzlu)
double totalTime = 70;		// cas simulace v sekundach
double speed = 5;		     	//rychlost v km/h
double max_rychlost = 100;
bool pcap = true;		   		// Zaznam provozu v pcap
bool printRoutes = true;	// Zaznam routovacich tabulek
bool nahoru = true;				//posun po ose x

//--------------graf pro zpozdeni----------------------------------------------
string jmenoZpozdeni = "Zpozdeni";
string zpozdeniGraphicsFileName = jmenoZpozdeni + ".png";
string zpozdeniFileName = jmenoZpozdeni + ".plt";
string zpozdeniTitle = "Velikost zpozdeni";
string zpozdeniOsa_Y = "Prumerne zpozdeni [ms]";
string zpozdeniOsa_X = "cas [s]";

//Vytvoeeni instance gnuplot a nazvu
Gnuplot gnuplotZP(zpozdeniGraphicsFileName);
Gnuplot2dDataset delay;
//-----------------------------------------------------------------------------

//--------------graf pro ztratu paketu------------------------------------------
string jmenoLost = "Ztratovost";
string lostGraphicsFileName = jmenoLost + ".png";
string lostFileName = jmenoLost + ".plt";
string lostTitle = "Ztratovost";
string lostOsa_Y = "Pocet ztracenych paketu";
string lostOsa_X = "cas [s]";

//Vytvoreni instance gnuplot a nazvu
Gnuplot gnuplotZT(lostGraphicsFileName);
Gnuplot2dDataset lostP;
//-----------------------------------------------------------------------------

//------------rx/tx bitrate----------------------------------------------------
string jmenoBitR = "BitRate";
string bitRGraphicsFileName = jmenoBitR + ".png";
string bitRFileName = jmenoBitR + ".plt";
string bitRTitle = "Bitrate";
string rxTitle = "rxRate";
string txTitle = "txRate";
string bitROsa_Y = "Propustnost [Kbps]";
string bitROsa_X = "cas [s]";

Gnuplot gnuplotBR(bitRGraphicsFileName);
Gnuplot2dDataset rxR;
Gnuplot2dDataset txR;

double lastLost = 0;
double lastTime = 0;
	//-----------------------------------------------------------------------------

	//--------------funkce pro vypis statistik linky mezi serverem a klientem------
void Stats(Ptr<FlowMonitor> flowMonitor) {

	flowMonitor->CheckForLostPackets();

	std::map<FlowId, FlowMonitor::FlowStats> stats =
			flowMonitor->GetFlowStats();
	for (std::map<FlowId, FlowMonitor::FlowStats>::const_iterator i =
			stats.begin(); i != stats.end(); ++i) {

		if (i->first == 2) {

			lostP.Add(Simulator::Now().GetSeconds(),
					i->second.lostPackets - lastLost);
			lastLost = i->second.lostPackets;

			delay.Add(Simulator::Now().GetSeconds() - 1,
					(i->second.lastDelay.GetMilliSeconds()));

			rxR.Add(Simulator::Now().GetSeconds() - 1,
					i->second.rxBytes * 8.0
							/ (i->second.timeLastRxPacket.GetSeconds()
									- i->second.timeFirstTxPacket.GetSeconds()) / 1024);

			txR.Add(Simulator::Now().GetSeconds() - 1,
					i->second.txBytes * 8.0
							/ (i->second.timeLastTxPacket.GetSeconds()
									- i->second.timeFirstTxPacket.GetSeconds()) / 1024);

			flowMonitor->SerializeToXmlFile("AODVFlowmon", true, true);
		}

	}
}
	//-----------------------------------------------------------------------------

	//-----------funkce pro posun ulzu---------------------------------------------


	//-----------------------------------------------------------------------------


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

  std::string animFile = "AODV_aminace.xml"; 	// Nazev souboru pro animaci
  std::cout << "Smerovaci protokol AODV";

  	//------------vytvoreni uzlu---------------------------------------------------
  	NodeContainer nodes;
  	nodes.Create(size);

	//-----------------------------------------------------------------------------

	//---------------mobilita jednoho bodu-----------------------------------------


	//-----------------------------------------------------------------------------

/*
	//---------------mobilita v rade-----------------------------------------------


	 //----------------------------------------------------------------------------
*/

/*
	 //--------nahodna mobilita, pocatek ve tvaru obdelniku------------------------


	 //----------------------------------------------------------------------------
*/

	//---------definice kanalu-----------------------------------------------------


	//-----------------------------------------------------------------------------

	//------------konfigurace AODV-------------------------------------------------


	//-----------------------------------------------------------------------------

	//-----------ping--------------------------------------------------------------


	//-----------------------------------------------------------------------------


	//-------------------------aplikace HTTP---------------------------------------



	//-----------------------------------------------------------------------------


	//-------------------PCAP a smerovaci tabulky-------------------------------------


	//-----------------------------------------------------------------------------

	//-----------------------------Flow monitor------------------------------------
	FlowMonitorHelper flowHelper;
	Ptr<FlowMonitor> flowMonitor;
	flowMonitor = flowHelper.Install(nodes.Get(0));
	flowMonitor = flowHelper.Install(nodes.Get(size - 1));

	Simulator::Stop(Seconds(totalTime)); 	 // Zastaveni simulace
	//-----------------------------------------------------------------------------

	//------------------------------NetAnim----------------------------------------
	AnimationInterface anim(animFile);
	anim.EnablePacketMetadata(true);			 //Povoli zobrazit popis zasilanych zprav v simulaci
	anim.SetMaxPktsPerTraceFile(100000000); 	 //zvyseni poctu paketu pro zaznam

	//-----------------------------------------------------------------------------

	//------------------graf pro zpozdeni - pokracovani----------------------------
	gnuplotZP.SetTitle(zpozdeniTitle);
		gnuplotZP.SetTerminal("png");						//vytvoreni png souboru
		gnuplotZP.SetLegend(zpozdeniOsa_X, zpozdeniOsa_Y);	//Popisy jednotlivych os

		//gnuplotZT.AppendExtra("set xrange [0:26]"); 		//nastaveni rozsahu osy x
		//gnuplotZP.AppendExtra("set yrange [0:40]");		//nastaveni rozsahu osy y

		gnuplotZP.AppendExtra("set grid"); 					//zapnuti mrizky grafu
		delay.SetTitle(zpozdeniOsa_Y); 						//vytisknuti nazvu grafu
		delay.SetStyle(Gnuplot2dDataset::LINES_POINTS); 	//volba typu grafu (zde krivka s body)
		//-----------------------------------------------------------------------------

		//----------------graf pro ztratovost - pokracovani----------------------------
		gnuplotZT.SetTitle(lostTitle);
		gnuplotZT.SetTerminal("png");						//vytvoreni png souboru
		gnuplotZT.SetLegend(lostOsa_X, lostOsa_Y);			//Popisy jednotlivych os

		//gnuplotZT.AppendExtra("set xrange [0:26]"); 		//nastaveni rozsahu osy x
		gnuplotZT.AppendExtra("set yrange [0:30]"); 		//nastaveni rozsahu osy y

		gnuplotZT.AppendExtra("set grid"); 					//zapnuti mrizky grafu
		lostP.SetTitle(lostOsa_Y); 							//vytisknuti nazvu grafu
		lostP.SetStyle(Gnuplot2dDataset::HISTEPS);			//volba typu grafu (zde sloupcovy)
		//-----------------------------------------------------------------------------

		//------------------graf pro bitrate - pokracovani-----------------------------
		gnuplotBR.SetTitle(bitRTitle);
		gnuplotBR.SetTerminal("png");						//vytvoreni png souboru
		gnuplotBR.SetLegend(bitROsa_X, bitROsa_Y);			//Popisy jednotlivych os
		gnuplotBR.AppendExtra("set grid"); 					//zapnuti mriyky grafu

		rxR.SetTitle(rxTitle); 								//vytisknuti nazvu grafu
		rxR.SetStyle(Gnuplot2dDataset::LINES_POINTS); 		//volba typu grafu (zde krivka s body)

		txR.SetTitle(txTitle); 								//vytisknuti nazvu grafu
		txR.SetStyle(Gnuplot2dDataset::LINES_POINTS); 		//volba typu grafu (zde krivka s body)

	//-----------------------------------------------------------------------------

	//-----------flowmonitor pro linku mezi serverem a klientem--------------------
		for (int t = 1; t <= totalTime; t++) {
			Simulator::Schedule(Seconds(t), Stats, flowMonitor);
		}

	//-----------------------------------------------------------------------------

	Simulator::Run();

	//---------------flowmonitor pro vsechny linky---------------------------------
	flowMonitor->CheckForLostPackets();
		Ptr<Ipv4FlowClassifier> classifier = DynamicCast<Ipv4FlowClassifier>(
				flowHelper.GetClassifier());
		std::map<FlowId, FlowMonitor::FlowStats> stats =
				flowMonitor->GetFlowStats();
		for (std::map<FlowId, FlowMonitor::FlowStats>::const_iterator i =
				stats.begin(); i != stats.end(); ++i) {
			Ipv4FlowClassifier::FiveTuple t = classifier->FindFlow(i->first);
			NS_LOG_UNCOND(
					"\n  Flow ID: " << i->first << "   Src Addr: " << t.sourceAddress << "   Dst Addr: " << t.destinationAddress);
			NS_LOG_UNCOND("  Tx Bytes: " << i->second.txBytes);
			NS_LOG_UNCOND("  Rx Bytes: " << i->second.rxBytes);
			NS_LOG_UNCOND("  Tx Packets: " << i->second.txPackets);
			NS_LOG_UNCOND("  Rx Packets: " << i->second.rxPackets);
			NS_LOG_UNCOND(
					"  Mean Delay: " << i->second.delaySum.GetSeconds () / (i->second.rxPackets) * 1000 << " ms");
			NS_LOG_UNCOND(
					"  Mean Jitter: " << i->second.jitterSum.GetSeconds () / (i->second.rxPackets - 1) * 1000 << " ms");
			NS_LOG_UNCOND(
					"  Throughput: " << i->second.rxBytes * 8.0 / (i->second.timeLastRxPacket.GetSeconds () - i->second.timeFirstTxPacket.GetSeconds ()) / 1024 << " Kbps");
			NS_LOG_UNCOND("  Lost Packets = " << i->second.lostPackets);
		}

		flowMonitor->SerializeToXmlFile("AODV_Flowmon", true, true);

	//-----------------------------------------------------------------------------

	Simulator::Destroy();

	//-----------graf pro zpozdeni - pokracovani-----------------------------------
	gnuplotZP.AddDataset(delay);
	ofstream plotFileZP(zpozdeniFileName.c_str());		//Otevre soubor
	gnuplotZP.GenerateOutput(plotFileZP);				//Zapise soubor
	plotFileZP.close();									//Zavre soubor
	//-----------------------------------------------------------------------------

	//-----------graf pro ztratovost - pokracovani-----------------------------------
	gnuplotZT.AddDataset(lostP);
	ofstream plotFileZT(lostFileName.c_str());			//Otevre soubor
	gnuplotZT.GenerateOutput(plotFileZT);				//Zapise soubor
	plotFileZT.close();									//Zavre soubor
	//-----------------------------------------------------------------------------

	//-----------graf pro bitrate - pokracovani------------------------------------
	gnuplotBR.AddDataset(rxR);
	gnuplotBR.AddDataset(txR);
	ofstream plotFileBR(bitRFileName.c_str());			//Otevre soubor
	gnuplotBR.GenerateOutput(plotFileBR);				//Zapise soubor
	plotFileBR.close();									//Zavre soubor
	//-----------------------------------------------------------------------------

	return 0;
}
