#include "msystem.h"
#include "ccu_define.h"
#include "ccu_config.h"
#include "secc_port.h"
#include "GBT27930.h"
#include "v2g_context.h"
#include "gun_port.h"
#include "ccu_port.h"
#include "sys_bsp.h"
#include "ocpp16_configkey.h"
#include "ocpp16_authorization.h"
#include "ocpp16_OfflineChargingRecords.h"


static GBT27930_t GBT27930[2];
static v2g_context_t V2GContext[2];


uint32_t secc_check_CP_State(float voltage, int pwm_state)
{
    if ( 11.5f <= voltage && voltage < 13.0f)
    {   
        if (pwm_state) { return CCSX_CP_STATE_A2; } 
        return CCSX_CP_STATE_A1;
    }
    if ( 7.5f <= voltage && voltage <= 11.5f)
    {
        if (pwm_state) { return CCSX_CP_STATE_B2; } 
        return CCSX_CP_STATE_B1;
    }
    if ( 4.5f <= voltage && voltage <= 7.5f)
    {
        if (pwm_state) { return CCSX_CP_STATE_C2; } 
        return CCSX_CP_STATE_C1;
    }
    if ( 1.5f <= voltage && voltage <= 4.5f)
    {
        if (pwm_state) { return CCSX_CP_STATE_D2; } 
        return CCSX_CP_STATE_D1;
    }
    if ( -1.5f <= voltage && voltage <= 1.5f)
    {
        return CCSX_CP_STATE_E;
    }
    if ( -13.0f < voltage && voltage < -10.0f)
    {
        return CCSX_CP_STATE_F;
    }
    return CCSX_CP_STATE_UNKNOW;
}


int secc_reserveNow(void* self, char* emaid, time_t expiryDate, int reservationId)
{
    secc_port_t* secc = (secc_port_t*)self;
    ccu_port_t* ccu = (ccu_port_t*)secc->ccu;
    pcu_port_t* pcu = (pcu_port_t*)secc->pcu;
    if (secc->GUN_State == GUN_NORMAL && secc->GUN_Error == 0)
    {
        secc_set_error(secc, GUN_RESERVED);
        sprintf(secc->reserve_emaid, "%s", emaid);
        secc->reserve_expiryDate = expiryDate;
        secc->reservationId = reservationId;
        return 0;
    }
    return -1;
}

int secc_start_Transaction(void *self)
{
    secc_port_t* secc = (secc_port_t*)self;
    ccu_port_t* ccu = (ccu_port_t*)secc->ccu;
    ccu_send_TransactionStart(ccu, secc->config->connectorId);
    return 0;
}

int secc_report_MeterValues(void* self)
{
    secc_port_t* secc = (secc_port_t*)self;
    ccu_port_t* ccu = (ccu_port_t*)secc->ccu;
    ccu_send_GUN_MeterValues(ccu, secc->config->connectorId);
    return 0;
}

int secc_stop_Transaction(void* self)
{
    secc_port_t* secc = (secc_port_t*)self;
    ccu_port_t* ccu = (ccu_port_t*)secc->ccu;
    ccu_send_TransactionStop(ccu, secc->config->connectorId, secc->transactionId);
    return 0;
}

uint32_t secc_recv_error_state(secc_port_t *secc, int timeout)
{
    fd_set rset;
    struct timeval tv;
    
    tv.tv_sec = timeout/1000;
    tv.tv_usec = (timeout%1000)*10000;
    FD_ZERO(&rset);
    FD_SET(secc->fp[0], &rset);
    int ret = select(secc->fp[0] + 1, &rset, NULL, NULL, &tv);
    if (ret > 0)
    {
        uint32_t state;
        ret = recv(secc->fp[0], &state, sizeof(state), 0);
        if (ret == 4) return state;
    }
    return 0;
}

