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


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

#include <fstream>
#include <strstream>     // class strstream
#include <math.h>
#include <stdlib.h>
#include <iostream>
#include "BSRegistry.h"
#include "UERegistry.h"
#include "UE.h"
#include "MeNB.h"
#include "randlib.h"         // Random numbers library
#include "message.h"         // InternalMessage 
#include "distri.h"          // class Distribution
#include "mainsimu.h"        // class MainSimulator
#include "strutil.h"   

using namespace std;
 extern bool URBAN ; //urban configuration (true) or rural (false) (first defined in UERegistry.cpp)

 int BSRegistry::defaultBSs = 8; //the number of network BSs at the start of simulation
 long BSRegistry::cellRadius = 5000;
 SIMModel simModel = SIMModel::UTRAFDD;

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*Function Name: BSGenerator
* 
* Description: Constructor
* 
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
BSRegistry::BSRegistry( const string &name) :
	Atomic(name),
	gen(addInputPort("gen")),
	deq(addInputPort("deq")),
	pos(addInputPort("pos")),
	aout( addOutputPort("aout")){
	//cout<<"BSRegistry.CPP --> BSRegistry::BSRegistry --> start"<<endl;			
	BSId = 1;
	string time( MainSimulator::Instance().getParameter( description(), "idletime" ) ) ;
	idleTime = time ;

	//string defBSs( MainSimulator::Instance().getParameter( description(), "defaultBSs" ) ) ;
	//if (defBSs!="") defaultBSs = atoi(defBSs.c_str());
	//cout << "Number of BSs " << defBSs << endl;
	string cellR( MainSimulator::Instance().getParameter( description(), "CellRadius" ) ) ;
	if (cellR!="") cellRadius = atol(cellR.c_str());
	string mdl( MainSimulator::Instance().getParameter( description(), "SIMModel" ) ) ;
	if(mdl == "utrafdd")
		simModel = SIMModel::UTRAFDD;//UTRA FDD
	else if(mdl == "utra128tdd")
		simModel = SIMModel::UTRA128TDD; //UTRA 1.28Mcps TDD
	else if(mdl == "utra384tdd")
		simModel = SIMModel::UTRA384TDD; //UTRA 3.84 Mcps TDD
	else if(mdl == "eutrafddtdd" )
		simModel = SIMModel::EUTRAFDDTDD; //E-UTRA FDD and E-UTRA TDD	
	bslist = new BSList();
	//createAndMountBSs();
	//cout<<"BSRegistry.CPP --> BSRegistry::BSRegistry --> stop"<<endl;
}

Model &BSRegistry::initFunction(){		
	//cout<<"BSRegistry.CPP --> BSRegistry::initFunction --> start"<<endl;
	state = initial;
	holdIn(Atomic::active, Time::Zero);
	//cout<<"BSRegistry.CPP --> BSRegistry::initFunction --> stop"<<endl;
	return *this ;
};

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*Function Name: external function
* 
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/	
Model &BSRegistry::externalFunction(const ExternalMessage &msg ){
	//cout << msg.time() << "\tBSRegistry.CPP --> BSRegistry::externalFunction --> start"<<endl;
	unsigned long x,y;
	if(msg.port() == gen && msg.value() == 1) {
		x = (unsigned long)(fmod(rand(),UERegistry::Xmax));
		y = (unsigned long)(fmod(rand(),UERegistry::Ymax));
		//bslist->addBS(new BS(BSId++,x,y,true,eNB));
		//UERegistry::nodes->updateLinks();

		state = generateBS;
		holdIn(active, Time::Zero);
	}
	
	//cout << msg.time() << "\tBSRegistry.CPP --> BSRegistry::externalFunction --> stop"<<endl;		
	return *this;
}


