#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <uv.h>
#include <dbus/dbus.h>
#include <errno.h>
#include <time.h>
#include <uthash/utlist.h>

#if defined(PLATFORM_R16) || defined (PLATFORM_CPU) || defined(PLATFORM_R311)
#include "log.h"
#include "libuv_dbus.h"
#include "crypto.h"
#include "json_struct.h"
#include "config_engine.h"
#include "assistant.h"
#else
#include <uvdbus/log.h>
#include <uvdbus/libuv_dbus.h>
#include <uvdbus/crypto.h>
#include <uvdbus/json_struct.h>
#include <uvdbus/config_engine.h>
#include <uvdbus/assistant.h>
#endif

#define SYNC_TIME_DELAY         (1)

static PASSISTANT_ARRAY_INFO    g_pAlarmArray   = NULL, 
                                g_pRemaindArray = NULL,
                                g_pSessionArray = NULL;

static uv_rwlock_t              g_uvListRwLock;
static unsigned char            g_syncFlags = 0;
static unsigned int             g_sessionId = 0;

static void __onAlarmCb(unsigned int tmId, unsigned int status, void *pUserData);

static int __getTimerPriorty(ASSISTANT_TYPE itemType)
{
    switch(itemType)
    {
        case ASSISTANT_TYPE_CLOCK:
            return (2);

        case ASSISTANT_TYPE_REMAIND:
            return (3);

        case ASSISTANT_TYPE_SESSION:
            return (1);
    }

    return (0);
}

static void __addTaskToTimer(PASSISTANT_ARRAY_INFO pItem)
{
    int             ret = 0;
    unsigned int    alarmId;
    
    pItem->alarmItem.second = 0;

    alarmId = AlarmTimerAdd(pItem->alarmItem.year,
                             pItem->alarmItem.month,
                             pItem->alarmItem.day,
                             pItem->alarmItem.hour,
                             pItem->alarmItem.minute,
                             pItem->alarmItem.second,
                             pItem->alarmItem.weekDay,
                             pItem->alarmItem.repeatMode, 
                             __onAlarmCb,
                             __getTimerPriorty(pItem->alarmItem.itemType),
                             &pItem->alarmItem, 
                             &ret);

    if(alarmId != 0xFFFFFFFF && ret == 0)
    {
        pItem->alarmItem.timerId = alarmId;
    }
    else
    {
        pItem->alarmItem.timerId = 0xFFFFFFFF;
    }
}

static int __assistantRspStatus(int cmd, int val)
{
    int ret = 0;
    ASSISTANT_RSP_STATUS oStatus;

    memset(&oStatus, 0, sizeof(ASSISTANT_RSP_STATUS));

    oStatus.cmd     = cmd;
    oStatus.val     = val;

    ret = DBusJsonSendToCommand(NULL,
                g_pModInfoTable[MODULE_CONTROLLER].modAliase,
                CMD_ASSISTANT_STATUS, 
                JSON_ENGINE_ASSISTANT_STATUS,
                &oStatus, TRUE);

    return (ret);
}

static int __assistantRunningEvent(PASSISTANT_ITEM_INFO pInfo)
{
    int ret = 0;
    
    ret = DBusJsonSendToCommand(NULL,
                g_pModInfoTable[MODULE_CONTROLLER].modAliase,
                CMD_ASSISTANT_RUNNING, 
                JSON_ENGINE_ASSISTANT_RUNNING,
                pInfo, FALSE);

    return (ret);
}

