#include <ctype.h>

#ifndef __RTL__

#include <stdio.h>
#include <sys/time.h>

#else /*__RTL__*/

#include <rtl.h>
#include <string.h>

#endif /*__RTL__*/

#include "can_vca.h"

/************************ support functions *********************/
/**
 * vca_gethex - gets one hexadecimal number from string
 * @str: scanned string
 * @u: pointer to store got value
 *
 * Returns the number of eaten chars
 */
int vca_gethex(const char *str, int *u)
{
    const char *pc = str;
    char c;
    int val = 0;
    int neg = 0;
    // skip leading spaces
    while(*pc <= ' ' && *pc) pc++; 
    if(*pc == '-') {neg = 1; pc++;}
    for( ; *pc; pc++) {
        c = tolower(*pc);
        if(c >= '0' && c <= '9') {
            val *= 16;
            val += c - '0';
        }
        else if(c >= 'a' && c <= 'f') {
            val *= 16;
            val += 10 + (c - 'a');
        }
        else break;
    }
    if(neg) val = -val;
    if(u) *u = val;
    return pc - str;
}

/**
 * vca_strmatch - get token from string
 * @str: scanned string
 * @template: token template
 * template consists of characters and '~' matching one or more of spaces
 * ie. '~hello' matches ' hello', '  hello', '   hello' etc.
 *
 * Returns the number of used chars from str if match
 * or negative value (number of partially matched chars from str - 1) 
 * if template does not match
 */
int vca_strmatch(const char *str, const char *template)
{
    const char *pcs = str, *pct;
    for(pct=template; *pct; pct++) {
        if(*pct == '~') {
            if(*pcs > ' ') break;
            while(*pcs <= ' ') pcs++;
        }
        else if(*pcs != *pct) break;
        else pcs++;
    }
    if(*pct) return -(pcs - str + 1);
    return pcs - str;
}

/*******************************************************************/
/* CAN messages serialization support */

/**
 * vca_msg2str - converts canmsg_t to the string
 * @can_msg: pointer to the serialized CAN message
 * @buff: buffer for the serialized string
 * @buff_len: max length of serialized string, including terminating zero
 *
 * Returns the number of written chars not including terminating zero
 */
int vca_msg2str(const struct canmsg_t *can_msg, char *buff, int buff_len)
{
    int n, i;
    unsigned long timestamp;
   #ifdef CAN_MSG_VERSION_2
    timestamp=can_msg->timestamp.tv_usec;
   #else /* CAN_MSG_VERSION_2 */
    timestamp=can_msg->timestamp;
   #endif /* CAN_MSG_VERSION_2 */
    buff_len--;

    n = snprintf(buff, buff_len, "{CANDTG %x %x %lx %lx [", 
        can_msg->flags, can_msg->cob, 
        timestamp, can_msg->id);
        //can_msg->length);  
    for(i=0; i<can_msg->length; i++) {
        if(buff_len > n && i > 0) 
            n += snprintf(buff + n, buff_len - n, " ");
        if(buff_len > n) 
            n += snprintf(buff + n, buff_len - n, "%02x", can_msg->data[i]);
    }
    if(buff_len > n) 
        n += snprintf(buff + n, buff_len - n, "]}");
    buff[buff_len] = '\0'; // ensure that string will be closed even if it not fit the buffer
    return n;
}

static char vca_byte2str_buff[10];

/**
 * vca_byte2str - converts byte to the string
 * @b: byte to convert
 * @base: base, can be (2, 8, 16)
 *
 * Returns: string representation of b in chosen base
 */
const char* vca_byte2str(unsigned char b, int base)
{
    int i;
    int digit_cnt = 0;
    switch(base) {
        case  2: digit_cnt = 8; break;
        case  8: digit_cnt = 3; break;
        case 16: digit_cnt = 2; break;
    }
    for(i=0; i<digit_cnt; i++) {
        int r = b % base;
        char c = '0' + r;
        if(r > 9) c = 'a' + (r - 10);
        vca_byte2str_buff[digit_cnt - i - 1] = c;
        b /= base;
    }
    vca_byte2str_buff[digit_cnt] = '\0';
    return vca_byte2str_buff;
}

/**
 * vca_str2msg - converts the string to the canmsg_t object
 * @can_msg: pointer to the serialized CAN message
 * @str: string representing CAN message
 *
 * Returns number of read chars if succeed else zero or negative value.
 */
int vca_str2msg(struct canmsg_t *can_msg, const char *str)
{
    int pos = 0, n, i;
    unsigned u;
    int ok = -1;
    if(!can_msg) return 0;
    while(1) {
        if((n = vca_strmatch(str + pos, "{CANDTG~")) <= 0) break;
        pos += n;
        if((n = vca_gethex(str + pos, &u)) <= 0) break;
        can_msg->flags = (short)u;
        pos += n;
        if((n = vca_gethex(str + pos, &u)) <= 0) break;
        can_msg->cob = (int)u;
        pos += n;
        if((n = vca_gethex(str + pos, &u)) <= 0) break;
       #ifdef CAN_MSG_VERSION_2
        can_msg->timestamp.tv_usec = (unsigned long)u;;
       #else /* CAN_MSG_VERSION_2 */
        can_msg->timestamp = (unsigned long)u;
       #endif /* CAN_MSG_VERSION_2 */
        pos += n;
        if((n = vca_gethex(str + pos, &u)) <= 0) break;
        can_msg->id = (unsigned long)u;
        pos += n;
        //if((n = vca_gethex(str + pos, &u)) <= 0) break;
        //can_msg->length = (unsigned int)u;
        if((n = vca_strmatch(str + pos, "~[")) <= 0) break;
        pos += n;
        for(i=0; i<8; i++) {
            if((n = vca_gethex(str + pos, &u)) <= 0) break;
            can_msg->data[i] = (unsigned char)u;
            pos += n;
        }
        can_msg->length = i;
        ok = 1;
        break;
    }
    return ok * pos;
}
//----------------------------------------------------
/** vca_subtimeval
 * Returns %t1 - %t2 in usec
 */
int vca_subtimeval(struct timeval *t1, struct timeval *t2)
{
    int sec = t1->tv_sec - t2->tv_sec;
    int usec = t1->tv_usec - t2->tv_usec;
    //mylog(LOG_DEB, "sec: %i usec: %i\n", sec, usec);
    return sec * 1000000 + usec;
}
//----------------------------------------------------
/** vca_subtimespec
 * Returns %t1 - %t2
 */
struct timespec vca_subtimespec(const struct timespec *t1, const struct timespec *t2)
{
    int sec = t1->tv_sec - t2->tv_sec;
    int nsec = t1->tv_nsec - t2->tv_nsec;
    struct timespec ret;
    if(nsec < 0) {
        sec--;
        nsec = 1000000000 + nsec;
    }
    ret.tv_sec = sec;
    ret.tv_nsec = nsec;
    return ret;
}

