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

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

#include "../SelectGun/SelectGun.h"
#include "main.h"

//------------------------------------------------------------------------------
typedef struct StLedConfig {
    //OutputDrvValue[0]
    uint8_t LeftButtonLed: 1;                   //bit 0,    H: ON,      L:OFF
    uint8_t RightButtonLed: 1;                  //bit 1,    H: ON,      L:OFF
    uint8_t GreenLED: 1;                        //bit 2,    H: ON,      L:OFF
    uint8_t YellowLED: 1;                       //bit 3,    H: ON,      L:OFF
    uint8_t RedLED: 1;                          //bit 4,    H: ON,      L:OFF
    uint8_t SystemLed4: 1;                      //bit 5,    H: ON,      L:OFF
    uint8_t AcContactor: 1;                     //bit 6,    H: ON,      L:OFF
    uint8_t Reserved: 1;                        //bit 7 reserved
} LedConfig;
time_t showInfoTimer;
//------------------------------------------------------------------------------
static uint8_t checkCabinetEthConnectState(LedConfig *ledConfig)
{
    uint8_t ret = NO;
    LedConfig *pLedConfig = (LedConfig *)ledConfig;
    struct AlarmCodeData *pAlarmCode = (struct AlarmCodeData *)GetShmAlarmCodeData();

    if (pAlarmCode->AlarmEvents.bits.DisconnectedFromDo == YES) {
        ret = YES;
        if (pLedConfig->RedLED == YES ||
                pLedConfig->YellowLED == YES ||
                pLedConfig->GreenLED == YES) {
            pLedConfig->RedLED = NO;
            pLedConfig->YellowLED = NO;
            pLedConfig->GreenLED = NO;
        } else {
            pLedConfig->RedLED = YES;
            pLedConfig->YellowLED = YES;
            pLedConfig->GreenLED = YES;
        }
    }

    return ret;
}

