#include "ocpp16_decode.h"
#include "msystem.h"
#include "cJSON.h"
#include "ocpp16_configkey.h"

int ocpp16_decode_ErrorCode(cJSON *root)
{
    // uint32_t msgType = (uint32_t)cJSON_GetNumberValue(cJSON_GetArrayItem(root, 0));
    // char *msgUUID = cJSON_GetStringValue(cJSON_GetArrayItem(root, 1));
    char *errorCode = cJSON_GetStringValue(cJSON_GetArrayItem(root, 2));
    // char *errorDescription = cJSON_GetStringValue(cJSON_GetArrayItem(root, 3));
    // cJSON *errorDetail = cJSON_GetArrayItem(root, 4);

    if (strncmp("NotImplemented", errorCode, strlen(errorCode)) == 0)
        return -ErrorCode_NotImplemented;
    if (strncmp("NotSupported", errorCode, strlen(errorCode)) == 0)
        return -ErrorCode_NotSupported;
    if (strncmp("InternalError", errorCode, strlen(errorCode)) == 0)
        return -ErrorCode_InternalError;
    if (strncmp("ProtocolError", errorCode, strlen(errorCode)) == 0)
        return -ErrorCode_ProtocolError;
    if (strncmp("SecurityError", errorCode, strlen(errorCode)) == 0)
        return -ErrorCode_SecurityError;
    if (strncmp("FormatViolation", errorCode, strlen(errorCode)) == 0)
        return -ErrorCode_FormatViolation;
    if (strncmp("PropertyConstraintViolation", errorCode, strlen(errorCode)) == 0)
        return -ErrorCode_PropertyConstraintViolation;
    if (strncmp("OccurenceConstraintViolation", errorCode, strlen(errorCode)) == 0)
        return -ErrorCode_OccurenceConstraintViolation;
    if (strncmp("TypeConstraintViolation", errorCode, strlen(errorCode)) == 0)
        return -ErrorCode_TypeConstraintViolation;
    if (strncmp("GenericError", errorCode, strlen(errorCode)) == 0)
        return -ErrorCode_GenericError;

    return -ErrorCode_GenericError;
}

int ocpp16_decode_AuthorizeConf(AuthorizeConf_t *conf, CidString37_t reqUUID, cJSON *root)
{
    memset(conf, 0, sizeof(AuthorizeConf_t));
    if (root)
    {
        uint32_t size = cJSON_GetArraySize(root);
        uint32_t msgType = (uint32_t)cJSON_GetNumberValue(cJSON_GetArrayItem(root, 0));
        char *msgUUID = cJSON_GetStringValue(cJSON_GetArrayItem(root, 1));
        if (strncmp(reqUUID, msgUUID, strlen(msgUUID)) == 0)
        {
            if (size == 5 && msgType == 4) // server.error,
            {
                return ocpp16_decode_ErrorCode(root);
            }
            if (size == 3 && msgType == 3) // server.conf
            {
                cJSON *payload = cJSON_GetArrayItem(root, 2);
                cJSON *idTagInfo = cJSON_GetObjectItem(payload, "idTagInfo");
                const char *status = cJSON_GetStringValue(cJSON_GetObjectItem(idTagInfo, "status"));
                if (strncmp("Accepted", status, strlen(status)) == 0)
                    conf->idTagInfo.status = AuthorizationStatus_Accepted;
                if (strncmp("Blocked", status, strlen(status)) == 0)
                    conf->idTagInfo.status = AuthorizationStatus_Blocked;
                if (strncmp("Expired", status, strlen(status)) == 0)
                    conf->idTagInfo.status = AuthorizationStatus_Expired;
                if (strncmp("Invalid", status, strlen(status)) == 0)
                    conf->idTagInfo.status = AuthorizationStatus_Invalid;
                if (strncmp("ConcurrentTx", status, strlen(status)) == 0)
                    conf->idTagInfo.status = AuthorizationStatus_ConcurrentTx;
                if (cJSON_HasObjectItem(idTagInfo, "parentIdTag"))
                {
                    sprintf(conf->idTagInfo.parentIdTag, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(idTagInfo, "parentIdTag")));
                }
                if (cJSON_HasObjectItem(idTagInfo, "expiryDate"))
                {
                    conf->idTagInfo.expiryDate = RFC3339String_to_time(cJSON_GetStringValue(cJSON_GetObjectItem(idTagInfo, "expiryDate")), NULL, NULL);
                }

                return 0;
            }
        }
    }
    return -ErrorCode_GenericError;
}

