#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <time.h>
#include <uv.h>
#include <dbus/dbus.h>
#include <readline/readline.h>

#if defined(PLATFORM_R16) || defined (PLATFORM_CPU)
#include "log.h"
#include "libuv_dbus.h"
#include "json_struct.h"

#else
#include <uvdbus/log.h>
#include <uvdbus/libuv_dbus.h>
#include <uvdbus/json_struct.h>
#endif

static MOD_INFO_TABLE       g_ModInfo;


static PDBUS_MSG_PACK DBusOnMessage(uv_loop_t* pLoop, DBusConnection* pConn, PDBUS_MSG_PACK pMsg)
{
    //int i, ret, err;
    //uint32_t tm = LIBUV_CURRENT_TIME_US();
 
    if(!pMsg || !pLoop || !pConn)
    {
        return NULL;
    }

    //LOG_EX(LOG_Info, "Process Message(%u --> 0x%08X) at [%lu.%06lu]: cmd = %u, size = %u, key = %d, msg(%d) = [%s]\n", 
    //            pMsg->msgSrc, pMsg->msgDests, tm / 1000000, tm % 1000000, pMsg->busCmd, pMsg->msgSize, pMsg->msgKey, pMsg->msgSize, pMsg->pMsg);
 
    return NULL;
}

