#include "v2g_context.h"
#include "ccu_define.h"

static int v2g_secc_wait_Startup(v2g_context_t* v2g)
{
    secc_port_t *secc = (secc_port_t*)v2g->secc;
    evse_slac_t* slac = (evse_slac_t*)&v2g->evse_slac;
    ccu_port_t *ccu = (ccu_port_t*)v2g->ccu;
    pcu_port_t *pcu = (pcu_port_t*)v2g->pcu;

    printi("step.\n");
    secc->set_PWM_ratio(secc, 6);
    v2g_slac_init(v2g, secc->config->slac_ifname);
    mthread_init(&slac->thread, v2g_slac_loop, v2g);
    
    return 1;
}

static int v2g_secc_wait_Authorizated(v2g_context_t* v2g)
{
    secc_port_t *secc = (secc_port_t*)v2g->secc;
    evse_slac_t* slac = (evse_slac_t*)&v2g->evse_slac;
    ccu_port_t *ccu = (ccu_port_t*)v2g->ccu;
    pcu_port_t *pcu = (pcu_port_t*)v2g->pcu;

    printd("slac->result=%d\n", slac->result);

    if (slac->result == 1)
    {
        printd("step, pcu:%p\n", pcu);
        pcu->update_ElecLock_state(pcu, 1);
        printd("step\n");
        secc_request_power(secc, POWER_REQUEST_PLACE_HOLD, 0.0f, 0.0f);
        printd("step\n");
        v2g_context_init(v2g, secc->config->slac_ifname);
        printd("step\n");
    }
    
    if (secc->request_KWh > 0)
    {
        printd("secc->request_KWh:%d\n", secc->request_KWh);
        secc_start_Transaction(secc);
        v2g->evse_processing[PHASE_AUTH] = iso2_EVSEProcessingType_Finished;
        v2g->evse_status_code[PHASE_AUTH] = iso2_DC_EVSEStatusCodeType_EVSE_Ready;

        v2g->evse_processing[PHASE_PARAMETER] = iso2_EVSEProcessingType_Finished;
        v2g->evse_status_code[PHASE_PARAMETER] = iso2_DC_EVSEStatusCodeType_EVSE_Ready;

        v2g->evse_processing[PHASE_ISOLATION] = iso2_EVSEProcessingType_Ongoing_WaitingForCustomerInteraction;
        v2g->evse_status_code[PHASE_ISOLATION] = iso2_DC_EVSEStatusCodeType_EVSE_NotReady;  
    
        pcu->get_PCU_maxVoltageCurrent(pcu, &secc->SECC_maxV, &secc->SECC_maxI);
        pcu->get_PCU_minVoltageCurrent(pcu, &secc->SECC_minV, &secc->SECC_minI);

        secc_set_state(secc, GUN_AUTHORIZED);

        return 1;
    }
    if (secc->request_SOC > 0)
    {
        printd("secc->request_SOC:%d\n", secc->request_SOC);
        secc_start_Transaction(secc);
        v2g->evse_processing[PHASE_AUTH] = iso2_EVSEProcessingType_Finished;
        v2g->evse_status_code[PHASE_AUTH] = iso2_DC_EVSEStatusCodeType_EVSE_Ready;

        v2g->evse_processing[PHASE_PARAMETER] = iso2_EVSEProcessingType_Finished;
        v2g->evse_status_code[PHASE_PARAMETER] = iso2_DC_EVSEStatusCodeType_EVSE_Ready;

        v2g->evse_processing[PHASE_ISOLATION] = iso2_EVSEProcessingType_Ongoing_WaitingForCustomerInteraction;
        v2g->evse_status_code[PHASE_ISOLATION] = iso2_DC_EVSEStatusCodeType_EVSE_NotReady; 
    
        pcu->get_PCU_maxVoltageCurrent(pcu, &secc->SECC_maxV, &secc->SECC_maxI);
        pcu->get_PCU_minVoltageCurrent(pcu, &secc->SECC_minV, &secc->SECC_minI);
        secc_set_state(secc, GUN_AUTHORIZED);
        return 1;
    }
    if (secc->request_Minutes > 0)
    {
        printd("secc->request_Minutes:%d\n", secc->request_Minutes);
        secc_start_Transaction(secc);
        v2g->evse_processing[PHASE_AUTH] = iso2_EVSEProcessingType_Finished;
        v2g->evse_status_code[PHASE_AUTH] = iso2_DC_EVSEStatusCodeType_EVSE_Ready;

        v2g->evse_processing[PHASE_PARAMETER] = iso2_EVSEProcessingType_Finished;
        v2g->evse_status_code[PHASE_PARAMETER] = iso2_DC_EVSEStatusCodeType_EVSE_Ready;

        v2g->evse_processing[PHASE_ISOLATION] = iso2_EVSEProcessingType_Ongoing_WaitingForCustomerInteraction;
        v2g->evse_status_code[PHASE_ISOLATION] = iso2_DC_EVSEStatusCodeType_EVSE_NotReady; 
    
        pcu->get_PCU_maxVoltageCurrent(pcu, &secc->SECC_maxV, &secc->SECC_maxI);
        pcu->get_PCU_minVoltageCurrent(pcu, &secc->SECC_minV, &secc->SECC_minI);
        secc_set_state(secc, GUN_AUTHORIZED);
        return 1;
    }

    v2g->evse_processing[PHASE_AUTH] = iso2_EVSEProcessingType_Ongoing;
    v2g->evse_status_code[PHASE_AUTH] = iso2_DC_EVSEStatusCodeType_EVSE_NotReady;

    v2g->evse_processing[PHASE_PARAMETER] = iso2_EVSEProcessingType_Ongoing;
    v2g->evse_status_code[PHASE_PARAMETER] = iso2_DC_EVSEStatusCodeType_EVSE_NotReady; 

    v2g->evse_processing[PHASE_ISOLATION] = iso2_EVSEProcessingType_Ongoing_WaitingForCustomerInteraction;
    v2g->evse_status_code[PHASE_ISOLATION] = iso2_DC_EVSEStatusCodeType_EVSE_NotReady; 
    return 0;
}