int ocpp16_decode_BootNotificationConf(BootNotificationConf_t *conf, CidString37_t reqUUID, cJSON *root)
{
    memset(conf, 0, sizeof(BootNotificationConf_t));
    if (root)
    {
        uint32_t size = cJSON_GetArraySize(root);
        uint32_t msgType = (uint32_t)cJSON_GetNumberValue(cJSON_GetArrayItem(root, 0));
        char *msgUUID = cJSON_GetStringValue(cJSON_GetArrayItem(root, 1));
        if (strncmp(reqUUID, msgUUID, strlen(msgUUID)) == 0)
        {
            if (size == 5 && msgType == 4) // server.error,
            {
                return ocpp16_decode_ErrorCode(root);
            }
            if (size == 3 && msgType == 3) // server.conf
            {
                cJSON *payload = cJSON_GetArrayItem(root, 2);
                const char *status = cJSON_GetStringValue(cJSON_GetObjectItem(payload, "status"));
                if (strncmp("Accepted", status, strlen(status)) == 0)
                    conf->status = AuthorizationStatus_Accepted;
                if (strncmp("Blocked", status, strlen(status)) == 0)
                    conf->status = AuthorizationStatus_Blocked;
                if (strncmp("Expired", status, strlen(status)) == 0)
                    conf->status = AuthorizationStatus_Expired;
                if (strncmp("Invalid", status, strlen(status)) == 0)
                    conf->status = AuthorizationStatus_Invalid;
                if (strncmp("ConcurrentTx", status, strlen(status)) == 0)
                    conf->status = AuthorizationStatus_ConcurrentTx;
                conf->interval = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "interval"));
                sprintf(conf->currentTime, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(payload, "currentTime")));
                return 0;
            }
        }
    }
    return -ErrorCode_GenericError;
}

int ocpp16_decode_DataTransferConf(DataTransferConf_t *conf, CidString37_t reqUUID, cJSON *root)
{
    memset(conf, 0, sizeof(DataTransferConf_t));
    if (root)
    {
        uint32_t size = cJSON_GetArraySize(root);
        uint32_t msgType = (uint32_t)cJSON_GetNumberValue(cJSON_GetArrayItem(root, 0));
        char *msgUUID = cJSON_GetStringValue(cJSON_GetArrayItem(root, 1));
        if (strncmp(reqUUID, msgUUID, strlen(msgUUID)) == 0)
        {
            if (size == 5 && msgType == 4) // server.error,
            {
                return ocpp16_decode_ErrorCode(root);
            }
            if (size == 3 && msgType == 3) // server.conf
            {
                cJSON *payload = cJSON_GetArrayItem(root, 2);
                const char *status = cJSON_GetStringValue(cJSON_GetObjectItem(payload, "status"));
                if (strncmp("Accepted", status, strlen(status)) == 0)
                    conf->status = DataTransferStatus_Accepted;
                if (strncmp("Rejected", status, strlen(status)) == 0)
                    conf->status = DataTransferStatus_Rejected;
                if (strncmp("UnknownMessageId", status, strlen(status)) == 0)
                    conf->status = DataTransferStatus_UnknownMessageId;
                if (strncmp("UnknownVendorId", status, strlen(status)) == 0)
                    conf->status = DataTransferStatus_UnknownVendorId;

                cJSON *data = cJSON_GetObjectItem(payload, "data");
                sprintf(conf->data.type, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(data, "type")));
                sprintf(conf->data.timeZone, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(data, "timeZone")));
                sprintf(conf->data.minAllowBalance, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(data, "minAllowBalance")));

                int i;
                cJSON *price = cJSON_GetObjectItem(payload, "price");
                conf->data.price.count = cJSON_GetArraySize(price);
                for (i = 0; i < conf->data.price.count; i++)
                {
                    cJSON *item = cJSON_GetArrayItem(price, i);
                    sprintf(conf->data.price.items[i].startTime, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(item, "startTime")));
                    sprintf(conf->data.price.items[i].stopTime, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(item, "stopTime")));
                    sprintf(conf->data.price.items[i].electrPrice, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(item, "electrPrice")));
                    sprintf(conf->data.price.items[i].servicePrice, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(item, "servicePrice")));
                    sprintf(conf->data.price.items[i].durationPrice, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(item, "durationPrice")));
                }

                return 0;
            }
        }
    }
    return -ErrorCode_GenericError;
}

int ocpp16_decode_DiagnosticsStatusNotificationConf(DiagnosticsStatusNotificationConf_t *conf, CidString37_t reqUUID, cJSON *root)
{
    memset(conf, 0, sizeof(DiagnosticsStatusNotificationConf_t));
    if (root)
    {
        uint32_t size = cJSON_GetArraySize(root);
        uint32_t msgType = (uint32_t)cJSON_GetNumberValue(cJSON_GetArrayItem(root, 0));
        char *msgUUID = cJSON_GetStringValue(cJSON_GetArrayItem(root, 1));
        if (strncmp(reqUUID, msgUUID, strlen(msgUUID)) == 0)
        {
            if (size == 5 && msgType == 4) // server.error,
            {
                return ocpp16_decode_ErrorCode(root);
            }
            if (size == 3 && msgType == 3) // server.conf
            {
                return 0;
            }
        }
    }
    return -ErrorCode_GenericError;
}