int secc_set_error(secc_port_t* secc, int ERRNO)
{
    ccu_port_t* ccu = (ccu_port_t*)secc->ccu;
    pcu_port_t* pcu = (pcu_port_t*)secc->pcu;
    printi("connectorID:%d, %08x\n", secc->config->connectorId, ERRNO);
    if (secc->fp[1] > 0)
    {
        send(secc->fp[1], &ERRNO, sizeof(ERRNO), 0);
    }
    if (secc->GUN_Error != ERRNO)
    {
        secc->GUN_Error = ERRNO;
        pcu->update_GUN_error_state(pcu, secc->GUN_Error, secc->GUN_State);
        ccu_send_GUN_error_state(ccu, secc->config->connectorId, secc->GUN_Error, secc->GUN_State);
    }
    if (ERRNO != GUN_RESERVED)
    {
        secc->reserve_on = 0;
    }else{
        secc->reserve_on = 1;
    }
    return 0;
}

int secc_set_state(secc_port_t* secc, int STATE)
{
    ccu_port_t* ccu = (ccu_port_t*)secc->ccu;
    pcu_port_t* pcu = (pcu_port_t*)secc->pcu;
    printd("secc->fp[1]:%d, STATE:%d\n", secc->fp[1], STATE);
    if (secc->fp[1] > 0 && STATE >= GUN_PLUGIN)
    {
        send(secc->fp[1], &STATE, sizeof(STATE), 0);
    }
    if (secc->GUN_State != STATE)
    {
        secc->GUN_State = STATE;
        pcu->update_GUN_error_state(pcu, secc->GUN_Error, secc->GUN_State);
        ccu_send_GUN_error_state(ccu, secc->config->connectorId, secc->GUN_Error, secc->GUN_State);
    }
    return 0;
}

int secc_should_stop(secc_port_t* secc)
{
    if (secc->GUN_Error!=0 && secc->GUN_Error!=GUN_RESERVED) return 1;
    if (secc->manul_stop) return 1;

    if (secc->request_KWh > 0.0f)
    {
        float totalKWh = secc->EMeters - secc->started_KWh;
        if (totalKWh > secc->request_KWh) return 1;
    }
    if (secc->request_Minutes > 0)
    {
        int totalMinutes = (time(NULL) - secc->started_UTC)/60;
        if (totalMinutes > secc->request_Minutes) return 1;
    }
    if (secc->request_SOC > 0)
    {
        if (secc->SOC > secc->request_SOC ) return 1;
    }
    return 0;
}

int secc_eim_startup(secc_port_t* secc, const char* emaid, float request_KWh, uint32_t request_Minutes, uint32_t request_SOC)
{
    if ((secc->GUN_State == GUN_PLUGIN ||  secc->GUN_State == GUN_SLACOK ||secc->GUN_State == GUN_STOPPING) && secc->GUN_Error == 0)
    {
        sprintf(secc->emaid, "%s", emaid);
        secc->transactionId = 0;
        secc->request_KWh = (float)request_KWh;
        secc->request_Minutes = request_Minutes;
        secc->request_SOC = request_SOC;
        secc->manul_stop = false;

        printi("EMAID:%s, request_KWh:%f, request_Minutes:%d, request_SOC:%d\n", emaid, request_KWh, request_Minutes, request_SOC);
        
        secc_set_state(secc, GUN_STARTUP);
    }
    return 0;
}

int secc_eim_shutdown(secc_port_t* secc)
{
    secc->manul_stop = true;
    secc_set_state(secc, GUN_STOPPING);
    return 0;
}

