#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>

#include <sys/timeb.h>

#include "Module_RatedCurrent.h"

//------------------------------------------------------------------------------
#define PASS                                    (1)
#define FAIL                                    (-1)

#define log_info(format, args...)               StoreLogMsg("[%s:%d][%s][Info] "format, __FILE__, __LINE__, __FUNCTION__, ##args)
#define log_warn(format, args...)               StoreLogMsg("[%s:%d][%s][Warn] "format, __FILE__, __LINE__, __FUNCTION__, ##args)
#define log_error(format, args...)              StoreLogMsg("[%s:%d][%s][Error] "format, __FILE__, __LINE__, __FUNCTION__, ##args)

//------------------------------------------------------------------------------
static SymStruct modelTable[] = {
    { "AC", MODEL_AC },
    { "AW", MODEL_AW },
    { "AP", MODEL_AP },
    { "DW", MODEL_DW },
    { "DS", MODEL_DS },
    { "DM", MODEL_DM },
    { "DR", MODEL_DR },
    //{ "DM", MODEL_DM },
    { "DD", MODEL_DD },
    { "DO", MODEL_DO },
};

static SymStruct regulationTable[] = {
    {"E", REG_CE},
    {"U", REG_UL},
    {"G", REG_GB},
    {"C", REG_CNS},
    {"J", REG_JARI},
    {"T", REG_TR25},
    {"K", REG_KC},
    {"B", REG_B},
    {"Z", REG_Z},
    {"M", REG_M},
    {"P", REG_P},
    {"I", REG_I},
    {"F", REG_F},
    {"L", REG_L},
};

static SymStruct powerTable[] = {
    {"30", POWER_30W},
    {"60", POWER_60W},
    {"90", POWER_90W},
    {"12", POWER_120W},
    {"15", POWER_150W},
    {"18", POWER_180W},
    {"24", POWER_240W},
    {"36", POWER_360W},
    {"48", POWER_480W},
    {"72", POWER_720W},
};

static SymStruct gunTypeTable[] = {
    {"0", GUN_TYPE_0},
    {"1", GUN_TYPE_1},
    {"2", GUN_TYPE_2},
    {"3", GUN_TYPE_3},
    {"4", GUN_TYPE_4},
    {"5", GUN_TYPE_5},
    {"6", GUN_TYPE_6},
    {"7", GUN_TYPE_7},
    {"8", GUN_TYPE_8},
    {"J", GUN_TYPE_J},
    {"U", GUN_TYPE_U},
    {"V", GUN_TYPE_V},
    {"E", GUN_TYPE_E},
    {"F", GUN_TYPE_F},
    {"G", GUN_TYPE_G},
};

//------------------------------------------------------------------------------
static int StoreLogMsg(const char *fmt, ...)
{
    char Buf[4096 + 256] = {0};
    char buffer[4096] = {0};
    int rc = 0;
    va_list args;
    struct timeb  SeqEndTime;
    struct tm *tm;

    va_start(args, fmt);
    rc = vsnprintf(buffer, sizeof(buffer), fmt, args);
    va_end(args);

    ftime(&SeqEndTime);
    SeqEndTime.time = time(NULL);
    tm = localtime(&SeqEndTime.time);

    //if (ShmSysConfigAndInfo->SysConfig.SwitchDebugFlag == YES) {
    //    sprintf(Buf, "%02d:%02d:%02d:%03d - %s",
    //            tm->tm_hour, tm->tm_min, tm->tm_sec, SeqEndTime.millitm, buffer);
    //    printf("%s \n", Buf);
    //} else {
    sprintf(Buf, "echo \"%04d-%02d-%02d %02d:%02d:%02d:%03d - %s\" >> /Storage/SystemLog/[%04d.%02d]SystemLog",
            tm->tm_year + 1900,
            tm->tm_mon + 1,
            tm->tm_mday,
            tm->tm_hour,
            tm->tm_min,
            tm->tm_sec,
            SeqEndTime.millitm,
            buffer,
            tm->tm_year + 1900,
            tm->tm_mon + 1);
    system(Buf);
    //}

    return rc;
}