int ocpp16_decode_FirmwareStatusNotificationConf(FirmwareStatusNotificationConf_t *conf, CidString37_t reqUUID, cJSON *root)
{
    memset(conf, 0, sizeof(FirmwareStatusNotificationConf_t));
    if (root)
    {
        uint32_t size = cJSON_GetArraySize(root);
        uint32_t msgType = (uint32_t)cJSON_GetNumberValue(cJSON_GetArrayItem(root, 0));
        char *msgUUID = cJSON_GetStringValue(cJSON_GetArrayItem(root, 1));
        if (strncmp(reqUUID, msgUUID, strlen(msgUUID)) == 0)
        {
            if (size == 5 && msgType == 4) // server.error,
            {
                return ocpp16_decode_ErrorCode(root);
            }
            if (size == 3 && msgType == 3) // server.conf
            {
                return 0;
            }
        }
    }
    return -ErrorCode_GenericError;
}

int ocpp16_decode_HeartbeatConf(HeartbeatConf_t *conf, CidString37_t reqUUID, cJSON *root)
{
    memset(conf, 0, sizeof(HeartbeatConf_t));
    if (root)
    {
        uint32_t size = cJSON_GetArraySize(root);
        uint32_t msgType = (uint32_t)cJSON_GetNumberValue(cJSON_GetArrayItem(root, 0));
        char *msgUUID = cJSON_GetStringValue(cJSON_GetArrayItem(root, 1));
        if (strncmp(reqUUID, msgUUID, strlen(msgUUID)) == 0)
        {
            if (size == 5 && msgType == 4) // server.error,
            {
                return ocpp16_decode_ErrorCode(root);
            }
            if (size == 3 && msgType == 3) // server.conf
            {
                cJSON *payload = cJSON_GetArrayItem(root, 2);
                if (cJSON_HasObjectItem(payload, "currentTime"))
                {
                    sprintf(conf->currentTime, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(payload, "currentTime")));
                }
                return 0;
            }
        }
    }
    return -ErrorCode_GenericError;
}

int ocpp16_decode_MeterValuesConf(MeterValuesConf_t *conf, CidString37_t reqUUID, cJSON *root)
{
    memset(conf, 0, sizeof(MeterValuesConf_t));
    if (root)
    {
        uint32_t size = cJSON_GetArraySize(root);
        uint32_t msgType = (uint32_t)cJSON_GetNumberValue(cJSON_GetArrayItem(root, 0));
        char *msgUUID = cJSON_GetStringValue(cJSON_GetArrayItem(root, 1));
        if (strncmp(reqUUID, msgUUID, strlen(msgUUID)) == 0)
        {
            if (size == 5 && msgType == 4) // server.error,
            {
                return ocpp16_decode_ErrorCode(root);
            }
            if (size == 3 && msgType == 3) // server.conf
            {
                return 0;
            }
        }
    }
    return -ErrorCode_GenericError;
}

int ocpp16_decode_StartTransactionConf(StartTransactionConf_t *conf, CidString37_t reqUUID, cJSON *root)
{
    memset(conf, 0, sizeof(StartTransactionConf_t));
    if (root)
    {
        uint32_t size = cJSON_GetArraySize(root);
        uint32_t msgType = (uint32_t)cJSON_GetNumberValue(cJSON_GetArrayItem(root, 0));
        char *msgUUID = cJSON_GetStringValue(cJSON_GetArrayItem(root, 1));
        conf->idTagInfo.status = 0;
        if (strncmp(reqUUID, msgUUID, strlen(msgUUID)) == 0)
        {
            if (size == 5 && msgType == 4) // server.error,
            {
                return ocpp16_decode_ErrorCode(root);
            }
            if (size == 3 && msgType == 3) // server.conf
            {
                cJSON *payload = cJSON_GetArrayItem(root, 2);
                conf->transactionId = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "transactionId"));
                cJSON *idTagInfo = cJSON_GetObjectItem(payload, "idTagInfo");
                if (cJSON_HasObjectItem(idTagInfo, "expiryDate"))
                {
                    conf->idTagInfo.expiryDate = RFC3339String_to_time(cJSON_GetStringValue(cJSON_GetObjectItem(idTagInfo, "expiryDate")),NULL,NULL);
                }
                if (cJSON_HasObjectItem(idTagInfo, "parentIdTag"))
                {
                    sprintf(conf->idTagInfo.parentIdTag, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(idTagInfo, "parentIdTag")));
                }
                const char *status = cJSON_GetStringValue(cJSON_GetObjectItem(idTagInfo, "status"));
                if (strncmp("Accepted", status, strlen(status)) == 0)
                    conf->idTagInfo.status = AuthorizationStatus_Accepted;
                if (strncmp("Blocked", status, strlen(status)) == 0)
                    conf->idTagInfo.status = AuthorizationStatus_Blocked;
                if (strncmp("Expired", status, strlen(status)) == 0)
                    conf->idTagInfo.status = AuthorizationStatus_Expired;
                if (strncmp("Invalid", status, strlen(status)) == 0)
                    conf->idTagInfo.status = AuthorizationStatus_Invalid;
                if (strncmp("ConcurrentTx", status, strlen(status)) == 0)
                    conf->idTagInfo.status = AuthorizationStatus_ConcurrentTx;
                return conf->idTagInfo.status;
            }
        }
    }
    return -ErrorCode_GenericError;
}