static int __assistantNotifyChange(int cmdNotify, int nItems, ASSISTANT_TYPE nType, PASSISTANT_ITEM_INFO pInfo)
{
    int ret = 0;
    ASSISTANT_NOTIFY_INFO notifyInfo;

    memset(&notifyInfo, 0, sizeof(ASSISTANT_NOTIFY_INFO));
    
    notifyInfo.type     = nType;
    notifyInfo.cmd      = cmdNotify;

    if(pInfo)
    {
        notifyInfo.nItems   = nItems;
        for(int i = 0; i < nItems; i++)
        {
            notifyInfo.ids[i] = pInfo[i].itemId;
        }
    }
    
    ret = DBusJsonSendToCommand(NULL,
                g_pModInfoTable[MODULE_CONTROLLER].modAliase,
                CMD_ASSISTANT_NOTIFY, 
                JSON_ENGINE_ASSISTANT_NOTIFY,
                &notifyInfo, TRUE);

    return (ret);
}

static int __assistantArrayNotifyChange(int cmdNotify, int nItems, ASSISTANT_TYPE nType, unsigned long long* pArray)
{
    int ret = 0;
    ASSISTANT_NOTIFY_INFO notifyInfo;

    memset(&notifyInfo, 0, sizeof(ASSISTANT_NOTIFY_INFO));
    
    notifyInfo.type     = nType;
    notifyInfo.cmd      = cmdNotify;

    if(pArray)
    {
        notifyInfo.nItems   = nItems;
        for(int i = 0; i < nItems; i++)
        {
            notifyInfo.ids[i] = pArray[i];
        }
    }
    
    ret = DBusJsonSendToCommand(NULL,
                g_pModInfoTable[MODULE_CONTROLLER].modAliase,
                CMD_ASSISTANT_NOTIFY, 
                JSON_ENGINE_ASSISTANT_NOTIFY,
                &notifyInfo, TRUE);

    return (ret);
}

static void __cleanupAlarmArray(void)
{
    PASSISTANT_ARRAY_INFO pItem = NULL, pTmp = NULL;
    
    uv_rwlock_wrlock(&g_uvListRwLock);
    DL_FOREACH_SAFE(g_pAlarmArray, pItem, pTmp)
    {
        AlarmTimerRemove(pItem->alarmItem.timerId);
        DL_DELETE(g_pAlarmArray, pItem);
        free(pItem);
    }
    uv_rwlock_wrunlock(&g_uvListRwLock);
}

static void __cleanupRemaindArray(void)
{
    PASSISTANT_ARRAY_INFO pItem = NULL, pTmp = NULL;
    
    uv_rwlock_wrlock(&g_uvListRwLock);
    DL_FOREACH_SAFE(g_pRemaindArray, pItem, pTmp)
    {
        AlarmTimerRemove(pItem->alarmItem.timerId);
        DL_DELETE(g_pRemaindArray, pItem);
        free(pItem);
    }
    uv_rwlock_wrunlock(&g_uvListRwLock);
}

static void __cleanupSessionArray(void)
{
    PASSISTANT_ARRAY_INFO pItem = NULL, pTmp = NULL;
    
    uv_rwlock_wrlock(&g_uvListRwLock);
    DL_FOREACH_SAFE(g_pSessionArray, pItem, pTmp)
    {
        AlarmTimerRemove(pItem->alarmItem.timerId);
        DL_DELETE(g_pSessionArray, pItem);
        free(pItem);
    }
	uv_rwlock_wrunlock(&g_uvListRwLock);
}

