#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdint.h>
#include <syslog.h>
#include <stdarg.h>

#include "../../status.h"
#include "../../feeder.h"

typedef struct logapackts_header_t
{
    uint8_t mac[6];
    uint8_t body_nb;
    uint8_t index;
    uint8_t status;
    uint16_t event;
    time_t timestamp;
} __attribute__((packed)) logapackts_header_t;

typedef struct logapackts_t
{
    uint8_t start;
    struct logapackts_header_t header;
    uint8_t body[256];
    uint8_t chs;
    uint8_t end;
} __attribute__((packed)) logapackts_t;

typedef struct logapackts_reply_t
{
    uint8_t start;
    uint8_t ack;
    time_t timestamp;
    uint8_t index;
    uint8_t chs;
    uint8_t end;
} __attribute__((packed)) logapackts_reply_t;


typedef struct logapackts_index_t
{
    uint8_t mac[6];
    uint8_t index;
    struct logapackts_index_t * next;
} logapackts_index_t;


struct logapackts_index_t * indexes;

uint16_t byteSwap16(uint16_t value)
{
    uint16_t swapped;
    swapped = (((0x00FF) & (value >> 8)) |
              ((0xFF00) & (value << 8)));
    return swapped;
}

uint32_t byteSwap32(uint32_t value)
{
    uint32_t swapped;
    swapped = (((0x000000FF) & (value >> 24)) |
              ((0x0000FF00) & (value >> 8)) |
              ((0x00FF0000) & (value << 8)) |
              ((0xFF000000) & (value << 24)));
    return swapped;
}

uint64_t byteSwap64(uint64_t value)
{
    uint64_t swapped;
    swapped = (((0x00000000000000FFULL) & (value >> 56)) |
              ((0x000000000000FF00ULL) & (value >> 40)) |
              ((0x0000000000FF0000ULL) & (value >> 24)) |
              ((0x00000000FF000000ULL) & (value >> 8)) |
              ((0x000000FF00000000ULL) & (value << 8)) |
              ((0x0000FF0000000000ULL) & (value << 24)) |
              ((0x00FF000000000000ULL) & (value << 40)) |
              ((0xFF00000000000000ULL) & (value << 56)));
    return swapped;
}

uint8_t calcChs(unsigned char * data, unsigned int len)
{
    uint8_t res;
    unsigned int i;

    res = 0;
    for(i = 0;i < len; i++)
    {
	res += data[i];
    }
    res = ~res;
    return res;
}


unsigned int deescape(unsigned char * data, unsigned int len)
{
    unsigned int i, dest;

    for (dest = 0, i = 0; i < len; i++)
    {
	if (data[i] == 0x09)
	    data[++i] -= 0x20;
	data[dest++] = data[i];
    }
    return dest;
}

unsigned int escape(unsigned char * data, unsigned int len)
{
    unsigned int i, dest;
    unsigned char temp[sizeof(logapackts_reply_t)];

    memcpy(temp, data, len);
    for (dest = 0, i = 0; i < len; i++)
    {
	if ((temp[i] == 0x02) || (temp[i] == 0x03) || (temp[i] == 0x09))
	{
	    data[dest++] = 0x09;
	    data[dest++] = temp[i] + 0x20;
	}
	else
	    data[dest++] = temp[i];
	    
//	printf("z %d %X\n", dest - 1, data[dest - 1]);
    }
    return dest;
}

struct logapackts_t logapackts;


struct logapackts_index_t * indexNew(uint8_t * mac, uint8_t index_no)
{
    struct logapackts_index_t * new_index;
    
    new_index = malloc(sizeof(struct logapackts_index_t));
    if (new_index == NULL)
	return NULL;
    memcpy(new_index->mac, mac, 6);
    new_index->index = index_no;
    new_index->next = NULL;
    return new_index;
}

int indexScan(uint8_t * mac, uint8_t index_no)
{
    struct logapackts_index_t * index_scan, * index_prev;
    
    index_scan = indexes;
    index_prev = NULL;
    while (index_scan != NULL)
    {
	if (memcmp(mac, index_scan->mac, 6) == 0)
	{
	    if (index_scan->index == index_no)
		return 1;
	    else
	    {
		index_scan->index = index_no;
		return 0;
	    }
	}
	index_prev = index_scan;
	index_scan = index_scan->next;
    }

    index_scan = indexNew(mac, index_no);
    if (indexes == NULL)
	indexes = index_scan;
    else
	index_prev->next = index_scan;
    return 0;
}

int init(void * param)
{
    indexes = NULL;
    return 0;
}

void (* feederLog)(int priority, const char * fmt, ...);

int setLog(void * func)
{
    feederLog = func;
    return 0;
}