int ocpp16_decode_StatusNotificationConf(StatusNotificationConf_t *conf, CidString37_t reqUUID, cJSON *root)
{
    memset(conf, 0, sizeof(StatusNotificationConf_t));
    if (root)
    {
        uint32_t size = cJSON_GetArraySize(root);
        uint32_t msgType = (uint32_t)cJSON_GetNumberValue(cJSON_GetArrayItem(root, 0));
        char *msgUUID = cJSON_GetStringValue(cJSON_GetArrayItem(root, 1));
        if (strncmp(reqUUID, msgUUID, strlen(msgUUID)) == 0)
        {
            if (size == 5 && msgType == 4) // server.error,
            {
                return ocpp16_decode_ErrorCode(root);
            }
            if (size == 3 && msgType == 3) // server.conf
            {
                return 0;
            }
        }
    }
    return -ErrorCode_GenericError;
}

int ocpp16_decode_StopTransactionConf(StopTransactionConf_t *conf, CidString37_t reqUUID, cJSON *root)
{
    memset(conf, 0, sizeof(StopTransactionConf_t));
    if (root)
    {
        uint32_t size = cJSON_GetArraySize(root);
        uint32_t msgType = (uint32_t)cJSON_GetNumberValue(cJSON_GetArrayItem(root, 0));
        char *msgUUID = cJSON_GetStringValue(cJSON_GetArrayItem(root, 1));
        if (strncmp(reqUUID, msgUUID, strlen(msgUUID)) == 0)
        {
            if (size == 5 && msgType == 4) // server.error,
            {
                return ocpp16_decode_ErrorCode(root);
            }
            if (size == 3 && msgType == 3) // server.conf
            {
                cJSON *payload = cJSON_GetArrayItem(root, 2);
                cJSON *idTagInfo = cJSON_GetObjectItem(payload, "idTagInfo");
                if (cJSON_HasObjectItem(idTagInfo, "expiryDate"))
                {
                    conf->idTagInfo.expiryDate = RFC3339String_to_time(cJSON_GetStringValue(cJSON_GetObjectItem(idTagInfo, "expiryDate")),NULL,NULL);
                }
                if (cJSON_HasObjectItem(idTagInfo, "parentIdTag"))
                {
                    sprintf(conf->idTagInfo.parentIdTag, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(idTagInfo, "parentIdTag")));
                }
                
                const char *status = cJSON_GetStringValue(cJSON_GetObjectItem(idTagInfo, "status"));
                if (strncmp("Accepted", status, strlen(status)) == 0)
                    conf->idTagInfo.status = AuthorizationStatus_Accepted;
                if (strncmp("Blocked", status, strlen(status)) == 0)
                    conf->idTagInfo.status = AuthorizationStatus_Blocked;
                if (strncmp("Expired", status, strlen(status)) == 0)
                    conf->idTagInfo.status = AuthorizationStatus_Expired;
                if (strncmp("Invalid", status, strlen(status)) == 0)
                    conf->idTagInfo.status = AuthorizationStatus_Invalid;
                if (strncmp("ConcurrentTx", status, strlen(status)) == 0)
                    conf->idTagInfo.status = AuthorizationStatus_ConcurrentTx;
                return conf->idTagInfo.status;
            }
        }
    }
    return -ErrorCode_GenericError;
}

//-----------------------------------------------------------------------------------------------------

int ocpp16_decode_CancelReservationReq(CancelReservationReq_t *conf, cJSON *payload)
{
    memset(conf, 0, sizeof(CancelReservationReq_t));
    if (payload)
    {
        conf->reservationId = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "transactionId"));
        return 0;
    }
    return -ErrorCode_FormatViolation;
}

int ocpp16_decode_ChangeAvailabilityReq(ChangeAvailabilityReq_t *conf, cJSON *payload)
{
    memset(conf, 0, sizeof(ChangeAvailabilityReq_t));
    if (payload)
    {
        conf->connectorId = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "connectorId"));
        const char *type = cJSON_GetStringValue(cJSON_GetObjectItem(payload, "type"));
        if (strncmp("Accepted", type, strlen(type)) == 0)
            conf->type = AvailabilityType_Inoperative;
        if (strncmp("Blocked", type, strlen(type)) == 0)
            conf->type = AvailabilityType_Operative;
        return 0;
    }
    return -ErrorCode_FormatViolation;
}

int ocpp16_decode_ChangeConfigurationReq(ChangeConfigurationReq_t *conf, cJSON *payload)
{
    memset(conf, 0, sizeof(ChangeConfigurationReq_t));
    if (payload)
    {
        sprintf(conf->key, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(payload, "key")));
        sprintf(conf->value, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(payload, "value")));
        return 0;
    }
    return -ErrorCode_FormatViolation;
}

int ocpp16_decode_ClearCacheReq(ClearCacheReq_t *conf, cJSON *payload)
{
    memset(conf, 0, sizeof(ClearCacheReq_t));
    return 0;
}

