#ifndef MISSION_ACS_ARCHIVE_GPSDEFINITIONS_H_
#define MISSION_ACS_ARCHIVE_GPSDEFINITIONS_H_

#include "eive/eventSubsystemIds.h"
#include "fsfw/datapoollocal/StaticLocalDataSet.h"
#include "fsfw/devicehandlers/DeviceHandlerIF.h"

namespace GpsHyperion {

enum class FixMode : uint8_t { NOT_SEEN = 0, NO_FIX = 1, FIX_2D = 2, FIX_3D = 3, UNKNOWN = 4 };

static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::GPS_HANDLER;
//! [EXPORT] : [COMMENT] Fix has changed. P1: Old fix. P2: New fix
//! 0: Not seen, 1: No Fix, 2: 2D-Fix, 3: 3D-Fix
static constexpr Event GPS_FIX_CHANGE = event::makeEvent(SUBSYSTEM_ID, 0, severity::INFO);
//! [EXPORT] : [COMMENT] Could not get fix in maximum allowed time. P1: Maximum allowed time
//! to get a fix after the GPS was switched on.
static constexpr Event CANT_GET_FIX = event::makeEvent(SUBSYSTEM_ID, 1, severity::LOW);

static constexpr DeviceCommandId_t GPS_REPLY = 0;
static constexpr DeviceCommandId_t TRIGGER_RESET_PIN_GNSS = 5;

enum SetIds : uint32_t {
  CORE_DATASET,
  SKYVIEW_DATASET,
};

enum GpsPoolIds : lp_id_t {
  LATITUDE,
  LONGITUDE,
  ALTITUDE,
  SPEED,
  FIX_MODE,
  SATS_IN_USE,
  SATS_IN_VIEW,
  UNIX_SECONDS,
  YEAR,
  MONTH,
  DAY,
  HOURS,
  MINUTES,
  SECONDS,
  SKYVIEW_UNIX_SECONDS,
  PRN_ID,
  AZIMUTH,
  ELEVATION,
  SIGNAL2NOISE,
  USED,
};

static constexpr uint8_t CORE_DATASET_ENTRIES = 14;
static constexpr uint8_t SKYVIEW_ENTRIES = 6;

static constexpr uint8_t MAX_SATELLITES = 30;

enum GpsFixModes : uint8_t { INVALID = 0, NO_FIX = 1, FIX_2D = 2, FIX_3D = 3 };

}  // namespace GpsHyperion

class GpsPrimaryDataset : public StaticLocalDataSet<GpsHyperion::CORE_DATASET_ENTRIES> {
 public:
  GpsPrimaryDataset(object_id_t gpsId)
      : StaticLocalDataSet(sid_t(gpsId, GpsHyperion::CORE_DATASET)) {
    setAllVariablesReadOnly();
  }

  lp_var_t<double> latitude = lp_var_t<double>(sid.objectId, GpsHyperion::LATITUDE, this);
  lp_var_t<double> longitude = lp_var_t<double>(sid.objectId, GpsHyperion::LONGITUDE, this);
  lp_var_t<double> altitude = lp_var_t<double>(sid.objectId, GpsHyperion::ALTITUDE, this);
  lp_var_t<double> speed = lp_var_t<double>(sid.objectId, GpsHyperion::SPEED, this);
  lp_var_t<uint8_t> fixMode = lp_var_t<uint8_t>(sid.objectId, GpsHyperion::FIX_MODE, this);
  lp_var_t<uint8_t> satInUse = lp_var_t<uint8_t>(sid.objectId, GpsHyperion::SATS_IN_USE, this);
  lp_var_t<uint8_t> satInView = lp_var_t<uint8_t>(sid.objectId, GpsHyperion::SATS_IN_VIEW, this);
  lp_var_t<uint16_t> year = lp_var_t<uint16_t>(sid.objectId, GpsHyperion::YEAR, this);
  lp_var_t<uint8_t> month = lp_var_t<uint8_t>(sid.objectId, GpsHyperion::MONTH, this);
  lp_var_t<uint8_t> day = lp_var_t<uint8_t>(sid.objectId, GpsHyperion::DAY, this);
  lp_var_t<uint8_t> hours = lp_var_t<uint8_t>(sid.objectId, GpsHyperion::HOURS, this);
  lp_var_t<uint8_t> minutes = lp_var_t<uint8_t>(sid.objectId, GpsHyperion::MINUTES, this);
  lp_var_t<uint8_t> seconds = lp_var_t<uint8_t>(sid.objectId, GpsHyperion::SECONDS, this);
  lp_var_t<uint32_t> unixSeconds =
      lp_var_t<uint32_t>(sid.objectId, GpsHyperion::UNIX_SECONDS, this);

 private:
  friend class GpsHyperionLinuxController;
  friend class GpsCtrlDummy;
  GpsPrimaryDataset(HasLocalDataPoolIF* hkOwner)
      : StaticLocalDataSet(hkOwner, GpsHyperion::CORE_DATASET) {}
};

class SkyviewDataset : public StaticLocalDataSet<GpsHyperion::SKYVIEW_ENTRIES> {
 public:
  SkyviewDataset(object_id_t gpsId)
      : StaticLocalDataSet(sid_t(gpsId, GpsHyperion::SKYVIEW_DATASET)) {
    setAllVariablesReadOnly();
  }

  lp_var_t<double> unixSeconds =
      lp_var_t<double>(sid.objectId, GpsHyperion::SKYVIEW_UNIX_SECONDS, this);
  lp_vec_t<int16_t, GpsHyperion::MAX_SATELLITES> prn_id =
      lp_vec_t<int16_t, GpsHyperion::MAX_SATELLITES>(sid.objectId, GpsHyperion::PRN_ID, this);
  lp_vec_t<int16_t, GpsHyperion::MAX_SATELLITES> azimuth =
      lp_vec_t<int16_t, GpsHyperion::MAX_SATELLITES>(sid.objectId, GpsHyperion::AZIMUTH, this);
  lp_vec_t<int16_t, GpsHyperion::MAX_SATELLITES> elevation =
      lp_vec_t<int16_t, GpsHyperion::MAX_SATELLITES>(sid.objectId, GpsHyperion::ELEVATION, this);
  lp_vec_t<double, GpsHyperion::MAX_SATELLITES> signal2noise =
      lp_vec_t<double, GpsHyperion::MAX_SATELLITES>(sid.objectId, GpsHyperion::SIGNAL2NOISE, this);
  lp_vec_t<uint8_t, GpsHyperion::MAX_SATELLITES> used =
      lp_vec_t<uint8_t, GpsHyperion::MAX_SATELLITES>(sid.objectId, GpsHyperion::USED, this);

 private:
  friend class GpsHyperionLinuxController;
  friend class GpsCtrlDummy;
  SkyviewDataset(HasLocalDataPoolIF* hkOwner)
      : StaticLocalDataSet(hkOwner, GpsHyperion::SKYVIEW_DATASET) {}
};

#endif /* MISSION_ACS_ARCHIVE_GPSDEFINITIONS_H_ */