/*
 * Module_Authorize.c
 *
 *  Created on: 2021年11月16日
 *      Author: 7978
 */

#include <sys/time.h>
#include <sys/timeb.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <linux/wireless.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#include <unistd.h>
#include <stdarg.h>
#include <stdio.h>      /*標準輸入輸出定義*/
#include <stdlib.h>     /*標準函數庫定義*/
#include <unistd.h>     /*Unix 標準函數定義*/
#include <fcntl.h>      /*檔控制定義*/
#include <termios.h>    /*PPSIX 終端控制定義*/
#include <errno.h>      /*錯誤號定義*/
#include <errno.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <ifaddrs.h>
#include <signal.h>
#include <net/if_arp.h>
#include "../../define.h"
#include "Module_Authorize.h"
#include "Module_EvComm.h"
#include "Config.h"
#include "Common.h"


#define AUTHORIZE_INTERVAL              100000          // unit: 1us
#define AUTHORIZE_WAIT_OCPP_TIMEOUT     30              // unit: 1s
#define SYS_AUTHORIZE_COMP_TIMEOUT      1               // unit: 1s
#define AUTH_TIME_OFFSET_TIME           3               // unit: 1s
#define AUTO_START_CHARGING             "AutoStartCharging"
#define DEFAULT_SN                      "NeedSetupSN"

struct SysConfigAndInfo             *ShmSysConfigAndInfo;
ChargerInfoData                     *ShmChargerInfo;
struct ChargingInfoData             *chargingInfo[GENERAL_GUN_QUANTITY];
struct OCPP16Data                   *ShmOCPP16Data;
struct OCPP20Data                   *ShmOCPP20Data;

struct timespec                     _SysAuth_Time;
struct timespec                     _GunAuth_Time[GENERAL_GUN_QUANTITY];
struct timespec                     _DispenserAuth_Time[GENERAL_GUN_QUANTITY];

unsigned char _preSysAuthStatus = 0;
unsigned char _preGunAuthStatus[GENERAL_GUN_QUANTITY];
unsigned char _preDispenserAuthStatus[GENERAL_GUN_QUANTITY];

//==========================================
// Init all share memory
//==========================================
int InitShareMemory(void)
{
    int result = PASS;
    int MeterSMId;

    //creat ShmSysConfigAndInfo
    if ((MeterSMId = shmget(ShmSysConfigAndInfoKey, sizeof(struct SysConfigAndInfo), 0777)) < 0)
    {
        #ifdef SystemLogMessage
        LOG_ERROR("shmget ShmSysConfigAndInfo NG");
        #endif
        result = FAIL;
    }
    else if ((ShmSysConfigAndInfo = shmat(MeterSMId, NULL, 0)) == (void *) -1)
    {
        #ifdef SystemLogMessage
        LOG_ERROR("shmat ShmSysConfigAndInfo NG");
        #endif
        result = FAIL;
     }
    else
    {

    }

    if ((MeterSMId = shmget(SM_ChargerInfoKey, sizeof(ChargerInfoData), 0777)) < 0)
    {
        #ifdef SystemLogMessage
        LOG_ERROR("shmat ChargerInfoData NG");
        #endif
        result = FAIL;
    }
    else if ((ShmChargerInfo = shmat(MeterSMId, NULL, 0)) == (void *) -1)
    {
        #ifdef SystemLogMessage
        LOG_ERROR("shmat ChargerInfoData NG");
        #endif
        result = FAIL;
    }

    if ((MeterSMId = shmget(ShmOcppModuleKey, sizeof(struct OCPP16Data), 0777)) < 0)
    {
        #ifdef SystemLogMessage
        LOG_ERROR("shmat ShmOCPP16Data NG");
        #endif
        result = FAIL;
    }
    else if ((ShmOCPP16Data = shmat(MeterSMId, NULL, 0)) == (void *) -1)
    {
        LOG_ERROR("shmat ShmOCPP16Data NG");
        result = FAIL;
    }

    if ((MeterSMId = shmget(ShmOcpp20ModuleKey, sizeof(struct OCPP20Data), 0777)) < 0)
    {
        LOG_ERROR("[main]CreatShareMemory:shmget OCPP20Data NG\n");
        result = FAIL;
    }
    else if ((ShmOCPP20Data = shmat(MeterSMId, NULL, 0)) == (void *) -1)
    {
        LOG_ERROR("[main]CreatShareMemory:shmat OCPP20Data NG\n");
        result = FAIL;
    }

    return result;
}

