#include "rtc.h"
#include "network.h"


RTC::RTC( void ){
	
}

void RTC::begin( RTCConfig* cfg, TwoWire *wireInstance, Stream* monitor ){
	_cfg = *cfg;
	_sync_timeout_ms = _cfg.getSyncTimeoutS()*1000UL;
	PrintLog::init( monitor, "RTC" );
	printlog( F("Initialize ...") );
	initialized = rtc.begin( wireInstance );
	print( F("\t") );
	
		if( initialized ) println( getStateText( RTCState::OK ) );
		else println( getStateText( RTCState::NOTINIT ) );
				
	configTime( 0, 0, _cfg.getNTPServer().c_str() );
	xTaskCreatePinnedToCore(
		rtcTask,
		"rtcTask",
		2048,
		this,
		1,
		&_taskHandle,
		0
	);
}

RTCState RTC::getLocalTimeFromRTC( struct tm * timeinfo ){
			
		if( !initialized ) return RTCState::NOTINIT;

	DateTime now = rtc.now();

		if( now.year() < 2024 ){
			return RTCState::NOTSET;
		}

	time_t raw = now.unixtime();

		if( currentTZ != _cfg.getTZ() ){
			setenv("TZ", _cfg.getTZ().c_str(), 1);
			tzset();
			currentTZ = _cfg.getTZ();
		}

	localtime_r( &raw, timeinfo );
	return RTCState::OK;
}

bool RTC::sync( void ){
	printlog( F("Synchronize ...") );
	_synchronized = false;
				
		if( !initialized ){
			println( F("\tNot initialized") );
			return false;
		}

	time_t now;
	time(&now);

		if( now < 100000 ){
			println( F("\tNTP error") );
			return false;
		}

	struct tm timeinfo;
	gmtime_r( &now, &timeinfo );

	rtc.adjust(DateTime(
		timeinfo.tm_year + 1900,
		timeinfo.tm_mon + 1,
		timeinfo.tm_mday,
		timeinfo.tm_hour,
		timeinfo.tm_min,
		timeinfo.tm_sec
	));

	print( F("\tOK (Set time: ") );

		if( getLocalTimeFromRTC(&timeinfo) == RTCState::OK ){
			printf( "%02d:%02d:%02d",
				timeinfo.tm_hour,
				timeinfo.tm_min,
				timeinfo.tm_sec
			);
		} else {
			print( F("--:--:--") );
		}
				
	println(")");
	_synchronized = true;
	return true;
}

void RTC::rtcTask(void* param) {
    RTC* self = static_cast<RTC*>(param);

		while( true ){
			// czekaj na sygnał
			ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
			self->printlog( F("Sync requested") );
			const uint32_t start = millis();

				while( true ){
						//disconnected
						if( !MyNetwork::isConnected() ){
							self->printlog( F("Network disconnected - sync aborted") );
							break;
						}
						
					uint32_t nowMs = millis();

						//timeout
						if( nowMs - start >= self->_sync_timeout_ms ){
							self->printlog( F("Sync timeout") );
							break;
						}

					time_t now;
					time(&now);

						if( now > 100000 ){
								
								if( self->sync() ){
									break;
								}
						}

					vTaskDelay( pdMS_TO_TICKS( 5000 ) );
				}
		}
}

RTC rtc;