#ifndef RTC_H
#define RTC_H
#include "common.h"
#include "../lib/RTClib/RTClib.h"

namespace RTCDefConfig {
	constexpr const char* NTP_SERVER = "pool.ntp.org";
	constexpr const char* TZ = "CET-1CEST,M3.5.0/2,M10.5.0/3";
	constexpr const uint16_t SYNC_TIMEOUT_S = 300;
}

class RTCConfig : public ConfigHandler {
	private:	
		String ntp_server = RTCDefConfig::NTP_SERVER, TZ = RTCDefConfig::TZ;
		uint16_t sync_timeout_s = RTCDefConfig::SYNC_TIMEOUT_S;

	public:
		bool handle( const char* section, const char* key, JsonVariant v ) override {
				
				if( !strcmp( section, "RTC" ) && !strcmp( key, "ntp_server" ) ){
					ntp_server = v | ntp_server;
					return true;
				}
				
				if( !strcmp( section, "RTC" ) && !strcmp( key, "sync_timeout_s" ) ){
					sync_timeout_s = v | sync_timeout_s;
					return true;
				}
				
				if( !strcmp( section, "RTC" ) && !strcmp( key, "TZ" ) ){
					TZ = v | TZ;
					return true;
				}

			return false;
		}
		
		void reset( void ){
			ntp_server = RTCDefConfig::NTP_SERVER;
			TZ = RTCDefConfig::TZ;
			sync_timeout_s = RTCDefConfig::SYNC_TIMEOUT_S;
		}
		
		void commit( void ) override {}
		
		const String& getNTPServer( void ){
			return ntp_server;
		}
		
		const String& getTZ( void ){
			return TZ;
		}
		
		const uint16_t getSyncTimeoutS( void ){
			return sync_timeout_s;
		}
};
enum class RTCState {
    OK,
    NOTSET,
    NOTINIT
};
class RTC : private PrintLog {
	private:
		RTC_DS3231 rtc;
		RTCConfig _cfg;
		
		String currentTZ;
		uint32_t _sync_timeout_ms = 0;
		bool initialized = false, _synchronized = false;
		TaskHandle_t _taskHandle = nullptr;
		
		bool sync( void );
		static void rtcTask( void* param );
		
		static constexpr char msg_notinit[] = "Couldn't find RTC";
		static constexpr char msg_notset[] = "RTC is not set";
		static constexpr char msg_ok[] = "OK";
		static constexpr char msg_unknown[] = "Unknown state";
	
	public:
		RTC( void );
		void begin( RTCConfig* cfg, TwoWire *wireInstance = &Wire, Stream* monitor=nullptr );
		RTCState getLocalTimeFromRTC( struct tm * timeinfo );

		const char* getStateText( RTCState state ){
				
				switch( state ){
					case RTCState::NOTINIT: return msg_notinit;
					case RTCState::NOTSET:  return msg_notset;
					case RTCState::OK:      return msg_ok;
					default:                return msg_unknown;
				}
		}
		
		void syncRequest( void ){
			_synchronized = false;
			
				if( initialized && _taskHandle ){
					xTaskNotifyGive( _taskHandle );
				}
		}
		
		const bool isSynchronized( void ){
			return _synchronized;
		}
};
extern RTC rtc;
#endif