static int __addNewItems(PASSISTANT_SYNC_INFO pInfo)
{
    struct  tm  localTime;
    time_t loclStamp, tmStamp      = time((time_t*)NULL);
    
    localtime_r(&tmStamp, &localTime);
    loclStamp   = mktime(&localTime);

    for(int i = 0; i < pInfo->nItems; i++)
    {
        PASSISTANT_ARRAY_INFO pItem = (PASSISTANT_ARRAY_INFO)malloc(sizeof(struct ASSISTANT_ARRAY_INFO));

        if(pItem == NULL)
        {
            LOG_EX(LOG_Error, "Malloc Memory Error\n");
            return (-ERR_MALLOC_MEMORY);
        }

        memset(pItem, 0, sizeof(struct ASSISTANT_ARRAY_INFO));

        strcpy(pItem->alarmItem.strTips,        pInfo->pAlarmInfo[i].strTips);
        strcpy(pItem->alarmItem.resUrl,         pInfo->pAlarmInfo[i].resUrl);
        strcpy(pItem->alarmItem.voiceRes,       pInfo->pAlarmInfo[i].voiceRes);
        strcpy(pItem->alarmItem.voiceResType,   pInfo->pAlarmInfo[i].voiceResType);
        
        pItem->alarmItem.itemType      = pInfo->pAlarmInfo[i].itemType;
        pItem->alarmItem.repeatMode    = pInfo->pAlarmInfo[i].repeatMode;
        pItem->alarmItem.voiceId       = pInfo->pAlarmInfo[i].voiceId;
        
        pItem->alarmItem.year          = pInfo->pAlarmInfo[i].year;
        pItem->alarmItem.month         = pInfo->pAlarmInfo[i].month;
        pItem->alarmItem.day           = pInfo->pAlarmInfo[i].day;
        pItem->alarmItem.hour          = pInfo->pAlarmInfo[i].hour;
        pItem->alarmItem.minute        = pInfo->pAlarmInfo[i].minute;
        pItem->alarmItem.second        = pInfo->pAlarmInfo[i].second;
        pItem->alarmItem.weekDay       = pInfo->pAlarmInfo[i].weekDay;

        if(ASSISTANT_TYPE_SESSION == pItem->alarmItem.itemType)
        {
            pItem->alarmItem.itemId        = g_sessionId++;
        }
        else
        {
            pItem->alarmItem.itemId        = pInfo->pAlarmInfo[i].itemId;
        }
        
        if(pItem->alarmItem.repeatMode == REPEAT_MODE_NONE)
        {
            struct tm   setTime;
            time_t  onTimeStamp;
            int     tmDiff;

            setTime.tm_year	= pItem->alarmItem.year;
            setTime.tm_mon	= pItem->alarmItem.month;
            setTime.tm_mday	= pItem->alarmItem.day;
            setTime.tm_hour	= pItem->alarmItem.hour;
            setTime.tm_min	= pItem->alarmItem.minute;
            setTime.tm_sec	= pItem->alarmItem.second;

            onTimeStamp         = mktime(&setTime);
            tmDiff              = (int)difftime(loclStamp, onTimeStamp);

            if(tmDiff >= 3)
            {
                LOG_EX(LOG_Warn, "%llu: Was Expired %d!!!!!!\n", pItem->alarmItem.itemId, tmDiff);
                continue;
            }
        }
        
        uv_rwlock_wrlock(&g_uvListRwLock);
        if(ASSISTANT_TYPE_CLOCK == pItem->alarmItem.itemType)
        {
            DL_APPEND(g_pAlarmArray, pItem);
        }
        else if(ASSISTANT_TYPE_REMAIND == pItem->alarmItem.itemType)
        {
            DL_APPEND(g_pRemaindArray, pItem);
        }
        else if(ASSISTANT_TYPE_SESSION == pItem->alarmItem.itemType)
        {
            DL_APPEND(g_pSessionArray, pItem);
        }
        else
        {
            LOG_EX(LOG_Error, "Unknown Type: %d\n", pItem->alarmItem.itemType);
        }
        uv_rwlock_wrunlock(&g_uvListRwLock);

        __addTaskToTimer(pItem);
    }

    return (0);
}

static void __removeAlarmItem(PASSISTANT_NOTIFY_INFO pRemove)
{
    PASSISTANT_ARRAY_INFO pItem = NULL, pTmp = NULL;

    for(int i = 0; i < pRemove->nItems; i++)
    {
		uv_rwlock_wrlock(&g_uvListRwLock);
        DL_FOREACH_SAFE(g_pAlarmArray, pItem, pTmp)
        {
            if(pItem->alarmItem.itemId == pRemove->ids[i]
                && pItem->alarmItem.itemType == pRemove->type)
            {
                AlarmTimerRemove(pItem->alarmItem.timerId);
                DL_DELETE(g_pAlarmArray, pItem);
                free(pItem);
            }
        }
		uv_rwlock_wrunlock(&g_uvListRwLock);
    }
}

