#include "Channel.h"
#include <stdio.h>

#define MAX_BUFFER_LENGTH 100

void Channel :: init_channel() {
	maxBufferLength = MAX_BUFFER_LENGTH;
	transferRate = MAX_BUFFER_LENGTH;
}

Channel :: Channel() {
	init_channel();
}

Channel :: Channel(char* name) {
	set_name(name);
	init_channel();
}

bool Channel :: set_maxBufferLength(unsigned int maxBufferLength) {
	if(maxBufferLength <= MAX_BUFFER_LENGTH) {
		this->maxBufferLength = maxBufferLength;
		return true;
	}
	return false;
}

unsigned int Channel :: get_maxBufferLength() {
	return maxBufferLength;
}

unsigned int Channel :: get_avlInputBufferUp() {
	return maxBufferLength-lInputMsgBufferUp.size();
}

unsigned int Channel :: get_avlOutputBufferUp() {
	return maxBufferLength-lOutputMsgBufferUp.size();
}

unsigned int Channel :: get_avlInputBufferDown() {
	return maxBufferLength-lInputMsgBufferDown.size();
}

unsigned int Channel :: get_avlOutputBufferDown() {
	return maxBufferLength-lOutputMsgBufferDown.size();
}

bool Channel :: set_transferRate(unsigned int transferRate) {
	if(transferRate <= MAX_BUFFER_LENGTH) {
		this->transferRate = transferRate;
		return true;
	}
	return false;
}

unsigned int Channel :: get_transferRate() {
	return transferRate;
}



bool Channel :: add_msgAtBegin (list<Message*>* buffer, Message* message) {
	try {
		buffer->push_front(message);
	}
	catch(bad_alloc& error) {
		delete message;
		return false;
	}
	return true;
}

bool Channel :: del_msgAtBegin (list<Message*>* buffer) {
	try {
		/*
		printf("a\n");
		getchar();
		delete buffer->back();
		printf("b\n");
		getchar();
		*/
		Message* first_Message = buffer->front();
		delete first_Message;
		buffer->pop_front();
		/*
		printf("c\n");
		getchar();
		*/
	}
	catch(bad_alloc& error) {
		return false;
	}
	return true;
}

bool Channel :: add_msgAtEnd (list<Message*>* buffer, Message* message) {
	try {
		buffer->push_back(message);
	}
	catch(bad_alloc& error) {
		cerr << "bad_alloc caught: " << error.what() << endl;
		delete message;
		return false;
	}
	return true;
}

bool del_msgAtEnd (list<Message*>* buffer) {
	try {
		Message* last_Message = buffer->back();
		delete last_Message;
		buffer->pop_back();
	}
	catch(bad_alloc& error) {
		return false;
	}
	return true;
}

bool Channel :: send_MsgUp(Message* message) {
	if(message != NULL) {
		if(transferRate == 0) {
			//TODO: at the moment only one packet (in the front) gets deleted if buffer is full. However, the whole message (instruction+value) should be deleted in case of a full buffer
			if(lOutputMsgBufferUp.size() == maxBufferLength) {
				del_msgAtBegin(&lOutputMsgBufferUp);
			}
			return add_msgAtEnd(&lOutputMsgBufferUp, message);
		}
		else {
			if(lInputMsgBufferUp.size() == maxBufferLength) { 
				//TODO: at the moment only one packet (in the front) gets deleted if buffer is full. However, the whole message (instruction+value) should be deleted in case of a full buffer
				del_msgAtBegin(&lInputMsgBufferUp);
			}
			return add_msgAtEnd(&lInputMsgBufferUp, message);
		}
	}
}

bool Channel :: send_MsgUp(float msg) {
	Message* message = new Message(msg);
	return send_MsgUp(message);
}

bool Channel :: send_MsgUp(int msg) {
	Message* message = new Message(msg);
	return send_MsgUp(message);
}

bool Channel :: get_MsgUp(float* msg) {
	if(isThereFloatMsgUp()) {
		float tempMsg;
		if(lOutputMsgBufferUp.front()->getMsg(&tempMsg)) {
			*msg = tempMsg;
			del_msgAtBegin(&lOutputMsgBufferUp);
			return true;
		}
	}
	return false;
}

bool Channel :: get_MsgUp(int* msg) {
	if(isThereIntMsgUp()) {
		int tempMsg;
		if(lOutputMsgBufferUp.front()->getMsg(&tempMsg)) {
			*msg = tempMsg;
			del_msgAtBegin(&lOutputMsgBufferUp);
			return true;
		}
	}
	return false;
}

bool Channel :: isThereFloatMsgUp() {
	if(lOutputMsgBufferUp.size() > 0 ) {
		if(lOutputMsgBufferUp.front() != NULL) {
			return lOutputMsgBufferUp.front()->isMsgFloat();
		}
	}
	return false;
}

bool Channel :: isThereIntMsgUp() {
	if(lOutputMsgBufferUp.size() > 0 ) {
		if(lOutputMsgBufferUp.front() != NULL) {
			return lOutputMsgBufferUp.front()->isMsgInt();
		}
	}
	return false;
}

bool Channel :: send_MsgDown(Message* message) {
	if(message != NULL) {
		if(transferRate == 0) {
			if(lOutputMsgBufferDown.size() == maxBufferLength) { 
				del_msgAtBegin(&lOutputMsgBufferDown);
			}
			return add_msgAtEnd(&lOutputMsgBufferDown, message);
		}
		else {
			if(lInputMsgBufferDown.size() == maxBufferLength) { 
				del_msgAtBegin(&lInputMsgBufferDown);
			}
			return add_msgAtEnd(&lInputMsgBufferDown, message);
		}
	}
}