int ocpp16_decode_ClearChargingProfileReq(ClearChargingProfileReq_t *conf, cJSON *payload)
{
    memset(conf, 0, sizeof(ClearChargingProfileReq_t));
    if (payload)
    {
        if (cJSON_HasObjectItem(payload, "id"))
        {
            conf->id = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "id"));
        }else{
            conf->id = -1;
        }
        if (cJSON_HasObjectItem(payload, "connectorId"))
        {
            conf->connectorId = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "connectorId"));
        }else{
            conf->connectorId = -1;
        }
        if (cJSON_HasObjectItem(payload, "stackLevel"))
        {
            conf->stackLevel = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "stackLevel"));
        }else{
            conf->stackLevel = -1;
        }
        if (cJSON_HasObjectItem(payload, "chargingProfilePurpose"))
        {
            const char *chargingProfilePurpose = cJSON_GetStringValue(cJSON_GetObjectItem(payload, "chargingProfilePurpose"));
            if (strncmp("ChargePointMaxProfile", chargingProfilePurpose, strlen(chargingProfilePurpose)) == 0)
                conf->chargingProfilePurpose = ChargingProfilePurposeType_ChargePointMaxProfile;
            if (strncmp("TxDefaultProfile", chargingProfilePurpose, strlen(chargingProfilePurpose)) == 0)
                conf->chargingProfilePurpose = ChargingProfilePurposeType_TxDefaultProfile;
            if (strncmp("TxProfile", chargingProfilePurpose, strlen(chargingProfilePurpose)) == 0)
                conf->chargingProfilePurpose = ChargingProfilePurposeType_TxProfile;
        }

        return 0;
    }
    return -ErrorCode_FormatViolation;
}

int ocpp16_decode_DataTransferReq(DataTransferReq_t *conf, cJSON *payload)
{
    memset(conf, 0, sizeof(DataTransferReq_t));
    if (payload)
    {
        sprintf(conf->vendorId, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(payload, "vendorId")));
        sprintf(conf->messageId, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(payload, "messageId")));

        cJSON *data = cJSON_GetObjectItem(payload, "data");
        sprintf(conf->data.type, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(payload, "type")));
        if (cJSON_HasObjectItem(payload, "timeZone"))
        {
            sprintf(conf->data.timeZone, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(payload, "timeZone")));
        }
        sprintf(conf->data.minAllowBalance, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(payload, "minAllowBalance")));

        cJSON *price = cJSON_GetObjectItem(payload, "price");
        conf->data.price.count = cJSON_GetArraySize(price);
        int i;
        for (i = 0; i < conf->data.price.count; i++)
        {
            cJSON *items = cJSON_GetArrayItem(price, i);
            sprintf(conf->data.price.items[i].startTime, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(items, "startTime")));
            sprintf(conf->data.price.items[i].stopTime, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(items, "stopTime")));
            if (cJSON_HasObjectItem(items, "electrPrice"))
            {
                sprintf(conf->data.price.items[i].electrPrice, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(items, "electrPrice")));
            }
            if (cJSON_HasObjectItem(items, "servicePrice"))
            {
                sprintf(conf->data.price.items[i].servicePrice, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(items, "servicePrice")));
            }
            if (cJSON_HasObjectItem(items, "durationPrice"))
            {
                sprintf(conf->data.price.items[i].durationPrice, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(items, "durationPrice")));
            }
        }
        return 0;
    }
    return -ErrorCode_FormatViolation;
}

int ocpp16_decode_GetCompositeScheduleReq(GetCompositeScheduleReq_t *conf, cJSON *payload)
{
    memset(conf, 0, sizeof(GetCompositeScheduleReq_t));
    if (payload)
    {
        conf->connectorId = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "connectorId"));
        conf->duration = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "duration"));

        if (cJSON_HasObjectItem(payload, "chargingRateUnit"))
        {
            const char *chargingRateUnit = cJSON_GetStringValue(cJSON_GetObjectItem(payload, "chargingRateUnit"));
            if (strncmp("W", chargingRateUnit, strlen(chargingRateUnit)) == 0)
                conf->chargingRateUnit = ChargingRateUnitType_W;
            if (strncmp("A", chargingRateUnit, strlen(chargingRateUnit)) == 0)
                conf->chargingRateUnit = ChargingRateUnitType_A;
        }

        return 0;
    }
    return -ErrorCode_FormatViolation;
}

int ocpp16_decode_GetConfigurationReq(GetConfigurationReq_t *conf, cJSON *payload)
{
    memset(conf, 0, sizeof(GetConfigurationReq_t));
    if (payload)
    {
        if (cJSON_HasObjectItem(payload, "key"))
        {
            cJSON *key = cJSON_GetObjectItem(payload, "key");
            conf->key.count = cJSON_GetArraySize(key);
            int i;
            for (i = 0; i < conf->key.count; i++)
            {
                sprintf(conf->key.items[i], "%s", cJSON_GetStringValue(cJSON_GetArrayItem(key, i)));
            }
        }
        return 0;
    }
    return -ErrorCode_FormatViolation;
}

