#pragma once

#include <stdint.h>
#include <cstddef>
#include <iostream>
using namespace std;

#include "MCURealTimeClock.hpp"
#include "FIFO.hpp"
#include "Logger.hpp"

//Implemented as a singleton per http://laristra.github.io/flecsi/src/developer-guide/patterns/meyers_singleton.html
//Had to remove destructors
//There may be better implementations like https://stackoverflow.com/questions/1008019/c-singleton-design-pattern/1008289#1008289
	
extern UART_HandleTypeDef uart4Handle;
extern bool gpsMsgReceived;
extern uint8_t rxBuffer[128];
extern uint8_t gpsMessage[256];
extern uint16_t gpsMsgCount;

class GPS1
{
public:
	static GPS1& getInstance()
	{
		static GPS1 instance;
		return instance;
	}
	
	struct GPS1Position
	{
		mcuRealTimeClock::CPFTimestamp datetimeStamp;
		double decLat;
		double decLon;
		int8_t numSats;
		string gpsDate;
		string gpsTime;
		string nmeaLat;
		string nmeaLon;
		string message;
	};
	
	uint8_t getPosition();
	GPS1Position parsePUBX00Position();
	uint8_t getTime();
	bool isGPSMsgReady();
	void processRX(UART_HandleTypeDef *uartHandle);
	void logPosition(string stateID, GPS1Position gpsPosition);
	mcuRealTimeClock::DateTimeStruct parsePUBX04Time(uint8_t pubx04Msg[]);
	uint8_t initUART4();

private:
	GPS1();
	
	Logger logger = Logger::getInstance();
	mcuRealTimeClock mcuRTC = mcuRealTimeClock::getInstance();
	
	enum CommandNum
	{
		cmdGetTime     = 0,
		cmdGetPosition,
		numCmds,
	};
	
	struct CommandStruct
	{
		uint8_t* commandPtr;
		size_t commandLength;
		size_t replyLength;
	};
	CommandStruct gpsCmd[numCmds];

	void defineCommands();	
	void cancelReceiveIT();
	void logRX_ITError();
	void logTX_ITError();
	int8_t txrxIT(CommandNum commandNumber);
	int8_t txrxDMA(CommandNum commandNumber);
		
	const string engMsgID = "$gps1";
	bool txrxIP = false;  	//TODO should this be static?
};