void PrimaryLedIndicatorCtrlFork(void)
{
#if !defined DD360ComBox
    return;
#endif //!defined DD360ComBox

    pid_t pid = fork();
    if (pid == 0) {
        uint8_t gunIndex = 0;
        int isContinue = 1;
        log_info("Primary Fork Child's PID is %d", getpid());
        struct SysConfigData *pSysConfig = (struct SysConfigData *)GetShmSysConfigData();
        struct SysInfoData *pSysInfo = (struct SysInfoData *)GetShmSysInfoData();
        struct WARNING_CODE_INFO *pSysWarning = (struct WARNING_CODE_INFO *)GetShmSysWarningInfo();
        struct PrimaryMcuData *ShmPrimaryMcuData = (struct PrimaryMcuData *)GetShmPrimaryMcuData();
        struct ChargingInfoData *pDcChargingInfo = NULL;

        LedConfig *pLedConfig = (LedConfig *)&ShmPrimaryMcuData->OutputDrv.OutputDrvValue[0];

        while (isContinue) {
            for (gunIndex = 0; gunIndex < pSysConfig->TotalConnectorCount; gunIndex++) {
                pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(gunIndex);

                if (pSysWarning->Level == WARN_LV_ER) {
                    if (checkCabinetEthConnectState(pLedConfig) == YES) {
                        usleep(500000);
                        continue;
                    }

                    pLedConfig->YellowLED = NO;
                    pLedConfig->GreenLED = NO;
                    pLedConfig->RedLED = YES;
                    usleep(500000);
                    continue;
                }

                //log_info("led indicator status = %d", pDcChargingInfo->SystemStatus);
                //printf("level = %d", pSysWarning->Level);
                switch (pDcChargingInfo->SystemStatus) {
                case S_BOOTING:
                    if (pSysInfo->SelfTestSeq == _STEST_COMPLETE) {
                        //Module_DoComm tcp disconnect
                        if (pLedConfig->RedLED == YES ||
                                pLedConfig->YellowLED == YES ||
                                pLedConfig->GreenLED == YES) {
                            pLedConfig->RedLED = NO;
                            pLedConfig->YellowLED = NO;
                            pLedConfig->GreenLED = NO;
                        } else {
                            pLedConfig->RedLED = YES;
                            pLedConfig->YellowLED = YES;
                            pLedConfig->GreenLED = YES;
                        }
                        break;
                    }

                    pLedConfig->RedLED = YES;
                    pLedConfig->YellowLED = YES;
                    pLedConfig->GreenLED = YES;
                    break;

                case S_IDLE:
                    //Module_DoComm connected and system idle
                    pLedConfig->RedLED = NO;
                    pLedConfig->YellowLED = NO;
                    pLedConfig->GreenLED = YES;
                    break;

                case S_RESERVATION:
                case S_AUTHORIZING:
                case S_REASSIGN_CHECK:
                case S_REASSIGN:
                case S_PREPARNING:
                case S_PREPARING_FOR_EV:
                case S_PREPARING_FOR_EVSE:
                case S_CCS_PRECHARGE_ST0:
                case S_CCS_PRECHARGE_ST1:
                    //precharging status
                    if (pLedConfig->GreenLED == YES) {
                        pLedConfig->GreenLED = NO;
                    } else {
                        pLedConfig->GreenLED = YES;
                    }
                    break;

                case S_CHARGING:
                    pLedConfig->RedLED = NO;
#ifdef DD360ComBox
                    pLedConfig->YellowLED = YES;
#else
                    if (pLedConfig->YellowLED == YES) {
                        pLedConfig->YellowLED = NO;
                    } else {
                        pLedConfig->YellowLED = YES;
                    }
#endif
                    pLedConfig->GreenLED = NO;
                    break;

                case S_ALARM:
                    pLedConfig->YellowLED = NO;
                    pLedConfig->GreenLED = NO;

                    if (checkCabinetEthConnectState(pLedConfig) == YES) {
                        break;
                    }

                    pLedConfig->RedLED = YES;
                    break;

                case S_TERMINATING:
                case S_COMPLETE:
                    //if (pSysWarning->Level == WARN_LV_ER) {
                    //    pLedConfig->YellowLED = NO;
                    //    pLedConfig->GreenLED = NO;
                    //    if (checkCabinetEthConnectState(pLedConfig) == YES) {
                    //        break;
                    //    }
                    //    pLedConfig->RedLED = YES;
                    //} else {
                    pLedConfig->RedLED = NO;
#ifdef DD360ComBox
                    if (pLedConfig->YellowLED == YES) {
                        pLedConfig->YellowLED = NO;
                    } else {
                        pLedConfig->YellowLED = YES;
                    }
#else
                        pLedConfig->YellowLED = YES;
#endif
                    pLedConfig->GreenLED = NO;
                    //}
                    break;

                case S_MAINTAIN:
                case S_FAULT:
                case S_UPDATE:
                    pLedConfig->YellowLED = NO;
                    pLedConfig->GreenLED = NO;
                    pLedConfig->RedLED = YES;
                    //if (pSysWarning->Level == WARN_LV_ER) {
                    //    if (checkCabinetEthConnectState(pLedConfig) == YES) {
                    //        break;
                    //    }
                    //    pLedConfig->RedLED = YES;
                    //}
                    break;

                case S_BOOKING:
                case S_DEBUG:
                case S_NONE:
                    break;
                }//switch
            }//for
            usleep(500000);
        }//while
    }//fork
}

//------------------------------------------------------------------------------
static void checkChargingInfoByDC(uint8_t systemStatus)
{
    struct SysConfigData *pSysConfig = (struct SysConfigData *)GetShmSysConfigData();
    struct SysInfoData *pSysInfo = (struct SysInfoData *)GetShmSysInfoData();
    struct ChargingInfoData *pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(pSysInfo->CurGunSelected);

    switch (systemStatus) {
    case S_IDLE:
    case S_RESERVATION:
        if (isDetectPlugin(pSysInfo->CurGunSelected)) {
            _DetectPlugInTimeout(pSysInfo->CurGunSelected);
            destroySelGun(pSysInfo->CurGunSelected);
            
        } else {
            if( pSysConfig->isAuthrizeByEVCCID && pSysInfo->ConnectorPage == _LCM_PRE_CHARGE) {
                _evccidlinktimeout(pSysInfo->CurGunSelected);
                pDcChargingInfo->isEVCCIDVerify = true;
                break;
            }
#if !defined DD360Audi
            break;
#endif //!defined DD360Audi

            if (getConfirmSelectedGun(pSysInfo->CurGunSelected) == PASS) {
                //printf("destroy gun = %d", pSysInfo->CurGunSelected);
                destroySelGun(pSysInfo->CurGunSelected);
            } else {
                confirmSelGun(pSysInfo->CurGunSelected);
                log_info("confirm select gun ............................... %d ",
                         pSysInfo->CurGunSelected);
            }
        }
        break;

    case S_REASSIGN_CHECK:
    case S_REASSIGN:
    case S_PREPARNING:
    case S_PREPARING_FOR_EV:
    case S_PREPARING_FOR_EVSE:
    case S_CCS_PRECHARGE_ST0:
    case S_CCS_PRECHARGE_ST1:
        // 取消充電
        if (pSysInfo->CurGunSelectedByAc != NO_DEFINE) {
            AcChargingTerminalProcess();
        } else {
            ChargingTerminalProcess(pSysInfo->CurGunSelected);
        }
        break;

    case S_CHARGING:
        if (pSysConfig->StopChargingByButton == YES ||
                pSysConfig->AuthorisationMode == AUTH_MODE_DISABLE ||
                pSysConfig->isAuthrizeByEVCCID) {
            // 停止充電
            ChargingTerminalProcess(pSysInfo->CurGunSelected);
        }
        break;

    case S_COMPLETE:
        break;
    }
}