int secc_request_power(void* self, int mode, float voltage, float current)
{
    secc_port_t* secc = (secc_port_t*)self;
    ccu_port_t* ccu = (ccu_port_t*)secc->ccu;
    pcu_port_t* pcu = (pcu_port_t*)secc->pcu;
    ccu_config_t *config = &ccu_config;

    // printi("secc.EVCC_maxV:%f, GUN_maxI:%f\n", secc->EVCC_maxV, secc->config->GUN_maxI);
    if (secc->EVCC_maxV > 0)
    {   //EV端对电压有限制
        if (voltage > secc->EVCC_maxV) { voltage = secc->EVCC_maxV; }
    }
    if (secc->config->GUN_maxI > 0) 
    {   //枪线容忍的最大电流限制
        if (current > secc->config->GUN_maxI) { current = secc->config->GUN_maxI;}
    }
    // printd("M:%d, V:%f, I:%f\n", mode, voltage, current);
    
    if (mode == POWER_REQUEST_CONST_VOLTAGE || mode == POWER_REQUEST_CONST_CURRENT)
    {
        // printi("ccu.limit_CPMaxCurrent:%f,limit_CPMaxPowerKW:%f\n", ccu->limit_CPMaxCurrent, ccu->limit_CPMaxPowerKW);
        if (ccu->limit_CPMaxCurrent > 0.0f)
        {
            if (current > ccu->limit_CPMaxCurrent)  { current = ccu->limit_CPMaxCurrent; }
        }
        // printd("M:%d, V:%f, I:%f\n", mode, voltage, current);
        if (ccu->limit_CPMaxPowerKW > 0.0f)
        {
            if ((voltage * current/1000) > ccu->limit_CPMaxPowerKW) { current = ccu->limit_CPMaxPowerKW*1000/voltage; }
        }
        // printd("M:%d, V:%f, I:%f\n", mode, voltage, current);

        // printi("secc.limit_TxCurrent:%f,limit_TxPowerKW:%f\n", secc->limit_TxCurrent, secc->limit_TxPowerKW);
        if (secc->limit_TxCurrent > 0.0f)
        {
            if (current > secc->limit_TxCurrent) { current = secc->limit_TxCurrent; }
        }

        if (secc->limit_TxPowerKW > 0.0f)
        {
            if ((voltage * current/1000) > secc->limit_TxPowerKW) { current = secc->limit_TxPowerKW*1000/voltage; }
        }
        // printd("M:%d, V:%f, I:%f\n", mode, voltage, current);
        
    
        // printi("secc.limit_DefaultCurrent:%f,limit_DefaultPowerKW:%f\n", secc->limit_DefaultCurrent, secc->limit_DefaultPowerKW);
        if (secc->limit_DefaultCurrent > 0.0f)
        {
            if (current > secc->limit_DefaultCurrent) { current = secc->limit_DefaultCurrent; }
        }
        if (secc->limit_DefaultPowerKW > 0.0f)
        {
            if ((voltage * current/1000) > secc->limit_DefaultPowerKW) { current = secc->limit_DefaultPowerKW*1000/voltage; }
        }
        // printd("M:%d, V:%f, I:%f\n", mode, voltage, current);
        
        // printi("secc.EVCC_maxI:%f,EVCC_maxP:%f\n", secc->EVCC_maxI, secc->EVCC_maxP);
        if (secc->EVCC_maxI > 0)
        {   //EV端限电流
            if (current > secc->EVCC_maxI) { current = secc->EVCC_maxI; }
        }
        // printd("M:%d, V:%f, I:%f\n", mode, voltage, current);
        if (secc->EVCC_maxP > 0)
        {   //EV端限功率
            if ((voltage * current/1000) > secc->EVCC_maxP) { current = secc->EVCC_maxP*1000/voltage; }
        }
        // printd("M:%d, V:%f, I:%f\n", mode, voltage, current);
    }
    // printd("M:%d, V:%f, I:%f\n", mode, voltage, current);

    if (secc->GUNTemp1 > (secc->config->GUNTempThreshold-20) || secc->GUNTemp2 > (secc->config->GUNTempThreshold-20))
    {
        // 枪线过温限电流，限制电流为1/2；
        printi("gun(%d)->GUNTemp(%f) > (Threshold(%f) - 20), limit current *= 0.5\n", secc->config->connectorId, secc->GUNTemp1, secc->config->GUNTempThreshold);
        current = current/2;
    }

    if (secc->GUNTemp1 > (secc->config->GUNTempThreshold-10) || secc->GUNTemp2 > (secc->config->GUNTempThreshold-10))
    {
        // 枪线过温限电流，限制电流为1/4； 
        printi("gun(%d)->GUNTemp(%f) > (Threshold(%f) - 20), limit current *= 0.5\n", secc->config->connectorId, secc->GUNTemp1, secc->config->GUNTempThreshold);
        current = current/2;
    }

    if (ccu->BoxTemp > (config->BoxTempThreshold-15))
    {
        // 枪线过温限电流，限制电流为1/2；
        printi("ccu->BoxTemp(%f) > (Threshold(%f) - 15), limit current *= 0.5\n", ccu->BoxTemp, config->BoxTempThreshold);
        current = current/2;
    }

    if (ccu->BoxTemp > (config->BoxTempThreshold-10))
    {
        // 枪线过温限电流，限制电流为1/4； 
        printi("ccu->BoxTemp(%f) > (Threshold(%f) - 10), limit current *= 0.5\n", ccu->BoxTemp, config->BoxTempThreshold);
        current = current/2;
    }


    pcu->request_Power(pcu, mode, voltage, current);
    return 0;
}