void InitialConnector(void)
{
    for(int i = 0; i < CONNECTOR_QUANTITY; i++)
    {
        chargingInfo[i] = &ShmSysConfigAndInfo->SysInfo.ConnectorInfo[i].GeneralChargingData;
    }
}

void Set_Connector_MiscCommand(int connector, int misc_cmd)
{
    ShmChargerInfo->ConnectorMiscReq[connector].CtrlValue |= misc_cmd;
}

//===============================================
// Ocpp Remote Start
//===============================================
bool Is_Ocpp_RemoteStartReq(int gun_index)
{
    if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16)
    {
        return ShmOCPP16Data->CsMsg.bits[gun_index].RemoteStartTransactionReq == YES ? true : false;
    }
    if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20)
    {
        return ShmOCPP20Data->CsMsg.bits[gun_index].RequestStartTransactionReq == YES ? true : false;
    }
    return false;
}

void Clean_Ocpp_RemoteStartReq(int gun_index)
{
    if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16)
    {
        ShmOCPP16Data->CsMsg.bits[gun_index].RemoteStartTransactionReq = false;
        return;
    }
    if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20)
    {
        ShmOCPP20Data->CsMsg.bits[gun_index].RequestStartTransactionReq = false;
        return;
    }
}

void Get_Ocpp_RemoteStartIdTag(int gun_index, char *idTag)
{
    if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16)
    {
        strcpy(idTag, (char *)&ShmOCPP16Data->RemoteStartTransaction[gun_index].IdTag[0]);
        return;
    }
    if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20)
    {
        strcpy(idTag, (char *)&ShmOCPP20Data->RequestStartTransaction[gun_index].idToken.idToken[0]);
        return;
    }
    strcpy(idTag, "");
}

//===============================================
// Ocpp AuthorizeRemoteTxRequests
//===============================================
bool Is_Ocpp_AuthorizeRemoteTxRequests(void)
{
    if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16)
    {
        return strstr((char *)ShmOCPP16Data->ConfigurationTable.CoreProfile[AuthorizeRemoteTxRequests].ItemData, "TRUE") > 0 ? true : false;
    }
    if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20)
    {
        return strstr((char *)ShmOCPP20Data->ControllerComponentVariable[AuthCtrlr_AuthorizeRemoteStart].variableAttribute[0].value, "TRUE") > 0 ? true : false;
    }
    return false;
}

//===============================================
// Ocpp AuthorizeReq
//===============================================
void Set_Ocpp_AuthorizeReq(void)
{
    if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16)
    {
        ShmOCPP16Data->SpMsg.bits.AuthorizeConf = false;
        ShmOCPP16Data->SpMsg.bits.AuthorizeReq = true;
        return;
    }
    if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20)
    {
        ShmOCPP20Data->SpMsg.bits.AuthorizeConf = false;
        ShmOCPP20Data->SpMsg.bits.AuthorizeReq = true;
        return;
    }
}

bool Is_Ocpp_AuthorizeConf(void)
{
    if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16)
    {
        return ShmOCPP16Data->SpMsg.bits.AuthorizeConf == YES ? true : false;
    }
    if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20)
    {
        return ShmOCPP20Data->SpMsg.bits.AuthorizeConf == YES ? true : false;
    }
    return false;
}

bool Is_Ocpp_Authorize_Status(char *status)
{
    if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16)
    {
        return strcmp((char *)ShmOCPP16Data->Authorize.ResponseIdTagInfo.Status, status) == EQUAL ? true : false;
    }
    if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20)
    {
        return strcmp((char *)ShmOCPP20Data->Authorize.Response_idTokenInfo.status, status) == EQUAL ? true : false;
    }
    return false;
}

//===============================================
// Ocpp Reserve Now
//===============================================
void Get_Ocpp_ReserveNowIdTag(int gun_index, char *idTag)
{
    if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16)
    {
        strcpy(idTag, (char *)ShmOCPP16Data->ReserveNow[gun_index].IdTag);
        return;
    }
    if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20)
    {
        strcpy(idTag, (char *)ShmOCPP20Data->ReserveNow[gun_index].idToken.idToken);
        return;
    }
    strcpy(idTag, "");
    return;
}

