/********************************************************
*	DESCRIPTION	: Atomic model Network statistics
* 
*	AUTHOR		: Mohammad Moallemi
*	Email		: moallemi@sce.carleton.ca
*	DATE		: 27-08-2012
* 
*
********************************************************/


/********** file includes ****************************/

#include <math.h>
#include <list>
#include <stdlib.h>
#include <iostream>
#include <sstream>
#include "root.h"
#include "cdtime.h"
#include "message.h"         // InternalMessage 
#include "mainsimu.h"        // class MainSimulator
#include "NetStats.h"
#include "UE.h"
#include "UERegistry.h"

  

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*Function Name: NodeGenerator
* 
* Description: Constructor
* 
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

NetStats::NetStats( const string &name) :
	Atomic(name),
	lin(addInputPort("lin")),
	nin(addInputPort("nin")),
	bsin(addInputPort("bsin")),
	ueidout( addOutputPort("ueidout")),
	bsidout( addOutputPort("bsidout")),
	uerxpwrout( addOutputPort("uerxpwrout")),
	bsrxpwrout( addOutputPort("bsrxpwrout")),
	distanceout( addOutputPort("distanceout")),
	pathlossout( addOutputPort("pathlossout")){
		nodes = 0;
		links = 0;
		std::string time( MainSimulator::Instance().getParameter( description(), "calcStatsTime" ) ) ;
		calcStatsTime = time ;
		string locFile( MainSimulator::Instance().getParameter( description(), "LocationPlotFile" ) ) ;
		if (locFile != ""){
			xgLocOut.open(locFile.c_str());
			xgLocOut<<"Title = BS and UE Location Plot \n setenv XGRAPH_BACKGROUND ffffff \n"
					<<" title_x = Area Length (meters) \n title_y = Area Width (meters) \n";
		}
		string distPlossFile( MainSimulator::Instance().getParameter( description(), "DistPlossPlotFile" ) ) ;
		distPlossFileName = distPlossFile;
		string distRxpwrFile( MainSimulator::Instance().getParameter( description(), "DistRxpwrPlotFile" ) ) ;
		distRxpwrFileName = distRxpwrFile;
		string RxpwrPlossFile( MainSimulator::Instance().getParameter( description(), "RxpwrPlossPlotFile" ) ) ;
		rxpwrPlossFileName = RxpwrPlossFile;

}
Model &NetStats::initFunction()
{
	if(xgLocOut.is_open()){
		plotBSs();
		plotUEs();
		xgLocOut.close();
	}
	state = calcStats;
    holdIn(Atomic::active, calcStatsTime);
	return *this ;
}
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*Function Name: external function
* 
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/	
Model &NetStats::externalFunction(const ExternalMessage &msg ){
	
	if(msg.port() == lin){
	}
	
	if(msg.port() == nin){
		
	}
	return *this;
}
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*Function Name: internal function
* 
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/	
Model &NetStats::internalFunction(const InternalMessage & )
{
	state = calcStats;
	holdIn(active, calcStatsTime);
	return *this;
}
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*Function Name: output function
* 
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/	
Model &NetStats::outputFunction(const InternalMessage &msg)
{
/*
	Node *ue;
	BSLink *bslink;
	UERegistry *myUERegistry = static_cast<UERegistry*>(&SingleProcessorAdmin::Instance().processor("UERegistry").model());
	for(ue=myUERegistry->nodes->head ; ue!= NULL; ue = ue->next){
		for (bslink = ue->BSLinkHead; bslink != NULL; bslink = bslink->Next()){
			this->sendOutput(msg.time(),ueidout,ue->getID());
			this->sendOutput(msg.time(),bsidout,bslink->getBS()->getID());
			this->sendOutput(msg.time(),uerxpwrout,bslink->findCorespUELink()->getRecievedPower());
			this->sendOutput(msg.time(),bsrxpwrout,bslink->getRecievedPower());
			this->sendOutput(msg.time(),distanceout,bslink->getDistance());
			this->sendOutput(msg.time(),pathlossout,bslink->getPathloss());
		}
	}
*/
	recordDistvsPloss();//record distance vs pathloss for each UE
	recordDistRxpwr();//record distance vs received power for each UE
	recordRxpwrPloss();//record received power vs pathloss for each UE

	if(Root::Instance().stopTime() <= (msg.time() + calcStatsTime)){//simulation is ending: plot the stats
		plotStats();
	}
	return *this;
}
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*Function Name: Destructor
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
NetStats::~NetStats(){
	plotStats();
}
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*Function Name: Plot UEs in an XGraph data file
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void NetStats::plotUEs(){
	Node *ue;
	UERegistry *myUERegistry = static_cast<UERegistry*>(&SingleProcessorAdmin::Instance().processor("UERegistry").model());
	xgLocOut<<" color = red \n shape = 5 \n thinkness = 2.0 \n";
	for(ue = myUERegistry->nodes->head; ue != NULL; ue = ue->next){
		xgLocOut<<ue->getX()<<" "<<ue->getY()<<" \n";
	}
}
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*Function Name: Plot BSs in an XGraph data file
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void NetStats::plotBSs(){
	BS *bs;
	BSRegistry *myBSRegistry = static_cast<BSRegistry*>(&SingleProcessorAdmin::Instance().processor("BSRegistry").model());
	xgLocOut<<"color = blue \n thinkness = 4.0 \n shape = 0 \n";

	for(bs = myBSRegistry->bslist->head; bs != NULL; bs = bs->next){
		xgLocOut<<bs->getX()<<" "<<bs->getY()<<"\n";
	}
}
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*Function Name: record distance vs pathloss for each UE
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void NetStats::recordDistvsPloss(){
	Node *ue;
	BSLink *bslink;
	UERegistry *myUERegistry = static_cast<UERegistry*>(&SingleProcessorAdmin::Instance().processor("UERegistry").model());
	for(ue=myUERegistry->nodes->head ; ue!= NULL; ue = ue->next){
		for (bslink = ue->BSLinkHead; bslink != NULL; bslink = bslink->Next()){
			distPloss[ue->getID()]<<bslink->getDistance()<<" "<<bslink->getPathloss()<<"\n";
		}
	}
}
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*Function Name: record distance vs received power for each UE
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void NetStats::recordDistRxpwr(){
	Node *ue;
	BSLink *bslink;
	UERegistry *myUERegistry = static_cast<UERegistry*>(&SingleProcessorAdmin::Instance().processor("UERegistry").model());
	for(ue=myUERegistry->nodes->head ; ue!= NULL; ue = ue->next){
		for (bslink = ue->BSLinkHead; bslink != NULL; bslink = bslink->Next()){
			distRxpwr[ue->getID()]<<bslink->getDistance()<<" "<<bslink->getRecievedPower()<<"\n";
		}
	}
}
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*Function Name: record received power vs pathloss for each UE
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void NetStats::recordRxpwrPloss(){
	Node *ue;
	BSLink *bslink;
	UERegistry *myUERegistry = static_cast<UERegistry*>(&SingleProcessorAdmin::Instance().processor("UERegistry").model());
	for(ue=myUERegistry->nodes->head ; ue!= NULL; ue = ue->next){
		for (bslink = ue->BSLinkHead; bslink != NULL; bslink = bslink->Next()){
			rxpwrPloss[ue->getID()]<<bslink->getRecievedPower()<<" "<<bslink->getPathloss()<<"\n";
		}
	}
}
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*Function Name: Save the values of the statistics calculated during the simulation into the xg files
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void NetStats::plotStats(){
	ofstream xgDistPlossOut; //XGraph data to plot the distance VS pathloss for each BS-UE Link
	ofstream xgDistRxpwrOut; //XGraph data to plot the distance VS Received power for each BS-UE Link
	ofstream xgRxpwrPlossOut; //XGraph data to plot the received power VS pathloss for each BS-UE Link
	Node *ue;
	UERegistry *myUERegistry = static_cast<UERegistry*>(&SingleProcessorAdmin::Instance().processor("UERegistry").model());

	if(distPlossFileName != ""){
		xgDistPlossOut.open(distPlossFileName.c_str());
		xgDistPlossOut<<"Title = Distance VS Pathloss for each UE \n "
				<<" title_x = Distance (meters) \n title_y = Pathloss (dB) \n thickness = 3\nshape 1\n";
		int color = 0 ;
		for(ue=myUERegistry->nodes->head, color = 0 ; ue!= NULL; ue = ue->next, color++){
			if (color >15) 	color = 0;
			if(distPloss[ue->getID()].str() != "")
				xgDistPlossOut<<"next  \ncolor = "<<color<<" \n"<<distPloss[ue->getID()].str()<<"\n";
		}
	xgDistPlossOut.close();
	}

	if(distRxpwrFileName != ""){
		xgDistRxpwrOut.open(distRxpwrFileName.c_str());
		xgDistRxpwrOut<<"Title = Distance VS Received Power for each UE \n"
				<<" title_x = Distance (meters) \n title_y = Received Power (dBm) \nthickness = 3\nshape 1\n";
		int color = 0 ;
		for(ue=myUERegistry->nodes->head, color = 0 ; ue!= NULL; ue = ue->next, color++){
			if (color >15) 	color = 0;
			if(distRxpwr[ue->getID()].str() != "")
				xgDistRxpwrOut<<"next \n color = "<<color<<" \n"<<distRxpwr[ue->getID()].str()<<"\n";
		}
		xgDistRxpwrOut.close();
	}

	if(rxpwrPlossFileName != ""){
		xgRxpwrPlossOut.open(rxpwrPlossFileName.c_str());
		xgRxpwrPlossOut<<"Title = Received Power VS Pathloss for each UE\n "
				<<" title_x = Received Power (dBm) \n title_y = Pathloss (dB) \nthickness = 3\nshape 1\n";
		int color = 0 ;
		for(ue=myUERegistry->nodes->head, color = 0 ; ue!= NULL; ue = ue->next, color++){
			if (color >15) 	color = 0;
			if(rxpwrPloss[ue->getID()].str() != "")
				xgRxpwrPlossOut<<"next \n color = "<<color<<" \n"<<rxpwrPloss[ue->getID()].str()<<"\n";
		}
		xgRxpwrPlossOut.close();
	}
}

