#ifndef __V2G_SDP_H__
#define __V2G_SDP_H__
#include "msystem.h"
#include "mthread.h"
#include <openssl/ssl.h>
#include <openssl/err.h>
#include "interface.h"
#include "common/exi_v2gtp.h"
#include "common/exi_bitstream.h"
#include "app_handshake/appHand_Datatypes.h"
#include "app_handshake/appHand_Decoder.h"
#include "app_handshake/appHand_Encoder.h"
#include "din/din_msgDefDatatypes.h"
#include "din/din_msgDefDecoder.h"
#include "din/din_msgDefEncoder.h"
#include "iso/iso2_msgDefDatatypes.h"
#include "iso/iso2_msgDefDecoder.h"
#include "iso/iso2_msgDefEncoder.h"
#include "evse_main.h"

extern const char* v2g_msg_type[];

#define LOG_TAG_V2G     "V2G"

#define DEFAULT_BUFFER_SIZE 8192

#define ISO_15118_2010_MSG_DEF "urn:iso:15118:2:2010:MsgDef"
#define ISO_15118_2010_MAJOR   1

#define DIN_70121_2012_MSG_DEF "urn:din:70121:2012:MsgDef"
#define DIN_70121_2012_MAJOR   2

#define ISO_15118_2013_MSG_DEF "urn:iso:15118:2:2013:MsgDef"
#define ISO_15118_2013_MAJOR   2

enum v2g_protocol {
    V2G_PROTO_UNKNOWN = 0,
    V2G_PROTO_ISO15118_2010,
    V2G_PROTO_DIN70121_2012,
    V2G_PROTO_ISO15118_2013
};

/* ISO 15118 table 105 */
enum v2g_service {
    V2G_SERVICE_ID_CHARGING = 1,
    V2G_SERVICE_ID_CERTIFICATE = 2,
    V2G_SERVICE_ID_INTERNET = 3,
    V2G_SERVICE_ID_USECASEINFORMATION = 4,
};

enum charging_phase {
    PHASE_INIT = 0,
    PHASE_AUTH,
    PHASE_PARAMETER,
    PHASE_ISOLATION,
    PHASE_PRECHARGE,
    PHASE_CHARGE,
    PHASE_WELDING,
    PHASE_STOP,
    PHASE_LENGTH
};

enum V2gMsgTypeId {
    V2G_SUPPORTED_APP_PROTOCOL_MSG = 0,
    V2G_SESSION_SETUP_MSG,
    V2G_SERVICE_DISCOVERY_MSG,
    V2G_SERVICE_DETAIL_MSG,
    V2G_PAYMENT_SERVICE_SELECTION_MSG,
    V2G_PAYMENT_DETAILS_MSG,
    V2G_AUTHORIZATION_MSG,
    V2G_CHARGE_PARAMETER_DISCOVERY_MSG,
    V2G_METERING_RECEIPT_MSG,
    V2G_CERTIFICATE_UPDATE_MSG,
    V2G_CERTIFICATE_INSTALLATION_MSG,
    V2G_CHARGING_STATUS_MSG,
    V2G_CABLE_CHECK_MSG,
    V2G_PRE_CHARGE_MSG,
    V2G_POWER_DELIVERY_MSG,
    V2G_CURRENT_DEMAND_MSG,
    V2G_WELDING_DETECTION_MSG,
    V2G_SESSION_STOP_MSG,
    V2G_UNKNOWN_MSG
};

enum v2g_event {
    V2G_EVENT_NO_EVENT = 0,
    V2G_EVENT_TERMINATE_CONNECTION, // Terminate the connection immediately
    V2G_EVENT_SEND_AND_TERMINATE,   // Send next msg and terminate the connection
    V2G_EVENT_SEND_RECV_EXI_MSG,    // If msg must not be exi-encoded and can be sent directly
    V2G_EVENT_IGNORE_MSG            // Received message can't be handled
};

struct SAE_Bidi_Data {
    bool enabled_sae_v2h;
    bool enabled_sae_v2g;
    int8_t sae_v2h_minimal_soc;
    bool discharging;
};

struct v2g_context;

