/*
 * GlobalConfigHandler.cpp
 *
 *  Created on: May 3, 2022
 *      Author: Jona Petri (IRS)
 */

#include "GlobalConfigHandler.h"

#include <fsfw/ipc/MessageQueueIF.h>
#include <fsfw/ipc/MutexFactory.h>
#include <fsfw/ipc/QueueFactory.h>

#include "fsfw/serviceinterface/ServiceInterface.h"

MutexIF* GlobalConfigHandler::CONFIG_LOCK = nullptr;

GlobalConfigHandler::GlobalConfigHandler(object_id_t objectId, std::string configFilePath)
    : SystemObject(objectId),
      NVMParameterBase(configFilePath),
      commandQueue(QueueFactory::instance()->createMessageQueue(20)) {
  if (CONFIG_LOCK == nullptr) {
    CONFIG_LOCK = MutexFactory::instance()->createMutex();
  }
}
ReturnValue_t GlobalConfigHandler::initialize() {
  ReturnValue_t result = SystemObject::initialize();
  if (result != returnvalue::OK) {
#if OBSW_VERBOSE_LEVEL >= 1
    sif::info << "GlobalConfigHandler::initialize: SystemObject::initialize() failed with "
              << result << std::endl;
#endif
    return result;
  }

  result = ReadConfigFile();
  if (result != returnvalue::OK) {
#if OBSW_VERBOSE_LEVEL >= 1
    sif::info << "GlobalConfigHandler::initialize: Creating JSON file at " << getFullName()
              << std::endl;
#endif
    result = ResetConfigFile();
    if (result != returnvalue::OK) {
      return result;
    }
  }

#if OBSW_VERBOSE_LEVEL >= 1
  sif::info << "GlobalConfigHandler::initialize success " << std::endl;
#endif
  return result;
}
GlobalConfigHandler::~GlobalConfigHandler() {}

ReturnValue_t GlobalConfigHandler::performOperation(uint8_t operationCode) {
  ReturnValue_t result = returnvalue::OK;
  sif::debug << "GlobalConfigHandler::performOperation" << std::endl;
  return result;
}

ReturnValue_t GlobalConfigHandler::lockConfigFile() {
  ReturnValue_t result = returnvalue::OK;
  result = CONFIG_LOCK->lockMutex(MutexIF::TimeoutType::WAITING, 10);
  return result;
}
ReturnValue_t GlobalConfigHandler::unlockConfigFile() {
  ReturnValue_t result = returnvalue::OK;
  result = CONFIG_LOCK->unlockMutex();
  return result;
}

template <typename T>
ReturnValue_t GlobalConfigHandler::setConfigFileValue(ParamIds paramID, T data) {
  ReturnValue_t result = returnvalue::OK;
  ReturnValue_t resultSet = returnvalue::OK;

  result = lockConfigFile();
  if (result != returnvalue::OK) {
#if OBSW_VERBOSE_LEVEL >= 1
    sif::info << "GlobalConfigHandler::setConfigFileValue lock mutex failed with " << result
              << std::endl;
#endif
    return result;
  }

  std::string paramString;
  paramString = PARAM_KEY_MAP[paramID];

  // Check if key exists in map before setting value. No check is done in setValue! Somehow
  // PARAM_KEY_MAP.count(paramID) == 0 does not work
  if (paramString.empty() == true) {
#if OBSW_VERBOSE_LEVEL >= 1
    sif::info << "GlobalConfigHandler::setConfigFileValue ParamId " << PARAM_KEY_MAP[paramID]
              << " not found!" << std::endl;
#endif
    triggerEvent(SET_CONFIGFILEVALUE_FAILED, 1, 0);
    return returnvalue::FAILED;
  }

  resultSet = setValue(PARAM_KEY_MAP[paramID], data);
  if (resultSet != returnvalue::OK) {
    triggerEvent(SET_CONFIGFILEVALUE_FAILED, 0, 0);
#if OBSW_VERBOSE_LEVEL >= 1
    sif::info << "GlobalConfigHandler::setConfigFileValue set json failed with " << resultSet
              << std::endl;
#endif
  }

  result = unlockConfigFile();
  if (result != returnvalue::OK) {
#if OBSW_VERBOSE_LEVEL >= 1
    sif::info << "GlobalConfigHandler::setConfigFileValue unlock mutex failed with " << result
              << std::endl;
#endif
    return result;
  }

  return resultSet;
}
template <typename T>
ReturnValue_t GlobalConfigHandler::getConfigFileValue(ParamIds paramID, T& data) {
  ReturnValue_t result = returnvalue::OK;
  ReturnValue_t resultGet = returnvalue::OK;

  result = lockConfigFile();
  if (result != returnvalue::OK) {
#if OBSW_VERBOSE_LEVEL >= 1
    sif::info << "GlobalConfigHandler::getConfigFileValue lock mutex failed with " << result
              << std::endl;
#endif
    return result;
  }

  resultGet = getValue(PARAM_KEY_MAP[paramID], data);
  if (resultGet != returnvalue::OK) {
    triggerEvent(GET_CONFIGFILEVALUE_FAILED, 0, 0);
#if OBSW_VERBOSE_LEVEL >= 1
    sif::info << "GlobalConfigHandler::getConfigFileValue getValue failed with " << resultGet
              << std::endl;
#endif
  }
  result = unlockConfigFile();
  if (result != returnvalue::OK) {
#if OBSW_VERBOSE_LEVEL >= 1
    sif::info << "GlobalConfigHandler::getConfigFileValue unlock mutex failed with " << result
              << std::endl;
#endif
    return result;
  }

  return resultGet;
}