static void __logCtrlProc(void *pParams)
{
    int i = 0;
    //int ret;

    LOG_LEVEL logLevelInfo[] = {
        LOG_Fatal, LOG_Error, LOG_Warn, LOG_Debug, LOG_Info, 
        LOG_Test, LOG_Call, LOG_Devp, LOG_Step, LOG_Unknown, LOG_All, LOG_Close
    };

    const char* g_Menu[] = {
        "Usage: enable/disable <modName> <operation> [params1] [params2]\n"
        "       help\n",
        "       quit\n",
    };

    const char* pOptMenu[] = {
        "\n     operation:\n"
        "     |--------------------------------------------------------------------------|\n",
        "     |  command |     operation       |         params1       |     params2     |\n",
        "     |--------------------------------------------------------------------------|\n",
        "     |  enable  |                     |                       |                 |\n",
        "     |----------| 0: Set log level    |       Log level       |      Unused     |\n",
        "     |  disable |                     |                       |                 |\n",
        "     |----------|---------------------|-----------------------|-----------------|\n",
        "     |  enable  |                     |                       |                 |\n",
        "     |----------| 1: Print to file    |         Unused        |      Unused     |\n",
        "     |  disable |                     |                       |                 |\n",
        "     |----------|---------------------|-----------------------|-----------------|\n",
        "     |  enable  |                     |                       |                 |\n",
        "     |----------| 2: Backup to email  |         Unused        |      Unused     |\n",
        "     |  disable |                     |                       |                 |\n",
        "     |----------|---------------------|-----------------------|-----------------|\n",
        "     |  enable  |                     | Log server ip address | Log server port |\n",
        "     |----------| 3: Send to network  |-----------------------|-----------------|\n",
        "     |  disable |                     |         Unused        |      Unused     |\n",
        "     |--------------------------------------------------------------------------|\n",
        "     |  enable  |                     |                       |                 |\n",
        "     |----------| 4: Backup to Server |         Unused        |      Unused     |\n",
        "     |  disable |                     |                       |                 |\n",
        "     |----------|---------------------|-----------------------|-----------------|\n",
    };
    
    while(TRUE)
    {
        char *pInput = NULL;
        char *pCmd = NULL;

        for(i = 0; i < sizeof(g_Menu) / sizeof(g_Menu[0]); i++)
        {
            LOG_EX2(LOG_Info, "%s", g_Menu[i]);
        }

        pInput = readline("Enter Command:");

        if(pInput == NULL)
        {
            continue;
        }

        pCmd = strtok(pInput, " ");
        i = 0;

        while(pCmd != NULL)
        {
            if(strcmp(pCmd, "help") == 0)
            {
                for(i = 0; i < sizeof(g_pModInfoTable) / sizeof(g_pModInfoTable[0]); i++)
                {
                    if(i == 0)
                    {
                        LOG_EX2(LOG_Info, "    modName  : %-2d --> %s\n",
                                i, ModuleNameToString(g_pModInfoTable[i].modName));
                    }
                    else
                    {
                        LOG_EX2(LOG_Info, "%15s%-2d --> %s\n", "",
                                i, ModuleNameToString(g_pModInfoTable[i].modName));
                    }
                }

                for(i = 0; i < sizeof(logLevelInfo) / sizeof(logLevelInfo[0]); i++)
                {
                    if(i == 0)
                    {
                        LOG_EX2(LOG_Info, "\n    Log Level: %-2d --> %s\n", i, LogLeveToString(logLevelInfo[i]));
                    }
                    else
                    {
                        LOG_EX2(LOG_Info, "%15s%-2d --> %s\n", "", i, LogLeveToString(logLevelInfo[i]));
                    }
                }

                for(i = 0; i < sizeof(pOptMenu) / sizeof(pOptMenu[0]); i++)
                {
                    LOG_EX2(LOG_Info, "%s", pOptMenu[i]);
                }
            }
            else if(strcmp(pCmd, "enable") == 0
                    || strcmp(pCmd, "disable") == 0)
            {
                LOG_CFG_PROTOCOL logItem;
                int iCmd, iMod;
                char *pParams1 = NULL, *pParams2 = NULL;
                char* pMod      = strtok(NULL, " ");
                char* pOperat   = strtok(NULL, " ");

                if(pMod == NULL || strlen(pMod) == 0)
                {
                    LOG_EX(LOG_Error, "Input <modName> error, see help\n");
                    break;
                }
                
                if(pOperat == NULL || strlen(pOperat) == 0)
                {
                    LOG_EX(LOG_Error, "Input <operation> error, see help\n");
                    break;
                }

                iMod = strtol(pMod, NULL, 10);

                if(iMod < 0 || iMod >= MODULE_MAX)
                {
                    LOG_EX(LOG_Error, "Input <modName> error: %s(%d)\n", pMod, iMod);
                    break;
                }

                iCmd = strtol(pOperat, NULL, 10);

                memset(&logItem, 0, sizeof(LOG_CFG_PROTOCOL));

                switch(iCmd)
                {
                    case 0:
                        pParams1 = strtok(NULL, " ");
                        if(pParams1 && strlen(pParams1) > 0)
                        {
                            int logLevel = strtol(pParams1, NULL, 10);

                            if(logLevel >= 0 && logLevel < sizeof(logLevelInfo) / sizeof(logLevelInfo[0]))
                            {
                                LOG_EX2(LOG_Info, "%s %d 0x%08X\n", pCmd, iCmd, logLevelInfo[logLevel]);

                                logItem.cfgCmd      = CMD_LOG_LEVEL;
                                logItem.iParams2    = (strcmp(pCmd, "disable") == 0) ? FALSE : TRUE;
                                logItem.iParams1    = logLevelInfo[logLevel];

                                DBusJsonSendToCommand(NULL,
                                            g_pModInfoTable[iMod].modAliase,
                                            CMD_LOG_CONFIG, 
                                            JSON_ENGINE_LOG_CFG_CMD,
                                            &logItem, TRUE);
                            }
                            else
                            {   
                                LOG_EX(LOG_Error, "Input <pParams1> error, see help\n");
                            }
                        }
                        else
                        {
                            LOG_EX(LOG_Error, "Input <pParams1> error, see help\n");
                        }
                        break;

                    case 1:
                        logItem.cfgCmd      = CMD_LOG_FILE;
                        logItem.iParams1    = (strcmp(pCmd, "disable") == 0) ? FALSE : TRUE;
                        DBusJsonSendToCommand(NULL,
                                            g_pModInfoTable[iMod].modAliase,
                                            CMD_LOG_CONFIG, 
                                            JSON_ENGINE_LOG_CFG_CMD,
                                            &logItem, TRUE);
                        break;

                    case 2:
                        logItem.cfgCmd      = CMD_LOG_MAIL;
                        logItem.iParams1    = (strcmp(pCmd, "disable") == 0) ? FALSE : TRUE;
                        DBusJsonSendToCommand(NULL,
                                            g_pModInfoTable[iMod].modAliase,
                                            CMD_LOG_CONFIG, 
                                            JSON_ENGINE_LOG_CFG_CMD,
                                            &logItem, TRUE);
                        break;
                        
                    case 3:
                        pParams1 = strtok(NULL, " ");

                        logItem.cfgCmd      = CMD_LOG_NETWORK;
                        if(pParams1 == NULL || strlen(pParams1) == 0)
                        {
                            
                            logItem.iParams1    = 0;
                            DBusJsonSendToCommand(NULL,
                                                g_pModInfoTable[iMod].modAliase,
                                                CMD_LOG_CONFIG, 
                                                JSON_ENGINE_LOG_CFG_CMD,
                                                &logItem, TRUE);
                        }
                        else
                        {
                            pParams2 = strtok(NULL, " ");
                            
                            if(pParams2 != NULL && strlen(pParams2) > 0)
                            {
                                logItem.iParams1    = inet_addr(pParams1);
                                logItem.iParams2    = strtol(pParams2, NULL, 10);
                                DBusJsonSendToCommand(NULL,
                                                g_pModInfoTable[iMod].modAliase,
                                                CMD_LOG_CONFIG, 
                                                JSON_ENGINE_LOG_CFG_CMD,
                                                &logItem, TRUE);
                            }
                            else
                            {
                                LOG_EX(LOG_Error, "Input <pParams> error, pParams2 = %s\n",
                                    SAFE_STRING_VALUE(pParams2));
                            }
                        }
                        
                        break;

                    case 4:
                        logItem.cfgCmd      = CMD_LOG_SERVER;
                        logItem.iParams1    = (strcmp(pCmd, "disable") == 0) ? FALSE : TRUE;
                        DBusJsonSendToCommand(NULL,
                                            g_pModInfoTable[iMod].modAliase,
                                            CMD_LOG_CONFIG, 
                                            JSON_ENGINE_LOG_CFG_CMD,
                                            &logItem, TRUE);
                        break;

                    default:
                        LOG_EX(LOG_Error, "Unknown operation(0-3) %s, see help\n", pOperat);
                        break;
                }
            }
            else if(strcmp(pCmd, "quit") == 0)
            {
                return;
            }

            pCmd = strtok(NULL, " ");
        }

        usleep(1000);
    }

    pthread_detach(pthread_self());
}

int main(int argc, char **argv)
{
    int ret = 0;
    DBusConnection* pBus = NULL;
    uv_thread_t uvThread;
    uv_loop_t* pLoop = GetDBusDefaultLoop();
    
    memcpy(&g_ModInfo, &g_pModInfoTable[MODULE_LOG_CTRL], sizeof(MOD_INFO_TABLE));

    pBus = DBusWithLibuvInit(pLoop, g_ModInfo.modAliase, 
                             DBusOnMessage, 
                             NULL, 
                             NULL,
                             &ret);

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

    uv_thread_create(&uvThread, __logCtrlProc, NULL);

    RunUVLoop(pLoop);

    while(TRUE)
    {
        usleep(1000);
    }
    
    return (0);
}