#include "Testbench.h"

#include "printError.h"
#include <stdio.h>

#define MAXNUMOF_REGISTEREDCAGENTS 1000
#define MAXNUMOF_REGISTEREDCHANNELS 1000
#define MAXNUMOF_REGISTEREDSENSORS 1000

using namespace std;

void Testbench::init_testbench() {
  maxNumOf_registeredAgents = MAXNUMOF_REGISTEREDCAGENTS;
  maxNumOf_registeredChannels = MAXNUMOF_REGISTEREDCHANNELS;
  maxNumOf_registeredSensors = MAXNUMOF_REGISTEREDSENSORS;
}

Testbench::Testbench() { set_name(NO_NAME); }

Testbench::Testbench(const char *name) { set_name(name); }

bool Testbench::register_agent(Agent *agent) {
  AgentSlotOfTestbench *agentSlot = new AgentSlotOfTestbench();
  if (agentSlot != NULL) {
    if (agentSlot->set_agent(agent)) {
      try {
        if (vector_registeredAgents.size() < maxNumOf_registeredAgents) {
          vector_registeredAgents.push_back(agentSlot);
        } else {
          printError("Max number of registered agents is already reached!");
          return false;
        }
      } catch (bad_alloc &error) {
        printError("bad_alloc caught: ", error.what());
        return false;
      }
      return true;
    } else {
      printError("Agent is not set!");
      vector_registeredAgents.pop_back(); // TODO: check if it is right?!?!
      return false;
    }
  } else {
    printError("Couldn't create AgentSlot!");
    return false;
  }
}

bool Testbench::register_sensor(Sensor *sensor) {
  SensorSlotOfTestbench *sensorSlot = new SensorSlotOfTestbench();
  if (sensorSlot != NULL) {
    if (sensorSlot->set_sensor(sensor)) {
      try {
        if (vector_registeredSensors.size() < maxNumOf_registeredSensors) {
          vector_registeredSensors.push_back(sensorSlot);
        } else {
          printError("Max number of registered sensors is already reached!");
          return false;
        }
      } catch (bad_alloc &error) {
        printError("bad_alloc caught: ", error.what());
        return false;
      }
      return true;
    } else {
      printError("Input port is no set!");
      vector_registeredSensors.pop_back(); // TODO: check if it is right?!?!
      return false;
    }
  } else {
    printError("Couldn't create SensorSlot!");
    return false;
  }
}

SensorSlotOfTestbench *
Testbench::get_sensorSlotAddressOfTestbench(Sensor *sensor) {
  for (auto &sensorSlot : vector_registeredSensors) {
    if (sensorSlot->get_sensor() == sensor) {
      return sensorSlot;
    }
  }
  return NULL;
}

bool Testbench::register_channel(Channel *channel) {
  ChannelSlotOfTestbench *channelSlot = new ChannelSlotOfTestbench();
  if (channelSlot != NULL) {
    if (channelSlot->set_channel(channel)) {
      try {
        if (vector_registeredChannels.size() < maxNumOf_registeredChannels) {
          vector_registeredChannels.push_back(channelSlot);
        } else {
          printError("Max number of registered channels is already reached!");
          return false;
        }
      } catch (bad_alloc &error) {
        printError("bad_alloc caught: ", error.what());
        return false;
      }
      return true;
    } else {
      printError("Channel is not set!");
      vector_registeredChannels.pop_back(); // TODO: check if it is right?!?!
      return false;
    }
  } else {
    printError("Couldn't create ChannelSlot!");
    return false;
  }
}

void Testbench::simulate(unsigned int rounds) {
  for (unsigned int sec = 1; sec <= rounds; sec++) {

    printf("cycle %u\n", sec);

    // update sensor values
    for (auto &sensorSlot : vector_registeredSensors) {
      Sensor *sensor = sensorSlot->get_sensor();
      if (sensor != NULL) {
        CSVreaderModule *csvReader = sensorSlot->get_csvReaderModule();
        if (csvReader != NULL) {
          float inputValue;
          if (csvReader->get_next_value(&inputValue)) {
            sensor->set_sensorValue(inputValue);
          }
        }
      }
    }

    // trigger sensors
    for (auto &sensorSlot : vector_registeredSensors) {
      Sensor *sensor = sensorSlot->get_sensor();
      if (sensor != NULL) {
        sensor->trigger();
      }
    }

    // trigger channels
    for (auto &channelSlot : vector_registeredChannels) {
      Channel *channel = channelSlot->get_channel();
      if (channel != NULL) {
        channel->trigger();
      }
    }

    // trigger agents
    for (auto &agentSlot : vector_registeredAgents) {
      Agent *agent = agentSlot->get_agent();
      if (agent != NULL) {
        agent->trigger();
      }
    }
    getchar();
  }
}

