/*****************************************************************************
*  	DESCRIPTION	: Atomic Model globalQueue
*	AUTHOR		: Baha Uddin Kazi, Mohammad Etemad
*	Email		: 
*	DATE		: 
*****************************************************************************/

#include "globalQueue.h"    // class Queue
#include "message.h"    // class ExternalMessage, InternalMessage
#include <iostream>


/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Function Name: globalQueue
*Description: Constructor
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
globalQueue::globalQueue( const string &name ) :
	Atomic(name), 
	In(addInputPort("In")),
	Req(addInputPort("Req")),
	X2in(addInputPort("X2in")),
	//OFin(addInputPort("OFin")),
	Out(addOutputPort("Out")),
	ProcessTime (00,00,00,000){
}

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Function Name: initFunction
*Description: Init function for DEVS atomic model 
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
Model &globalQueue::initFunction(){
	std::string ID( MainSimulator::Instance().getParameter( description(), "ID" ) ) ;
	if (ID!="") id = atoi(ID.c_str()); //read the queue ID from the MA file
	

	//if (firstRun == 0) {
	{
		std::ofstream logfile;
		logfile.open("logfile.txt", std::ofstream::out | std::ofstream::trunc);
		logfile.close();
	}
	{
		std::ofstream logfile("resultCount.txt", std::ofstream::out | std::ofstream::trunc);
  		logfile.close();
  	}
  	
	{
		std::ofstream logfile("receivedMsg.txt", std::ofstream::out | std::ofstream::trunc);
  		logfile.close();
	}


	//	firstRun = 1;
	//

	Request = 0;
	Qlen = 0;
	state = Idle;
	elements.erase( elements.begin(), elements.end() ) ;
	elementsO.erase( elementsO.begin(), elementsO.end() ) ;
	passivate();
	return *this ;
}

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Function Name: externalFunction
*Description: External function for DEVS atomic model 
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
Model &globalQueue::externalFunction( const ExternalMessage &msg ){
	if(msg.port() == In || msg.port() == X2in ){
			

		if((msg.valueO()->getDestID() == this->id || msg.valueO()->getDestID()==9999) &&  (msg.valueO()->getSrcID() != this->id)){//this filters the destination's ID
	//cout << "------------------- IN QUEUE : MESSAGE SOURCE " << msg.valueO()->getSrcID() << " AND MESSAGE DEST " << msg.valueO()->getDestID() << " AND THIS ID IS " << this->id << endl;
			//elements.push_back( msg.value() ) ; //Store Input value in Queue		
			//if (msg.valueO()->getMsgT()==HO_REQ){
			//	std::ofstream logfile("logfile.txt", std::ios_base::app | std::ios_base::out);
			//	logfile << "eNB ID: " << this->id << " %%%%%%%%%%%%%%%%%%%%%RECEIVED THE HO_REQ FROM  eNB ID: "  << msg.valueO()->getSrcID() << " TeNB " << msg.valueO()->getDestID() << endl;
			//	logfile.close();
			//}


			elementsO.push_back( msg.valueO() ) ; //Store Input valueO in Queue	
			state = Push; // no expression here before
			Qlen++;
		}
	}else{ 		//message input port is Req
		
		if (msg.value() == 1) { // 1 means add message to the queue. 
			//1-queue is empty   2-queue is not empty
			if(elementsO.size() <= 0 /*|| elements.size() < 0*/){
				Request = 1;
				passivate(); // it was commented before
			}else{
				Request = 1;
				state = Send; 
				holdIn( Atomic::active, ProcessTime);
			}				
		}else if(msg.value() == 2 && elementsO.size()>0 /*&& elements.size() > 0*/){// 2 means delete received message from the queue
			//delete from the queue
		//	cout << " ^^^^^^^^^^^^^^^^STATE IS CHANGING TO POP " << endl;
			state = Pop;

			elementsO.pop_front();
			Qlen--;		
			Request = 0;  // new change------------------------
			holdIn( Atomic::active, ProcessTime);
			}
//if (elementsO.size()>0){ cout << " I AM QUEUE " << this->id << " A MESSAGE HAS BEEN REQUESTED MY SIZE IS " << elementsO.size()<< endl; cout << Request << " & STATE = " << state << endl;}
		}
	return *this;
}

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*Function Name: internalFunction
*Description: Internal function for DEVS atomic model 
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
Model &globalQueue::internalFunction( const InternalMessage & ){
	switch (state){
		case Idle:
			if (Request == 1) state = Send; 
			else passivate();
			break;

		case Push:	

	//		cout << "$$$$$$$$$$$$$$$$$$$$$$$INSODE PUSH STATE " << Qlen << endl;	
		//	Qlen++;
			state = Idle;
			break;

		case Send:
			Request = 0;
			passivate();
			break;
		case Pop : 
			//elements.pop_front(); 
			//elementsO.pop_front();
			//Qlen--;
		//	cout << "  QUEUE: " << this->id << " ***  Queue length is : " << Qlen <<endl;
			state = Idle;
		//	Request = 0;
			break;

	}// end of switch

	return *this;
}

/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*Function Name: outputFunction
*Description: Output function for DEVS atomic model 
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
Model &globalQueue::outputFunction( const InternalMessage &msg ){

	if ((state == Send) && (Request == 1))
	//if (Request == 1)
	{
		//cout << "||||||||||| INSIDE OUTPUT OF QUEUE |||||||||||||||" << endl;
		sendOutput(msg.time(), Out, NULL, elementsO.front());

	}
	return *this ;
}


/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*Function Name: globalQueue
*Description: Deconstructor
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
globalQueue::~globalQueue()
{
}


