#include <xavia/alerts.h>
#include <xavia/iSensor.h>
#include <xavia/logs.h>
#include <xavia/sensorFactory.h>

#include <cstdlib>
#include <chrono>
#include <iostream>
#include <optional>
#include <thread>
#include <xavia/sensorState.h>

namespace xsdk = xavia::sdk;

/*  EVENT HANDLING EXAMPLE
 * 
 * This example shows how to handling incoming events.
 *
 * Events (aka alerts) are situations that arise on the sensor that will trigger
 * a change in behaviour or are problematic. An example is the 
 * `temperature_critical` alert. This event says that the temperature exceeds 
 * certain limits and that the sensor will power down to prevent damage.
 * 
 * Most events have a boolean flag. This flag is true if the event is turned on,
 * and false if the situation goes away. For example if the alert says temperature
 * alert and the flag is true, then the temperature is to high. But if the sensor
 * cools, the event will be send again and the flag will be false.
 * 
 * Events are transmitted when the situation occurs. If you want to check if the
 * sensor is currently in a certain conditions (e.g. overheated), then you should
 * query the sensor status. (not part of this example)
 * 
 * This example translates events into English language and prints a message on 
 * the stdout. In production you should act on the events because they mean that
 * the state of the sensor changed.
 * 
 * Note: this example is a bit theoretical. It is not possible to trigger an event
 * from the sensor in any normal way.
 * 
 * Note: if you don't act on the event, then you do not need to add the event handler
 * the SDK will log any event that
 * arrives very similarly to this example.
 */

namespace
{
  void HandleAlert(const xsdk::Alert& alert, const std::optional<bool> flag)
  {
    std::string log = "Received an alert from the sensor: ";
    switch(alert)
    {
    case xsdk::Alert::temperature_critical:
      log += flag.value() ? "critical temperature reached" : "temperature normalized";
      break;
    case xsdk::Alert::power_abnormal:
      log += flag.value() ? "power issue occurred" : "power normalized";
      break;
    case xsdk::Alert::voltage_abnormal:
      log += flag.value() ? "voltage issue occurred" : "voltage normalized";
      break;
    case xsdk::Alert::eye_safety_issue:
      log += flag.value() ? "eye safety issue occurred" : "eye safety normalized";
      break;
    case xsdk::Alert::humidity:
      log += flag.value() ? "humidity issue occurred" : "humidity normalized";
      break;
    case xsdk::Alert::shutting_down:
      log += "System shutting down";
      break;
    default:
      log += "unknown";
    }

    std::cout << log << std::endl;
  }
}

int main()
{
  std::cout << "=== Starting Event Handling Example ===" << std::endl;

  try
  {
    xsdk::SensorFactory factory;

    factory.SetAlertCallback(&HandleAlert);

    // build sensor
    auto sensor = factory.Build();

    // run
    if(sensor->GetCurrentState()!= xsdk::SensorState::RUNNING)
    {
      sensor->Start();
    }
    std::this_thread::sleep_for(std::chrono::seconds(5));
    sensor->Stop();
  }
  catch(const std::exception& e)
  {
    std::cerr << "Error received: " << e.what() << std::endl;
    return EXIT_FAILURE;
  }

  std::cout << "=== Event Handling Example Completed ===" << std::endl;
  return EXIT_SUCCESS;
}
