#include <stdio.h>      /*標準輸入輸出定義*/
#include <stdlib.h>     /*標準函數庫定義*/
#include <string.h>
#include <stdint.h>
#include <time.h>

#include <unistd.h>
#include <sys/time.h>
#include <sys/timeb.h>

#include "../Define/define.h"
#include "../ShareMemory/shmMem.h"
#include "../Config.h"
#include "../Log/log.h"
#include "Module_InternalComm.h"
#include "internalComm.h"

//------------------------------------------------------------------------------
static struct SysConfigData *pSysConfig = NULL;
static struct SysInfoData *pSysInfo = NULL;
static struct WARNING_CODE_INFO *pSysWarning = NULL;
static struct AlarmCodeData *pAlarmCode = NULL;
static struct LedModuleData *ShmLedModuleData = NULL;

static int Uart5Fd = 0;

static Led_Color cur_led_color = {COLOR_MIN_LV};
static Led_Color led_color;

static struct timeval _led_priority_time;

//------------------------------------------------------------------------------
static bool IsNoneMatchLedColor(void)
{
    bool result = false;

    if (cur_led_color.Connect_1_Red != led_color.Connect_1_Red ||
            cur_led_color.Connect_1_Green != led_color.Connect_1_Green ||
            cur_led_color.Connect_1_Blue != led_color.Connect_1_Blue ||
            cur_led_color.Connect_2_Red != led_color.Connect_2_Red ||
            cur_led_color.Connect_2_Green != led_color.Connect_2_Green ||
            cur_led_color.Connect_2_Blue != led_color.Connect_2_Blue) {
        result = true;
    }

    return result;
}