static void __removeRemaindItem(PASSISTANT_NOTIFY_INFO pRemove)
{
    PASSISTANT_ARRAY_INFO pItem = NULL, pTmp = NULL;

    for(int i = 0; i < pRemove->nItems; i++)
    {
		uv_rwlock_wrlock(&g_uvListRwLock);
        DL_FOREACH_SAFE(g_pRemaindArray, pItem, pTmp)
        {
            if(pItem->alarmItem.itemId == pRemove->ids[i]
                && pItem->alarmItem.itemType == pRemove->type)
            {
                AlarmTimerRemove(pItem->alarmItem.timerId);
                DL_DELETE(g_pRemaindArray, pItem);
                free(pItem);
            }
        }
		uv_rwlock_wrunlock(&g_uvListRwLock);
    }
}

static int __alarmItemCmp(PASSISTANT_ARRAY_INFO pSrc, PASSISTANT_ARRAY_INFO pDst)
{
#if 0
    fprintf(stdout, "id: %llu --> %llu, type: %u --> %u\n", 
            pSrc->alarmItem.itemId, pDst->alarmItem.itemId,
            pSrc->alarmItem.itemType, pDst->alarmItem.itemType);
#endif
    if(pSrc->alarmItem.itemId == pDst->alarmItem.itemId
        && pSrc->alarmItem.itemType == pDst->alarmItem.itemType)
    {
        return (0);
    }
    else
    {
        return (1);
    }
}

static void __onAlarmCb(unsigned int tmId, unsigned int status, void *pUserData)
{
    PASSISTANT_ITEM_INFO pAlarm = (PASSISTANT_ITEM_INFO)pUserData;
    PASSISTANT_ARRAY_INFO pItem = NULL;
    struct ASSISTANT_ARRAY_INFO tmpItem;

    struct  tm  localTime;
    time_t tmStamp     = time((time_t*)NULL);
        
    localtime_r(&tmStamp, &localTime);

    LOG_EX(LOG_Debug, "Timer[%lld] %u On at [%04u-%02u-%02u %02u:%02u:%02u], status = %u\n", pAlarm->itemId, tmId,
           localTime.tm_year + 1900, localTime.tm_mon + 1, localTime.tm_mday,
           localTime.tm_hour, localTime.tm_min, localTime.tm_sec,
           status);

    memset(&tmpItem, 0, sizeof(struct ASSISTANT_ARRAY_INFO));

    tmpItem.alarmItem.itemId    = pAlarm->itemId;
    tmpItem.alarmItem.itemType  = pAlarm->itemType;

    uv_rwlock_rdlock(&g_uvListRwLock);
    if(pAlarm->itemType == ASSISTANT_TYPE_CLOCK)
    {
        DL_SEARCH(g_pAlarmArray, pItem, &tmpItem, __alarmItemCmp);
    }
    else if(pAlarm->itemType == ASSISTANT_TYPE_REMAIND)
    {
        DL_SEARCH(g_pRemaindArray, pItem, &tmpItem, __alarmItemCmp);
    }
    else if(pAlarm->itemType == ASSISTANT_TYPE_SESSION)
    {
        DL_SEARCH(g_pSessionArray, pItem, &tmpItem, __alarmItemCmp);
    }
    else
    {
        LOG_EX(LOG_Error, "Unknown type: %d\n", pAlarm->itemType);
    }
    uv_rwlock_rdunlock(&g_uvListRwLock);

    if(pItem)
    {
        pItem->alarmItem.year  += 1900;
        pItem->alarmItem.month += 1;

        __assistantRunningEvent(&pItem->alarmItem);

        if((pItem->alarmItem.repeatMode & 0xFF) == REPEAT_MODE_NONE)
        {
            uv_rwlock_wrlock(&g_uvListRwLock);
            if(pAlarm->itemType == ASSISTANT_TYPE_CLOCK)
            {
                DL_DELETE(g_pAlarmArray, pItem);
            }
            else if(pAlarm->itemType == ASSISTANT_TYPE_REMAIND)
            {
                DL_DELETE(g_pRemaindArray, pItem);
            }
            else if(pAlarm->itemType == ASSISTANT_TYPE_SESSION)
            {
                DL_DELETE(g_pSessionArray, pItem);
            }
            else
            {
                LOG_EX(LOG_Error, "Unknown type: %d\n", pAlarm->itemType);
            }
            uv_rwlock_wrunlock(&g_uvListRwLock);

            free(pItem);
        }
    }
}