bool Is_Ocpp_ReserveNowIdTag(uint8_t gun_index, char *authIdTag)
{
    char ReserveIdTag[32];

    Get_Ocpp_ReserveNowIdTag(gun_index, ReserveIdTag);

    return strcmp(ReserveIdTag, authIdTag) == EQUAL ? true : false;
}

void SetAuthorize(AuthorizingInfoData *AuthInfo, unsigned char type)
{
    memcpy(ShmSysConfigAndInfo->SysConfig.UserId, AuthInfo->AuthId, 32);

    AuthInfo->AuthStatus = _AuthorizeStatus_Busy;
    AuthInfo->AuthType = type;

    ShmSysConfigAndInfo->SysInfo.AuthorizedTarget = AuthInfo->AuthTarget;
    ShmSysConfigAndInfo->SysInfo.AuthorizedType = type;
}

void CheckAutoStartChargingToSNToOcpp(void)
{
    if(strcmp((char *)&ShmSysConfigAndInfo->SysConfig.UserId, AUTO_START_CHARGING) == EQUAL)
    {
        int len = strlen((char *)&ShmSysConfigAndInfo->SysConfig.SerialNumber);
        if(len > 0 && len < sizeof(ShmSysConfigAndInfo->SysConfig.UserId))
        {
            strcpy((char *)&ShmSysConfigAndInfo->SysConfig.UserId, (char *)&ShmSysConfigAndInfo->SysConfig.SerialNumber);
        }
        else
        {
            strcpy((char *)&ShmSysConfigAndInfo->SysConfig.UserId, DEFAULT_SN);
        }
        AUTH_INFO("Received Auto Start Charging IdTag, Set SN [%s] To Authorize", ShmSysConfigAndInfo->SysConfig.UserId);
    }
}

bool IsRemoteStartRequest(int *connector)
{
    AuthorizingInfoData *AuthInfo;

    // remote start check
    for(int index = 0; index < GENERAL_GUN_QUANTITY; index++)
    {
        if(Is_Ocpp_RemoteStartReq(index))
        {
            AuthInfo = &ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].AuthInfo;
            AuthInfo->AuthTarget = index + 1;
            Get_Ocpp_RemoteStartIdTag(index, (char *)AuthInfo->AuthId);

            SetAuthorize(AuthInfo, _AuthType_RemoteStart);
            Clean_Ocpp_RemoteStartReq(index);
            AuthInfo->AuthRequest = NO;
            *connector = index;
            return true;
        }
    }

    return false;
}

bool IsAuthorizingRequest(int *connector)
{
    AuthorizingInfoData *AuthInfo;

    // connector authorize check
    for(int index = 0; index < GENERAL_GUN_QUANTITY; index++)
    {
        AuthInfo = &ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].AuthInfo;
        if(AuthInfo->AuthStatus == _AuthorizeStatus_Idle && AuthInfo->AuthRequest == YES)
        {
            if(strlen((char *)AuthInfo->AuthId) > 0)
            {
                SetAuthorize(AuthInfo, _AuthType_RFID);
                AuthInfo->AuthRequest = NO;
                *connector = index;
                return true;
            }
        }
    }

    return false;
}

bool IsDispenserAuthorizingRequest(int *dispenser)
{
    AuthorizingInfoData *AuthInfo;

    // AUTO_GUN_SELECTION authorize check
    for(int index = 0; index < GENERAL_GUN_QUANTITY; index++)
    {
        AuthInfo = &ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[index].AuthInfo;
        if(AuthInfo->AuthStatus == _AuthorizeStatus_Idle && AuthInfo->AuthRequest == YES)
        {
            if(strlen((char *)AuthInfo->AuthId) > 0)
            {
                SetAuthorize(AuthInfo, _AuthType_RFID);
                AuthInfo->AuthRequest = NO;
                *dispenser = index;
                return true;
            }
        }
    }

    return false;
}