typedef struct v2g_connect
{
    void* next_client;
    void* private;
    struct v2g_context *v2g;
    mthread_t thread;
    char* ifname;

    int quit;

    int tcp_socket;
    SSL *ssl;
    int (*v2g_connection_send)(struct v2g_connect* self, uint8_t* data, int length);
    int (*v2g_connection_recv)(struct v2g_connect* self, uint8_t* buff, int length, int timeout);
    void (*v2g_connection_exit)(struct v2g_connect* self);


    /* V2GTP EXI encoding/decoding stuff */
    uint8_t rxbuff[DEFAULT_BUFFER_SIZE];
    uint32_t rxlen;
    exi_bitstream_t stream;

    int selected_protocol;
    int is_tls_connection;

    struct appHand_exiDocument handshake_req;
    struct appHand_exiDocument handshake_resp;

    struct din_exiDocument dinEXIDocument_xin;
    struct din_exiDocument dinEXIDocument_out;

    struct iso2_exiDocument iso2EXIDocument_xin;
    struct iso2_exiDocument iso2EXIDocument_out;

    EVP_PKEY *pubkey;
}v2g_connect_t;

#define GEN_CHALLENGE_SIZE            16
#define SHA256_SIGNATURE_SIZE     32
#define MAX_EXI_SIZE                8192

typedef struct v2g_context
{
    int quit;

    evse_slac_t evse_slac;

    pcu_port_t  *pcu;
    ccu_port_t  *ccu;
    secc_port_t *secc;

    mthread_t thread;
    pthread_mutex_t mutex;
    
    const char* if_name;

    int tcp_server_quit;
    int tls_server_quit;
    int sdp_server_quit;

    int sdp_socket;
    int tcp_socket;
    int tls_socket;

    SSL_CTX *ctx;
    struct sockaddr_in6 local_tcp_addr;
    struct sockaddr_in6 local_tls_addr;

    mthread_t sdp_thread;
    mthread_t tcp_thread;
    mthread_t tls_thread;

    v2g_connect_t client[2];
    void* next_client;
    uint64_t evse_session_id; // Is the evse session id, generated by the evse. This id shall not change during a V2G Communication Session.
    uint64_t evcc_session_id;

    
    int state;
    enum V2gMsgTypeId last_v2g_msg;    /* holds the current v2g msg type */
    enum V2gMsgTypeId current_v2g_msg; /* holds the last v2g msg type */

    struct din_DC_EVStatusType last_ev_status;

    uint8_t evse_isolation_status;
    uint8_t evse_notification;
    uint8_t iso_selected_payment_option;
    uint8_t sa_schedule_tuple_id;

    uint8_t evse_status_code[PHASE_LENGTH];
    uint8_t evse_processing[PHASE_LENGTH];

    bool terminate_connection_on_failed_response;
    bool receipt_required;

    int64_t auth_start_timeout;
    int64_t auth_timeout_pnc;
    int64_t auth_timeout_eim;
    uint8_t gen_challenge[GEN_CHALLENGE_SIZE];
} v2g_context_t;

int v2g_sdp_server_init(v2g_context_t* v2g);
void v2g_sdp_server_exit(v2g_context_t* v2g);
void* v2g_sdp_server_listen(void* args) ;

int v2g_tcp_server_init(v2g_context_t* v2g);
void v2g_tcp_server_exit(v2g_context_t* v2g);
void* v2g_tcp_server_loop(void* args);
int v2g_tcp_client_init(v2g_connect_t* conn, v2g_context_t* v2g);
void v2g_tcp_client_exit(struct v2g_connect* conn);

int v2g_tls_server_init(v2g_context_t* v2g);
void v2g_tls_server_exit(v2g_context_t* v2g);
void* v2g_tls_server_loop(void* args);
int v2g_tls_client_init(v2g_connect_t* conn, v2g_context_t* v2g);
void v2g_tls_client_exit(struct v2g_connect* conn);

int v2g_context_init(v2g_context_t* v2g, const char* if_name);
void v2g_context_exit(v2g_context_t* v2g);
void v2g_connection_free(v2g_context_t* v2g, v2g_connect_t* conn);
void* v2g_connection_loop(void* args);

int v2g_handle_iso_request(v2g_connect_t* conn);
int v2g_handle_din_request(v2g_connect_t* conn);

float calc_physical_value(const int16_t value, const int8_t multiplier) ;
#endif//__V2G_SDP_H__



