#include <ctype.h>
#include <stdio.h>
#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, unsigned *u)
{
    const char *pc = str;
    char c;
    unsigned val = 0;
    // skip leading spaces
    while(*pc <= ' ' && *pc) 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(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 number of partialy matched chars from str 
 * 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);
    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;
    buff_len--;
    n = snprintf(buff, buff_len, "{CANDTG %x %x %lx %lx [", 
        can_msg->flags, can_msg->cob, 
        can_msg->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';
    return n;
}

/**
 * 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;
        can_msg->timestamp = (unsigned long)u;
        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;
}