//static void SetLedColor(struct ChargingInfoData *chargingData_1, struct ChargingInfoData *chargingData_2)
static void SetLedColor(void)
{
    static uint8_t _checkLedChanged = 3;
    struct ChargingInfoData *chargingData_1 = NULL;
    struct ChargingInfoData *chargingData_2 = NULL;
    uint8_t _colorBuf = COLOR_MAX_LV * LED_INTENSITY_BRIGHTEST;

    if (pSysConfig->TotalConnectorCount == 1) {
        chargingData_1 = (struct ChargingInfoData *)GetDcChargingInfoData(0);
        chargingData_2 = (struct ChargingInfoData *)GetDcChargingInfoData(0);
    } else if (pSysConfig->TotalConnectorCount == 2) {
        chargingData_1 = (struct ChargingInfoData *)GetDcChargingInfoData(0);
        chargingData_2 = (struct ChargingInfoData *)GetDcChargingInfoData(1);
    }

    if (pSysConfig->LedInfo.Intensity == _LED_INTENSITY_DARKEST) {
        _colorBuf = COLOR_MAX_LV * LED_INTENSITY_DARKEST;
    } else if (pSysConfig->LedInfo.Intensity == _LED_INTENSITY_MEDIUM) {
        _colorBuf = COLOR_MAX_LV * LED_INTENSITY_MEDIUM;
    }

    //printf("chargingData_1->SystemStatus=%d\n",chargingData_1->SystemStatus);
    //printf("chargingData_2->SystemStatus=%d\n",chargingData_2->SystemStatus);
    //printf("pSysWarning->Level=%d\n",pSysWarning->Level);
    if (pSysWarning->Level == 2) {
        led_color.Connect_1_Green = COLOR_MIN_LV;
        led_color.Connect_1_Blue = COLOR_MIN_LV;
        led_color.Connect_1_Red = _colorBuf;
        led_color.Connect_2_Green = COLOR_MIN_LV;
        led_color.Connect_2_Blue = COLOR_MIN_LV;
        led_color.Connect_2_Red = _colorBuf;
    } else {
        if (pSysInfo->IsAlternatvieConf) {
            if ((chargingData_1->SystemStatus == S_BOOTING ||
                    chargingData_1->SystemStatus == S_IDLE ||
                    chargingData_1->SystemStatus == S_RESERVATION) &&
                    (chargingData_2->SystemStatus == S_BOOTING ||
                     chargingData_2->SystemStatus == S_IDLE ||
                     chargingData_2->SystemStatus == S_RESERVATION)) {
#if defined DD360Audi
                led_color.Connect_1_Green = _colorBuf;
                led_color.Connect_1_Blue = _colorBuf;
                led_color.Connect_1_Red = _colorBuf;

                led_color.Connect_2_Green = _colorBuf;
                led_color.Connect_2_Blue = _colorBuf;
                led_color.Connect_2_Red = _colorBuf;
#else
                led_color.Connect_1_Green = _colorBuf;
                led_color.Connect_1_Blue = COLOR_MIN_LV;
                led_color.Connect_1_Red = COLOR_MIN_LV;

                led_color.Connect_2_Green = _colorBuf;
                led_color.Connect_2_Blue = COLOR_MIN_LV;
                led_color.Connect_2_Red = COLOR_MIN_LV;
#endif
            } else if ((chargingData_1->SystemStatus >= S_AUTHORIZING &&
                        chargingData_1->SystemStatus <= S_COMPLETE) ||
                       (chargingData_1->SystemStatus >= S_CCS_PRECHARGE_ST0 &&
                        chargingData_1->SystemStatus <= S_CCS_PRECHARGE_ST1) ||
                       (chargingData_2->SystemStatus >= S_AUTHORIZING &&
                        chargingData_2->SystemStatus <= S_COMPLETE) ||
                       (chargingData_2->SystemStatus >= S_CCS_PRECHARGE_ST0 &&
                        chargingData_2->SystemStatus <= S_CCS_PRECHARGE_ST1)) {
                led_color.Connect_1_Green = COLOR_MIN_LV;
                led_color.Connect_1_Blue = _colorBuf;
                led_color.Connect_1_Red = COLOR_MIN_LV;
                led_color.Connect_2_Green = COLOR_MIN_LV;
                led_color.Connect_2_Blue = _colorBuf;
                led_color.Connect_2_Red = COLOR_MIN_LV;
            } else if ( chargingData_1->SystemStatus == S_UPDATE ||
                    chargingData_2->SystemStatus == S_UPDATE ) {
                led_color.Connect_1_Green = COLOR_MIN_LV;
                led_color.Connect_1_Blue = COLOR_MIN_LV;
                led_color.Connect_1_Red = _colorBuf;
                led_color.Connect_2_Green = COLOR_MIN_LV;
                led_color.Connect_2_Blue = COLOR_MIN_LV;
                led_color.Connect_2_Red = _colorBuf;
            }
        } else {

            // 實際操作
            if (chargingData_1->SystemStatus == S_BOOTING ||
                    chargingData_1->SystemStatus == S_IDLE ||
                    chargingData_1->SystemStatus == S_MAINTAIN) {

                if (chargingData_1->IsAvailable == NO) { //For Audi
                    led_color.Connect_1_Green = COLOR_MIN_LV;
                    led_color.Connect_1_Blue = COLOR_MIN_LV;
                    led_color.Connect_1_Red = _colorBuf;
                } else {
#if defined DD360Audi
                    led_color.Connect_1_Green = _colorBuf;
                    led_color.Connect_1_Blue = _colorBuf;
                    led_color.Connect_1_Red = _colorBuf;
#else
                    led_color.Connect_1_Green = _colorBuf;
                    led_color.Connect_1_Blue = COLOR_MIN_LV;
                    led_color.Connect_1_Red = COLOR_MIN_LV;
#endif
                }
            } else if ((chargingData_1->SystemStatus >= S_AUTHORIZING &&
                        chargingData_1->SystemStatus <= S_COMPLETE) ||
                       (chargingData_1->SystemStatus >= S_CCS_PRECHARGE_ST0 &&
                        chargingData_1->SystemStatus <= S_CCS_PRECHARGE_ST1)) {
                led_color.Connect_1_Green = COLOR_MIN_LV;
                led_color.Connect_1_Blue = _colorBuf;
                led_color.Connect_1_Red = COLOR_MIN_LV;
            } else if ( chargingData_1->SystemStatus == S_UPDATE ) {
                led_color.Connect_1_Green = COLOR_MIN_LV;
                led_color.Connect_1_Blue = COLOR_MIN_LV;
                led_color.Connect_1_Red = _colorBuf;
            } else if (chargingData_1->SystemStatus == S_RESERVATION) {

            }

            // --------------------------------------------------------------------------
            if (chargingData_2->SystemStatus == S_BOOTING ||
                    chargingData_2->SystemStatus == S_IDLE ||
                    chargingData_2->SystemStatus == S_RESERVATION ||
                    chargingData_2->SystemStatus == S_MAINTAIN) {
                if (chargingData_2->IsAvailable == NO) {
                    led_color.Connect_2_Green = COLOR_MIN_LV;
                    led_color.Connect_2_Blue = COLOR_MIN_LV;
                    led_color.Connect_2_Red = _colorBuf;
                } else {
#if defined DD360Audi
                    led_color.Connect_2_Green = _colorBuf;
                    led_color.Connect_2_Blue = _colorBuf;
                    led_color.Connect_2_Red = _colorBuf;
#else
                    led_color.Connect_2_Green = _colorBuf;
                    led_color.Connect_2_Blue = COLOR_MIN_LV;
                    led_color.Connect_2_Red = COLOR_MIN_LV;
#endif
                }
            } else if ((chargingData_2->SystemStatus >= S_AUTHORIZING &&
                        chargingData_2->SystemStatus <= S_COMPLETE) ||
                       (chargingData_2->SystemStatus >= S_CCS_PRECHARGE_ST0 &&
                        chargingData_2->SystemStatus <= S_CCS_PRECHARGE_ST1)) {
                led_color.Connect_2_Green = COLOR_MIN_LV;
                led_color.Connect_2_Blue = _colorBuf;
                led_color.Connect_2_Red = COLOR_MIN_LV;
            } else if ( chargingData_2->SystemStatus == S_UPDATE ) {
                led_color.Connect_2_Green = COLOR_MIN_LV;
                led_color.Connect_2_Blue = COLOR_MIN_LV;
                led_color.Connect_2_Red = _colorBuf;
            } else if (chargingData_2->SystemStatus == S_RESERVATION) {

            }

        }
    }

    if (_checkLedChanged > 0) {
        if (Config_Led_Color(Uart5Fd, ADDR_LED, &led_color,2) == PASS) {
            _checkLedChanged--;

            cur_led_color.Connect_1_Red     = led_color.Connect_1_Red;
            cur_led_color.Connect_1_Green   = led_color.Connect_1_Green;
            cur_led_color.Connect_1_Blue    = led_color.Connect_1_Blue;
            cur_led_color.Connect_2_Red     = led_color.Connect_2_Red;
            cur_led_color.Connect_2_Green   = led_color.Connect_2_Green;
            cur_led_color.Connect_2_Blue    = led_color.Connect_2_Blue;
        }
    } else if (IsNoneMatchLedColor()) {
        _checkLedChanged = 3;
    }
}

