#include "SlaveAgentHandlerOfAgent.h"

#include "instruction_set_architecture.h"
#include <stdio.h>
#include "printError.h"

#include <algorithm> 

#define MAXNUMOF_MOUNTEDSENSORS 100

using namespace std;

SlaveAgentHandlerOfAgent :: SlaveAgentHandlerOfAgent() {
	initSlaveAgentHandler();
}

void SlaveAgentHandlerOfAgent :: initSlaveAgentHandler() {
	maxNumOfMountedSlaveAgents = MAXNUMOF_MOUNTEDSENSORS;
}

bool SlaveAgentHandlerOfAgent :: mount_slaveAgentIntoSlaveAgentSlot(Channel* inputPort) {
	SlaveAgentSlotOfAgent* slaveAgentSlotOfAgent = new SlaveAgentSlotOfAgent();
	if(slaveAgentSlotOfAgent != NULL) {
		if(slaveAgentSlotOfAgent->set_comPort(inputPort)) {
			if(vMountedSlaveAgents.size() < maxNumOfMountedSlaveAgents) {
				try {
					vMountedSlaveAgents.push_back(slaveAgentSlotOfAgent);
				}
				catch(bad_alloc& error) {
					printError("bad_alloc caught: ", error.what());
					delete slaveAgentSlotOfAgent;
					return false;
				}
			}
			else {
				printError("Max number of mounted slaveAgents is already reached!");
				delete slaveAgentSlotOfAgent;
				return false;
			}
			return true;
		}
		else {
			printError("Input port is no set!");
			vMountedSlaveAgents.pop_back(); //TODO: check if it is right?!?!
			delete slaveAgentSlotOfAgent;
			return false;
		}
	}
	else {
		printError("Couldn't create SlaveAgentSlot!");
		return false;
	}
}

//TODO: what to do when 2 slaveAgentSlots have the same inputPort??!!
SlaveAgentSlotOfAgent* SlaveAgentHandlerOfAgent :: get_slaveAgentSlotAddress(Channel* inputPort) {
	for(auto &slaveAgentSlot : vMountedSlaveAgents) {
		if(slaveAgentSlot->get_comPort() == inputPort) {
			return slaveAgentSlot;
		}
	}
	return NULL;
}

//TODO: what to do when 2 slaveAgentSlots have the same inputPort??!!
//TODO: case if slot with comPort is not in this vector
unsigned int  SlaveAgentHandlerOfAgent :: get_slaveAgentSlotNumber(Channel* inputPort) {
	unsigned int slotNumber = 0;
	for(auto &slaveAgentSlot : vMountedSlaveAgents) {
		if(slaveAgentSlot->get_comPort() == inputPort) {
			return slotNumber;
		}
		slotNumber++;
	}
	return NULL;
}

//TODO: what to do when 2 slaveAgentSlots have the same historyModule??!!
SlaveAgentSlotOfAgent* SlaveAgentHandlerOfAgent :: get_slaveAgentSlotAddress(HistoryModule* historyModule) {
	for(auto &slaveAgentSlot : vMountedSlaveAgents) {
		if(slaveAgentSlot->get_historyModule() == historyModule) {
			return slaveAgentSlot;
		}
	}
	return NULL;
}

//TODO: what to do when 2 slaveAgentSlots have the same confidenceModule??!!
SlaveAgentSlotOfAgent* SlaveAgentHandlerOfAgent :: get_slaveAgentSlotAddress(ConfidenceModule* confidenceModule) {
	for(auto &slaveAgentSlot : vMountedSlaveAgents) {
		if(slaveAgentSlot->get_confidenceModule() == confidenceModule) {
			return slaveAgentSlot;
		}
	}
	return NULL;
}

bool SlaveAgentHandlerOfAgent :: demount_slaveAgentIntoSlaveAgentSlot(Channel* inputPort) {
	vMountedSlaveAgents.erase(vMountedSlaveAgents.begin() + get_slaveAgentSlotNumber(inputPort));
	return false;
}

//TODO: do it also for integer variables
bool SlaveAgentHandlerOfAgent :: read_slaveAgentValue(SlaveAgentSlotOfAgent* slaveAgentSlotOfAgent) {
	if(slaveAgentSlotOfAgent != NULL) {
		Channel* channel = slaveAgentSlotOfAgent->get_comPort();
		if(channel != NULL) {
			int msg;
			if(channel->get_MsgUp(&msg)) {
				if(msg == ISA_SensoryData) {
					printf("got msg: \n");
					float inputValue;
					if(channel->get_MsgUp(&inputValue)) {
						slaveAgentSlotOfAgent->set_slaveAgentValue(inputValue);
						return true;
					}
				}
			}
		}
	}
	return false;
}