unsigned char Chk_OfflinePolicy(char *idTag)
{
    if(ShmSysConfigAndInfo->SysConfig.OfflinePolicy == _OFFLINE_POLICY_NO_CHARGING)
    {
        AUTH_INFO("*********** Offline Policy [No Charging] ***********");
        return _AuthResult_Invalid;
    }
    else if(ShmSysConfigAndInfo->SysConfig.OfflinePolicy == _OFFLINE_POLICY_FREE_CHARGING)
    {
        // set authorize pass when offline policy is free charge
        AUTH_INFO("*********** Offline Policy [Free Charging] ***********");
        return _AuthResult_Valid;
    }
    else if(ShmSysConfigAndInfo->SysConfig.OfflinePolicy == _OFFLINE_POLICY_LOCAL_LIST)
    {
        BOOL find = false;

        // check white list
        for(int i = 0; i < 10; i++)
        {
            if(strcmp((char *)ShmSysConfigAndInfo->SysConfig.LocalWhiteCard[i], "") != EQUAL)
            {
                if(strcmp((char *)ShmSysConfigAndInfo->SysConfig.LocalWhiteCard[i], idTag) == EQUAL)
                {
                    find = true;
                    AUTH_INFO("***********  [White Card OK] ***********");
                    break;
                }
            }
        }

        if(find == false)
        {
            if((ShmChargerInfo->AuthInfo.AuthMode.bits.AutoStartEnable || ShmSysConfigAndInfo->SysConfig.AuthorisationMode == AUTH_MODE_DISABLE) &&
                strcmp((char *)ShmSysConfigAndInfo->SysConfig.UserId, AUTO_START_CHARGING) == EQUAL)
            {
                find = true;
                AUTH_INFO("******** [Auto Start Charging] ********");
            }
        }

        AUTH_INFO("*********** Local Authorization %s ***********", find ? "OK" : "NG");

        if(find)
        {
            return _AuthResult_Valid;
        }
        else
        {
            return _AuthResult_Invalid;
        }
    }
    else
    {
        AUTH_INFO("*********** [Invalid Policy]   ***********");

        return _AuthResult_Invalid;
    }

    return _AuthResult_Invalid;
}

void SysAuthInitial(void)
{
    memset(ShmSysConfigAndInfo->SysConfig.UserId, 0x00, 32);

    ShmSysConfigAndInfo->SysInfo.AuthorizedDispenser = 0;
    ShmSysConfigAndInfo->SysInfo.AuthorizedTarget = 0;
    ShmSysConfigAndInfo->SysInfo.AuthorizedType = _AuthResult_None;
    ShmSysConfigAndInfo->SysInfo.AuthorizedStatus = _AuthorizeStatus_Idle;
}

void AuthTimeoutProcess(void)
{
    int timeout = 0;

    for(int index = 0; index < GENERAL_GUN_QUANTITY; index++)
    {
        if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].AuthInfo.AuthStatus == _AuthorizeStatus_End)
        {
            if(_preGunAuthStatus[index] != ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].AuthInfo.AuthStatus)
            {
                GetClockTime(&_GunAuth_Time[index]);
            }

            timeout = ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].AuthInfo.AuthStatus == _AuthResult_Valid ?
                ShmChargerInfo->CabinetMiscValue.ConnectionTimeout : AUTHORIZE_COMPLETED_TIME;
            timeout += AUTH_TIME_OFFSET_TIME;

            if(GetTimeoutValue(_GunAuth_Time[index]) / uSEC_VAL >= timeout)
            {
                AUTH_INFO("*********** Gun %d Authorizing Initial ***********", index + 1);
                memset(&ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].AuthInfo, 0x00, sizeof(AuthorizingInfoData));
            }
        }
        _preGunAuthStatus[index] = ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].AuthInfo.AuthStatus;
    }
    for(int index = 0; index < GENERAL_GUN_QUANTITY; index++)
    {
        if(ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[index].AuthInfo.AuthStatus == _AuthorizeStatus_End)
        {
            if(_preDispenserAuthStatus[index] != ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[index].AuthInfo.AuthStatus)
            {
                GetClockTime(&_DispenserAuth_Time[index]);
            }

            timeout = ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[index].AuthInfo.AuthResult == _AuthResult_Valid ?
                ShmChargerInfo->CabinetMiscValue.ConnectionTimeout : AUTHORIZE_COMPLETED_TIME;
            timeout += AUTH_TIME_OFFSET_TIME;

            if(GetTimeoutValue(_DispenserAuth_Time[index]) / uSEC_VAL >= timeout)
            {
                AUTH_INFO("*********** Dispenser %d Authorizing Initial ***********", index + 1);
                memset(&ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[index].AuthInfo, 0x00, sizeof(AuthorizingInfoData));
            }
        }
        _preDispenserAuthStatus[index] = ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[index].AuthInfo.AuthStatus;
    }
}