static int keyfromstring(char *key, SymStruct *table, int tableCount)
{
    int i = 0;
    //int loop = sizeof(table) / sizeof(SymStruct);
    SymStruct *sym = NULL;

    for (i = 0; i < tableCount; i++) {
        sym = (SymStruct *)&table[i];
        if (strcmp(sym->key, key) == 0) {
            //printf("val = %x\r\n", sym->val);
            return sym->val;
        }
    }

    return BADKEY;
}

//------------------------------------------------------------------------------
static uint16_t exchangeRatingCur(uint32_t key)
{
    switch (key) {
    //60A J
    case DW_CE_30_J:
    case DM_CE_30_J:

    case DW_CE_30_E:
    case DM_CE_30_E:
        return RC_60A; //rating current 60A

    //65A U
    case DW_UL_30_U:
    case DM_UL_30_U:

    case DW_CNS_30_U:
    case DM_CNS_30_U:
        return RC_65A;

    //80A J
    case DW_UL_30_J:
    case DM_UL_30_J:
    case DW_CNS_30_J:
    case DM_CNS_30_J:

    //80A G
    case DM_CNS_30_G:
    case DS_UL_30_G:

    //80A M
    case DW_CE_30_M:
    case DM_CE_30_M:

    //80A N
    case DW_UL_30_N:
    case DM_UL_30_N:
    case DW_CNS_30_N:
    case DM_CNS_30_N:
        return RC_80A; //rating current 80A

    //125A J
    case DS_CE_60_J:
    case DS_CE_90_J:
    case DS_CE_120_J:
    case DS_CE_150_J:
    case DS_CE_180_J:

    case DS_UL_60_J:
    case DS_UL_90_J:
    case DS_UL_120_J:
    case DS_UL_150_J:
    case DS_UL_180_J:

    case DS_CNS_60_J:
    case DS_CNS_90_J:
    case DS_CNS_120_J:
    case DS_CNS_150_J:
    case DS_CNS_180_J:

    //125A U
    case DS_UL_60_U:

    case DS_CNS_60_U:

    //125A E
    case DS_CE_60_E:
        return RC_125A; //rating current 125A

    //200A U
    case DS_UL_90_U:
    case DS_UL_120_U:
    case DS_UL_150_U:
    case DS_UL_180_U:
    case DD_UL_360_U:

    case DS_CNS_90_U:
    case DS_CNS_120_U:
    case DS_CNS_150_U:
    case DS_CNS_180_U:
    case DD_CNS_360_U:

    //200A E
    case DS_CE_90_E:
    case DS_CE_120_E:
    case DS_CE_150_E:
    case DS_CE_180_E:

    //200A K
    case DS_CE_90_K:
    case DS_CE_120_K:
    case DS_CE_150_K:
    case DS_CE_180_K:

    case DD_CE_360_K:

    case DS_UL_90_K:
    case DS_UL_120_K:
    case DS_UL_150_K:
    case DS_UL_180_K:

    case DD_UL_360_K:
        return RC_200A; //rating current 200A

    //250A G
    case DS_CNS_120_G:
        return RC_250A;

    //300A T
    case DS_CE_90_T:
    case DS_CE_120_T:
    case DS_CE_150_T:
    case DS_CE_180_T:

    case DD_CE_360_T:

    case DS_UL_90_T:
    case DS_UL_120_T:
    case DS_UL_150_T:
    case DS_UL_180_T:

    case DD_UL_360_T:

    case DS_CNS_90_T:
    case DS_CNS_120_T:
    case DS_CNS_150_T:
    case DS_CNS_180_T:

    case DD_CNS_360_T:

    //300A D
    case DS_CE_90_D:
    case DS_CE_120_D:
    case DS_CE_150_D:
    case DS_CE_180_D:
    case DD_CE_360_D:

    case DS_UL_90_D:
    case DS_UL_120_D:
    case DS_UL_150_D:
    case DS_UL_180_D:

    case DD_UL_360_D:

    case DS_CNS_90_D:
    case DS_CNS_120_D:
    case DS_CNS_150_D:
    case DS_CNS_180_D:

    case DD_CNS_360_D:
        return RC_300A;

    //500A V
    case DD_UL_360_V:

    case DD_CNS_360_V:

    case DO_UL_360_V:
    case DO_CNS_360_V:

    //500A F
    case DD_CE_360_F:
    case DO_CE_360_F:

    //P
    case DD_CE_360_P:

    case DD_UL_360_R:
    case DD_CNS_360_R:
        return RC_500A; //rating current 500A

    default:
        return RC_0A; //rating current 200A
    }
}

