#include "SyrlinksFdir.h"

#include "fsfw/devicehandlers/DeviceHandlerIF.h"
#include "fsfw/health/HealthTableIF.h"
#include "fsfw/modes/HasModesIF.h"
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/power/Fuse.h"
#include "fsfw/serviceinterface/ServiceInterfaceStream.h"
#include "fsfw/thermal/ThermalComponentIF.h"
#include "mission/devices/devicedefinitions/SyrlinksDefinitions.h"

SyrlinksFdir::SyrlinksFdir(object_id_t syrlinksId)
    : DeviceHandlerFailureIsolation(syrlinksId, objects::NO_OBJECT) {}

ReturnValue_t SyrlinksFdir::eventReceived(EventMessage* event) {
  if (isFdirInActionOrAreWeFaulty(event)) {
    return RETURN_OK;
  }
  ReturnValue_t result = RETURN_FAILED;
  switch (event->getEvent()) {
    case HasModesIF::MODE_TRANSITION_FAILED:
    case HasModesIF::OBJECT_IN_INVALID_MODE:
    case DeviceHandlerIF::DEVICE_WANTS_HARD_REBOOT:
      // We'll try a recovery as long as defined in MAX_REBOOT.
      // Might cause some AssemblyBase cycles, so keep number low.
      // handleRecovery(event->getEvent());
      triggerEvent(syrlinks::FDIR_REACTION_IGNORED, event->getEvent(), 0);
      break;
    case DeviceHandlerIF::DEVICE_INTERPRETING_REPLY_FAILED:
    case DeviceHandlerIF::DEVICE_READING_REPLY_FAILED:
    case DeviceHandlerIF::DEVICE_UNREQUESTED_REPLY:
    case DeviceHandlerIF::DEVICE_UNKNOWN_REPLY:  // Some DH's generate generic reply-ids.
    case DeviceHandlerIF::DEVICE_BUILDING_COMMAND_FAILED:
      // These faults all mean that there were stupid replies from a device.
      if (strangeReplyCount.incrementAndCheck()) {
        // handleRecovery(event->getEvent());
        triggerEvent(syrlinks::FDIR_REACTION_IGNORED, event->getEvent(), 0);
      }
      break;
    case DeviceHandlerIF::DEVICE_SENDING_COMMAND_FAILED:
    case DeviceHandlerIF::DEVICE_REQUESTING_REPLY_FAILED:
      // The two above should never be confirmed.
    case DeviceHandlerIF::DEVICE_MISSED_REPLY:
      result = sendConfirmationRequest(event);
      if (result == HasReturnvaluesIF::RETURN_OK) {
        break;
      }
      // else
      if (missedReplyCount.incrementAndCheck()) {
        // handleRecovery(event->getEvent());
        triggerEvent(syrlinks::FDIR_REACTION_IGNORED, event->getEvent(), 0);
      }
      break;
    case StorageManagerIF::GET_DATA_FAILED:
    case StorageManagerIF::STORE_DATA_FAILED:
      // Rather strange bugs, occur in RAW mode only. Ignore.
      break;
    case DeviceHandlerIF::INVALID_DEVICE_COMMAND:
      // Ignore, is bad configuration. We can't do anything in flight.
      break;
    case HasHealthIF::HEALTH_INFO:
    case HasModesIF::MODE_INFO:
    case HasModesIF::CHANGING_MODE:
      // Do nothing, but mark as handled.
      break;
      //****Power*****
    case PowerSwitchIF::SWITCH_WENT_OFF:
      if (powerConfirmation != MessageQueueIF::NO_QUEUE) {
        result = sendConfirmationRequest(event, powerConfirmation);
        if (result == RETURN_OK) {
          setFdirState(DEVICE_MIGHT_BE_OFF);
        }
      }
      break;
    case Fuse::FUSE_WENT_OFF:
      // Not so good, because PCDU reacted.
    case Fuse::POWER_ABOVE_HIGH_LIMIT:
      // Better, because software detected over-current.
      setFaulty(event->getEvent());
      break;
    case Fuse::POWER_BELOW_LOW_LIMIT:
      // Device might got stuck during boot, retry.
      // handleRecovery(event->getEvent());
      triggerEvent(syrlinks::FDIR_REACTION_IGNORED, event->getEvent(), 0);
      break;
      //****Thermal*****
    case ThermalComponentIF::COMPONENT_TEMP_LOW:
    case ThermalComponentIF::COMPONENT_TEMP_HIGH:
    case ThermalComponentIF::COMPONENT_TEMP_OOL_LOW:
    case ThermalComponentIF::COMPONENT_TEMP_OOL_HIGH:
      // Well, the device is not really faulty, but it is required to stay off as long as possible.
      setFaulty(event->getEvent());
      break;
    case ThermalComponentIF::TEMP_NOT_IN_OP_RANGE:
      // Ignore, is information only.
      break;
      //*******Default monitoring variables. Are currently not used.*****
      //    case DeviceHandlerIF::MONITORING_LIMIT_EXCEEDED:
      //        setFaulty(event->getEvent());
      //        break;
      //    case DeviceHandlerIF::MONITORING_AMBIGUOUS:
      //        break;
    default:
      // We don't know the event, someone else should handle it.
      return RETURN_FAILED;
  }
  return RETURN_OK;
}

void SyrlinksFdir::eventConfirmed(EventMessage* event) {
  switch (event->getEvent()) {
    case DeviceHandlerIF::DEVICE_SENDING_COMMAND_FAILED:
    case DeviceHandlerIF::DEVICE_REQUESTING_REPLY_FAILED:
    case DeviceHandlerIF::DEVICE_MISSED_REPLY:
      if (missedReplyCount.incrementAndCheck()) {
        // handleRecovery(event->getEvent());
        triggerEvent(syrlinks::FDIR_REACTION_IGNORED, event->getEvent(), 0);
      }
      break;
    case PowerSwitchIF::SWITCH_WENT_OFF:
      // This means the switch went off only for one device.
      // handleRecovery(event->getEvent());
      triggerEvent(syrlinks::FDIR_REACTION_IGNORED, event->getEvent(), 0);
      break;
    default:
      break;
  }
}