static void GetFwAndHwVersion_Led(void)
{
    Ver ver = {0};

    if (Query_FW_Ver(Uart5Fd, ADDR_LED, &ver) == PASS) {
        // LedModuleData
        strcpy((char *) ShmLedModuleData->version, ver.Version_FW);
        // SystemInfo
        strcpy((char *) pSysInfo->LedModuleFwRev, ver.Version_FW);
        log_info("GetFwAndHwVersion_Led s1 = %s \n", ver.Version_FW);
        ShmLedModuleData->SelfTest_Comp = YES;
    } else {
        //log_info("GetFwAndHwVersion_Led fail \n");
    }

//  if (Query_HW_Ver(Uart5Fd, ADDR_LED, &ver) == PASS)
//  {
//      // SystemInfo
//      strcpy((char *) pSysInfo->RelayModuleHwRev, ver.Version_FW);
//      //log_info("GetFwAndHwVersion_Relay s2 = %s \n", ver.Version_HW);
//  }
}

static void LEDBoardProcess(void)
{
    //struct ChargingInfoData *pDcChargingInfo0 = NULL;
    //struct ChargingInfoData *pDcChargingInfo1 = NULL;

    if (ShmLedModuleData->SelfTest_Comp == NO) {
        return;
    }

    if (GetTimeoutValue(_led_priority_time) / 1000 >= 1000) {

        //if (pSysConfig->TotalConnectorCount == 1) {
        //    pDcChargingInfo0 = (struct ChargeingInfoData *)GetDcChargingInfoData(0);
        //    SetLedColor(pDcChargingInfo0, pDcChargingInfo0);
        //} else if (pSysConfig->TotalConnectorCount == 2) {
        //    pDcChargingInfo0 = (struct ChargeingInfoData *)GetDcChargingInfoData(0);
        //    pDcChargingInfo1 = (struct ChargeingInfoData *)GetDcChargingInfoData(1);
        //    SetLedColor(pDcChargingInfo0, pDcChargingInfo1);
        //}
        SetLedColor();
        gettimeofday(&_led_priority_time, NULL);
    }
}

static void LEDBoardSelfTest(void)
{
    // 自檢階段處理,自檢階段如果讀不到版號則代表該系統沒有掛燈板
    if (ShmLedModuleData->SelfTest_Comp == YES) {
        return;
    }

#if defined DD360 ||defined DD360Audi
    GetFwAndHwVersion_Led();
    sleep(1);
    gettimeofday(&_led_priority_time, NULL);

    return;
#endif //defined DD360 || defined DD360Audi

    // 自檢階段
    if (pSysInfo->SelfTestSeq <= _STEST_PSU_CAP) {
        GetFwAndHwVersion_Led();
        sleep(1);
        gettimeofday(&_led_priority_time, NULL);
    } else {
        // 自檢階段沒有問到版號
        if (pAlarmCode->AlarmEvents.bits.LedboardStestFail == NO) {
            pAlarmCode->AlarmEvents.bits.LedboardStestFail = YES;
        }
    }
}

void LEDBoardTask(int uartFD)
{
#if defined DD360ComBox
    return;
#endif //defined DD360ComBox

    pid_t pid = fork();

    if (pid == 0) {
        int isContinue = 1;

        pSysConfig = (struct SysConfigData *)GetShmSysConfigData();
        pSysInfo = (struct SysInfoData *)GetShmSysInfoData();
        pSysWarning = (struct WARNING_CODE_INFO *)GetShmSysWarningInfo();

        pAlarmCode = (struct AlarmCodeData *)GetShmAlarmCodeData();
        ShmLedModuleData = (struct LedModuleData *)GetShmLedModuleData();
        Uart5Fd = uartFD;

        while (isContinue) {
            LEDBoardSelfTest();
            LEDBoardProcess();
            usleep(100000);
        }
    }
}