int ocpp16_decode_GetDiagnosticsReq(GetDiagnosticsReq_t *conf, cJSON *payload)
{
    memset(conf, 0, sizeof(GetDiagnosticsReq_t));
    if (payload)
    {
        sprintf(conf->location, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(payload, "location")));
        if (cJSON_HasObjectItem(payload, "retries"))
        {
            conf->retries = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "retries"));
        }else{
            conf->retries = 1;
        }
        if (cJSON_HasObjectItem(payload, "retryInterval"))
        {
            conf->retryInterval = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "retryInterval"));
        }else{
            conf->retryInterval = 3;
        }
        if (cJSON_HasObjectItem(payload, "startTime"))
        {
            conf->startTime = RFC3339String_to_time(cJSON_GetStringValue(cJSON_GetObjectItem(payload, "startTime")), NULL, NULL);
        }
        if (cJSON_HasObjectItem(payload, "stopTime"))
        {
            conf->stopTime = RFC3339String_to_time(cJSON_GetStringValue(cJSON_GetObjectItem(payload, "stopTime")), NULL, NULL);
        }
        return 0;
    }
    return -ErrorCode_FormatViolation;
}

int ocpp16_decode_GetLocalListVersionReq(GetLocalListVersionReq_t *conf, cJSON *payload)
{
    memset(conf, 0, sizeof(GetLocalListVersionReq_t));

    return -ErrorCode_FormatViolation;
}

static void ocpp16_decode_ChargeProfile(ChargingProfile_t *conf, cJSON *payload)
{
    conf->chargingProfileId = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "chargingProfileId"));
    if (cJSON_HasObjectItem(payload, "transactionId"))
    {
        conf->transactionId = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "transactionId"));
    }
    conf->stackLevel = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "stackLevel"));

    char* chargingProfilePurpose = cJSON_GetStringValue(cJSON_GetObjectItem(payload, "chargingProfilePurpose"));
    if (strncmp("ChargePointMaxProfile", chargingProfilePurpose, strlen(chargingProfilePurpose))==0) conf->chargingProfilePurpose = ChargingProfilePurposeType_ChargePointMaxProfile;
    if (strncmp("TxDefaultProfile", chargingProfilePurpose, strlen(chargingProfilePurpose))==0) conf->chargingProfilePurpose = ChargingProfilePurposeType_TxDefaultProfile;
    if (strncmp("TxProfile", chargingProfilePurpose, strlen(chargingProfilePurpose))==0) conf->chargingProfilePurpose = ChargingProfilePurposeType_TxProfile;

    char* chargingProfileKind = cJSON_GetStringValue(cJSON_GetObjectItem(payload, "chargingProfileKind"));
    if (strncmp("Absolute", chargingProfileKind, strlen(chargingProfileKind))==0) conf->chargingProfileKind = ChargingProfileKindType_Absolute;
    if (strncmp("Recurring", chargingProfileKind, strlen(chargingProfileKind))==0) conf->chargingProfileKind = ChargingProfileKindType_Recurring;
    if (strncmp("Relative", chargingProfileKind, strlen(chargingProfileKind))==0) conf->chargingProfileKind = ChargingProfileKindType_Relative;

    if (cJSON_HasObjectItem(payload, "recurrencyKind"))
    {
        char* recurrencyKind = cJSON_GetStringValue(cJSON_GetObjectItem(payload, "recurrencyKind"));
        if (strncmp("Relative", recurrencyKind, strlen(recurrencyKind))==0) conf->recurrencyKind = RecurrencyKindType_Daily;
        if (strncmp("Weekly", recurrencyKind, strlen(recurrencyKind))==0) conf->recurrencyKind = RecurrencyKindType_Weekly;
    }
    if (cJSON_HasObjectItem(payload, "validFrom"))
    {
        conf->validFrom = RFC3339String_to_time(cJSON_GetStringValue(cJSON_GetObjectItem(payload, "validFrom")), NULL, NULL);
    }
    if (cJSON_HasObjectItem(payload, "validTo"))
    {
        conf->validTo = RFC3339String_to_time(cJSON_GetStringValue(cJSON_GetObjectItem(payload, "validTo")), NULL, NULL);
    }

    cJSON *chargingSchedule = cJSON_GetObjectItem(payload, "chargingSchedule");
    if (cJSON_HasObjectItem(payload, "duration"))
    {
        conf->chargingSchedule.duration = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(chargingSchedule, "duration"));
    }
    if (cJSON_HasObjectItem(payload, "startTime"))
    {
        conf->chargingSchedule.startTime = RFC3339String_to_time(cJSON_GetStringValue(cJSON_GetObjectItem(chargingSchedule, "startTime")), NULL, NULL);
    }
    
    char* chargingRateUnit = cJSON_GetStringValue(cJSON_GetObjectItem(chargingSchedule, "chargingRateUnit"));
    if (strncmp("W", chargingRateUnit, strlen(chargingRateUnit))==0) conf->chargingSchedule.chargingRateUnit = ChargingRateUnitType_W;
    if (strncmp("A", chargingRateUnit, strlen(chargingRateUnit))==0) conf->chargingSchedule.chargingRateUnit = ChargingRateUnitType_A;
    
    if (cJSON_HasObjectItem(payload, "minChargingRate"))
    {
        conf->chargingSchedule.minChargingRate = cJSON_GetNumberValue(cJSON_GetObjectItem(chargingSchedule, "minChargingRate"));
    }

    cJSON *chargingSchedulePeriod = cJSON_GetObjectItem(chargingSchedule, "chargingSchedulePeriod");
    conf->chargingSchedule.chargingSchedulePeriod.count = cJSON_GetArraySize(chargingSchedulePeriod);
    int i;
    for (i = 0; i < conf->chargingSchedule.chargingSchedulePeriod.count; i++)
    {
        cJSON *items = cJSON_GetArrayItem(chargingSchedulePeriod, i);
        conf->chargingSchedule.chargingSchedulePeriod.items[i].startPeriod = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(items, "startPeriod"));
        conf->chargingSchedule.chargingSchedulePeriod.items[i].limit = cJSON_GetNumberValue(cJSON_GetObjectItem(items, "limit"));
        if (cJSON_HasObjectItem(payload, "numberPhases"))
        {
            conf->chargingSchedule.chargingSchedulePeriod.items[i].numberPhases = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(items, "numberPhases"));
        }
    }
}

