/**************************************************************************************************
*******
**************************************************************************************************/


#include <stdlib.h>
#include "OSAL.h"
#include <string.h>
#include <time.h>
#include "app_err.h"
#include "app_wrist.h"
#include "app_datetime.h"
#include "types.h"
#include "clock.h"
#include "log.h"

#ifndef USE_SYS_TICK
    #define USE_SYS_TICK  FASLE  //default use RTC, if system use RC32K as RTC clock source, system tick is usually recommended
#endif

#if(USE_SYS_TICK)
    #define RTC_CNT_RANGE 0x100000000
    #define TM_RATE (1000000/625)
#else
    #define RTC_CNT_RANGE 0x1000000
    #define TM_RATE (32768)
#endif
#define DT_INTV_SYNC 60    //sync interval every 60s



//static app_dtm_hdl_t s_evt_hdl = NULL;

static datetime_cfg_t s_stm_cfg = {0};

static const char* const month_str[12] =
{
    "Jan",
    "Feb",
    "Mar",
    "Apr",
    "May",
    "Jun",
    "Jul",
    "Aug",
    "Sep",
    "Oct",
    "Nov",
    "Dec"
};


static void app_datetime_adjust_baseline(struct tm* datetm);

static void print_hex (uint8_t* data, uint16 len)
{
    uint16 i;

    for (i = 0; i < len - 1; i++)
    {
        LOG("%x",data[i]);
        LOG(" ");
    }

    LOG("%x",data[i]);
}

static void dt_timer_start(uint32_t intval_ms)
{
    osal_start_timerEx(AppWrist_TaskID, TIMER_DT_EVT, intval_ms);
}

void timer_cnt_get(uint32_t* tick)
{
    #if(USE_SYS_TICK)
    *tick = hal_systick();         // read current RTC counter
    #else
    *tick = rtc_get_counter();         // read current RTC counter
    #endif
}


static void get_default_tm(struct tm* datetm)
{
    int i;
    datetime_t dtm;
    char dt[20];
    char* pstr = NULL;
    LOG(__DATE__);
    LOG(__TIME__);
    strcpy(dt, __DATE__);
    pstr = strtok(dt, " ");

    for(i = 0; i< 12; i++)
    {
        if(strcmp(dt,month_str[i]) == 0)
        {
            dtm.month = i+1;
            break;
        }
    }

    pstr = strtok(NULL, " ");
    dtm.day = atoi(pstr);
    pstr = strtok(NULL, " ");
    dtm.year = atoi(pstr);
    strcpy(dt, __TIME__);
    pstr = strtok(dt, ":");
    dtm.hour = atoi(pstr);
    pstr = strtok(NULL, ":");
    dtm.minutes = atoi(pstr);
    pstr = strtok(NULL, ":");
    dtm.seconds = atoi(pstr);
    DTM2TM(datetm, &dtm);
}


static void check_default_datetime(void)
{
    struct tm datetm;
    get_default_tm(&datetm);
    LOG("check_default_datetime\nTime is %d-%d-%d, %d:%d:%d",
        datetm.tm_year+1900,
        datetm.tm_mon+1,
        datetm.tm_mday,
        datetm.tm_hour,
        datetm.tm_min,
        datetm.tm_sec);
    app_datetime_adjust_baseline(&datetm);
    return;
}

static void datetime_print(void)
{
    datetime_t dtm;
    app_datetime(&dtm);
    LOG("Time is %d-%d-%d, %d:%d:%d\n", dtm.year, dtm.month, dtm.day, dtm.hour, dtm.minutes, dtm.seconds);
}

void app_datetime_sync_handler(void )
{
    uint32_t tick= 0;
    timer_cnt_get(&tick);

    if(tick < s_stm_cfg.snapshot)
        s_stm_cfg.tm_base += RTC_CNT_RANGE;

    s_stm_cfg.snapshot = tick;
    dt_timer_start(DATETIME_SYNC_INTERVAL);
    datetime_print();
}



static void app_datetime_adjust_baseline(struct tm* datetm)
{
    uint64_t tmstamp;
    uint32_t ticks;
    timer_cnt_get(&ticks);
    tmstamp = (uint64_t)mktime(datetm);
    LOG("%x",(uint32_t)tmstamp);
    tmstamp = tmstamp*TM_RATE;
    s_stm_cfg.tm_base = tmstamp - ticks;
    s_stm_cfg.snapshot = ticks;
    LOG("app_datetime_adjust_baseline:\n");
    print_hex((uint8_t*)&s_stm_cfg, sizeof(s_stm_cfg));
    LOG("\n");
}


int app_datetime_set(datetime_t dtm)
{
    struct tm tm;
    memset(&tm,0, sizeof(tm));
    DTM2TM(&tm, &dtm);
    LOG("\napp_datetime_set:\n");
    LOG("Time is %d-%d-%d, %d:%d:%d\n", dtm.year, dtm.month, dtm.day, dtm.hour, dtm.minutes, dtm.seconds);
    app_datetime_adjust_baseline(&tm);
    print_hex((uint8_t*)&s_stm_cfg, sizeof(s_stm_cfg));
    LOG("\n");
    return APP_SUCCESS;
}




int app_datetime_diff(const datetime_t* pdtm_base, const datetime_t* pdtm_cmp)
{
    time_t time_base, time_cmp;
    struct tm tm_base, tm_cmp;
    DTM2TM(&tm_base, pdtm_base);
    DTM2TM(&tm_cmp, pdtm_cmp);
    time_base = mktime(&tm_base);
    time_cmp = mktime(&tm_cmp);
    return (int)difftime(time_base, time_cmp);
}


time_t app_datetime_time_t(void)
{
    time_t tm = (time_t)(s_stm_cfg.tm_base / TM_RATE);
    return tm;
}

int app_datetime(datetime_t* pdtm)
{
    struct tm* ptm = NULL;
    uint32_t ticks;
    time_t tm = (time_t)(s_stm_cfg.tm_base / TM_RATE);
    timer_cnt_get(&ticks);

    if(s_stm_cfg.snapshot > ticks)
        tm += RTC_CNT_RANGE/TM_RATE;

    tm += ticks/TM_RATE;
    ptm = localtime(&tm);
    TM2DTM(pdtm, ptm)
    return APP_SUCCESS;
}

void app_datetime_init(void)//app_dtm_hdl_t evt_hdl)
{
    //s_evt_hdl = evt_hdl;
    check_default_datetime();
    dt_timer_start(DATETIME_SYNC_INTERVAL);
}