static int v2g_secc_Insulation(v2g_context_t* v2g)
{
    int i;
    secc_port_t *secc = (secc_port_t*)v2g->secc;
    pcu_port_t *pcu = (pcu_port_t*)v2g->pcu;

    printi("SECC(%d) Insulation...\n", secc->config->connectorId);
    int64_t now_ms = systime_ms();
    int64_t end_ms = systime_ms() + 60000;

    if (secc->set_K1K2_state(secc, 0, 1000) == 1) 
    {
        pcu->update_K1K2_state(pcu, 0, 0);
    }else {
        secc_set_error(secc, GUN_CONTACTOR_FAULT);
        printe("secc->VMeters:%f\n", secc->VMeters);
        return -1;
    }

    for (now_ms = systime_ms(); now_ms <= end_ms && secc->GUN_Error==0; now_ms = systime_ms())
    {
        if (0.0f <= secc->VMeters && secc->VMeters < 10.0f) { break; }
        printv("secc->VMeters:%f\n", secc->VMeters);
        msleep(100);
    }

    if (now_ms >= end_ms)
    {
        if (secc->VMeters < 0.0f)
        {
            secc_set_error(secc, BMS_VOLTAGE_INVERSE);
        }else{
            secc_set_error(secc, BMS_CONTACTOR_FAULT);
        }
        printe("secc->VMeters:%f\n", secc->VMeters);
        return -1;
    }

    if (secc->set_K1K2_state(secc, 1, 1000) == 1) 
    {
        pcu->update_K1K2_state(pcu, 1, 1);
    }else {
        secc_set_error(secc, GUN_CONTACTOR_FAULT);
        printe("secc->VMeters:%f\n", secc->VMeters);
        return -1;
    }

    float Vimd = 400;
    secc->set_IMD_state(secc, 1);
    secc_request_power(secc, POWER_REQUEST_INSULATION, Vimd, 0);
    printd("now_ms:%lld, end_ms:%lld, now<=end(%d)\n", now_ms, end_ms, (now_ms<=end_ms));
    end_ms = systime_ms() + 60000;
    for (now_ms = systime_ms(); now_ms <= end_ms; now_ms = systime_ms())
    {
        printd("secc->VGround:%f, secc->VMeters:%f, Vimd:%f, Rimd:%f\n", secc->VGround, secc->VMeters, Vimd, secc->RGround);
        if (secc->VGround >= 200.0f)
        {
            if (secc->RGround > (secc->VGround * 100.0f))
            {
                secc->set_IMD_state(secc, 0);
                // secc_request_power(secc, POWER_REQUEST_SHUTDOWN, 0, 0);
                // if (secc->set_K1K2_state(secc, 0, 1000) == 1) 
                // {
                //     pcu->update_K1K2_state(pcu, 0, 0);
                // }
                v2g->evse_status_code[PHASE_ISOLATION] = iso2_DC_EVSEStatusCodeType_EVSE_Ready;
                v2g->evse_processing[PHASE_ISOLATION] = iso2_EVSEProcessingType_Finished;
                v2g->evse_isolation_status = din_isolationLevelType_Valid;
                return 1;
            }
        }
        msleep(200);
    }
    secc->set_IMD_state(secc, 0);
    secc_request_power(secc, POWER_REQUEST_SHUTDOWN, 0, 0);
    secc_set_error(secc, GUN_INSULATION_FAULT);
    printd("now_ms:%lld, end_ms:%lld, now<=end(%d)\n", now_ms, end_ms, (now_ms<=end_ms));
    v2g->evse_status_code[PHASE_ISOLATION] = iso2_DC_EVSEStatusCodeType_EVSE_NotReady;
    v2g->evse_isolation_status = din_isolationLevelType_Fault;
    return 0;
}

