#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"

static uint32_t sensors_id;
static double values_out[32];
static uint32_t sensors_out[32];
static int sensors_len;

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

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

int init(void * param)
{
    param = param;

    return 0;
}

enum states {STATE_OFF = 0, STATE_TAG_START, STATE_TAG_BODY, STATE_TAG_CHILD, STATE_TAG_END};

void stringAppend(char * string, char c)
{
    unsigned int len;
    
    len = strlen(string);
    string[len] = c;
    string[len + 1] = 0;
}

enum idents {TAG_OFF = 0, TAG_NODEID, TAG_SENSOR};

typedef struct type_t
{
    char tag[32];
    int ident;
    int type_AA;
    int type_BBB;
} type_t;

struct type_t types[] =
{
    {"internalTemp", 0, TYPE_THERMOMETER, 1},
    {"batteryV", 0, TYPE_VOLTAGE, 1},
    {"solarV", 0, TYPE_VOLTAGE, 2},
    {"humidity", 0, TYPE_HUMIDITY, 1},
    {"dewPoint", 0, TYPE_DEW_POINT, 1},
    {"temperature", 0, TYPE_THERMOMETER, 2},
    {"soilMoisture", 0, TYPE_HUMIDITY, 2},
    {"soilTemperature", 0, TYPE_THERMOMETER, 3},
    {"parent_rssi", 0, TYPE_LINK, 1},
    {"parent", 0, TYPE_LINK, 2},
    {"forwarded", 0, TYPE_LINK, 3},
    {"dropped", 0, TYPE_LINK, 4},
    {"packetNumber", 0, TYPE_LINK, 5},
    {"", TAG_OFF, 0, 0}
};

void tagAnalyze(char * tag, char * body)
{
    static int type = TAG_OFF;
    static int sensor_type;
    int i;
    
    
//    printf("cmp %s %s\n", tag, body);
    switch (type)
    {
	case TAG_OFF:
	    if ((strcmp(tag, "Name") == 0) && ((strcmp(body, "nodeid") == 0) || (strcmp(body, "nodeId") == 0)))
	    {
    		type = TAG_NODEID;
	    }
	    
	    for (i = 0; strlen(types[i].tag) > 0; i++)
	    {
		if ((strcmp(tag, "Name") == 0) && (strcmp(body, types[i].tag) == 0))
		{
		    type = TAG_SENSOR;
		    sensor_type = i;
		}
	    }
/*	    
	    if ((strcmp(tag, "Name") == 0) && ((strcmp(body, "internaltemp") == 0) || (strcmp(body, "internalTemp") == 0)))
	    {
    		type = TAG_INTERNALTEMP;
	    }
	    
	    if ((strcmp(tag, "Name") == 0) && ((strcmp(body, "solarv") == 0) || (strcmp(body, "solarV") == 0)))
	    {
    		type = TAG_SOLARV;
	    }*/
	    break;
	case TAG_NODEID:
	    if (strcmp(tag, "ConvertedValue") == 0)
	    {
		feederLog(LOG_DEBUG, "eko: nodeid %s\n", body);
		sensors_id = atoi(body);
		type = TAG_OFF;
	    }
	    break;
	case TAG_SENSOR:
	    if (strcmp(tag, "ConvertedValue") == 0)
	    {
		feederLog(LOG_DEBUG, "eko: sensor %s, value %s\n", types[sensor_type].tag, body);
		values_out[sensors_len] = atof(body);
		sensors_out[sensors_len] = types[sensor_type].type_AA * 10000000 + types[sensor_type].type_BBB * 10000;
		sensors_len++;
		type = TAG_OFF;
	    }
	    break;
	
/*	case TAG_INTERNALTEMP:
	    if (strcmp(tag, "ConvertedValue") == 0)
	    {
		feederLog(LOG_DEBUG, "eko: internal temperature %s\n", body);
		values_out[sensors_len] = atof(body);
		sensors_out[sensors_len] = TYPE_THERMOMETER * 10000000 + 1 * 10000;
		sensors_len++;
		type = TAG_OFF;
	    }
	    break;
	case TAG_SOLARV:
	    if (strcmp(tag, "ConvertedValue") == 0)
	    {
		feederLog(LOG_DEBUG, "eko: solar voltage %s\n", body);
		values_out[sensors_len] = atof(body);
		sensors_out[sensors_len] = TYPE_VOLTAGE * 10000000 + 2 * 10000;
		sensors_len++;
		type = TAG_OFF;
	    }
	    break;
*/	    
	    
    }
}

void stateMachine(char c)
{
    static int state = STATE_OFF;
    static char body[256], tag[256];

    if ((c < 0x21))
	return;
//printf("%c ", c);
    switch (state)
    {
	case STATE_OFF:
	    body[0] = tag[0] = 0;
	    if (c == '<')
	    {
		state = STATE_TAG_START;
	    }
	    break;
	case STATE_TAG_BODY:
	    if (c == '<')
	    {
		state = STATE_TAG_CHILD;
//		feederLog(LOG_DEBUG, "eko: body %s, tag %s\n", body, tag);
		tagAnalyze(tag, body);
		body[0] = 0;
		tag[0] = 0;
	    }
	    else 
		stringAppend(body, c);
	    break;
	case STATE_TAG_CHILD:
	    if (c == '/')
	    {
		state = STATE_TAG_END;
		break;
	    }
	    else
		state = STATE_TAG_START;
	case STATE_TAG_START:
	    if (c == '>')
	    {
		state = STATE_TAG_BODY;
//		feederLog(LOG_DEBUG, "eko: tag %s\n", tag);
	    }
	    else
		{
		    if (c == '/')
		    {
			state = STATE_TAG_END;
		    }
		    else
			stringAppend(tag, c);
		}
	    break;
	case STATE_TAG_END:
	    if (c == '>')
		state = STATE_OFF;
	    break;
	default:
	    state = STATE_OFF;
	    break;
    }
}

unsigned int process(int fd, unsigned char * data, unsigned int length, unsigned long long int * id, time_t * tm, double * result_array, uint32_t * sensors, unsigned int * type)
{
    unsigned int ret = 0;
    unsigned int i;

    feederLog(LOG_DEBUG, "eko: processing data\n");

    sensors_len = 0;
    for (i = 0; i < length;i++)
    {
	stateMachine(data[i]);
    }
    *id = sensors_id;
    *tm = time(NULL);
    *type = VALUES_TYPE_OBS;
    memcpy(result_array, values_out, sizeof(double) * sensors_len);
    memcpy(sensors, sensors_out, sizeof(uint32_t) * sensors_len);
    
    ret = sensors_len;
    return ret;
}

unsigned int reply(unsigned char * data)
{
    return 0;
}

int open(int socket)
{
    feederLog(LOG_DEBUG, "eko: socket %d opened\n", socket);

    return 0;
}

int close(int socket)
{
    feederLog(LOG_DEBUG, "eko: socket %d closed\n", socket);

    return 0;
}