void Node::Depart(Message *message)
{
	_waitTimes[_ID][0] -= _serviceTime->GetMean();
	_waitTimes[_ID][1] = GetCurrentSimTime();

	_state = idle;
	_serverReserved = false;

	if (message->GetDestination() == _ID) {
		message->OutputStatistics(*_outFile);
		Sink(message);
	}
	else
	{
		message->UpdateLastNode(_ID);
		cout << GetCurrentSimTime() << ", Node " << _ID << ", Depart, Message " << message->GetID();
		neighors[DetermineNextNode(message)]->Arrive(message);
		
	}

	for (int i = 0; i <= _numEdges; i++) {
		if (!(_queues[currentQueue].IsEmpty()) && (!_serverReserved))
		{
			ScheduleEventIn(0, new ServeEvent(this));
			_serverReserved = true;
		}
		currentQueue = (currentQueue + 1) % (_numEdges + 1);
	}
}
void Node::OutputStatistics() {
	Time AverageProcessingTime = processingTime / numArrivedMessages;
	Time Efficency = processingTime / GetCurrentSimTime();
	Time AverageWaitTime = totalWaitTime / numArrivedMessages;
	*_outFile << "Node - " << _ID << endl
		<< "Average Processing Time: " << AverageProcessingTime << endl
		<< "Efficency: " << Efficency << endl
		<< "Average Wait Time: " << AverageWaitTime << endl
		<< "Average Messages in Queue: " << averageMessagesInQueue / GetCurrentSimTime() << endl;
}
Packet::Packet()
{
	_id = _nextId++;
	_prevId = -1;
	_destId = -1;
	_prevQueueSize = -1;
	_creationTime = GetCurrentSimTime();
	_waitTime = 0.0;
}
void Node::Serve()
{
	while (_queues[currentQueue].IsEmpty() == true) {
		currentQueue = (currentQueue + 1) % (_numEdges + 1); 
	}
	Message *message = _queues[currentQueue].GetEntity();

	totalWaitTime += message->GetTimeSpentWaiting();
	averageMessagesInQueue += (messagesInQueue * (GetCurrentSimTime() - lastReading));
	lastReading = GetCurrentSimTime();
	messagesInQueue--;

	message->UpdateTimeSpentWaiting();
	cout << GetCurrentSimTime() << ", SSSQ " << _ID << ", Serve, Message " << message->GetID() << endl;
	_state = busy;
	_serverReserved = true;
	Time serviceTime = _serviceTime->GetRV();
	processingTime += serviceTime;
	ScheduleEventIn(serviceTime, new DepartEvent(this, message));
}
void Node::NextMessage()
{
	if ((_numMsgs == -1) || (_numMsgs > 0))
	{
		if (_numMsgs > 0) 
			_numMsgs--;
		int randomNode = (_ID + (rand() % _numVertices - 1) + 1) % _numVertices;
		Message *msg = new Message(randomNode, _numVertices);
		msg->UpdateLastNode(-1);
		cout << GetCurrentSimTime() << ", " << _ID << ", NextMessage, Message " << msg->GetID() << ", Destination " << randomNode << endl;
		this->ScheduleArrivalIn(0, msg);
		ScheduleEventIn(_generationRate->GetRV(), new NextMessageEvent(this));
	}
}
void Node::Arrive(Message *message)
{
	Time currentSimTime = GetCurrentSimTime();
	cout << currentSimTime << ", SSSQ " << _ID << ", Arrive, Message " << message->GetID() << endl;
	//count nmber of messages and then update current wait time at the node
	averageMessagesInQueue += (messagesInQueue * (currentSimTime - lastReading));
	lastReading = currentSimTime;
	messagesInQueue++;
	numArrivedMessages++;
	if (messagesInQueue > maxQueueSize) {
		maxQueueSize = messagesInQueue;
	}
	_waitTimes[_ID][0] += _serviceTime->GetMean();
	_waitTimes[_ID][1] = currentSimTime;

	message->UpdateEnteredQueue();


	//Update last node
	//Add entity to the correct queue
	if (message->GetLastNode() == -1) {
		_queues[0].AddEntity(message); //Add to Internal Queue
	}
	else
	{
		for (int i = 1; i <= _numEdges; i++) 
		{
			if (_queues[i].GetID() == message->GetLastNode()) 
			{
				_queues[i].AddEntity(message);
				break;
			}
		}
	}

	if ((_state == idle) && (!_serverReserved)) 
	{
		ScheduleEventIn(0, new ServeEvent(this));
		_serverReserved = true;
	}

}
void Node::Sink(Message *message)
{
	cout << GetCurrentSimTime() << ", Node " << _ID << ", Sink, Message " << message->GetID() << endl;
	delete message;
}