static int v2g_secc_Stopping(v2g_context_t* v2g)
{
    int i;
    secc_port_t *secc = (secc_port_t*)v2g->secc;
    ccu_port_t *ccu = (ccu_port_t*)v2g->ccu;
    pcu_port_t *pcu = (pcu_port_t*)v2g->pcu;

    if (secc->transactionId == 0) return 0;

    secc->set_PWM_ratio(secc, 100);
    secc_request_power(secc, POWER_REQUEST_PLACE_FREE, 0, 0);
    secc_stop_Transaction(secc);

    for (i = 0; i< 1000; i+=100)
    {
        if (secc->IMeters < 5.5f) { break; }
        msleep(100);
    }
    
    if (secc->set_K1K2_state(secc, 0, 1000) == 1) 
    {
        pcu->update_K1K2_state(pcu, 0, 0);
    }else {
        secc_set_error(secc, GUN_CONTACTOR_FAULT);
    }
    
    secc->request_Minutes = 0;
    secc->request_SOC = 0;
    secc->request_KWh = 0;
    secc->reserve_on = 0;
    secc->reservationId = 0;
    secc->started_KWh = 0;
    secc->started_UTC = 0;
    secc->GUN_Error = 0;
    secc->GUN_State = 0;
    secc->SOC = 0;
    secc->EV_Charging_current = 0;
    secc->EV_Charging_voltage = 0;
    secc->EV_Estimate_Minutes = 0;
    secc->transactionId = 0;
    secc_set_state(secc, GUN_PLUGIN);
    printd("GUN_Error:%08x, GUN_State:%08x\n", secc->GUN_Error, secc->GUN_State);
    return 0;
}

/*********************************************************************/

static void* v2g_secc_loop(void* argv)
{
    v2g_context_t* v2g = (v2g_context_t*)argv;
    secc_port_t *secc = (secc_port_t*)v2g->secc;
    evse_slac_t* slac = (evse_slac_t*)&v2g->evse_slac;
    ccu_port_t *ccu = (ccu_port_t*)v2g->ccu;
    pcu_port_t *pcu = (pcu_port_t*)v2g->pcu;
    printd("Enter.\n");
    
    while(v2g->quit == 0)
    {
        uint32_t state = secc_recv_error_state(secc, 1000);
        // printi("recv state:%d\n", state);
        if (state == 0) continue;
        switch(state)
        {
            case GUN_STARTUP:       { v2g_secc_wait_Startup(v2g); }break;
            case GUN_SLACOK:        { v2g_secc_wait_Authorizated(v2g); }break;
            case GUN_INSULATION:    { v2g_secc_Insulation(v2g); } break;
            case GUN_STOPPING:      
            {
                v2g_secc_Stopping(v2g);
                v2g_context_exit(v2g);
                v2g_slac_exit(v2g);
            } break;
        }
        if (secc->GUN_Error &= 0 && secc->GUN_Error== GUN_RESERVED) 
        {
            v2g_secc_Stopping(v2g);
            v2g_context_exit(v2g);
            v2g_slac_exit(v2g);
        };
    }
    
    v2g_secc_Stopping(v2g);
    v2g_context_exit(v2g);
    v2g_slac_exit(v2g);    
    mthread_exit(&v2g->thread);
    pthread_mutex_destroy(&v2g->mutex);
    printd("Leave.\n");
    return NULL;
}

int secc_init_v2g(void* secc_self)
{
    secc_port_t* secc = (secc_port_t*)secc_self;
    v2g_context_t *v2g = (v2g_context_t*)secc->priv;
    evse_slac_t* slac = (evse_slac_t*)&v2g->evse_slac;
    v2g->ccu = secc->ccu;
    v2g->pcu = secc->pcu;
    if (v2g)
    {
        v2g->quit = 0;
        v2g->sdp_server_quit = 1;
        v2g->tcp_server_quit = 1;
        v2g->tls_server_quit = 1;
        v2g->sdp_socket = -1;
        v2g->tcp_socket = -1;
        v2g->tls_socket = -1;
        v2g->next_client == NULL;
        v2g->current_v2g_msg = 0;
        v2g->state = 0;
        socketpair(AF_UNIX, SOCK_STREAM, 0, secc->fp);
        pthread_mutex_init(&v2g->mutex, NULL);
        mthread_init(&v2g->thread, v2g_secc_loop, v2g);
    }
    return 0;
}

void secc_exit_v2g(void* secc_self)
{
    secc_port_t* secc = (secc_port_t*)secc_self;
    v2g_context_t *v2g = (v2g_context_t*)secc->priv;
    ccu_port_t *ccu = (ccu_port_t*)v2g->ccu;
    pcu_port_t *pcu = (pcu_port_t*)v2g->pcu;
    if (v2g->quit == 0)
    {        
        v2g->quit = 1;
        secc->manul_stop = true;
        secc->set_PWM_ratio(secc, 100);
        if (secc->fp[0] > 0)
        {
            shutdown(secc->fp[0], SHUT_RDWR);
            close(secc->fp[0]);
            secc->fp[0] = -1;
        }
        if (secc->fp[1] > 0)
        {
            shutdown(secc->fp[1], SHUT_RDWR);
            close(secc->fp[1]);
            secc->fp[1] = -1;
        }
        v2g_secc_Stopping(v2g);
        v2g_context_exit(v2g);
        v2g_slac_exit(v2g);
        mthread_exit(&v2g->thread);
        pthread_mutex_destroy(&v2g->mutex);
    }
}
