#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 "main.h"
#include "../timeout.h"

//------------------------------------------------------------------------------
extern void ChkPrimaryStatus(void);

//------------------------------------------------------------------------------
void SelfTestRun(void)
{
    bool evInitFlag = false;
    uint8_t index = 0;
    struct SysConfigData *pSysConfig = (struct SysConfigData *)GetShmSysConfigData();
    struct SysInfoData *pSysInfo = (struct SysInfoData *)GetShmSysInfoData();
    struct WARNING_CODE_INFO *pSysWarning = (struct WARNING_CODE_INFO *)GetShmSysWarningInfo();

    struct PsuData *ShmPsuData = (struct PsuData *)GetShmPsuData();
    struct CHAdeMOData *ShmCHAdeMOData = (struct CHAdeMOData *)GetShmCHAdeMOData();
    struct GBTData *ShmGBTData = (struct GBTData *)GetShmGBTData();
    struct CcsData *ShmCcsData = (struct CcsData *)GetShmCcsData();

    struct PrimaryMcuData *ShmPrimaryMcuData = (struct PrimaryMcuData *)GetShmPrimaryMcuData();
    struct FanModuleData *ShmFanModuleData = (struct FanModuleData *)GetShmFanModuleData();
    struct RelayModuleData *ShmRelayModuleData = (struct RelayModuleData *)GetShmRelayModuleData();
    struct ChargingInfoData *pDcChargingInfo = NULL;
    struct ChargingInfoData *pAcChargingInfo = NULL;

    StartSystemTimeoutDet(Timeout_SelftestChk);
    pSysInfo->SelfTestSeq = _STEST_VERSION;

    while (pSysInfo->SelfTestSeq != _STEST_COMPLETE) {
        if (pSysInfo->SelfTestSeq == _STEST_COMPLETE) { //自檢完成
            return;
        }

        ChkPrimaryStatus(); //確認硬體有無錯誤,如急停按鈕或門有打開

        if (pSysWarning->Level == WARN_LV_ER) {
            pSysInfo->SelfTestSeq = _STEST_FAIL;
            return;
        }

        if (pSysConfig->TotalConnectorCount <= 0) {
            pSysInfo->SelfTestSeq = _STEST_FAIL;
            return;
        }

        if (ShmPsuData->Work_Step == _NO_WORKING ||
                pSysInfo->SelfTestSeq == _STEST_FAIL) {
            pSysInfo->SelfTestSeq = _STEST_FAIL;
            return;
        }

        switch (pSysInfo->SelfTestSeq) {
        case _STEST_VERSION:
            if ((strlen((char *)pSysInfo->RelayModuleFwRev) != 0 ||
                    pSysInfo->RelayModuleFwRev[0] != '\0') &&
                    (ShmRelayModuleData->SelfTest_Comp != YES)
               ) {
                log_info("Relay Board FW Rev = %s", pSysInfo->RelayModuleFwRev);
                ShmRelayModuleData->SelfTest_Comp = YES;
            }

#if !defined NO_FAN_BOARD && !defined DD360ComBox
            if ((strlen((char *)pSysInfo->FanModuleFwRev) != 0 ||
                    pSysInfo->FanModuleFwRev[0] != '\0') &&
                    (ShmFanModuleData->SelfTest_Comp != YES)
               ) {
                log_info("Fan Board FW Rev = %s", pSysInfo->FanModuleFwRev);
                ShmFanModuleData->SelfTest_Comp = YES;
            }
#else
            ShmFanModuleData->SelfTest_Comp = YES;
#endif //NO_FAN_BOARD

            if ((strlen((char *)ShmPrimaryMcuData->version) != 0 ||
                    ShmPrimaryMcuData->version[0] != '\0') &&
                    (ShmPrimaryMcuData->SelfTest_Comp != YES)
               ) {
                log_info("Primary FW Rev = %s", pSysInfo->CsuPrimFwRev);
                ShmPrimaryMcuData->SelfTest_Comp = YES;
            }

            // EV 小板
            if (!evInitFlag) {
                evInitFlag = YES;
                for (index = 0; index < pSysConfig->TotalConnectorCount; index++) {
                    pDcChargingInfo = (struct ChargingInfoData *)GetDcChargingInfoData(index);

                    //log_info("index = %d, charging index = %d, type = %d\r\n",
                    //         index,
                    //         chargingInfo[index]->type_index,
                    //         chargingInfo[index]->Type);
                    if (pDcChargingInfo->Type == _Type_Chademo) {
                        if ((strlen((char *)ShmCHAdeMOData->evse[pDcChargingInfo->type_index].version) != 0 ||
                                ShmCHAdeMOData->evse[pDcChargingInfo->type_index].version[0] != '\0')
                                //&& (ShmCHAdeMOData->evse[pDcChargingInfo->type_index].SelfTest_Comp != YES)
                           ) {
                            log_info("CHAdeMO[%d] FW Rev = %s",
                                     pDcChargingInfo->type_index,
                                     ShmCHAdeMOData->evse[pDcChargingInfo->type_index].version);
                            ShmCHAdeMOData->evse[pDcChargingInfo->type_index].SelfTest_Comp = YES;
                        } else {
                            //log_info("chademo fw lose...... %s \n", ShmCHAdeMOData->evse[pDcChargingInfo->type_index].version);
                            evInitFlag = NO;
                        }
                    } else if (pDcChargingInfo->Type == _Type_GB) {
                        if ((strlen((char *)ShmGBTData->evse[pDcChargingInfo->type_index].version) != 0 ||
                                ShmGBTData->evse[pDcChargingInfo->type_index].version[0] != '\0')
                                //&& (ShmGBTData->evse[pDcChargingInfo->type_index].SelfTest_Comp != YES)
                           ) {
                            log_info("GBT[%d] FW Rev = %s",
                                     pDcChargingInfo->type_index,
                                     ShmGBTData->evse[pDcChargingInfo->type_index].version);
                            ShmGBTData->evse[pDcChargingInfo->type_index].SelfTest_Comp = YES;
                        } else {
                            //log_info("GBT fw lose...... %s \n", ShmCHAdeMOData->evse[pDcChargingInfo->type_index].version);
                            evInitFlag = NO;
                        }
                    } else if (pDcChargingInfo->Type == _Type_CCS_2) {
                        if (ShmCcsData->CommProtocol == _CCS_COMM_V2GMessage_DIN70121) {
                            if ((strlen((char *)ShmCcsData->V2GMessage_DIN70121[pDcChargingInfo->type_index].version) != 0 ||
                                    ShmCcsData->V2GMessage_DIN70121[pDcChargingInfo->type_index].version[0] != '\0')
                                    /*&&(ShmCcsData->V2GMessage_DIN70121[pDcChargingInfo->type_index].SelfTest_Comp != YES)*/
                               ) {
                                log_info("CCS[%d] FW Rev = %s",
                                         pDcChargingInfo->type_index,
                                         ShmCcsData->V2GMessage_DIN70121[pDcChargingInfo->type_index].version);
                                ShmCcsData->V2GMessage_DIN70121[pDcChargingInfo->type_index].SelfTest_Comp = YES;
                            } else {
                                //log_info("CCS[%d] ccs fw lose...... %s \n",
                                //         chargingInfo[index]->type_index,
                                //         ShmCcsData->V2GMessage_DIN70121[chargingInfo[index]->type_index].version);
                                evInitFlag = NO;
                            }
                        }
                    }
                }

                for (index = 0; index < pSysConfig->AcConnectorCount; index++) {
                    pAcChargingInfo = (struct ChargingInfoData *)GetAcChargingInfoData(index);

                    if (pAcChargingInfo->Type == _Type_AC) {
                        if ((strlen((char *)pAcChargingInfo->version) != 0 ||
                                pAcChargingInfo->version[0] != '\0')
                                && (pAcChargingInfo->SelfTest_Comp != YES)
                           ) {
                            log_info("AC connector[%d] FW Rev = %s", index, pAcChargingInfo->version);
                            pAcChargingInfo->SelfTest_Comp = YES;
                        } else {
                            evInitFlag = NO;
                        }
                    }
                }
            }

            if (ShmFanModuleData->SelfTest_Comp &&
                    ShmRelayModuleData->SelfTest_Comp &&
                    ShmPrimaryMcuData->SelfTest_Comp &&
                    evInitFlag
               ) {
                pSysInfo->SelfTestSeq = _STEST_AC_CONTACTOR;
            }
            break;

        case _STEST_AC_CONTACTOR:
            //ShmPsuData->Work_Step = _TEST_COMPLETE;
            // 因為 30KW 以下沒有 Relay feedback 功能,所以暫時先直接跳過
#if defined DD360 || defined DD360Audi || defined DD360ComBox
            pSysInfo->SelfTestSeq = _STEST_PSU_DETECT;
            log_info("Waiting for DO communication");
            break;
#endif //defined DD360 || defined DD360Audi || defined DD360ComBox

            if (pSysInfo->AcContactorStatus == YES) {
                pSysInfo->SelfTestSeq = _STEST_PSU_DETECT;
                log_info("AC contactor self test OK");
            }
            break;

        case _STEST_PSU_DETECT:
#if defined DD360 || defined DD360Audi || defined DD360ComBox
            pSysInfo->SelfTestSeq = _STEST_PSU_CAP;
            break;
#endif //defined DD360 || defined DD360Audi || defined DD360ComBox

            if (ShmPsuData->Work_Step >= GET_SYS_CAP) {
                pSysInfo->SelfTestSeq = _STEST_PSU_CAP;
            }
            break;

        case _STEST_PSU_CAP:
            // 此測試是要確認當前總輸出能力
            // 如果沒有 PSU 模組請 bypass

#if defined DD360 || defined DD360Audi || defined DD360ComBox
            //check the power limit from DO
            pSysInfo->SelfTestSeq = _STEST_COMPLETE;
            pSysInfo->BootingStatus = BOOT_COMPLETE;
            log_info("Successful Self Test");
            break;
#endif //defined DD360 || defined DD360Audi || defined DD360ComBox

            if (ShmPsuData->Work_Step == BOOTING_COMPLETE) {
                sleep(1);
                pSysInfo->SelfTestSeq = _STEST_COMPLETE;
                pSysInfo->BootingStatus = BOOT_COMPLETE;
            }
            break;
        }

        usleep(100000);
    }
}