 /***********************************************
 *
 *  DESCRIPTION: Atomic Model MeNB Processor
 *
 *  AUTHOR: Baha Uddin Kazi, Victor Silva
 *
 *  DATE: 30/06/2016
 *  
 *
 ***********************************************/

 #include "MeNB.h"
 #include "message.h"       // InternalMessage ....
 #include "Msg.h"
 #include "cdtime.h"
 #include <iostream>
 #include <algorithm>
 #include <vector>
 #include <map>
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Function Name: initializeParameters			*
 * Description: To initialize parameters		*
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void MeNB::initializeParameters(long ID, unsigned long px, unsigned long py, long freq, long pwr){
	id = ID;
	posx = px;
	posy = py;
	f = freq;
	p = pwr;
}


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

	string frequency( MainSimulator::Instance().getParameter( description(), "frequency" ) ) ;
	if (frequency!="") f = atol(frequency.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 MeNBPower( MainSimulator::Instance().getParameter( description(), "MeNBPower" ) ) ;
	if (MeNBPower!="") p = atol(MeNBPower.c_str());


	cout << "MeNB created with id " << this->id << " at position " << "(" << posx << ", " << posy << ")" <<" with frequency: " << f << " and Power: "<< p << endl;

	//std::ofstream logfile("receivedMsg.txt", std::ofstream::out | std::ofstream::trunc);
  	//logfile.close();
	
}

 Model &MeNB::initFunction() // Initialize the parameters
  {
	state = Idle;
	ctrlCmdFlag = true;
		
		
	holdIn(Atomic::active, 0);  //Programmed to have an instantaneous internal transition.
	return *this ;
  }


 Model &MeNB::externalFunction( const ExternalMessage &msg )
  { 
	cout << "    MeNB " << this->id<<endl<<endl;

	if (msg.port()==In){


		state = SendPack; // Received a new packet from Queue and will process and sent to others.
		//For messages received from the UE
		if (msg.valueO()->getMsgT()==CSI_FEEDBACK){ //from the UE
			cout << "MeNB " << this->id << " Received CSI_FEEDBACK from the UE " << endl;
			std::ofstream logfile("logfile.txt", std::ios_base::app | std::ios_base::out);
			logfile << " @UE: " << msg.valueO()->getSrcID() << " eNB ID: " << this->id << " RECEIVED THE CSI_FEEDBACK FROM  UE ID: " << msg.valueO()->getSrcID() << endl;
			logfile.close();

			MRFlags[msg.valueO()->getSrcID()] = false;
			HOReqFlags[msg.valueO()->getSrcID()] = false;
			HOAckFlags[msg.valueO()->getSrcID()] = false;
		}

		//Received MR from the UE
		else if (msg.valueO()->getMsgT()==MES_REP){ //from the UE
			cout << "MeNB " << this->id << "Received MR from the UE " << endl;
			MR  = (MeasurementReport*)msg.valueO();
			MRtargedID = MR->getTargetID();
			MRsourceUEid = MR->getSrcID();
			std::ofstream logfile("logfile.txt", std::ios_base::app | std::ios_base::out);
			logfile << " @UE: " << MRsourceUEid << " eNB ID: " << this->id << " RECEIVED THE MR FROM  UE ID: " << MRsourceUEid << " MR->getTargetID() "<< MRtargedID << endl;
			logfile.close();
			MRFlags[MRsourceUEid] = true;
		}

		//Received HO_REQ from the  eNB
		else if (msg.valueO()->getMsgT()==HO_REQ){ 
			cout << "MeNB " << this->id << " Received HO_REQ from the  eNB" << endl;
			recHOreq  = (HOReq*)msg.valueO();
			HOReqSourceIDeNB = recHOreq->getSrcID();
			HOReqSourceUEid = recHOreq->getSourceUEid();
			HOReqtargedID = recHOreq->getTargetID();
			cout << "MeNB " << this->id << " Received HO_REQ from the  eNB" << endl;
			std::ofstream logfile("logfile.txt", std::ios_base::app | std::ios_base::out);
			logfile << " @UE: " << HOReqSourceUEid << " eNB ID: " << this->id << " RECEIVED THE HO_REQ FROM  eNB ID: " << HOReqSourceIDeNB << " HOReqtargedID "<< HOReqtargedID << endl;
			logfile.close();
			HOReqFlags[HOReqSourceUEid] = true;
		}

		//Received HO_ACK from the  eNB
		else if (msg.valueO()->getMsgT()==HO_ACK){ 
			cout << "MeNB " << this->id << "Received HO_ACK from the  eNB" << endl;
			recHOReqAcknowledgement  = (HOReqAck*)msg.valueO();
			HOAckSourceIDeNB = recHOReqAcknowledgement->getSrcID();
			HOAcktargedID =  recHOReqAcknowledgement->getTargetID();
			HOAcksourceUEid = recHOReqAcknowledgement->getSourceUEid();
			cout << "MeNB " << this->id << " Received HO_ACK from the  eNB" << endl;
			std::ofstream logfile("logfile.txt", std::ios_base::app | std::ios_base::out);
			logfile << " @UE: " << HOAcksourceUEid << " eNB ID: " << this->id << " RECEIVED THE HO_ACK FROM  eNB ID: " << HOAckSourceIDeNB << " HOAcktargedID "<< HOAcktargedID << endl;
			logfile.close();
			HOAckFlags[HOAcksourceUEid] = true;
		}

		else if (msg.valueO()->getMsgT()==CTRL_MeNB){ // eNB received CTRL message from other eNBs
			cout << "MeNB " << this->id<< "Received from the eNB " << endl;
			CTRLcommand = (CTRLCmd*)msg.valueO();
			rID = CTRLcommand->getSrcID();	
			rFreq = CTRLcommand->getFreq();
			rPow = CTRLcommand->getMeNBPower();
			//std::ofstream logfile("receivedMsg.txt", std::ios_base::app | std::ios_base::out);
			//logfile << "eNB ID: " << this->id << " RECEIVED THE CTRL_MeNB FROM  eNB ID: " << msg.valueO()->getSrcID() << " f "<< rFreq << " p " << rPow <<endl;
			//logfile.close();

		}		
		
	}
	
	return *this;
  }

 Model &MeNB::outputFunction( const InternalMessage &msg )
 {	
	//cout << " inside the Output Function   MeNB " << this->id<<endl<<endl;
	
	if (ctrlCmdFlag == true){ // All the Macro and Pico eNBs share the system information and also send to UEs
		CTRLcommand = new CTRLCmd(this->id, 9999, posx, posy, f, p);
		sendOutput(msg.time(), Out, NULL, CTRLcommand);
		sendOutput(msg.time(), X2out, NULL, CTRLcommand);
		ctrlCmdFlag = false;

	}

	if (MRFlags[MRsourceUEid] == true){ // All the Macro and Pico eNBs share the system information and also send to UEs
		HOreq = new HOReq(this->id, MRtargedID, 1, MRtargedID,MRsourceUEid);
		sendOutput(msg.time(), X2out, NULL, HOreq);
		MRFlags[MRsourceUEid] = false;
		std::ofstream logfile("logfile.txt", std::ios_base::app | std::ios_base::out);
		logfile <<" MRtargedID "<< MRtargedID <<endl;
		logfile.close();

	}

	if (HOReqFlags[HOReqSourceUEid] == true){ // All the Macro and Pico eNBs share the system information and also send to UEs

		HOReqAcknowledgement = new HOReqAck(this->id, HOReqSourceIDeNB, 1, HOReqtargedID, HOReqSourceUEid);
		sendOutput(msg.time(), X2out, NULL, HOReqAcknowledgement);
		HOReqFlags[HOReqSourceUEid] = false;

	}

	if (HOAckFlags[HOAcksourceUEid] == true){ // All the Macro and Pico eNBs share the system information and also send to UEs

		RRCcmd = new RRCConnReconf(this->id, HOAcksourceUEid, 1, HOAcktargedID);
		sendOutput(msg.time(), Out, NULL, RRCcmd);
		HOAckFlags[HOAcksourceUEid] = false;

	}


	if ( state == Idle){ // Send request to Queue to send him (the processor) stored message  				
		sendOutput(msg.time(), Req, 1, NULL);
		//cout << "Send 1" <<endl;
			
	}
	
	if (state == SendPack){ // Send required messages to others (eNBs or UEs) and after sending the message send request to Queue to delete the received message
	
		sendOutput(msg.time(), Req, 2, NULL);
	
	}
	return *this ;
 }

 Model &MeNB::internalFunction( const InternalMessage & )
 {
	switch (state){
		case Idle:
			state = RecPack;
			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;
 }

 MeNB::~MeNB()
{
	
}
