#include "SlaveAgentHandlerOfAgent.h"

#include "instruction_set_architecture.h"
#include "printError.h"
#include <stdio.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 0;
}

// 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;
}