bool Channel :: send_MsgDown(float msg) {
	Message* message = new Message(msg);
	return send_MsgDown(message);
}

bool Channel :: send_MsgDown(int msg) {
	Message* message = new Message(msg);
	return send_MsgDown(message);
}

bool Channel :: get_MsgDown(float* msg) {
	if(isThereFloatMsgDown()) {
		float tempMsg;
		if(lOutputMsgBufferDown.front()->getMsg(&tempMsg)) {
			*msg = tempMsg;
			del_msgAtBegin(&lOutputMsgBufferDown);
			return true;
		}
	}
	return false;
}

bool Channel :: get_MsgDown(int* msg) {
	if(isThereIntMsgDown()) {
		int tempMsg;
		if(lOutputMsgBufferDown.front()->getMsg(&tempMsg)) {
			*msg = tempMsg;
			del_msgAtBegin(&lOutputMsgBufferDown);
			return true;
		}
	}
	return false;
}

bool Channel :: isThereFloatMsgDown() {
	if(lOutputMsgBufferDown.size() > 0 ) {
		if(lOutputMsgBufferDown.front() != NULL) {
			return lOutputMsgBufferDown.front()->isMsgFloat();
		}
	}
	return false;
}

bool Channel :: isThereIntMsgDown() {
	if(lOutputMsgBufferDown.size() > 0 ) {
		if(lOutputMsgBufferDown.front() != NULL) {
			return lOutputMsgBufferDown.front()->isMsgInt();
		}
	}
	return false;
}

bool Channel :: transferMsgs(list<Message*>* dest_buffer, list<Message*>* src_buffer) {	
	unsigned int NumOfMsgsToMove;

	if(transferRate <= src_buffer->size()) {
		NumOfMsgsToMove = transferRate;
	}
	else {
		NumOfMsgsToMove = src_buffer->size();
	}

	if(NumOfMsgsToMove <= maxBufferLength-dest_buffer->size()) {
		for(unsigned int i=0; i<NumOfMsgsToMove; i++) {	
			if(add_msgAtEnd(dest_buffer, src_buffer->front())) {
				if(!del_msgAtBegin(src_buffer)) {
					return false;
				}
			}
			else {
				return false;
			}
		}
		return true;
	}
	return false;
}

bool Channel :: trigger() {
	bool flag_worked = transferMsgs(&lOutputMsgBufferUp, &lInputMsgBufferUp) && transferMsgs(&lOutputMsgBufferUp, &lInputMsgBufferUp);
	//printf("Channel %s: in_up %u, out_up %u, in_dn %u, out_dn %u,\n", name, lInputMsgBufferUp.size(), lOutputMsgBufferUp.size(), lInputMsgBufferDown.size(), lOutputMsgBufferDown.size());
	return flag_worked;

}

bool Channel :: delete_all_InputMsgBufferUp()
{
	Message* cur_Message;
	unsigned int cur_index_Message 		= 0;
	unsigned int size_li_Inp_MsgBufUp 	= lInputMsgBufferUp.size();
	for(cur_index_Message = 0; cur_index_Message < size_li_Inp_MsgBufUp; cur_index_Message){
		cur_Message = lInputMsgBufferUp.front();
		delete cur_Message;
		lInputMsgBufferUp.pop_front();
	}

	return true; //added by Ali, it is an error in VS.
}

bool Channel :: delete_all_OuputMsgBufferUp()
{
	Message* cur_Message;
	unsigned int cur_index_Message 		= 0;
	unsigned int size_li_Out_MsgBufUp 	= lOutputMsgBufferUp.size();
	for(cur_index_Message = 0; cur_index_Message < size_li_Out_MsgBufUp; cur_index_Message){
		cur_Message = lOutputMsgBufferUp.front();
		delete cur_Message;
		lOutputMsgBufferUp.pop_front();
	}
	return true; //added by Ali, it is an error in VS.
}
bool Channel :: delete_all_InputMsgBufferDown()
{
	Message* cur_Message;
	unsigned int cur_index_Message 		= 0;
	unsigned int size_li_Out_MsgBufDown = lInputMsgBufferDown.size();
	for(cur_index_Message = 0; cur_index_Message < size_li_Out_MsgBufDown; cur_index_Message){
		cur_Message = lInputMsgBufferDown.front();
		delete cur_Message;
		lInputMsgBufferDown.pop_front();
	}
	return true; //added by Ali, it is an error in VS.
}
bool Channel :: delete_all_OutputMsgBufferDown()
{
	Message* cur_Message;
	unsigned int cur_index_Message 		= 0;
	unsigned int size_li_Out_MsgBufDown = lOutputMsgBufferDown.size();
	for(cur_index_Message = 0; cur_index_Message < size_li_Out_MsgBufDown; cur_index_Message){
		cur_Message = lOutputMsgBufferDown.front();
		delete cur_Message;
		lOutputMsgBufferDown.pop_front();
	}
	return true; //added by Ali, it is an error in VS.
}

Channel :: ~Channel()
{
	delete_all_InputMsgBufferUp();
	delete_all_OuputMsgBufferUp();
	delete_all_InputMsgBufferDown();
	delete_all_OutputMsgBufferDown();
}