int main(void)
{
    int _dispenser = 0, _connector = 0;
    unsigned char _authResult = _AuthResult_None;

    bool _autoSelection = false;
    bool _needOcppAuthorize = false;
    bool _keepRun = false;

    if(InitShareMemory() == FAIL)
    {
        #ifdef SystemLogMessage
        LOG_ERROR("InitShareMemory NG");
        #endif

        sleep(5);
        return 0;
    }

    InitialConnector();

    while(1)
    {
        _keepRun = false;
        AuthTimeoutProcess();

        switch(ShmSysConfigAndInfo->SysInfo.AuthorizedStatus)
        {
            case _AuthorizeStatus_Idle:
                if(_preSysAuthStatus != ShmSysConfigAndInfo->SysInfo.AuthorizedStatus)
                {
                    AUTH_INFO("[SysAuthStatus Idle]");
                    _preSysAuthStatus = ShmSysConfigAndInfo->SysInfo.AuthorizedStatus;
                    _authResult = _AuthResult_None;
                    _autoSelection = false;
                }

                if(IsRemoteStartRequest(&_connector))
                {
                    ShmSysConfigAndInfo->SysInfo.AuthorizedStatus = _AuthorizeStatus_Wait;
                    _keepRun = true;
                    AUTH_INFO("Gun %d Remote Start Authorize", _connector + 1);
                    break;
                }
                if(IsAuthorizingRequest(&_connector))
                {
                    ShmSysConfigAndInfo->SysInfo.AuthorizedStatus = _AuthorizeStatus_Wait;
                    _keepRun = true;
                    AUTH_INFO("Gun %d RFID Authorize", _connector + 1);
                    break;
                }
                if(IsDispenserAuthorizingRequest(&_dispenser))
                {
                    _autoSelection = true;
                    ShmSysConfigAndInfo->SysInfo.AuthorizedStatus = _AuthorizeStatus_Wait;
                    _keepRun = true;
                    AUTH_INFO("Dispenser %d AutoSelection Authorize", _dispenser + 1);
                    break;
                }
                break;

            case _AuthorizeStatus_Wait:
                if(_preSysAuthStatus != ShmSysConfigAndInfo->SysInfo.AuthorizedStatus)
                {
                    AUTH_INFO("[SysAuthStatus Wait]");
                    _preSysAuthStatus = ShmSysConfigAndInfo->SysInfo.AuthorizedStatus;
                }
                _needOcppAuthorize = false;

                if(ShmSysConfigAndInfo->SysInfo.AuthorizedType == _AuthType_RemoteStart)
                {
                    if(Is_Ocpp_AuthorizeRemoteTxRequests())
                    {
                        _needOcppAuthorize = true;
                    }
                    else
                    {
                        AUTH_INFO("*********** Gun %d Remote Start Authorizing Bypass ***********",
                            ShmSysConfigAndInfo->SysInfo.AuthorizedTarget);
                        _authResult = _AuthResult_Valid;
                        ShmSysConfigAndInfo->SysInfo.AuthorizedStatus = _AuthorizeStatus_Done;
                        _keepRun = true;
                        break;
                    }
                }
                else if(ShmSysConfigAndInfo->SysInfo.AuthorizedType == _AuthType_RFID)
                {
                    if(ShmSysConfigAndInfo->SysInfo.OcppConnStatus &&
                        ShmSysConfigAndInfo->SysConfig.AuthorisationMode == AUTH_MODE_ENABLE &&
                        !ShmChargerInfo->AuthInfo.AuthMode.bits.AutoStartEnable)
                    {
                        _needOcppAuthorize = true;
                    }
                    else
                    {
                        _authResult = Chk_OfflinePolicy((char *)ShmSysConfigAndInfo->SysConfig.UserId);
                        ShmSysConfigAndInfo->SysInfo.AuthorizedStatus = _AuthorizeStatus_Done;
                        _keepRun = true;
                        break;
                    }
                }

                if(_needOcppAuthorize)
                {
                    CheckAutoStartChargingToSNToOcpp();
                    Set_Ocpp_AuthorizeReq();
                    AUTH_INFO("*********** Set OPCC AuthorizeReq ***********");
                    ShmSysConfigAndInfo->SysInfo.AuthorizedStatus = _AuthorizeStatus_Busy;
                }
                break;

            case _AuthorizeStatus_Busy:
                if(_preSysAuthStatus != ShmSysConfigAndInfo->SysInfo.AuthorizedStatus)
                {
                    AUTH_INFO("[SysAuthStatus Busy]");
                    _preSysAuthStatus = ShmSysConfigAndInfo->SysInfo.AuthorizedStatus;
                    GetClockTime(&_SysAuth_Time);
                }

                if(GetTimeoutValue(_SysAuth_Time) / uSEC_VAL >= AUTHORIZE_WAIT_OCPP_TIMEOUT)
                {
                    AUTH_INFO("*********** Ocpp Authorizing Timeout ***********");
                    _authResult = _AuthResult_Invalid;
                    ShmSysConfigAndInfo->SysInfo.AuthorizedStatus = _AuthorizeStatus_Done;
                    _keepRun = true;
                    break;
                }
                else
                {
                    if(ShmSysConfigAndInfo->SysInfo.OcppConnStatus)
                    {
                        if(Is_Ocpp_AuthorizeConf())
                        {
                            BOOL accept = false;
                            if(Is_Ocpp_Authorize_Status("Accepted"))
                            {
                                accept = true;
                            }

                            AUTH_INFO("*********** OCPP Authorize %s ***********", accept ? "OK" : "NG");
                            _authResult = accept ? _AuthResult_Valid : _AuthResult_Invalid;
                            ShmSysConfigAndInfo->SysInfo.AuthorizedStatus = _AuthorizeStatus_Done;
                            _keepRun = true;
                            break;
                        }
                    }
                    else
                    {
                        AUTH_INFO("*********** OCPP Authorize Disconnected ***********");
                        _authResult = Chk_OfflinePolicy((char *)ShmSysConfigAndInfo->SysConfig.UserId);
                        ShmSysConfigAndInfo->SysInfo.AuthorizedStatus = _AuthorizeStatus_Done;
                        _keepRun = true;
                        break;
                    }
                }
                break;

            case _AuthorizeStatus_Done:
                if(_preSysAuthStatus != ShmSysConfigAndInfo->SysInfo.AuthorizedStatus)
                {
                    AUTH_INFO("[SysAuthStatus Done]");
                    _preSysAuthStatus = ShmSysConfigAndInfo->SysInfo.AuthorizedStatus;
                    GetClockTime(&_SysAuth_Time);
                }

                if(_autoSelection)
                {
                    AUTH_INFO("*********** Dispense %d RFID Authorize %s ***********", _dispenser + 1, _authResult == _AuthResult_Valid ? "OK" : "NG");
                    if(_authResult == _AuthResult_Valid)
                    {
                        if(strcmp((char *)ShmSysConfigAndInfo->SysConfig.UserId, AUTO_START_CHARGING) == EQUAL)
                        {
                            sprintf((char*)ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[_dispenser].AuthInfo.AuthId, "%s",
                                ShmSysConfigAndInfo->SysConfig.SerialNumber);
                        }
                    }
                    ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[_dispenser].AuthInfo.AuthResult = _authResult;
                    ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[_dispenser].AuthInfo.AuthStatus = _AuthorizeStatus_End;
                }
                else
                {
                    unsigned char connector = 0;

                    connector = ShmSysConfigAndInfo->SysInfo.AuthorizedTarget - 1;
                    if(chargingInfo[connector]->SystemStatus == S_IDLE && _authResult == _AuthResult_Valid)
                    {
                        if(strcmp((char *)ShmSysConfigAndInfo->SysConfig.UserId, AUTO_START_CHARGING) == EQUAL)
                        {
                            sprintf((char*)ShmSysConfigAndInfo->SysConfig.UserId, "%s", ShmSysConfigAndInfo->SysConfig.SerialNumber);
                        }
                        memcpy(chargingInfo[connector]->StartUserId, ShmSysConfigAndInfo->SysConfig.UserId, 32);

                        if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connector].AuthInfo.AuthType == _AuthType_RFID)
                        {
                            AUTH_INFO("*********** Gun %d RFID Authorize %s ***********", connector + 1, _authResult == _AuthResult_Valid ? "OK" : "NG");
                        }
                        if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connector].AuthInfo.AuthType == _AuthType_RemoteStart)
                        {
                            AUTH_INFO("*********** Gun %d RemoteAuthorize %s ***********", connector + 1, _authResult == _AuthResult_Valid ? "OK" : "NG");
                            Set_Connector_MiscCommand(connector, MISC_CONN_REMOTE_START);
                        }
                    }
                    else if(chargingInfo[connector]->SystemStatus == S_RESERVATION && _authResult == _AuthResult_Valid)
                    {
                        _authResult = Is_Ocpp_ReserveNowIdTag(connector, (char *)ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connector].AuthInfo.AuthId) ? _AuthResult_Valid : _AuthResult_Invalid;

                        if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connector].AuthInfo.AuthType == _AuthType_RFID)
                        {
                            AUTH_INFO("*********** Gun %d RFID Reserve Authorize %s ***********", connector + 1, _authResult == _AuthResult_Valid ? "OK" : "NG");
                        }
                        if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connector].AuthInfo.AuthType == _AuthType_RemoteStart)
                        {
                            AUTH_INFO("*********** Gun %d Reserve RemoteAuthorize %s ***********", connector + 1, _authResult == _AuthResult_Valid ? "OK" : "NG");
                            Set_Connector_MiscCommand(connector, MISC_CONN_REMOTE_START);
                        }
                    }
                    else if(chargingInfo[connector]->SystemStatus == S_AUTHORIZING && _authResult == _AuthResult_Valid)
                    {
                        if(strcmp((char *)chargingInfo[connector]->StartUserId, (char *)ShmSysConfigAndInfo->SysConfig.UserId) == EQUAL)
                        {
                            if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connector].AuthInfo.AuthType == _AuthType_RFID)
                            {
                                AUTH_INFO("*********** Gun %d RFID Authorize Already OK ***********", connector + 1);
                            }
                            if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connector].AuthInfo.AuthType == _AuthType_RemoteStart)
                            {
                                AUTH_INFO("*********** Gun %d RemoteAuthorize Already OK ***********", connector + 1);
                            }
                        }
                        else
                        {
                            _authResult = _AuthResult_Invalid;
                        }
                    }
                    else
                    {
                        AUTH_INFO("*********** Gun %d Authorize %s Status Fail (%d) ***********",
                            connector + 1, _authResult == _AuthResult_Valid ? "OK But" : "NG Or", chargingInfo[connector]->SystemStatus);
                        _authResult = _AuthResult_Invalid;
                    }
                    ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connector].AuthInfo.AuthResult = _authResult;
                    ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connector].AuthInfo.AuthStatus = _AuthorizeStatus_End;
                }

                ShmSysConfigAndInfo->SysInfo.AuthorizedStatus = _AuthorizeStatus_End;
                break;

            case _AuthorizeStatus_End:
                if(_preSysAuthStatus != ShmSysConfigAndInfo->SysInfo.AuthorizedStatus)
                {
                    AUTH_INFO("[SysAuthStatus End]");
                    _preSysAuthStatus = ShmSysConfigAndInfo->SysInfo.AuthorizedStatus;
                    GetClockTime(&_SysAuth_Time);
                }

                if(GetTimeoutValue(_SysAuth_Time) / uSEC_VAL >= SYS_AUTHORIZE_COMP_TIMEOUT)
                {
                    AUTH_INFO("*********** PowerCabinet Authorize Completed ***********");
                    SysAuthInitial();
                }
                break;

            default:
                if(_preSysAuthStatus != ShmSysConfigAndInfo->SysInfo.AuthorizedStatus)
                {
                    AUTH_INFO("[SysAuthStatus Unknown]");
                    _preSysAuthStatus = ShmSysConfigAndInfo->SysInfo.AuthorizedStatus;
                }

                ShmSysConfigAndInfo->SysInfo.AuthorizedStatus = _AuthorizeStatus_End;
                break;
        }

        if(!_keepRun)
        {
            usleep(AUTHORIZE_INTERVAL);
        }
    }

    return 0;
}