unsigned int reply(unsigned char * data)
{
    struct logapackts_reply_t * logapackts_reply;
    unsigned int len;

    logapackts_reply = (struct logapackts_reply_t *)data;
    logapackts_reply->start = 0x02;
    logapackts_reply->ack = 0x06;
    logapackts_reply->timestamp = byteSwap32(time(NULL));
    logapackts_reply->index = logapackts.header.index;
    logapackts_reply->chs = calcChs((unsigned char *)logapackts_reply + 1, sizeof(logapackts_reply_t) - 3);
    logapackts_reply->end = 0x03;
    len = escape(data + 1, sizeof(logapackts_reply_t) - 2);
    data[len + 2 - 1] = 0x03;	//again end sign because of escaping, crap
    feederLog(LOG_DEBUG, "Logapacts2: replying\n");
    
    return len + 2;
}

unsigned int parse(unsigned char * data, unsigned int length)
{
    length = deescape(data + 1, length - 2);

    memcpy(&logapackts.header, data + sizeof(unsigned char), sizeof(logapackts_header_t));
    memcpy(logapackts.body, data + sizeof(unsigned char) + sizeof(logapackts_header_t), logapackts.header.body_nb);

    return length;
}

unsigned int process(unsigned char * data, unsigned int length, unsigned long long int * id, time_t * tm, unsigned int * status, unsigned char * result, unsigned int * pbb_status, unsigned int * data_type)
{
    int i;
    struct tm * t;
    uint16_t * events;
    uint16_t type;
/*
    data[17] = 255;
    for (i = 0; i < length; i++)
	printf("%0X, ", data[i]);
    printf("\n");
*/
/*    
    length = deescape(data + 1, length - 2);
    
    memcpy(&logapackts.header, data + sizeof(unsigned char), sizeof(logapackts_header_t));
    memcpy(logapackts.body, data + sizeof(unsigned char) + sizeof(logapackts_header_t), logapackts.header.body_nb);
*/
    parse(data, length);
        
    *id = 0;
    for (i = 0;i < 6; i++)
	((unsigned char *)(id))[i] = logapackts.header.mac[5 - i];
    *tm = byteSwap32(logapackts.header.timestamp);
    *status = 0;
    *pbb_status = logapackts.header.status;
    type = byteSwap16(logapackts.header.event);
    
    feederLog(LOG_DEBUG, "Logapacts2: packet from ");
    for (i = 0; i < 6;i++)
	feederLog(LOG_DEBUG, "%02X ", logapackts.header.mac[i]);
    feederLog(LOG_DEBUG, " , type %05d\n", type);
    t = gmtime(tm);
    feederLog(LOG_DEBUG, "Logapacts2: %llu, on %04d-%02d-%02d %02d:%02d:%02d\n", 
	*id, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
	
    events = (uint16_t *)logapackts.body;

/*
    for (i = 0; i < 32; i++)
	printf("%0X, ", byteSwap16(events[i]));
    printf("\n");
    events[0] = 0;
*/
    result[0] = 0;
    for (i = 0; i < 31; i++)
        sprintf(result + strlen(result), "'NULL',");
    
    if (type == 5000)
    {
	result[0] = 0;
	for (i = 0; i < 16; i++)
	    sprintf(result + strlen(result), "'%d',", byteSwap16(events[i]));
	for (i = 0; i < 15; i++)
	    sprintf(result + strlen(result), "'NULL',");
    }
    if (type == 4000)
    {
	result[0] = 0;
	for (i = 0; i < 16; i++)
	    sprintf(result + strlen(result), "'NULL',");
	for (i = 0; i < 15; i++)
	    sprintf(result + strlen(result), "'%d',", byteSwap16(events[i]));
    }
    if (type == 1501)
    {
	result[0] = 0;
	sprintf(result + strlen(result), "'%d',", byteSwap16(events[0]));
	for (i = 0; i < 15; i++)
	    sprintf(result + strlen(result), "'NULL',");
	for (i = 0; i < 15; i++)
	    sprintf(result + strlen(result), "'NULL',");
	*data_type = LOGAPACTS_ID;
    }
    sprintf(result + strlen(result), "'%d',", logapackts.header.index);
    
    result[strlen(result) - 1] = 0; //remove last ','
    feederLog(LOG_DEBUG, "Logapacts2: decoded values %s\n", result);
    if (indexScan(logapackts.header.mac, logapackts.header.index))
    {
	feederLog(LOG_DEBUG, "Logapacts2: same index %d, omitting packet \n", logapackts.header.index);
	return 0;
    }
    return 32;
}

unsigned int processId(unsigned char * data, unsigned int length, unsigned int * id_code, unsigned char * name, unsigned char * group)
{
    uint16_t type;

    type = byteSwap16(logapackts.header.event);
    feederLog(LOG_DEBUG, "Logapacts2: decoded type %05d\n", type);
    
    if (type == 1501)
//    if (1)
    {
	*id_code = 1501;
	strncpy(name, logapackts.body, logapackts.header.body_nb);
//	sprintf(name, "testovaci jmeno");
	group[0] = 0;
//	sprintf(group, "testovaci grupa");
	
	feederLog(LOG_DEBUG, "Logapacts2: decoded id name %s, group %s\n", name, group);
	
	return 1;
    }
    else
	return 0;
}