/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*Function Name: internal function
* 
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/	
Model &BSRegistry::internalFunction(const InternalMessage &msg ){
	//cout << msg.time() << "\tBSRegistry.CPP --> BSRegistry::internalFunction --> start"<<endl;
	switch(state){
		case initial:
			state = idle;
			holdIn(active, idleTime); //update position of the nodes every idleTime
			break;
		case idle:
			state = idle;
			holdIn(active, idleTime); //update every idleTime

			break;
		case generateBS:
			break;
	}
	//cout << msg.time() << "\tBSRegistry.CPP --> BSRegistry::internalFunction --> stop"<<endl;
	return *this;
}


/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*Function Name: output function
* 
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/	
Model &BSRegistry::outputFunction(const InternalMessage &msg){
	//cout << msg.time() << "\tBSRegistry.CPP --> BSRegistry::outputFunction --> start"<<endl;
	switch(state){
		case initial:
			sendOutput(msg.time(),aout,getBSNum(), NULL); // send number of UEs
			break;
		case idle:
			break;
		case generateBS:
			break;
	}
	//cout << msg.time() << "\tBSRegistry.CPP --> BSRegistry::outputFunction --> stop"<<endl;
	return *this;
}

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*Function Name: Destructor
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
BSRegistry::~BSRegistry(){
	if(bslist->head == NULL){
		if(bslist != NULL)
			delete bslist;
		return;
	}
	BS *n = bslist->head;
	BS *p;
	while(n != NULL){
		p = n;
		n = n->next;
		delete(p);
	}
	if(bslist != NULL)
		delete bslist;
}
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*Function Name: generate and mount BSs based on TR_36.942: 4.4.2.2	Coordinated macro cellular deployment
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/*void BSRegistry::createAndMountBSs(){
	unsigned long x = 0, y = 0;
	BS *n;
	bool toggleRows = true;
	double gain; //antenna gain (dBi)
	int Dhb;// base station antenna height in meters, measured from the average rooftop level
	int Hb; //base station antenna height above ground in meters
	long frequency; //carrier frequency in MHz
	bslist = new BSList();

	//read the user specified values for antennas from model file
	string dhb( MainSimulator::Instance().getParameter( description(), "Dhb" ) ) ;
	if (dhb!= "" && atoi(dhb.c_str()) != 0)
		Dhb = atoi(dhb.c_str()) ;
	else
		Dhb = 15;
	string hb( MainSimulator::Instance().getParameter( description(), "Hb" ) ) ;
	if (hb!= "" && atoi(hb.c_str()) != 0)
		Hb = atoi(hb.c_str()) ;
	else{
		if(URBAN)
			Hb = 30;
		else
			Hb = 45;
	}
	string fr( MainSimulator::Instance().getParameter( description(), "frequency" ) ) ;
	if (fr!= "" && atol(fr.c_str()) != 0)
		frequency = atol(fr.c_str()) ;
	else{
		if(URBAN)
			frequency = 2000;
		else
			frequency = 900;
	}
	string g( MainSimulator::Instance().getParameter( description(), "gain" ) ) ;
	if (g!= "" && atof(g.c_str())!= 0)
		gain = atof(g.c_str()) ;
	else{
		if(URBAN)
			gain = 15;
		else
			gain = 15;
	}
	for(BSId=1;BSId<=defaultBSs; BSId++){

		//x = (unsigned long)(fmod(rand(),UERegistry::Xmax));
		//y = (unsigned long)(fmod(rand(),UERegistry::Ymax));

		n = new BS(BSId,x,y,true,eNB, Dhb, Hb, frequency, gain);
		bslist->addBS(n);

		x = x + 3*cellRadius;
//		y = y + 3*cellRadius;
		if (x > UERegistry::Xmax && y < UERegistry::Ymax && toggleRows){
			x = 3*cellRadius*0.7071f;
			y += 3*cellRadius*0.7071f;
			toggleRows = false;
		}else if (x > UERegistry::Xmax && y < UERegistry::Ymax && !toggleRows){

			x = 0;
			y += 3*cellRadius*0.7071f;
			toggleRows = true;
		}else if (x > UERegistry::Xmax && y > UERegistry::Ymax ){
			return;
		}
	}

}*/

void BSRegistry::addBS(BS *bs){
	bslist->addBS(bs);
}
	