int ocpp16_decode_RemoteStartTransactionReq(RemoteStartTransactionReq_t *conf, cJSON *payload)
{
    memset(conf, 0, sizeof(RemoteStartTransactionReq_t));
    if (payload)
    {
        sprintf(conf->idTag, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(payload, "idTag")));
        if (cJSON_HasObjectItem(payload, "connectorId"))
        {
            conf->connectorId = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "connectorId"));
        }
        if (cJSON_HasObjectItem(payload, "chargingProfile"))
        {
            cJSON *chargingProfile = cJSON_GetObjectItem(payload, "chargingProfile");
            ocpp16_decode_ChargeProfile(&conf->chargingProfile, chargingProfile);
            conf->chargingProfile_used = 1;
        }
        return 0;
    }
    return -ErrorCode_FormatViolation;
}

int ocpp16_decode_RemoteStopTransactionReq(RemoteStopTransactionReq_t *conf, cJSON *payload)
{
    memset(conf, 0, sizeof(RemoteStopTransactionReq_t));
    if (payload)
    {
        conf->transactionId = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "transactionId"));
        return 0;
    }
    return -ErrorCode_FormatViolation;
}

int ocpp16_decode_ReserveNowReq(ReserveNowReq_t *conf, cJSON *payload)
{
    memset(conf, 0, sizeof(ReserveNowReq_t));
    if (payload)
    {
        conf->connectorId = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "connectorId"));
        conf->expiryDate = RFC3339String_to_time(cJSON_GetStringValue(cJSON_GetObjectItem(payload, "expiryDate")), NULL, NULL);
        sprintf(conf->idTag, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(payload, "idTag")));
        if (cJSON_HasObjectItem(payload, "parentIdTag"))
        {
            sprintf(conf->parentIdTag, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(payload, "parentIdTag")));
        }
        conf->reservationId = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "reservationId"));
        return 0;
    }
    return -ErrorCode_FormatViolation;
}

int ocpp16_decode_ResetReq(ResetReq_t *conf, cJSON *payload)
{
    memset(conf, 0, sizeof(ResetReq_t));
    if (payload)
    {
        const char *type = cJSON_GetStringValue(cJSON_GetObjectItem(payload, "type"));
        if (strncmp("Hard", type, strlen(type)) == 0)
            conf->type = ResetType_Hard;
        if (strncmp("Soft", type, strlen(type)) == 0)
            conf->type = ResetType_Soft;
        return 0;
    }
    return -ErrorCode_FormatViolation;
}