bool SlaveAgentHandlerOfAgent :: read_allSlaveAgentValues() {
	bool flag_readSlaveAgent = false;
	for(auto &slaveAgentSlot : vMountedSlaveAgents) {
		if(read_slaveAgentValue(slaveAgentSlot)) {
			flag_readSlaveAgent = true;
		}
	}
	return flag_readSlaveAgent;
}

bool SlaveAgentHandlerOfAgent :: attach_historyModule(Channel* inputPort, HistoryModule* historyModule) {
	SlaveAgentSlotOfAgent* slaveAgentSlotOfAgent = get_slaveAgentSlotAddress(inputPort);
	if(slaveAgentSlotOfAgent != NULL) {
		return slaveAgentSlotOfAgent->set_historyModule(historyModule);
	}
	return false;
}

bool SlaveAgentHandlerOfAgent :: detach_historyModule(SlaveAgentSlotOfAgent* slaveAgentSlotOfAgent) {
	if(slaveAgentSlotOfAgent != NULL) {
		return slaveAgentSlotOfAgent->del_historyModule();
	}
	return false;
}

bool SlaveAgentHandlerOfAgent :: detach_historyModule(Channel* inputPort) {
	SlaveAgentSlotOfAgent* slaveAgentSlotOfAgent = get_slaveAgentSlotAddress(inputPort);
	return detach_historyModule(slaveAgentSlotOfAgent);
}

bool SlaveAgentHandlerOfAgent :: detach_historyModule(HistoryModule* historyModule) {
	SlaveAgentSlotOfAgent* slaveAgentSlotOfAgent = get_slaveAgentSlotAddress(historyModule);
	return detach_historyModule(slaveAgentSlotOfAgent);
}

HistoryModule* SlaveAgentHandlerOfAgent :: get_historyModuleOfSlaveAgentSlot(Channel* inputPort) {
	SlaveAgentSlotOfAgent* slaveAgentSlotOfAgent = get_slaveAgentSlotAddress(inputPort);
	return slaveAgentSlotOfAgent->get_historyModule();
}

bool SlaveAgentHandlerOfAgent :: attach_confidenceModule(Channel* inputPort, ConfidenceModule* confidenceModule) {
	SlaveAgentSlotOfAgent* slaveAgentSlotOfAgent = get_slaveAgentSlotAddress(inputPort);
	if(slaveAgentSlotOfAgent != NULL) {
		return slaveAgentSlotOfAgent->set_confidenceModule(confidenceModule);
	}
	return false;
}

bool SlaveAgentHandlerOfAgent :: detach_confidenceModule(SlaveAgentSlotOfAgent* slaveAgentSlotOfAgent) {
	if(slaveAgentSlotOfAgent != NULL) {
		return slaveAgentSlotOfAgent->del_confidenceModule();
	}
	return false;
}

bool SlaveAgentHandlerOfAgent :: detach_confidenceModule(Channel* inputPort) {
	SlaveAgentSlotOfAgent* slaveAgentSlotOfAgent = get_slaveAgentSlotAddress(inputPort);
	return detach_confidenceModule(slaveAgentSlotOfAgent);
}

bool SlaveAgentHandlerOfAgent :: detach_confidenceModule(ConfidenceModule* confidenceModule) {
	SlaveAgentSlotOfAgent* slaveAgentSlotOfAgent = get_slaveAgentSlotAddress(confidenceModule);
	return detach_confidenceModule(slaveAgentSlotOfAgent);
}

ConfidenceModule* SlaveAgentHandlerOfAgent :: get_confidenceModuleOfSlaveAgentSlot(Channel* inputPort) {
	SlaveAgentSlotOfAgent* slaveAgentSlotOfAgent = get_slaveAgentSlotAddress(inputPort);
	return slaveAgentSlotOfAgent->get_confidenceModule();
}

vector<SlaveAgentSlotOfAgent*>* SlaveAgentHandlerOfAgent :: get_vMountedSlaveAgents() {
	return &vMountedSlaveAgents;
}