ReturnValue_t GlobalConfigHandler::resetConfigFileValues() {
  ReturnValue_t result = returnvalue::OK;
  result = lockConfigFile();
  if (result != returnvalue::OK) {
#if OBSW_VERBOSE_LEVEL >= 1
    sif::info << "GlobalConfigHandler::resetConfigFileValues lock mutex failed with " << result
              << std::endl;
#endif
    return result;
  }
  insertValue(PARAM_KEY_MAP[PARAM0], PARAM0_DEFAULT);
  insertValue(PARAM_KEY_MAP[PARAM1], PARAM1_DEFAULT);

  result = unlockConfigFile();
  if (result != returnvalue::OK) {
#if OBSW_VERBOSE_LEVEL >= 1
    sif::info << "GlobalConfigHandler::resetConfigFileValues unlock mutex failed with " << result
              << std::endl;
#endif
    return result;
  }
  return result;
}
ReturnValue_t GlobalConfigHandler::WriteConfigFile() {
  ReturnValue_t result = returnvalue::OK;
  ReturnValue_t resultWrite = returnvalue::OK;
  result = lockConfigFile();
  if (result != returnvalue::OK) {
#if OBSW_VERBOSE_LEVEL >= 1
    sif::info << "GlobalConfigHandler::WriteConfigFile lock mutex failed with " << result
              << std::endl;
#endif
    return result;
  }

  resultWrite = writeJsonFile();
  if (resultWrite != returnvalue::OK) {
    triggerEvent(WRITE_CONFIGFILE_FAILED, 0, 0);
#if OBSW_VERBOSE_LEVEL >= 1
    sif::info << "GlobalConfigHandler::WriteConfigFile write json failed with " << resultWrite
              << std::endl;
#endif
  }

  result = unlockConfigFile();
  if (result != returnvalue::OK) {
#if OBSW_VERBOSE_LEVEL >= 1
    sif::info << "GlobalConfigHandler::WriteConfigFile unlock mutex failed with " << result
              << std::endl;
#endif
    return result;
  }
  return resultWrite;
}
ReturnValue_t GlobalConfigHandler::ReadConfigFile() {
  ReturnValue_t result = returnvalue::OK;
  ReturnValue_t resultRead = returnvalue::OK;
  result = lockConfigFile();
  if (result != returnvalue::OK) {
#if OBSW_VERBOSE_LEVEL >= 1
    sif::info << "GlobalConfigHandler::ReadConfigFile lock mutex failed with " << result
              << std::endl;
#endif
    return result;
  }

  resultRead = readJsonFile();
  if (resultRead != returnvalue::OK) {
    triggerEvent(READ_CONFIGFILE_FAILED, 0, 0);
#if OBSW_VERBOSE_LEVEL >= 1
    sif::info << "GlobalConfigHandler::ReadConfigFile read json failed with " << resultRead
              << std::endl;
#endif
  }

  result = unlockConfigFile();
  if (result != returnvalue::OK) {
#if OBSW_VERBOSE_LEVEL >= 1
    sif::info << "GlobalConfigHandler::ReadConfigFile unlock mutex failed with " << result
              << std::endl;
#endif
    return result;
  }

  return resultRead;
}
ReturnValue_t GlobalConfigHandler::ResetConfigFile() {
  ReturnValue_t result = returnvalue::OK;
  result = resetConfigFileValues();
  if (result != returnvalue::OK) {
#if OBSW_VERBOSE_LEVEL >= 1
    sif::info << "GlobalConfigHandler::ResetConfigFile failed with " << result << std::endl;
#endif
    return result;
  }
  result = writeJsonFile();
  return result;
}

ReturnValue_t GlobalConfigHandler::setConfigFileName(std::string configFileName) {
  ReturnValue_t result = returnvalue::OK;
  setFullName(configFileName);
  result = ResetConfigFile();
  return result;
}
std::string GlobalConfigHandler::getConfigFileName() { return getFullName(); }

template ReturnValue_t GlobalConfigHandler::getConfigFileValue<double>(ParamIds paramID,
                                                                       double& data);
template ReturnValue_t GlobalConfigHandler::getConfigFileValue<int32_t>(ParamIds paramID,
                                                                        int32_t& data);

template ReturnValue_t GlobalConfigHandler::setConfigFileValue<double>(ParamIds paramID,
                                                                       double data);
template ReturnValue_t GlobalConfigHandler::setConfigFileValue<int32_t>(ParamIds paramID,
                                                                        int32_t data);