static secc_port_t SECC_PortA =
{
    .priv = NULL,
    .ccu = &ccu_port,
    .pcu = &ccu_port.pcuA,
    .set_K1K2_state = gunA_Set_K1K2_State,
    .set_ELock_state = gunA_Set_ELock_State,
    .set_Aux12V_state = gunA_Set_Aux12V,
    .set_IMD_state = sys_set_DCGroundA_state,
    .set_PWM_ratio = gunA_Set_PWM,
    .transactionId = 0,
    .reservationId = 0,

    .offline_recorder = &gunArecord
};

static secc_port_t SECC_PortB =
{
    .priv = NULL,
    .ccu = &ccu_port,
    .pcu = &ccu_port.pcuB,
    .set_K1K2_state = gunB_Set_K1K2_State,
    .set_ELock_state = gunB_Set_ELock_State,
    .set_Aux12V_state = gunB_Set_Aux12V,
    .set_IMD_state = sys_set_DCGroundB_state,
    .set_PWM_ratio = gunB_Set_PWM,
    .transactionId = 0,
    .reservationId = 0,

    .offline_recorder = &gunBrecord
};

void secc_portA_bind(ccu_port_t* ccu)
{
    V2GContext[0].secc = &SECC_PortA;
    GBT27930[0].secc = &SECC_PortA;
    ccu->seccA = &SECC_PortA;
    secc_port_t* secc = &SECC_PortA;
    secc->config = (GUN_config_t*)&ccu_config.GUN_config[0];
    secc->ccu = &ccu_port;
    secc->pcu = ccu->pcuA;
    switch (secc->config->GUN_Type)
    {
        case GUN_TYPE_NACS:
        case GUN_TYPE_CCS1:
        case GUN_TYPE_CCS2: {secc->priv = &V2GContext[0]; }break;
        case GUN_TYPE_CHADEMO:
        case GUN_TYPE_GBDC:
        default: { secc->priv = &GBT27930[0]; }break;
    }
}

void secc_portB_bind(ccu_port_t* ccu)
{
    V2GContext[1].secc = &SECC_PortB;
    GBT27930[1].secc = &SECC_PortB;
    ccu->seccB = &SECC_PortB;
    secc_port_t* secc = &SECC_PortB;
    secc->config = (GUN_config_t*)&ccu_config.GUN_config[1];
    secc->ccu = &ccu_port;
    secc->pcu = ccu->pcuB;
    switch (secc->config->GUN_Type)
    {
        case GUN_TYPE_NACS:
        case GUN_TYPE_CCS1:
        case GUN_TYPE_CCS2: { secc->priv = &V2GContext[1]; }break;
        case GUN_TYPE_CHADEMO:
        case GUN_TYPE_GBDC:
        default: { secc->priv = &GBT27930[1]; }break;
    }
}

