#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "types.h"
#include "platform.h"
#include "ssl_log.h"
#include "ssl_utils.h"
#include "ssl_profile.h"

#include "samsung_softsim_logic_api.h"

#define l1 "%02x"
#define l2 l1 l1
#define l4 l2 l2
#define l8 l4 l4
#define l16 l8 l8
#define l32 l16 l16

#define v1(i) tmp[i]
#define v2(i) v1(i), v1(i+1)
#define v4(i) v2(i), v2(i+2)
#define v8(i) v4(i), v4(i+4)
#define v16(i) v8(i), v8(i+8)
#define v32(i) v16(i), v16(i+16)

void dump_bytes(const char *prompt, uint8_t *buff, size_t size){
    uint8_t *tmp = buff;

    if(NULL == tmp ) {
        MLOG_D("========= buff is null=======");
        return;
    }

    MLOG_D("=========START: %s=======", prompt);

    int i,j;
    for(i = 0; i + 31 < size; i += 32) {
        MLOG_D(l32, v32(i));
    }

    if (i < size) {
        uint8_t buf[32] = {0};
        for (j = i; j < size; j++) {
            buf[j - i] = tmp[j];
        }

        tmp = buf;
        MLOG_D(l32, v32(0));
    }

    MLOG_D("=========END(%d): %s=======", size, prompt);
}

uint8_t* string_to_bytes(const char *str, size_t *size){
    /*FUNC_ENTER();*/
    int buff_sz = plt_strlen(str) / 2;
    uint8_t *bytes = plt_malloc(buff_sz);
    if(NULL == bytes) {
        MLOG_E("error ERR_MALLOC_FAILED");

        return NULL;
    }

    size_t i =0;
    char msb = 0;
    char lsb = 0;
    uint8_t c;

    for( i = 0; i < buff_sz; i++){
        msb = str[i * 2];
        lsb = str[i * 2 + 1];

        if ( msb >= '0' && msb <= '9'){
            msb -= '0';
        }

        if ( msb >= 'a' && msb <= 'z'){
            msb -= ('a' - 0xa ) ;
        }

        if ( msb >= 'A' && msb <= 'Z'){
            msb -= ('A' - 0xa ) ;
        }

        if ( lsb >= '0' && lsb <= '9'){
            lsb -= '0';
        }

        if ( lsb >= 'a' && lsb <= 'z'){
            lsb -= ('a' - 0xa ) ;
        }

        if ( lsb >= 'A' && lsb <= 'Z'){
            lsb -= ('A' - 0xa ) ;
        }

        c = msb <<4 | lsb;

        bytes[i] = c;
    }

    if(NULL != size){
        *size = buff_sz;
    }

    return bytes;
}

void bytes_to_string(uint8_t *bytes, size_t size, char *str){
    int i = 0, len = size * 2 + 1;

    if(NULL == bytes){
        return;
    }
    // str must be allocated correctly
    //
    plt_memset(str, 0, len);

    for(i = 0; i < size; i++){
        sprintf((char*)(str + 2 * i), "%02X", bytes[i]);
    }

    str[len - 1] = 0;
}

void print_byte_line(const char *desc, uint8_t* bytes, size_t len){
    FUNC_ENTER();

    char *line_str = (char*)plt_malloc(len*2 + 1);
    if(NULL == line_str){
        MLOG_E("memory allocate failed");
        return;
    }

    bytes_to_string(bytes, len, line_str);

    plt_free(line_str);
}

void dump_cmd_apdu(const command_apdu_t *cmd_apdu){

    if(NULL == cmd_apdu) {
        MLOG_E("cmd_apdu is NULL");
    }

    size_t apdu_size = cmd_apdu->size_of_apdu;

    MLOG_D("=========START: command apdu =======");

    MLOG_D("header::CLA [0x%02x]", cmd_apdu->header.CLA);
    MLOG_D("header::INS [0x%02x]", cmd_apdu->header.INS);
    MLOG_D("header::P1 [0x%02x]", cmd_apdu->header.P1);
    MLOG_D("header::P2 [0x%02x]", cmd_apdu->header.P2);

    if(4 == apdu_size) {
        return;
    }

    if(5 == apdu_size) {
        MLOG_D("body::Lc [0x%02x]", cmd_apdu->body.lc);
        return;
    }

    MLOG_D("body::Le [0x%02x]", cmd_apdu->body.le);

    if(0 != cmd_apdu->body.lc){
        MLOG_D("body::Lc [0x%02x]", cmd_apdu->body.lc);
        dump_bytes("body::data", (uint8_t*)cmd_apdu->body.data, (size_t)cmd_apdu->body.lc);
    }
}

void ltrim(char *s) {
    int l=0, p=0, k=0;

    l = plt_strlen(s);
    if( l == 0 ) return;

    p = 0;
    while( s[p] == ' ' || s[p] == '\t' )  p++;

    if( p == 0 ) return;

    while( s[k] != '\0') s[k++] = s[p++];

    return;
}

void rtrim(char *s) {
    int l=0,p=0;

    l = plt_strlen(s);
    if( l == 0 ) return;

    p = l -1;
    while( s[p] == ' ' || s[p] == '\t' ) {
        s[p--] = '\0';
        if( p < 0 ) break;
    }

    return;
}

int char_to_hex(char c) {
    if ('0' <= c && c <= '9') {
        return c - '0';
    }
    if ('A' <= c && c <= 'F') {
        return c - 'A' + 10;
    }
    if ('a' <= c && c <= 'f') {
        return c - 'a' + 10;
    }

    return -1;
}

void Ops(void){
    /**(int*)0 = 0;*/
}

void not_implemented_yet(){
    MLOG_E("sorry, not implemented yet...");
}