void ChkPrimaryStatus(void)
{
    static bool leftBtnPush = false;
    static bool rightBtnPush = false;
    uint8_t i = 0;
    uint8_t Rtn = 0;
    uint8_t _setGun = 0;
    struct SysConfigData *pSysConfig = (struct SysConfigData *)GetShmSysConfigData();
    struct SysInfoData *pSysInfo = (struct SysInfoData *)GetShmSysInfoData();
    struct WARNING_CODE_INFO *pSysWarning = (struct WARNING_CODE_INFO *)GetShmSysWarningInfo();
    struct PrimaryMcuData *ShmPrimaryMcuData = (struct PrimaryMcuData *)GetShmPrimaryMcuData();
    struct AlarmCodeData *pAlarmCode = (struct AlarmCodeData *)GetShmAlarmCodeData();
    struct ChargingInfoData *pDcChargingInfo = NULL;
    DcCommonInfo *ShmDcCommonData = (DcCommonInfo *)GetShmDcCommonData();

    if (pSysWarning->WarningCount > 0) {
        Rtn = 0;
        for (i = 0; i < pSysWarning->WarningCount; i++) {
            if (memcmp(&pSysWarning->WarningCode[i][0], "042251", 6) == 0) {
                EmcOccureByString("042251");
                ShmDcCommonData->PowerAlarmState.StatusBit.EmergencyStop = YES;
                Rtn = 1;
            } else if (memcmp(&pSysWarning->WarningCode[i][0], "042252", 6) == 0) {
                ShmDcCommonData->PowerAlarmState.StatusBit.DoorOpen = YES;
                EmcOccureByString("042252");
                Rtn = 1;
            } else if (memcmp(&pSysWarning->WarningCode[i][0], "042327", 6) == 0) {
                ShmDcCommonData->PowerAlarmState.StatusBit.DcInputOVP = YES;
                EmcOccureByString("042327");
                Rtn = 1;
            } else if (memcmp(&pSysWarning->WarningCode[i][0], "042328", 6) == 0) {
                ShmDcCommonData->PowerAlarmState.StatusBit.DcInputUVP = YES;
                EmcOccureByString("042328");
                Rtn = 1;
            } else if (memcmp(&pSysWarning->WarningCode[i][0], "042200", 6) == 0) {
                ShmDcCommonData->PowerAlarmState.StatusBit.SystemL1InputOVP = YES;
                EmcOccureByString("042200");
                Rtn = 1;
            } else if (memcmp(&pSysWarning->WarningCode[i][0], "042201", 6) == 0) {
                ShmDcCommonData->PowerAlarmState.StatusBit.SystemL2InputOVP = YES;
                EmcOccureByString("042201");
                Rtn = 1;
            } else if (memcmp(&pSysWarning->WarningCode[i][0], "042202", 6) == 0) {
                ShmDcCommonData->PowerAlarmState.StatusBit.SystemL3InputOVP = YES;
                EmcOccureByString("042202");
                Rtn = 1;
            } else if (memcmp(&pSysWarning->WarningCode[i][0], "042267", 6) == 0) {
                ShmDcCommonData->PowerAlarmState.StatusBit.PsuFailure = YES;
                EmcOccureByString("042267");
                Rtn = 1;
            } else if (memcmp(&pSysWarning->WarningCode[i][0], "012304", 6) == 0) {
                EmcOccureByString("012304");
                Rtn = 1;
            }
        }

        if (Rtn == 0) {
            ShmDcCommonData->PowerAlarmState.StatusBit.EmergencyStop = NO;
            ShmDcCommonData->PowerAlarmState.StatusBit.DoorOpen = NO;
            ShmDcCommonData->PowerAlarmState.StatusBit.DcInputOVP = NO;
            ShmDcCommonData->PowerAlarmState.StatusBit.DcInputUVP = NO;
            ShmDcCommonData->PowerAlarmState.StatusBit.SystemL1InputOVP = NO;
            ShmDcCommonData->PowerAlarmState.StatusBit.SystemL2InputOVP = NO;
            ShmDcCommonData->PowerAlarmState.StatusBit.SystemL3InputOVP = NO;
            ShmDcCommonData->PowerAlarmState.StatusBit.PsuFailure = NO;
            ReleaseEmsOccureByString(0, "042251");
            ReleaseEmsOccureByString(0, "042252");
            ReleaseEmsOccureByString(0, "042327");
            ReleaseEmsOccureByString(0, "042328");
            ReleaseEmsOccureByString(0, "042200");
            ReleaseEmsOccureByString(0, "042201");
            ReleaseEmsOccureByString(0, "042202");
            ReleaseEmsOccureByString(0, "042267");
            ReleaseEmsOccureByString(0, "012304");
        }
    } else {
        ShmDcCommonData->PowerAlarmState.StatusBit.EmergencyStop = NO;
        ShmDcCommonData->PowerAlarmState.StatusBit.DoorOpen = NO;
        ShmDcCommonData->PowerAlarmState.StatusBit.DcInputOVP = NO;
        ShmDcCommonData->PowerAlarmState.StatusBit.DcInputUVP = NO;
        ShmDcCommonData->PowerAlarmState.StatusBit.SystemL1InputOVP = NO;
        ShmDcCommonData->PowerAlarmState.StatusBit.SystemL2InputOVP = NO;
        ShmDcCommonData->PowerAlarmState.StatusBit.SystemL3InputOVP = NO;
        ShmDcCommonData->PowerAlarmState.StatusBit.PsuFailure = NO;
        ReleaseEmsOccureByString(0, "042251");
        ReleaseEmsOccureByString(0, "042252");
        ReleaseEmsOccureByString(0, "042327");
        ReleaseEmsOccureByString(0, "042328");
        ReleaseEmsOccureByString(0, "042200");
        ReleaseEmsOccureByString(0, "042201");
        ReleaseEmsOccureByString(0, "042202");
        ReleaseEmsOccureByString(0, "042267");
        ReleaseEmsOccureByString(0, "012304");
    }

    if (ShmPrimaryMcuData->InputDet.bits.EmergencyButton == ABNORMAL) {
        pAlarmCode->AlarmEvents.bits.EmergencyStopTrip = YES;
        EmcOccureByString("012251");
    } else {
        ReleaseEmsOccureByString(0, "012251");
    }

    if (ShmPrimaryMcuData->InputDet.bits.Ac_Drop == ABNORMAL) {
        pAlarmCode->AlarmEvents.bits.ChillerAlarmFail = YES;
        EmcOccureByString("012348");
    } else {
        ReleaseEmsOccureByString(0, "012348");
    }
    
    if (ShmPrimaryMcuData->InputDet.bits.AcMainBreakerDetec == ABNORMAL) {
        pAlarmCode->AlarmEvents.bits.MainPowerBreakerTrip = YES;
        EmcOccureByString("012238");
    } else {
        ReleaseEmsOccureByString(0, "012238");
    }

    if (ShmPrimaryMcuData->InputDet.bits.SpdDetec == ABNORMAL) {
        pAlarmCode->AlarmEvents.bits.SpdTrip = YES;
    } else {
        pAlarmCode->AlarmEvents.bits.SpdTrip = NO;
    }

    if (ShmPrimaryMcuData->InputDet.bits.DoorOpen == ABNORMAL) {
        pAlarmCode->AlarmEvents.bits.DoorOpen = YES;
        EmcOccureByString("012252");
    } else {
        ReleaseEmsOccureByString(0, "012252");
    }

    //DS60-120 add
    if (ShmPrimaryMcuData->InputDet.bits.Button1 == BTN_PRESS &&
            ShmPrimaryMcuData->InputDet.bits.Button2 == BTN_PRESS) {
        pSysConfig->ShowInformation = YES;
        showInfoTimer = time((time_t*)NULL);
    } else {
        if ( (time((time_t*)NULL) - showInfoTimer) > 3 )
            pSysConfig->ShowInformation = NO;
    }

    if (ShmPrimaryMcuData->InputDet.bits.Button1 == BTN_PRESS &&
            !leftBtnPush &&
            pSysInfo->SystemPage != _LCM_AUTHORIZING &&
            pSysInfo->SystemPage != _LCM_AUTHORIZ_COMP &&
            pSysInfo->SystemPage != _LCM_AUTHORIZ_FAIL
       ) {
        pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(pSysInfo->CurGunSelected);

        if (!leftBtnPush) {
            leftBtnPush = true;
            log_info("left btn down...............................%x",
                     pDcChargingInfo->SystemStatus);
            checkChargingInfoByDC(pDcChargingInfo->SystemStatus);
        }
    } else if (ShmPrimaryMcuData->InputDet.bits.Button1 == BTN_RELEASE) {
        if (leftBtnPush) {
            leftBtnPush = false;
            //log_info("left btn up............................... ");
        }
    }
    bool isCharging = false;
    for (uint8_t i = 0; i < pSysConfig->TotalConnectorCount; i++) {
        pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(i);

        if (pDcChargingInfo->SystemStatus == S_IDLE) {
            continue;
        }

        isCharging = true;
        break;
    }
    if (ShmPrimaryMcuData->InputDet.bits.Button2 == BTN_PRESS &&
            !rightBtnPush &&
#if defined DD360Audi
            pSysInfo->SystemPage != _LCM_IDLE &&
            pSysInfo->SystemPage != _LCM_WAIT_FOR_PLUG &&
#endif
            pSysInfo->SystemPage != _LCM_AUTHORIZING &&
            pSysInfo->SystemPage != _LCM_AUTHORIZ_COMP &&
            pSysInfo->SystemPage != _LCM_AUTHORIZ_FAIL
       ) {
        if (!rightBtnPush) {
            if (pSysInfo->SystemPage == _LCM_WAIT_FOR_PLUG && !isCharging) {
                return;
            }
            rightBtnPush = true;
            log_info("right btn down............................... %d ", pSysInfo->CurGunSelected);
            if (pSysInfo->CurGunSelected + 1 < pSysConfig->TotalConnectorCount &&
                    pSysInfo->IsAlternatvieConf == NO) {
                pSysInfo->CurGunSelected++;
                ChangeGunSelectByIndex(pSysInfo->CurGunSelected);
            /*
            } else if (pSysConfig->AcConnectorCount > 0 &&
                       pSysInfo->CurGunSelectedByAc == NO_DEFINE) {
                pSysInfo->CurGunSelectedByAc = DEFAULT_AC_INDEX;
            } else if (pSysInfo->IsAlternatvieConf == YES) {
                for (uint8_t _index = 0; _index < pSysConfig->TotalConnectorCount; _index++) {
                    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(_index);

                    if (pDcChargingInfo->SystemStatus != S_BOOTING &&
                            pDcChargingInfo->SystemStatus != S_IDLE &&
                            pDcChargingInfo->SystemStatus != S_RESERVATION) {
                        pSysInfo->CurGunSelected = _index;
                        ChangeGunSelectByIndex(pSysInfo->CurGunSelected);
                        return;
                    }
                }
                pSysInfo->CurGunSelected = 0;
                ChangeGunSelectByIndex(pSysInfo->CurGunSelected);
                */
            } else {
                pSysInfo->CurGunSelected = 0;
                ChangeGunSelectByIndex(pSysInfo->CurGunSelected);
            }
            //log_info("current select gun ............................... %d ",
            //         pSysInfo->CurGunSelected);
        }

    } else if (ShmPrimaryMcuData->InputDet.bits.Button2 == BTN_RELEASE) {
        if (rightBtnPush) {
            rightBtnPush = false;
            //log_info("right btn up............................... ");
        }
    }
}