static PDBUS_MSG_PACK __dBusOnMessage(uv_loop_t *pLoop, DBusConnection *pConn, PDBUS_MSG_PACK pMsg)
{
    PASSISTANT_SYNC_INFO    pInfo = NULL;
    PASSISTANT_NOTIFY_INFO  pNotifyInfo = NULL;
    int err = 0;

    if(!pMsg || !pLoop || !pConn)
    {
        return (NULL);
    }

    if(pMsg->msgDests == 0xFFFFFFFF)
    {
        return (NULL);
    }
    
    LOG_EX(LOG_Debug, "JSON(%08X) %s: %s\n", pMsg->busCmd, DBusCmdToString(pMsg->busCmd), (const char *)pMsg->pMsg);
    
    switch(pMsg->busCmd)
    {
        case CMD_SESSION_ALARM_SYNC:
            if(IsHolidayDBSynced() != TRUE)
            {
                LOG_EX(LOG_Warn, "CMD_SESSION_ALARM_SYNC: Wait sync holiday database, this is dirty data.\n");
                break;
            }

            pInfo = (PASSISTANT_SYNC_INFO)Json2Struct((const char *)pMsg->pMsg, JSON_ENGINE_ASSISTANT_SYNC_RSP, FALSE, &err);

            if(pInfo)
            {
                __printAssistantSyncInfo(DBusCmdToString(pMsg->busCmd), pInfo);

                __cleanupSessionArray();

                if(pInfo->pAlarmInfo && pInfo->nItems > 0)
                {
                    err = __addNewItems(pInfo);
                }

                __assistantRspStatus(pMsg->busCmd, err);

                free(pInfo->pAlarmInfo);
                free(pInfo);
            }
            else
            {
                __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS);
            }
            break;

        case CMD_ALARM_SYNC_RSP:
            if(IsHolidayDBSynced() != TRUE)
            {
                LOG_EX(LOG_Warn, "CMD_ALARM_SYNC_RSP: Wait sync holiday database, this is dirty data.\n");
                break;
            }

            pInfo = (PASSISTANT_SYNC_INFO)Json2Struct((const char *)pMsg->pMsg, JSON_ENGINE_ASSISTANT_SYNC_RSP, FALSE, &err);

            if(pInfo)
            {
                g_syncFlags |=  1 << ASSISTANT_TYPE_CLOCK;

                __printAssistantSyncInfo(DBusCmdToString(pMsg->busCmd), pInfo);
                
                __cleanupAlarmArray();

                if(pInfo->pAlarmInfo && pInfo->nItems > 0)
                {
                    err = __addNewItems(pInfo);
                }

                __assistantRspStatus(pMsg->busCmd, err);
                
                free(pInfo->pAlarmInfo);
                free(pInfo);
            }
            else
            {
                __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS);
            }
            
            break;

        case CMD_ALARM_ADD:
            pInfo = (PASSISTANT_SYNC_INFO)Json2Struct((const char *)pMsg->pMsg, JSON_ENGINE_ASSISTANT_SYNC_RSP, TRUE, &err);

            if(pInfo)
            {
                __printAssistantSyncInfo(DBusCmdToString(pMsg->busCmd), pInfo);
                
                if(pInfo->pAlarmInfo && pInfo->nItems > 0)
                {
                    err = __addNewItems(pInfo);
                    __assistantRspStatus(pMsg->busCmd, err);

                    if(err == 0)
                    {
                        __assistantNotifyChange(pMsg->busCmd, pInfo->nItems, ASSISTANT_TYPE_CLOCK, pInfo->pAlarmInfo);
                    }
                }
                else
                {
                    __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS);
                }
                
                free(pInfo->pAlarmInfo);
                free(pInfo);
            }
            else
            {
                __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS);
            }
            break;

        case CMD_ALARM_REMOVE:
            pNotifyInfo = (PASSISTANT_NOTIFY_INFO)Json2Struct((const char *)pMsg->pMsg, 
                                                      JSON_ENGINE_ASSISTANT_NOTIFY, FALSE, &err);

            if(pNotifyInfo)
            {
                __printAssistantNofifyInfo(DBusCmdToString(pMsg->busCmd), pNotifyInfo);
                
                if(pNotifyInfo->nItems > 0)
                {
                    __removeAlarmItem(pNotifyInfo);
                    __assistantRspStatus(pMsg->busCmd, 0);
                    __assistantArrayNotifyChange(pMsg->busCmd, pNotifyInfo->nItems, ASSISTANT_TYPE_CLOCK, pNotifyInfo->ids);
                }
                else
                {
                    __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS);
                }
                
                free(pNotifyInfo);
            }
            else
            {
                __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS);
            }

            break;

        case CMD_ALARM_REMOVEALL:
            __cleanupAlarmArray();
            __assistantRspStatus(pMsg->busCmd, 0);
            __assistantNotifyChange(pMsg->busCmd, 0, ASSISTANT_TYPE_CLOCK, NULL);
            break;       
        
        case CMD_REMAIND_SYNC_RSP:
            if(IsHolidayDBSynced() != TRUE)
            {
                LOG_EX(LOG_Warn, "CMD_REMAIND_SYNC_RSP: Wait sync holiday database, this is dirty data.\n");
                break;
            }

            pInfo = (PASSISTANT_SYNC_INFO)Json2Struct((const char *)pMsg->pMsg, JSON_ENGINE_ASSISTANT_SYNC_RSP, FALSE, &err);

            if(pInfo)
            {
                g_syncFlags |=  1 << ASSISTANT_TYPE_REMAIND;

                __printAssistantSyncInfo(DBusCmdToString(pMsg->busCmd), pInfo);
                
                __cleanupRemaindArray();

                if(pInfo->pAlarmInfo && pInfo->nItems > 0)
                {
                    err = __addNewItems(pInfo);
                }

                __assistantRspStatus(pMsg->busCmd, err);
                
                free(pInfo->pAlarmInfo);
                free(pInfo);
            }
            else
            {
                __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS);
            }
            break;

        case CMD_REMAIND_ADD:
            pInfo = (PASSISTANT_SYNC_INFO)Json2Struct((const char *)pMsg->pMsg, JSON_ENGINE_ASSISTANT_SYNC_RSP, TRUE, &err);

            if(pInfo)
            {
                __printAssistantSyncInfo(DBusCmdToString(pMsg->busCmd), pInfo);
                
                if(pInfo->pAlarmInfo && pInfo->nItems > 0)
                {
                    err = __addNewItems(pInfo);
                    __assistantRspStatus(pMsg->busCmd, err);

                    if(err == 0)
                    {
                        __assistantNotifyChange(pMsg->busCmd, pInfo->nItems, ASSISTANT_TYPE_REMAIND, pInfo->pAlarmInfo);
                    }
                }
                else
                {
                    __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS);
                }
                
                free(pInfo->pAlarmInfo);
                free(pInfo);
            }
            else
            {
                __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS);
            }
            break;

        case CMD_REMAIND_REMOVE:
            pNotifyInfo = (PASSISTANT_NOTIFY_INFO)Json2Struct((const char *)pMsg->pMsg, 
                                                      JSON_ENGINE_ASSISTANT_NOTIFY, FALSE, &err);

            if(pNotifyInfo)
            {
                __printAssistantNofifyInfo(DBusCmdToString(pMsg->busCmd), pNotifyInfo);
                
                if(pNotifyInfo->nItems > 0)
                {
                    __removeRemaindItem(pNotifyInfo);
                    __assistantRspStatus(pMsg->busCmd, 0);
                    __assistantArrayNotifyChange(pMsg->busCmd, pNotifyInfo->nItems, ASSISTANT_TYPE_REMAIND, pNotifyInfo->ids);
                }
                else
                {
                    __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS);
                }
                
                free(pNotifyInfo);
            }
            else
            {
                __assistantRspStatus(pMsg->busCmd, -ERR_INPUT_PARAMS);
            }
            break;

        case CMD_REMAIND_REMOVEALL:
            __cleanupRemaindArray();
            __assistantRspStatus(pMsg->busCmd, 0);
            __assistantNotifyChange(pMsg->busCmd, 0, ASSISTANT_TYPE_REMAIND, NULL);
            break;
    }

    return (NULL);
}

