#pragma once

#include <string>
#include <cmath>
#include <system_time.hpp>

class GPS
{
  public:
	GPS(std::string id) : gpsID(id)
	{
	}

  protected:
	virtual ~GPS() = default;

  public:
	enum GPSCmdNums : uint8_t
	{
		getTimeCmdNum = 0,
		getPositionCmdNum,
		numCmds,
	};

	struct GPSFix
	{
		double latDD;
		double lonDD;
		std::string latNMEA;
		std::string lonNMEA;
		systime::DateTimeStruct TOF; // TODO: will this work for the acquisition time?
		std::string TOF_NMEA;
		unsigned int numSats;
		float hdop;
		std::string navStat;
		uint64_t acquisition_tickstamp;

		void reset()
		{
			latDD = static_cast<double>(NAN);
			lonDD = static_cast<double>(NAN);
			latNMEA = "NaN";
			lonNMEA = "NaN";
			numSats = static_cast<int>(NAN);
			hdop = NAN;
			navStat = "NaN";
			TOF_NMEA = "NaN";
			TOF.year = 0;
			TOF.month = 0;
			TOF.date = 0;
			TOF.hour = 0;
			TOF.minute = 0;
			TOF.second = 0;
			TOF.milliSecond = 0;
			acquisition_tickstamp = 0;
		}
	};

  public:
  	/// Request a position from the GPS device
  	/// This will trigger an asynchronous operation to receive the position.
  	/// When a new position is available, a GPSPositionReadyEvent will be fired.
  	/// At that point, the latest position will be available via getLatestPosition().
  	/// @returns true if request was successfully submitted, false otherwise
  	virtual bool requestPosition() = 0;

  /// Returns the latest cached GPS position. To determine whether
  /// The sample is new enough for your purposes, check the associated timestamp
  /// and compare it to the system time.
  ///
  /// To get a newer sample, invoke requestPosition(). When the GPSPositionReadyEvent
  /// fires, the new sample will be available through this interface.
  /// TODO: update with proper time field to check
	GPSFix getLatestPosition()
	{
		return latestGPSFix_;
	}

	/// Request the time from the GPS device
	/// This will trigger an asynchronous operation to receive the time.
	/// When new time data is available, a GPSTimestampReadyEvent will be fired.
	/// This event will contain the returned timestamp.
	/// @returns true if request was successfully submitted, false otherwise
	virtual bool requestTime() = 0;

	/// TODO Gene: What does this command do?
	virtual void defineCommands() = 0;

	/// Perform all actions required to initialize the GPS device and put it in an
	/// operational state.
	/// @pre Device is stopped
	virtual void start() = 0;

	/// Perform all actions required to stop the GPS device.
	/// @pre Device is started
	virtual void stop() = 0;

	/// TODO: Gene document expected behavior
	virtual bool doSelftest() = 0;

	void logEngLine(GPSFix& fix, std::string comment);
	void logEngLine(std::string comment);
	// virtual const std::string_view getEngFileHeader() = 0;
	void logEngFileHeader();

  protected:
	const std::string gpsID;
	GPSFix latestGPSFix_;
};