static void exchangeGunTypeAndVolValue(uint8_t key, GunTypeAndVolInfo *gunAndVol)
{
    GunTypeAndVolInfo *pGunAndVol = (GunTypeAndVolInfo *)gunAndVol;

    switch (key) {
    case GUN_TYPE_0:// : none
    case GUN_TYPE_1:// : IEC 62196-2 Type 1/SAE J1772 Plug
    case GUN_TYPE_2:// : IEC 62196-2 Type 1/SAE J1772 Socket
    case GUN_TYPE_3:// : IEC 62196-2 Type 2 Plug
    case GUN_TYPE_4:// : IEC 62196-2 Type 2 Socket
    case GUN_TYPE_5:// : GB/T AC Plug
    case GUN_TYPE_6:// : GB/T AC Socket
    case GUN_TYPE_7:// :CCS2 AC Plug
        pGunAndVol->GunType = Gun_Type_AC;
        pGunAndVol->GunVoltage = VOL_CHADEMO;
        break;

    case GUN_TYPE_8:// :Type E socket
        break;

    case GUN_TYPE_J:// : CHAdeMO
        pGunAndVol->GunType = Gun_Type_Chademo;
        pGunAndVol->GunVoltage = VOL_CHADEMO;
        break;

    case GUN_TYPE_U:// : Natural cooling CCS1 combo
    case GUN_TYPE_V:// : Liquid cooling CCS1 combo
    case GUN_TYPE_E:// : Natural cooling CCS2 combo
    case GUN_TYPE_F:// : Liquid cooling CCS2 combo
        pGunAndVol->GunType = Gun_Type_CCS_2;
        pGunAndVol->GunVoltage = VOL_CCS;
        break;

    case GUN_TYPE_G:// : GBT DC
        pGunAndVol->GunType = Gun_Type_GB;
        pGunAndVol->GunVoltage = VOL_GBT;
        break;
    }
}

static int exchangePowerValue(uint8_t key)
{
    switch (key) {
    case POWER_30W:
        return 300;

    case POWER_60W:
        return 600;

    case POWER_90W:
        return 900;

    case POWER_120W:
        return 1200;

    case POWER_150W:
        return 1500;

    case POWER_180W:
        return 1800;

    case POWER_240W:
        return 2400;

    case POWER_360W:
        return 3600;

    case POWER_480W:
        return 4800;

    case POWER_720W:
        return 7200;

    default:
        return 600;
        break;
    }
}

/**
 * [RatedCurrentParsing : Parsing Rating Current]
 * @param  pModuleName  [description]
 * @param  pDestStruct  [save parameter structure array]
 * @param  parsingCount [parameter structure array count, array 0, 1 for DC Gun, 2 for AC Gun]
 * @return              [return -1 is module name format non match.]
 */