static void __dBusDeameonCb(MODULE_NAME modName, int status)
{
    if(status)
    {
        LOG_EX(LOG_Error, "Daemon(%d) Msg: [%s]\n", modName, status == 0 ? "Connect" : "Disconnect");
    }
    else
    {
        LOG_EX(LOG_Info, "Daemon(%d) Msg: [%s]\n", modName, status == 0 ? "Connect" : "Disconnect");
    }

#if 0
    if(modName == MODULE_CONTROLLER && status == 0)
    {
        int ret = DBusSendToCommand(NULL, 
                        g_pModInfoTable[MODULE_CONTROLLER].modAliase, 
                        CMD_ALARM_SYNC_REQ, "");
        
        LOG_EX(LOG_Debug, "Send CMD_ALARM_SYNC_REQ Command: %d\n", ret);

        ret = DBusSendToCommand(NULL, 
                        g_pModInfoTable[MODULE_CONTROLLER].modAliase, 
                        CMD_REMAIND_SYNC_REQ, "");
        
        LOG_EX(LOG_Debug, "Send CMD_REMAIND_SYNC_REQ Command: %d\n", ret);
    }
#endif
}

static void __assistantSyncThread(void *pParam)
{
    int ret, i = 0, isSynced = -1;

    LOG_EX(LOG_Debug, "Beging Sync holiday Database\n");
    while(TRUE)
    {
        if(IsHolidayDBSynced() != TRUE)
        {
            CurrentIsWorkDay(0, 0);
            if(i++ % 10 == 0 && i <= 1000)
            {
                LOG_EX(LOG_Debug, "Retry sync holiday database: %d\n", i);
            }
            sleep(SYNC_TIME_DELAY);
        }
        else
        {
            break;
        }
    }
    LOG_EX(LOG_Debug, "Sync holiday Database Finished\n");

    LOG_EX(LOG_Debug, "Beging sync ASSISTANT_TYPE_CLOCK\n");
    do
    {
        if(g_syncFlags & (1 << ASSISTANT_TYPE_CLOCK))
        {
            LOG_EX(LOG_Debug, "Sync ASSISTANT_TYPE_CLOCK Finished\n");
            break;
        }

        ret = DBusSendToCommand(NULL,
                            g_pModInfoTable[MODULE_CONTROLLER].modAliase, 
                            CMD_ALARM_SYNC_REQ, "");
            
        LOG_EX(LOG_Debug, "Send CMD_ALARM_SYNC_REQ Command: %d\n", ret);

        sleep(SYNC_TIME_DELAY);
    } while(TRUE);

    LOG_EX(LOG_Debug, "Beging sync ASSISTANT_TYPE_REMAIND\n");
    do
    {
        if(g_syncFlags & (1 << ASSISTANT_TYPE_REMAIND))
        {
            LOG_EX(LOG_Debug, "Sync ASSISTANT_TYPE_REMAIND Finished\n");
            break;
        }

        ret = DBusSendToCommand(NULL, 
                        g_pModInfoTable[MODULE_CONTROLLER].modAliase, 
                        CMD_REMAIND_SYNC_REQ, "");
        
        LOG_EX(LOG_Debug, "Send CMD_REMAIND_SYNC_REQ Command: %d\n", ret);

        sleep(SYNC_TIME_DELAY);
    } while(TRUE);

#if 0
    do
    {
        if((g_syncFlags & (1 << ASSISTANT_TYPE_CLOCK))
            && (g_syncFlags & (1 << ASSISTANT_TYPE_REMAIND)))
        {
            LOG_EX(LOG_Debug, "Sync Alarm And Remaind Finished\n");
            break;
        }

        if((g_syncFlags & (1 << ASSISTANT_TYPE_CLOCK)) == 0)
        {
            ret = DBusSendToCommand(NULL,
                            g_pModInfoTable[MODULE_CONTROLLER].modAliase, 
                            CMD_ALARM_SYNC_REQ, "");
            
            LOG_EX(LOG_Debug, "Send CMD_ALARM_SYNC_REQ Command: %d\n", ret);
        }

        if((g_syncFlags & (1 << ASSISTANT_TYPE_REMAIND)) == 0)
        {
            ret = DBusSendToCommand(NULL, 
                            g_pModInfoTable[MODULE_CONTROLLER].modAliase, 
                            CMD_REMAIND_SYNC_REQ, "");
            
            LOG_EX(LOG_Debug, "Send CMD_REMAIND_SYNC_REQ Command: %d\n", ret);
        }

        sleep(SYNC_TIME_DELAY);
    } while(TRUE);
    //while(g_syncFlags != ((1 << ASSISTANT_TYPE_CLOCK) | (1 << ASSISTANT_TYPE_REMAIND)));


    ret = DBusSendToCommand(NULL, 
					g_pModInfoTable[MODULE_CONTROLLER].modAliase, 
					CMD_ALARM_SYNC_REQ, "");
	
	LOG_EX(LOG_Debug, "Send CMD_ALARM_SYNC_REQ Command: %d\n", ret);

	ret = DBusSendToCommand(NULL, 
					g_pModInfoTable[MODULE_CONTROLLER].modAliase, 
					CMD_REMAIND_SYNC_REQ, "");
	
	LOG_EX(LOG_Debug, "Send CMD_REMAIND_SYNC_REQ Command: %d\n", ret);
#endif

    pthread_detach(pthread_self());
}

int main(int argc, char **argv)
{
	int ret = 0;
    DBusConnection* pBus;
    uv_loop_t* pLoop = GetDBusDefaultLoop();
    uv_thread_t uvSyncThread;
        
    pBus = DBusWithLibuvInit(pLoop, g_pModInfoTable[MODULE_ALARM].modAliase,
        __dBusOnMessage, 
        __dBusDeameonCb,
        NULL, &ret);

    if(pBus == NULL)
    {
        fprintf(stderr, "DBusWithLibuvInit Error: %d\n", ret);
        return 0;
    }

    uv_rwlock_init(&g_uvListRwLock);

    AlarmTimerInit(pLoop);
    
    uv_thread_create(&uvSyncThread, __assistantSyncThread, NULL);
    RunUVLoop(pLoop);

    while(TRUE)
    {
        usleep(1000);
    }

    return 0;
}