int ocpp16_decode_SendLocalListReq(SendLocalListReq_t *conf, cJSON *payload)
{
    memset(conf, 0, sizeof(SendLocalListReq_t));
    if (payload)
    {
        conf->listVersion = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "listVersion"));

        if (cJSON_HasObjectItem(payload, "localAuthorizationList"))
        {
            cJSON *localAuthorizationList = cJSON_GetObjectItem(payload, "localAuthorizationList");
            conf->localAuthorizationList.count = cJSON_GetArraySize(localAuthorizationList);
            int i;
            for (i = 0; i < conf->localAuthorizationList.count; i++)
            {
                cJSON *items = cJSON_GetArrayItem(localAuthorizationList, i);
                sprintf(conf->localAuthorizationList.items[i].idTag, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(items, "idTag")));
                if (cJSON_HasObjectItem(items, "idTagInfo"))
                {
                    const char *status = cJSON_GetStringValue(cJSON_GetObjectItem(items, "status"));
                    if (strncmp("Accepted", status, strlen(status)) == 0)
                        conf->localAuthorizationList.items[i].idTagInfo.status = AuthorizationStatus_Accepted;
                    if (strncmp("Blocked", status, strlen(status)) == 0)
                        conf->localAuthorizationList.items[i].idTagInfo.status = AuthorizationStatus_Blocked;
                    if (strncmp("Expired", status, strlen(status)) == 0)
                        conf->localAuthorizationList.items[i].idTagInfo.status = AuthorizationStatus_Expired;
                    if (strncmp("Invalid", status, strlen(status)) == 0)
                        conf->localAuthorizationList.items[i].idTagInfo.status = AuthorizationStatus_Invalid;
                    if (strncmp("ConcurrentTx", status, strlen(status)) == 0)
                        conf->localAuthorizationList.items[i].idTagInfo.status = AuthorizationStatus_ConcurrentTx;
                    if (cJSON_HasObjectItem(items, "parentIdTag"))
                    {
                        sprintf(conf->localAuthorizationList.items[i].idTagInfo.parentIdTag, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(items, "parentIdTag")));
                    }
                    if (cJSON_HasObjectItem(items, "expiryDate"))
                    {
                        conf->localAuthorizationList.items[i].idTagInfo.expiryDate = RFC3339String_to_time(cJSON_GetStringValue(cJSON_GetObjectItem(items, "expiryDate")),NULL,NULL);
                    }
                }
            }
        }
        const char *updateType = cJSON_GetStringValue(cJSON_GetObjectItem(payload, "updateType"));
        if (strncmp("Differential", updateType, strlen(updateType)) == 0)
            conf->updateType = UpdateType_Differential;
        if (strncmp("Full", updateType, strlen(updateType)) == 0)
            conf->updateType = UpdateType_Full;
        return 0;
    }
    return -ErrorCode_FormatViolation;
}

int ocpp16_decode_SetChargingProfileReq(SetChargingProfileReq_t *conf, cJSON *payload)
{
    memset(conf, 0, sizeof(SetChargingProfileReq_t));
    if (payload)
    {
        conf->connectorId = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "connectorId"));
        ocpp16_decode_ChargeProfile(&conf->csChargingProfiles, cJSON_GetObjectItem(payload, "csChargingProfiles"));
        return 0;
    }
    return -ErrorCode_FormatViolation;
}

int ocpp16_decode_TriggerMessageReq(TriggerMessageReq_t *conf, cJSON *payload)
{
    memset(conf, 0, sizeof(TriggerMessageReq_t));
    if (payload)
    {
        if (cJSON_HasObjectItem(payload, "connectorId"))
        {
            conf->connectorId = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "connectorId"));
        }
        const char *requestedMessage = cJSON_GetStringValue(cJSON_GetObjectItem(payload, "requestedMessage"));
        if (strncmp("BootNotification", requestedMessage, strlen(requestedMessage)) == 0)
            conf->requestedMessage = MessageTrigger_BootNotification;
        if (strncmp("DiagnosticsStatusNotification", requestedMessage, strlen(requestedMessage)) == 0)
            conf->requestedMessage = MessageTrigger_DiagnosticsStatusNotification;
        if (strncmp("FirmwareStatusNotification", requestedMessage, strlen(requestedMessage)) == 0)
            conf->requestedMessage = MessageTrigger_FirmwareStatusNotification;
        if (strncmp("Heartbeat", requestedMessage, strlen(requestedMessage)) == 0)
            conf->requestedMessage = MessageTrigger_Heartbeat;
        if (strncmp("MeterValues", requestedMessage, strlen(requestedMessage)) == 0)
            conf->requestedMessage = MessageTrigger_MeterValues;
        if (strncmp("StatusNotification", requestedMessage, strlen(requestedMessage)) == 0)
            conf->requestedMessage = MessageTrigger_StatusNotification;
        return 0;
    }
    return -ErrorCode_FormatViolation;
}

int ocpp16_decode_UnlockConnectorReq(UnlockConnectorReq_t *conf, cJSON *payload)
{
    memset(conf, 0, sizeof(UnlockConnectorReq_t));
    if (payload)
    {
        conf->connectorId = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "connectorId"));
        return 0;
    }
    return -ErrorCode_FormatViolation;
}

int ocpp16_decode_UpdateFirmwareReq(UpdateFirmwareReq_t *conf, cJSON *payload)
{
    memset(conf, 0, sizeof(UpdateFirmwareReq_t));
    if (payload)
    {
        sprintf(conf->location, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(payload, "location")));
        if (cJSON_HasObjectItem(payload, "retrieveDate"))
        {
            sprintf(conf->retrieveDate, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(payload, "retrieveDate")));
        }
        if (cJSON_HasObjectItem(payload, "retries"))
        {
            conf->retries = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "retries"));
        }
        if (cJSON_HasObjectItem(payload, "retryInterval"))
        {
            conf->retryInterval = (int)cJSON_GetNumberValue(cJSON_GetObjectItem(payload, "retryInterval"));
        }
        return 0;
    }
    return -ErrorCode_FormatViolation;
}