int RatedCurrentParsing(char *pModuleName, void *pDestStruct)
{
    uint8_t gunTypeIndex = 0;

    uint8_t modelKey = 0;
    uint8_t reguKey = 0;
    uint8_t powerKey = 0;
    uint8_t gunTypeKey = 0;
    uint16_t powerVal = 0;
    uint16_t ratingCurVal = 0;
    int i = 0;
    uint32_t ret = 0;
    char model[2] = {'\0'};
    char regulation[1] = {'\0'};
    char power[2] = {'\0'};
    char gunType[1] = {'\0'};
    ParsingRatedCur *pParsingInfo = NULL;
    GunRateCurInfo *pGunRateCurInfo = NULL;
    GunTypeAndVolInfo fGunAndVol = {0};

    if (pModuleName == NULL || pDestStruct == NULL) {
        log_error("Failed to parse source data\r\n");
        return FAIL;
    }

    pParsingInfo = (ParsingRatedCur *)pDestStruct;

    strncpy(model, &pModuleName[0], 2);
    model[2] = '\0';
    strncpy(regulation, &pModuleName[3], 1);
    regulation[1] = '\0';
    strncpy(power, &pModuleName[4], 2);
    power[2] = '\0';


    pParsingInfo->GetGunCount = 0;
    for (i = 0; i < sizeof(pParsingInfo->ParsingInfo) / sizeof(GunRateCurInfo); i++) {
        pGunRateCurInfo = (GunRateCurInfo *)&pParsingInfo->ParsingInfo[pParsingInfo->GetGunCount];

        if (i == 0) {
            gunTypeIndex = DC_ONE;
        } else if (i == 1) {
            gunTypeIndex = AC_ONE;
        } else if (i == 2) {
            gunTypeIndex = DC_SEC;
        }

        strncpy(gunType, &pModuleName[gunTypeIndex], 1);
        gunType[1] = '\0';

        modelKey = keyfromstring(&model[0], &modelTable[0], sizeof(modelTable) / sizeof(SymStruct));
        reguKey = keyfromstring(&regulation[0], &regulationTable[0], sizeof(regulationTable) / sizeof(SymStruct));
        powerKey = keyfromstring(&power[0], &powerTable[0], sizeof(powerTable) / sizeof(SymStruct));
        if ((gunTypeKey = keyfromstring(&gunType[0], &gunTypeTable[0], sizeof(gunTypeTable) / sizeof(SymStruct))) == GUN_TYPE_0) {
            log_error("The type of gun is none\r\n");
            continue;
        }

        ret = 0;
        ret = ((modelKey << 24) | (reguKey << 16) | (powerKey << 8) | gunTypeKey);
        ratingCurVal = exchangeRatingCur(ret);
        if (ratingCurVal == RC_0A) {
            log_error("Model name format none match\r\n");
            continue;
            //return FAIL;
        }

        memset((uint8_t *)&fGunAndVol, 0, sizeof(GunTypeAndVolInfo));
        exchangeGunTypeAndVolValue(gunTypeKey, &fGunAndVol);
        powerVal = exchangePowerValue(powerKey);

        pGunRateCurInfo->GunType = fGunAndVol.GunType;
        pGunRateCurInfo->Current = ratingCurVal;
        pGunRateCurInfo->Voltage = fGunAndVol.GunVoltage;
        pGunRateCurInfo->Power = powerVal;

        pParsingInfo->GetGunCount++;

        //log_info("%d GunType = %d, Rating current = %d, Vol = %d, Power = %d\r\n",
        //         i,
        //         pGunRateCurInfo->GunType,
        //         pGunRateCurInfo->Current,
        //         pGunRateCurInfo->Voltage,
        //         pGunRateCurInfo->Power);

    }

    return PASS;
}

//------------------------------------------------------------------------------
//Test function
//------------------------------------------------------------------------------
void TestParsingRatingCurrent(void)
{
    uint8_t i = 0;
    ParsingRatedCur fParsingRateCur = {0};

    RatedCurrentParsing("DDYC362V0UE2AD", &fParsingRateCur);
    log_info("Get gun = %d\r\n", fParsingRateCur.GetGunCount);
    for (i = 0; i < fParsingRateCur.GetGunCount; i++) {
        log_info("%d GunType = %d, Rating current = %d, Vol = %d, Power = %d\r\n",
                 i,
                 fParsingRateCur.ParsingInfo[i].GunType,
                 fParsingRateCur.ParsingInfo[i].Current,
                 fParsingRateCur.ParsingInfo[i].Voltage,
                 fParsingRateCur.ParsingInfo[i].Power);
    }
    //log_info("%d GunType = %d, Rating current = %d, Vol = %d, Power = %d\r\n",
    //         0,
    //         fGunRateCurInfo[0].GunType,
    //         fGunRateCurInfo[0].Current,
    //         fGunRateCurInfo[0].Voltage,
    //         fGunRateCurInfo[0].Power);

    RatedCurrentParsing("DMYE301E00D2PH", &fParsingRateCur);
    log_info("Get gun = %d\r\n", fParsingRateCur.GetGunCount);
    for (i = 0; i < fParsingRateCur.GetGunCount; i++) {
        log_info("%d GunType = %d, Rating current = %d, Vol = %d, Power = %d\r\n",
                 i,
                 fParsingRateCur.ParsingInfo[i].GunType,
                 fParsingRateCur.ParsingInfo[i].Current,
                 fParsingRateCur.ParsingInfo[i].Voltage,
                 fParsingRateCur.ParsingInfo[i].Power);
    }
}