 /***********************************************
 *
 *  DESCRIPTION: Atomic Model UE Processor
 *
 *  AUTHOR: Baha Uddin Kazi, Victor Silva
 *
 *  DATE: 30/06/2016
 *
 ***********************************************/
 #include "UE.h"
 #include "message.h"       // InternalMessage ....
 #include "Msg.h"
 #include "math.h"
 #include <iostream>
 #include <algorithm>
 #include <vector>
 #include "Point.h"
 #include "movement.h"
 #include <map>
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Function Name: initializeParameters
*Description: To initialize parameters
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void UE::initializeParameters(long ID, long px, long py, long st, long et){
	id = ID;
	posx = px;
	posy = py;
	startTime = st;
	endTime = et;
	
}


 UE::UE( const std::string &name ) : Atomic( name )
 , In( addInputPort( "In" ) )
 , Out( addOutputPort( "Out" ) )
 , Req( addOutputPort( "Req" ) )
 , ProcessTime (00,00,00,001) //--
 {
	string ID( MainSimulator::Instance().getParameter( description(), "ID" ) ) ;
	if (ID!="") id = atol(ID.c_str());
	string currentX( MainSimulator::Instance().getParameter( description(), "currentX" ) ) ;
	if (currentX!="") posx = atol(currentX.c_str());

	string currentY( MainSimulator::Instance().getParameter( description(), "currentY" ) ) ;
	if (currentY!="") posy = atol(currentY.c_str());

	string sTime( MainSimulator::Instance().getParameter( description(), "sTime" ) ) ;
	if (sTime!="") startTime = atol(sTime.c_str());

	string eTime( MainSimulator::Instance().getParameter( description(), "eTime" ) ) ;
	if (eTime!="") endTime = atol(eTime.c_str());

	string endX( MainSimulator::Instance().getParameter( description(), "endX" ) ) ;
	if (endX!="") posEndx = atol(endX.c_str());

	string endY( MainSimulator::Instance().getParameter( description(), "endY" ) ) ;
	if (endY!="") posEndy = atol(endY.c_str());

	string speed( MainSimulator::Instance().getParameter( description(), "speed" ) ) ;
	if (speed!="") SpeedKM_H = atol(speed.c_str());



	initialPosition = Point(posx, posy);
	finalPosition = Point(posEndx, posEndy);
	SpeedM_S =  SpeedKM_H*(10.0/36.0);
	mov = movement(initialPosition,finalPosition, SpeedM_S);
	distanceInitialFinal = mov.distance(initialPosition, finalPosition);//290.367;
	angleInitialFinal = mov.findAnglePoints(initialPosition, finalPosition);//7.32081;
	traveledD = 0.0;
	stopMovFlag = 0;
	eNBs;
	hys = 2;
	TTT = 160;
	HODecisionTimer = 0;
	countHO = 0;
	HOflag = false;
	TTTflag = false;
	NormalRunFlag = false;
	HOCounter = 0;
	countRecPower = 0;
	cout << " UE created with id " << this->id << " at position " << "(" << posx << ", " << posy << ")" << " starting at: " << startTime 
	<< ", end position at " << "(" << posEndx << ", " << posEndy << ") " <<" and speed: " << SpeedM_S << " m/s " << " Angle: " << angleInitialFinal << endl;
	
	

}

 Model &UE::initFunction()
  {
	state = Idle;
	maximumRecPower = -1000;
	NueNB = 7;//4;//////change this according to the total number of eNBs
	ReceivedPower;
	

	for (int i=0; i<NueNB; i++){
		ReceivedPower.insert(ReceivedPower.begin()+i, -1000);
				
	}

	//ctrlCmdFlag = false;
	firstRun = false;
	firstTimeFinalPosition = true;
	
	holdIn(Atomic::active, 0);

	
  	



	return *this ;
  }

 Model &UE::externalFunction( const ExternalMessage &msg )
 {
	
	if (msg.port()==In) 
	{
		state = SendPack;
		if (msg.valueO()->getMsgT()==CTRL_MeNB){ // UE received CTRL message from MeNBs
			CTRLcommand = (CTRLCmd*)msg.valueO();	
			f[CTRLcommand->getSrcID()] = CTRLcommand->getFreq();
		
		
				
			eNBs.push_back(eNB(CTRLcommand->getSrcID(), Point(CTRLcommand->getMeNBx(),CTRLcommand->getMeNBy()),CTRLcommand->getMeNBPower(), f[CTRLcommand->getSrcID()]));
				
  
			//ctrlCmdFlag = true;

			//std::ofstream logfile("receivedMsg.txt", std::ios_base::app | std::ios_base::out);
			//logfile << "UE ID: " << this->id << " RECEIVED THE CTRL COMMAND FROM eNB ID: " << CTRLcommand->getSrcID() << endl;
			//logfile.close();
		
			countRecPower++;
	
			if(countRecPower%NueNB == 0){
				maximumRecPower = -1000;
				CSIVectorPows.clear();
				CSIVectorPows.resize(0);
				

				
				for (long i=0; i<NueNB; i++){
					
						dis = computeDistance(posx, posy, eNBs[i].getPosition().getX(), eNBs[i].getPosition().getY());
				
						ReceivedPower[i] = computeRecPower(dis, f[eNBs[i].getID()], eNBs[i].getPower(), eNBs[i].getID());
					

						CSIVectorPows.insert(CSIVectorPows.begin()+i, ReceivedPower[i]); 
						 
						CSIVectorIDs.insert(CSIVectorIDs.begin()+i, eNBs[i].getID());

						if(ReceivedPower[i] > maximumRecPower){
						
							maximumRecPower = ReceivedPower[i];
							maxPowID = eNBs[i].getID();
							
						}

						else if (ReceivedPower[i] == maximumRecPower){
							maximumRecPower = ReceivedPower[i];
							maxPowID = std::min(eNBs[i].getID(),maxPowID);
						}
						
						
				
			
				}
				//std::ofstream logfile("logfile.txt", std::ios_base::app | std::ios_base::out);
				//logfile << " " << endl << endl;
				//logfile.close();
				
				ActualServingPower = maximumRecPower;
				ActualServingID = maxPowID;
				firstRun = true;
				//NormalRunFlag=true;
	
			}
			//logfile << "   " << endl << endl;
			//logfile.close();	
			
			//ctrlCmdFlag = false;
			




		
		}

		else if (msg.valueO()->getMsgT()==HO_CMD){
			HOcmd = (RRCConnReconf*)msg.valueO();
			cmdValue = HOcmd->getCmd();
			TeNB = HOcmd->getTargetID();
			SeNB = HOcmd->getSrcID();
			cout << " UE " << this->id << " Received HO_CMD from the  eNB " << endl;
			std::ofstream logfile("logfile.txt", std::ios_base::app | std::ios_base::out);
			logfile << " UE ID: " << this->id << " RECEIVED THE HO_CMD FROM  eNB ID: " << SeNB << " TeNB "<< TeNB << endl << endl;
			logfile.close();
			HOcmdFlag = true;
			
		}
		
	}
	
	counter++;
	holdIn(Atomic::active, ProcessTime);
		
	

	return *this;
  
}

 Model &UE::outputFunction( const InternalMessage &msg )
 {
		//std::ofstream logfile("receivedMsg.txt", std::ios_base::app | std::ios_base::out);
		//logfile << " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!@UE " << this->id << " outputFunction  time" << (int)(msg.time().asMsecs()) <<endl<<endl;
		//logfile.close();

	
	if ( state == Idle){				
		sendOutput(msg.time(), Req, 1, NULL);// 1 means UE processor requesting to queue to send him message
			
	}
	
	else if (state == SendPack){
		//std::ofstream logfile("receivedMsg.txt", std::ios_base::app | std::ios_base::out);
		//logfile << " ###############################################@UE " << this->id << " SendPack  time" << (int)(msg.time().asMsecs()) <<endl<<endl;
		//logfile.close();

	

		/*first run*/
		if( (int)(msg.time().asMsecs()) >= startTime){ //start sending CSIfdbck
					

			if (firstRun == true ){
				//if (countRecPower%NueNB == 0){
					NormalRunFlag=true;
	
					CSIfdbck = new CSIFeedback(this->id, ActualServingID, ActualServingPower, CSIVectorIDs, CSIVectorPows, 0);
					sendOutput(msg.time(), Out, NULL, CSIfdbck);
					firstRun = false;
					std::ofstream logfile("receivedMsg.txt", std::ios_base::app | std::ios_base::out);
					logfile << " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%@UE " << this->id << " CSIFeedback time" << (int)(msg.time().asMsecs()) <<endl;
					logfile.close();

				//}			
			}
						
		}

		if(HOcmdFlag && (cmdValue == 1) && (msg.time().asMsecs() >= HODecisionTimer+50)){
			ActualServingID = TeNB;
			NormalRunFlag = true;
			HOCounter++;
			HOcmdFlag = false;
			std::ofstream logfile("resultCount.txt", std::ios_base::app | std::ios_base::out);
			logfile << " @UE " << this->id << " #HO " << HOCounter <<endl<<endl;
			logfile.close();

		}	

		///////////////////////////////////////////////////////////////////////////////////////////////////////
		//cout << " (((int)(msg.time().asMsecs()) % 40) == 0): " << (((int)(msg.time().asMsecs()) % 40) == 0) << endl;
		/*calculate every 40ms*/
		if((NormalRunFlag) && (((int)(msg.time().asMsecs()) % 40) == 0) ){ 
				
			countRecPower = 0;
			//cout << "Normal run, msg.time().asMsecs()" << msg.time().asMsecs() << endl;
			std::ofstream logfile("logfile.txt", std::ios_base::app | std::ios_base::out);
			//logfile <<" @UE: " << this->id << " Normal Run " <<endl<<endl;
			logfile.close();
			maximumRecPower = -1000;
			ReceivedPower.clear();
			ReceivedPower.resize(0);
				

			for (int i=0; i<NueNB; i++){

				ReceivedPower.insert(ReceivedPower.begin()+i, -1000);

			}
			CSIVectorPows.clear();
			CSIVectorPows.resize(0);
			CSIVectorIDs.clear();
			CSIVectorIDs.resize(0);

			double time = (msg.time().asMsecs())*0.001;
			if (!stopMovFlag) {
				traveledD = mov.findTraveledDistance(time, SpeedM_S);
			}
			else
				{ traveledD = traveledD;}

			if (nearbyint(traveledD) >= nearbyint(distanceInitialFinal)) {
				traveledD = traveledD;
				instantX = instantX;
				instantY = instantY;
				if(firstTimeFinalPosition){

					std::ofstream logfile("logfile.txt", std::ios_base::app | std::ios_base::out);
					logfile <<" UE: " << this->id << " reached final Position "<< nearbyint(traveledD) << " metres "<<endl<<endl;
					logfile.close();
					firstTimeFinalPosition = false;
				}	
				stopMovFlag = 1;
				
			}
			else if(!stopMovFlag) {
				traveledD = mov.findTraveledDistance(time, SpeedM_S);
				Point position(Point(mov.findPosition(traveledD, angleInitialFinal, initialPosition)));
				instantX = nearbyint(position.getX());
				instantY = nearbyint(position.getY());
			}
			/*std::ofstream logfile("logfile.txt", std::ios_base::app | std::ios_base::out);
			logfile << " Normal run " << " UE ID: " << this->id << " ActualServingID: " << ActualServingID<< " msg.time().asMsecs(): " << msg.time().asMsecs() << " TRAVELED DISTANCE: " << traveledD << " metres "<< " at position: " << "(" << instantX << ", " << instantY << ")" 
			<< " Total distance to be done: " << distanceInitialFinal << " metres "<<endl<<endl;
			logfile.close();

			logfile << " " << endl << endl;
			logfile.close();*/

			//this calculates and stores the power to find the highest power
		    for (long i=0; i<NueNB; i++) {
					
				countRecPower++;
					

				dis = computeDistance(instantX, instantY, eNBs[i].getPosition().getX(), eNBs[i].getPosition().getY());
					
				ReceivedPower[i] = computeRecPower(dis, f[eNBs[i].getID()], eNBs[i].getPower(), eNBs[i].getID());
						
				CSIVectorPows.insert(CSIVectorPows.begin()+i, ReceivedPower[i]); 
						
				CSIVectorIDs.insert(CSIVectorIDs.begin()+i, eNBs[i].getID());

				if(ReceivedPower[i] > maximumRecPower){
							
					maximumRecPower = ReceivedPower[i];
					maxPowID = eNBs[i].getID();
						
				}

				else if (ReceivedPower[i] == maximumRecPower){
					maximumRecPower = ReceivedPower[i];
					maxPowID = std::min(eNBs[i].getID(),maxPowID);
				}
					
						
			}

					

			//verify if all eNBs were taken into account	
			if (countRecPower%NueNB == 0) {
				
			//////////////////////////////////////////////////////////
				/*code to find the second highest power and its ID*/
				firstHighPower = CSIVectorPows[0];
				firstHighID = CSIVectorIDs[0];
				
				int jj = 0,ii;
				
				for(ii=1;ii < CSIVectorPows.size(); ii++){
					if(firstHighPower < CSIVectorPows[ii]) {
						firstHighPower = CSIVectorPows[ii];
						firstHighID = CSIVectorIDs[ii];
						jj = ii;
					}
					else if(firstHighPower == CSIVectorPows[ii]){
						firstHighPower = CSIVectorPows[ii];
						firstHighID = std::min(CSIVectorIDs[ii],firstHighID);
					}


				}

				
				secondHighPower = CSIVectorPows[CSIVectorPows.size() - jj - 1];
				secondHighID = CSIVectorIDs[CSIVectorIDs.size() - jj - 1];

				for(ii=1;ii < CSIVectorPows.size(); ii++){
					if((secondHighPower < CSIVectorPows[ii]) && (jj != ii)) {
						secondHighPower = CSIVectorPows[ii];
						secondHighID = CSIVectorIDs[ii];
					}
					else if((secondHighPower == CSIVectorPows[ii]) && (jj != ii)) {
						secondHighPower = CSIVectorPows[ii];
						secondHighID = std::min(CSIVectorIDs[ii],secondHighID);
					}
				}
				
				if(firstHighID == ActualServingID){
					ActualServingPower = firstHighPower;
					ActualServingID = firstHighID;
					NewServingPower = secondHighPower;
					NewServingID = secondHighID;
				}	
				else{
					NewServingPower = firstHighPower;
					NewServingID = firstHighID;
					for(int index = 0; index < CSIVectorIDs.size(); index++){
						if(ActualServingID == CSIVectorIDs[index]){
								ActualServingPower = CSIVectorPows[index];
						}
					}
				}	



				/////////////////////////////////////////////////////////
				
				/*std::ofstream logfile("logfile.txt", std::ios_base::app | std::ios_base::out);
				logfile << endl << endl <<" UE ID " << this->id <<" ActualServingID: " << ActualServingID 
				<< " ActualServingPower: " << ActualServingPower << " NewServingID: " << NewServingID 
				<< " NewServingPower: " << NewServingPower << endl << endl<< endl;
				logfile.close();*/
			}
			
			if (ActualServingPower < (NewServingPower - hys)) {
				NormalRunFlag = false;
				HOflag = true;
				//cout << "NormalRunFlag %%%%%%%%%%%%%%%%%%%%%" << NormalRunFlag << endl;
			}
						
								
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////



		//verifies if there is a change of serving eNB
		//if ((!NormalRunFlag) && ActualServingPower < (NewServingPower - hys)){
		//if (!NormalRunFlag){
			///////////////////////////////////////////////////////////////////////////////////////////////////////
			//NormalRunFlag = false;
			/*calculate every 40ms*/
			if((HOflag) && (((int)(msg.time().asMsecs()) % 40) == 0) ){ //start sending MR (change CSI to MR) //
				
				countRecPower = 0;
				cout << "HO verification, msg.time().asMsecs()" << msg.time().asMsecs() << endl;
				maximumRecPower = -1000;
				ReceivedPower.clear();
				ReceivedPower.resize(0);
				

				for (int i=0; i<NueNB; i++){

					ReceivedPower.insert(ReceivedPower.begin()+i, -1000);

				}
				CSIVectorPows.clear();
				CSIVectorPows.resize(0);
				CSIVectorIDs.clear();
				CSIVectorIDs.resize(0);

				double time = (msg.time().asMsecs())*0.001;
				if (!stopMovFlag) {
					traveledD = mov.findTraveledDistance(time, SpeedM_S);
				}
				else
					{ traveledD = traveledD;}

				if (nearbyint(traveledD) >= nearbyint(distanceInitialFinal)) {
					traveledD = traveledD;
					instantX = instantX;
					instantY = instantY;

					if(firstTimeFinalPosition){

						std::ofstream logfile("logfile.txt", std::ios_base::app | std::ios_base::out);
						logfile <<" UE: " << this->id << " reached final Position "<< nearbyint(traveledD) << " metres "<<endl<<endl;
						logfile.close();
						firstTimeFinalPosition = false;

					}	


					stopMovFlag = 1;
				}
				else if(!stopMovFlag) {
					traveledD = mov.findTraveledDistance(time, SpeedM_S);
					Point position(Point(mov.findPosition(traveledD, angleInitialFinal, initialPosition)));
					instantX = nearbyint(position.getX());
					instantY = nearbyint(position.getY());
				}

				std::ofstream logfile("logfile.txt", std::ios_base::app | std::ios_base::out);
				logfile << " @UE: " << this->id <<" Verifying HO "  <<" msg.time().asMsecs() " << msg.time().asMsecs() 
				<< " TRAVELED DISTANCE: " << traveledD << " metres"<< " at position: " << "(" << instantX << ", " << instantY << ")" 
				<< " Total distance to be done: " << distanceInitialFinal << " metres "<< " ActualServingID: " 
				<< ActualServingID << " ActualServingPower: " << ActualServingPower  << " NewServingID: " 
				<< NewServingID << " NewServingPower: "<< NewServingPower <<endl<<endl<< endl;
				logfile.close();



				//this calculates and stores the power to find the highest power
			    for (long i=0; i<NueNB; i++) {
					
						countRecPower++;
						

						dis = computeDistance(instantX, instantY, eNBs[i].getPosition().getX(), eNBs[i].getPosition().getY());
					
						ReceivedPower[i] = computeRecPower(dis, f[eNBs[i].getID()], eNBs[i].getPower(), eNBs[i].getID());
						
						CSIVectorPows.insert(CSIVectorPows.begin()+i, ReceivedPower[i]); 
						
						CSIVectorIDs.insert(CSIVectorIDs.begin()+i, eNBs[i].getID());

						if(ReceivedPower[i] > maximumRecPower){
							
							maximumRecPower = ReceivedPower[i];
							maxPowID = eNBs[i].getID();
						
						}

						else if (ReceivedPower[i] == maximumRecPower){
							maximumRecPower = ReceivedPower[i];
							maxPowID = std::min(eNBs[i].getID(),maxPowID);
						}
					
						
				}

					

				//verify if all eNBs were taken into account	
				if (countRecPower%NueNB == 0) {

					countHO++;
					
					
					//////////////////////////////////////////////////////////
					/*code to find the second highest power and its ID*/
					firstHighPower = CSIVectorPows[0];
					firstHighID = CSIVectorIDs[0];
					
					int jj = 0,ii;
					for(ii=1;ii < CSIVectorPows.size(); ii++){
						if(firstHighPower < CSIVectorPows[ii]) {
							firstHighPower = CSIVectorPows[ii];
							firstHighID = CSIVectorIDs[ii];
							jj = ii;
						}
						else if(firstHighPower == CSIVectorPows[ii]){
							firstHighPower = CSIVectorPows[ii];
							firstHighID = std::min(CSIVectorIDs[ii],firstHighID);
						}


					}

					
					secondHighPower = CSIVectorPows[CSIVectorPows.size() - jj - 1];
					secondHighID = CSIVectorIDs[CSIVectorIDs.size() - jj - 1];

					for(ii=1;ii < CSIVectorPows.size(); ii++){
						if((secondHighPower < CSIVectorPows[ii]) && (jj != ii)) {
							secondHighPower = CSIVectorPows[ii];
							secondHighID = CSIVectorIDs[ii];
						}
						else if((secondHighPower == CSIVectorPows[ii]) && (jj != ii)) {
							secondHighPower = CSIVectorPows[ii];
							secondHighID = std::min(CSIVectorIDs[ii],secondHighID);
						}
					}
					//////////////////////////////////////////////////////////
					//cout << "firstHighPower: " << firstHighPower << "firstHighID: " << firstHighID <<endl;
					//cout << "secondHighPower: " << secondHighPower << "secondHighID: " << secondHighID <<endl;
					
					if(firstHighID == ActualServingID){
						ActualServingPower = firstHighPower;
						ActualServingID = firstHighID;
						NewServingPower = secondHighPower;
						NewServingID = secondHighID;
					}	
					else{
						NewServingPower = firstHighPower;
						NewServingID = firstHighID;
						for(int index = 0; index < CSIVectorIDs.size(); index++){
							if(ActualServingID == CSIVectorIDs[index]){
									ActualServingPower = CSIVectorPows[index];
							}
						}
					}	



					/////////////////////////////////////////////////////////	





					//code to store the serving power(Ps) in a vector
					for(int index = 0; index < CSIVectorIDs.size(); index++){
						if(ActualServingID == CSIVectorIDs[index]){
							Ps.push_back(CSIVectorPows[index]);
						}

					}

					//code to store the 2nd highest power(Pn) in a vector
					for(int index = 0; index < CSIVectorIDs.size(); index++){
						if(NewServingID == CSIVectorIDs[index]){
							Pn.push_back(CSIVectorPows[index]);
						}

					}


				}

				if (countHO == 5) {
				
					
					countHO = 0;
					///////////////////////////////////////
					//code to find the average of Ps and Pn
					averagePs = 0;
					averagePn = 0;
					for (int i = 0; i < Ps.size(); i++){
						
						averagePs = averagePs + Ps[i];
						averagePn = averagePn + Pn[i];
					}
					averagePs = averagePs/Ps.size();
					averagePn = averagePn/Pn.size();
					Ps.clear();
					Ps.resize(0);
					Pn.clear();
					Pn.resize(0);
					//////////////////////////////////////
					/*std::ofstream logfile("logfile.txt", std::ios_base::app | std::ios_base::out);
					logfile << endl << endl <<" UE ID " << this->id <<" (averagePs < (averagePn - hys)): " << (averagePs < (averagePn - hys)) << endl<< endl<< endl;
					logfile.close();*/
					if(averagePs < (averagePn - hys)){ //pay attention to the signals
						HOflag = false;
						TTTflag = true;

					}

					else {
						
						NormalRunFlag = true;
					}	
						

				}			
								
			}

			///////////////////////////////////////////////////////////////////////////////////////////////////////


			/*TTT*/
			if (TTTflag && (((int)(msg.time().asMsecs()) % TTT) == 0)) {
				//
				countRecPower = 0;
				cout << " TTT msg.time().asMsecs() " << msg.time().asMsecs() << endl;
				maximumRecPower = -1000;
				ReceivedPower.clear();
				ReceivedPower.resize(0);
				

				for (int i=0; i<NueNB; i++){

					ReceivedPower.insert(ReceivedPower.begin()+i, -1000);

				}
				CSIVectorPows.clear();
				CSIVectorPows.resize(0);
				CSIVectorIDs.clear();
				CSIVectorIDs.resize(0);

				double time = (msg.time().asMsecs())*0.001;
				if (!stopMovFlag) {
					traveledD = mov.findTraveledDistance(time, SpeedM_S);
				}
				else
					{ traveledD = traveledD;}

				if (nearbyint(traveledD) >= nearbyint(distanceInitialFinal)) {
					traveledD = traveledD;
					instantX = instantX;
					instantY = instantY;
					if(firstTimeFinalPosition){

						std::ofstream logfile("logfile.txt", std::ios_base::app | std::ios_base::out);
						logfile <<" UE: " << this->id << " reached final Position "<< nearbyint(traveledD) << " metres "<<endl<<endl;
						logfile.close();
						firstTimeFinalPosition = false;
					}
					stopMovFlag = 1;
				}
				else if(!stopMovFlag) {
					traveledD = mov.findTraveledDistance(time, SpeedM_S);
					Point position(Point(mov.findPosition(traveledD, angleInitialFinal, initialPosition)));
					instantX = nearbyint(position.getX());
					instantY = nearbyint(position.getY());
				}

			
				std::ofstream logfile("logfile.txt", std::ios_base::app | std::ios_base::out);
				logfile << " @UE: " << this->id <<" TTT "  <<" msg.time().asMsecs() " << msg.time().asMsecs() 
				<< " TRAVELED DISTANCE: " << traveledD << " metres"<< " at position: " << "(" << instantX << ", " << instantY << ")" 
				<< " Total distance to be done: " << distanceInitialFinal << " metres "<< " ActualServingID: " 
				<< ActualServingID << " ActualServingPower: " << ActualServingPower  << " NewServingID: " 
				<< NewServingID << " NewServingPower: "<< NewServingPower <<endl<<endl<< endl;
				logfile.close();


				//this calculates and stores the power to find the highest power
			    for (long i=0; i<NueNB; i++) {
					
						countRecPower++;
						

						dis = computeDistance(instantX, instantY, eNBs[i].getPosition().getX(), eNBs[i].getPosition().getY());
					
						ReceivedPower[i] = computeRecPower(dis, f[eNBs[i].getID()], eNBs[i].getPower(), eNBs[i].getID());
						
						CSIVectorPows.insert(CSIVectorPows.begin()+i, ReceivedPower[i]); 
						
						CSIVectorIDs.insert(CSIVectorIDs.begin()+i, eNBs[i].getID());

						if(ReceivedPower[i] > maximumRecPower){
							
							maximumRecPower = ReceivedPower[i];
							maxPowID = eNBs[i].getID();
						
						}

						else if (ReceivedPower[i] == maximumRecPower){
							maximumRecPower = ReceivedPower[i];
							maxPowID = std::min(eNBs[i].getID(),maxPowID);
						}
					
						
				}

				
				logfile << "    " << endl << endl << endl;
				logfile.close();		

				//verify if all eNBs were taken into account	
				if (countRecPower%NueNB == 0) {

					
					//////////////////////////////////////////////////////////
					/*code to find the second highest power and its ID*/
					firstHighPower = CSIVectorPows[0];
					firstHighID = CSIVectorIDs[0];
					
					int jj = 0,ii;
					for(ii=1;ii < CSIVectorPows.size(); ii++){
						if(firstHighPower < CSIVectorPows[ii]) {
							firstHighPower = CSIVectorPows[ii];
							firstHighID = CSIVectorIDs[ii];
							jj = ii;
						}
						else if(firstHighPower == CSIVectorPows[ii]){
							firstHighPower = CSIVectorPows[ii];
							firstHighID = std::min(CSIVectorIDs[ii],firstHighID);
						}


					}

					
					secondHighPower = CSIVectorPows[CSIVectorPows.size() - jj - 1];
					secondHighID = CSIVectorIDs[CSIVectorIDs.size() - jj - 1];

					for(ii=1;ii < CSIVectorPows.size(); ii++){
						if((secondHighPower < CSIVectorPows[ii]) && (jj != ii)) {
							secondHighPower = CSIVectorPows[ii];
							secondHighID = CSIVectorIDs[ii];
						}
						else if((secondHighPower == CSIVectorPows[ii]) && (jj != ii)) {
							secondHighPower = CSIVectorPows[ii];
							secondHighID = std::min(CSIVectorIDs[ii],secondHighID);
						}
					}
					/////////////////////////////////////////////////////////////////
					
					if(firstHighID == ActualServingID){
						ActualServingPower = firstHighPower;
						ActualServingID = firstHighID;
						NewServingPower = secondHighPower;
						NewServingID = secondHighID;
					}	
					else{
						NewServingPower = firstHighPower;
						NewServingID = firstHighID;
						for(int index = 0; index < CSIVectorIDs.size(); index++){
							if(ActualServingID == CSIVectorIDs[index]){
									ActualServingPower = CSIVectorPows[index];
							}
						}
					}	



					/////////////////////////////////////////////////////////

			

					TTTflag = false;
					//NormalRunFlag = true;
					MR = new MeasurementReport(this->id, ActualServingID, NewServingPower,NewServingID, CSIVectorIDs, CSIVectorPows, 0);
					sendOutput(msg.time(), Out, NULL, MR);
					firstRun = false;
					HODecisionTimer = msg.time().asMsecs();

					
										
				}

			///////////////////////////////////////////////////////////////////////////////////////////////////////	

			}

		//}	

		sendOutput(msg.time(), Req, 2, NULL);// 2 means UE processor requesting to queue to delete received message
										     // NULL means no object being sent
 	}
	
	return *this ;
 }

 Model &UE::internalFunction( const InternalMessage & )
 {
		

	switch (state){
		case Idle:
			state = SendPack;
			//holdIn(Atomic::active, ProcessTime);
			break;
		case RecPack:
			state = Idle; // it was commented before
			//passivate();
			break;
		case SendPack:
			state = RecPack;
			holdIn(Atomic::active, ProcessTime);
			break;
	}



	 return *this;
 }

 UE::~UE()
{


}

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*Function Name: computeDistance
*Description: Computes the distance based on the x y coordinates
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
float UE::computeDistance(long x, long y, long eNBx, long eNBy){
	return (sqrt(pow((eNBx-x),2)+pow((eNBy-y),2)))/1000;
}

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*Function Name: computeRecPower
*Description: Computes the received power by the UE (RSRP)
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
float UE::computeRecPower(float d, long f, long pt, long id){
	float l, pl, pr=-1000;
	float mcl = 70;
	//float pt = 46;
	float gr = 0;
	float gt = 14;
	float h = 15;//30;
	if (pt != 0 ){	
		l = 40*(1-4*pow(10,-3)*h)*log10(d)-18*log10(h)+21*log10(f)+80;
		//l = 120.9 + 37.6*log10 (d);
		//cout << " l SHOUL BE 120.9 + 37.6logD= " << l << endl; 
		
		//cout << "**** THIS IS l " << l << endl;
		pl = l+10;
		pr = pt-max((pl-gt-gr), mcl);
		/*std::ofstream logfile("logfile.txt", std::ios_base::app | std::ios_base::out);
		logfile << "UE " << this->id << " RECEIVED Power: " << pr << " eNB ID: "<< id << endl;
		logfile.close();*/
	}
	return pr;
}
