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

#include <curl/curl.h>
#include "json-c/json.h"
#include "libllist/inc/llist.h"


#include "../../status.h"
#include "../../feeder.h"
/*
typedef struct measurement_t
{
	unsigned long unit_id;
	unsigned int sensor_id;
	time_t time;
	double value;
	struct measurement_t * next;
} measurement_t;

struct measurement_t * measurement_list;
*/

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

int setLog(void *func)
{
    feederLog = func;
    return 0;
}
/*
typedef struct packet_t
{
    uint32_t daid;
    int utype;
    double lat;
    double lon;
    time_t time;
    int speed;
    int azimuth;
    int airdistance;
    int din;
    int dpid;
} packet_t;
*/
//#define PACKET_COMPARATOR(e1, e2) (e1->daid - e2->daid)

//SGLIB_DEFINE_LIST_PROTYPES(packet_t, PACKET_COMPARATOR, next)
//SGLIB_DEFINE_LIST_FUNCTIONS(packet_t, PACKET_COMPARATOR, next)
/*
struct unit_t
{
    uint16_t id;
    time_t time_next_data;
    struct packet_t * packets;
};

struct unit_t unit;
*/
struct curl_fetch_st
{
    char * payload;
    size_t size;
};

static int from_start;


int curlDebug(CURL * curl, curl_infotype info, char * string, size_t size, void * data)
{
    (void)curl;
    (void)data;
    
    if (feederLog != NULL)
    {
	if (info == CURLINFO_TEXT)
	{
	    string[size] = 0;
	    feederLog(LOG_DEBUG, "vidimte: curl debug: %s", string);
	}
    }
    return 0;
}

size_t curlCallback (void *contents, size_t size, size_t nmemb, void *userp)
{
    size_t realsize = size * nmemb;                             /* calculate buffer size */
    struct curl_fetch_st *p = (struct curl_fetch_st *) userp;   /* cast pointer to fetch struct */

    /* expand buffer */
    p->payload = (char *) realloc(p->payload, p->size + realsize + 1);

    /* check buffer */
    if (p->payload == NULL)
    {
	/* this isn't good */
        feederLog(LOG_ERR, "vidimte: Failed to expand buffer in curl_callback to size %d\n", p->size + realsize + 1);
        /* free buffer */
	free(p->payload);
	return -1;
    }

    /* copy contents to buffer */
    memcpy(&(p->payload[p->size]), contents, realsize);

    /* set new buffer size */
    p->size += realsize;
    /* ensure null termination */
    p->payload[p->size] = 0;

    /* return size */
    return realsize;
}


int fetch(char * url, char * action, char * param, json_object ** jo)
{
    CURL *ch;
    CURLcode res;
    json_object *json, * joerr;
    struct curl_fetch_st cf;
    enum json_tokener_error jerr = json_tokener_success;
//	struct curl_slist *headers = NULL;
    static char post[1024];
    long info;

    ch = curl_easy_init();
    if (ch)
    {
        curl_easy_setopt(ch, CURLOPT_DEBUGFUNCTION, curlDebug);
        curl_easy_setopt(ch, CURLOPT_VERBOSE, 1L);
//	strcpy(path, "http://api.vidimte.cz");
	curl_easy_setopt(ch, CURLOPT_URL, url);
	curl_easy_setopt(ch, CURLOPT_POST, 1L);
//		headers = curl_slist_append(headers, "Accept: application/json");
//		headers = curl_slist_append(headers, "Content-Type: text/html");
//		curl_easy_setopt(curl_g, CURLOPT_HTTPHEADER, headers);
	curl_easy_setopt(ch, CURLOPT_HEADER, 0);
	curl_easy_setopt(ch, CURLOPT_SSL_VERIFYPEER, 0);
		
	sprintf(post, "user=lesprojekt-api&apikey=741E2A79B1B4E60670D7933F2BA8540D&action=%s&%s", action, param);
	curl_easy_setopt(ch, CURLOPT_POSTFIELDS, post);
	curl_easy_setopt(ch, CURLOPT_POSTFIELDSIZE, strlen(post));
	cf.payload = (char *)calloc(1, sizeof(cf.payload));
	cf.size = 0;
	curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, curlCallback);
	curl_easy_setopt(ch, CURLOPT_WRITEDATA, (void *)&cf);
		
	//	res = curl_fetch_url(curl_g, path, &cf);
        feederLog(LOG_INFO, "vidimte: %s %s\n", url, post);
	
	res = curl_easy_perform(ch);
	curl_easy_cleanup(ch);
//	curl_slist_free_all(headers);
//	headers = NULL;

		
	curl_easy_getinfo(ch, CURLINFO_HTTP_CODE, &info);
	if (res != CURLE_OK)
	{
	    feederLog(LOG_ERR, "vidimte: curl POST error %d\n", res);
	    return -1;
	}
	if (info != 200)
	{
	    feederLog(LOG_ERR, "vidimte: curl page error %d\n", info);
	    return -1;
	}
	
	if (cf.payload != NULL)
	{
	    uint32_t pos;
	    pos = 0;
	    while (pos < strlen(cf.payload))
	    {
		feederLog(LOG_DEBUG, "vidimte: %.1024s\n", cf.payload + pos);
		pos += 1024;
	    }
	    json = json_tokener_parse_verbose(cf.payload + 3, &jerr);
	}
	else
	{
	    feederLog(LOG_ERR, "vidimte: payload error\n", res);
	    free(cf.payload);

	    return -1;
	}
		
	if (jerr != json_tokener_success)
	{
	    feederLog(LOG_ERR, "vidimte: Failed to parse json err %s\n", json_tokener_error_desc(jerr));
	    free(cf.payload);
	    json_object_put(json);
	    return -1;
	}
/*		else
		    feederLog(LOG_DEBUG, "vidimte: Parsed JSON: %s\n", json_object_to_json_string(json));
*/		
	if (strncmp(cf.payload, "OK", 2) == 0)
	{
	    *jo = json;
	    free(cf.payload);
	}
	else
	{
	    joerr = json_object_object_get(json, "message");
	    feederLog(LOG_ERR, "vidimte: Error reported: %s\n", json_object_get_string(joerr));
	    free(cf.payload);
	    json_object_put(json);
	    return -1;
	}
	return 0;
    }
    return -1;
}

#define STATUS_POS 1
#define STATUS_OBS 2

typedef struct vidimte_json_t
{
    json_object * json_unitslist;
    json_object * json_unitdata;
    size_t json_unit_no;
    size_t json_packet_no;
    int json_status;
} vidimte_json_t;

static struct vidimte_json_t vidimte_json;

unsigned int timeout(void * lib_data, int sock, unsigned char * data)
{
    json_object *json;

    (void)lib_data;
    (void)sock;
    (void)data;

    vidimte_json.json_unitslist = vidimte_json.json_unitdata = NULL;
    vidimte_json.json_unit_no = vidimte_json.json_packet_no = 0;
    vidimte_json.json_status = STATUS_POS;
    
    if (fetch((char *)"http://api.vidimte.cz", (char *)"unitslist", (char *)"", &json) == 0)//todo: likvidace alokovaneho json az nebude potreba, stejne i unitdata
    {
//        vidimte_json.json_unitslist = json_object_object_get(json, "data");
        vidimte_json.json_unitslist = json;
        vidimte_json.json_unit_no = 0;
    }
    else
    {
        vidimte_json.json_unitslist = NULL;
        return -1;
    }
    return 0;
}

unsigned int
process(void *lib_data, int sock, unsigned char *data,
        unsigned int length, unsigned long long int *id, time_t * tm,
        double *result_array, uint64_t * sensors, unsigned int *type)
{
    unsigned int res;
    json_object *json, *json_unit, *json_packet;
    char param[512];
    const char * s;
	
    (void)lib_data;
    (void)sock;
    (void)data;
    (void)length;
	

//    sleep(2);

    res = 0;
    if (vidimte_json.json_unitdata == NULL)
    {
	if (vidimte_json.json_unitslist == NULL)
	{
	    return 0;
	}
	
//	/**/feederLog(LOG_DEBUG, "vidimte: no %d, %d\n", vidimte_json.json_unit_no, json_object_array_length(json_object_object_get(vidimte_json.json_unitslist, "data")));

	
	if (vidimte_json.json_unit_no < json_object_array_length(json_object_object_get(vidimte_json.json_unitslist, "data")))
	{
    	    json_unit = json_object_array_get_idx(json_object_object_get(vidimte_json.json_unitslist, "data"), vidimte_json.json_unit_no++);
/*	    sprintf(param, "data={\"unitid\":%u,\"from\":%u,\"to\":%u}", 
	    json_object_get_int(json_object_object_get(json_unit, "unitid")),
	    (uint32_t)json_object_get_int(json_object_object_get(json_unit, "timeNextData")) + 1,
	    (uint32_t)json_object_get_int(json_object_object_get(json_unit, "timeNextData")) + 500); //todo: poskladat pres json*/

/*	    sprintf(param, "data={\"unitid\":%u,\"from\":%u}", 			//cteme jen nova data
	    json_object_get_int(json_object_object_get(json_unit, "unitid")),
	    (uint32_t)json_object_get_int(json_object_object_get(json_unit, "timeNextData")));
*/

    
/*
	    sprintf(param, "data={\"unitid\":%u,\"from\":%u}", 			//cteme historicky jednotku 5371
	    5371,//ujson_object_get_int(json_object_object_get(json_unit, "unitid")),
	    1);
*/
	    
//	    0 + 1,
//	    0 + 50); //todo: poskladat pres json
	    //todo: jak je to s velikosti dat - parametr 'to'

	    //sleep(2);//todo: aby se nezahlitil feeder


	    if (json_object_get_int(json_object_object_get(json_unit, "unitid")) == 5370)	//chceme jen tuhle jednotku
	    {
	        
	    
	    if (from_start)
	    {
		sprintf(param, "data={\"unitid\":%u,\"from\":%u}", 			//cteme historicky
		json_object_get_int(json_object_object_get(json_unit, "unitid")),
//		1);
		1484752524);
/*		
		sprintf(param, "data={\"unitid\":%u,\"from\":%u,\"to\":%u}", 			//cteme historicky
		json_object_get_int(json_object_object_get(json_unit, "unitid")),
//		1);
		1476403200,
		1493574400);
*/		
		from_start = 0;
	    }
	    else
	    {
		sprintf(param, "data={\"unitid\":%u,\"from\":%u}", 			//cteme jen nova data
		json_object_get_int(json_object_object_get(json_unit, "unitid")),
		(uint32_t)json_object_get_int(json_object_object_get(json_unit, "timeNextData")) + 1);

/*
		sprintf(param, "data={\"unitid\":%u,\"from\":%u,\"to\":%u}", 			//cteme jen nova data
		json_object_get_int(json_object_object_get(json_unit, "unitid")),
		(uint32_t)json_object_get_int(json_object_object_get(json_unit, "timeNextData")) + 1,
		1493574400);
*/
	    }

	    
    	    if (fetch((char *)"http://api.vidimte.cz", (char *)"unitdata", param, &json) == 0)
	    {
//    	        vidimte_json.json_unitdata = json_object_object_get(json, "data");
    	        vidimte_json.json_unitdata = json;
    	        feederLog(LOG_DEBUG, "vidimte: %d packets downloaded\n", json_object_array_length(json_object_object_get(vidimte_json.json_unitdata, "data")));
    	        vidimte_json.json_packet_no = 0;
    	        vidimte_json.json_status = STATUS_POS;
	    }
	    }
	    else
		return 10000;
	}
	else
	{
	    json_object_put(vidimte_json.json_unitslist);
	    vidimte_json.json_unitslist = NULL;
	}
    }
    if (vidimte_json.json_unitdata != NULL)
    {
        json_unit = json_object_array_get_idx(json_object_object_get(vidimte_json.json_unitslist, "data"), vidimte_json.json_unit_no - 1);
	feederLog(LOG_DEBUG, "vidimte: parsing unit %d data\n", (uint32_t)json_object_get_int(json_object_object_get(json_unit, "unitid")));
	
        if (vidimte_json.json_packet_no < json_object_array_length(json_object_object_get(vidimte_json.json_unitdata, "data")))
        {
	    json_packet = json_object_array_get_idx(json_object_object_get(vidimte_json.json_unitdata, "data"), vidimte_json.json_packet_no);
    	    feederLog(LOG_DEBUG, "vidimte: parsing packet daid %ld\n", (uint32_t)json_object_get_int(json_object_object_get(json_packet, "daid")));
	
	    switch (vidimte_json.json_status)
	    {
    	        case STATUS_POS:
		{
	    	    result_array[0] = json_object_get_double(json_object_object_get(json_object_object_get(json_packet, "position"), "lat"));
		    result_array[1] = json_object_get_double(json_object_object_get(json_object_object_get(json_packet, "position"), "lng"));
		    sensors[0] = sensors[1] = 0x10;
		    *type = VALUES_TYPE_POS;
	    
		    vidimte_json.json_status = STATUS_OBS;
		    res = 2;
		    
		    if ((json_object_get_int(json_object_object_get(json_packet, "airdistance")) == 0) || (json_object_get_int(json_object_object_get(json_packet, "V2")) == 0))		//totacky nebo airspeed 0 vyhazujeme
		    {
		        feederLog(LOG_WARNING, "vidimte: airdistance or V2 zero val\n");
			res = 10000;
		    }
		}
		break;
		case STATUS_OBS:
		{
/*		    result_array[0] = (double)json_object_get_int(json_object_object_get(json_packet, "utype"));
		    result_array[1] = (double)json_object_get_int(json_object_object_get(json_packet, "speed"));
		    result_array[2] = (double)json_object_get_int(json_object_object_get(json_packet, "azimuth"));
		    result_array[3] = (double)json_object_get_int(json_object_object_get(json_packet, "airdistance"));
		    result_array[4] = (double)json_object_get_int(json_object_object_get(json_packet, "din"));
		    result_array[5] = (double)json_object_get_int(json_object_object_get(json_packet, "dpid"));
		    
		    result_array[6] = (double)json_object_get_int(json_object_object_get(json_packet, "V1"));
		    result_array[7] = (double)json_object_get_int(json_object_object_get(json_packet, "V2")) / 10.0;
		    result_array[8] = (double)json_object_get_int(json_object_object_get(json_packet, "V3"));
		    result_array[9] = (double)json_object_get_int(json_object_object_get(json_packet, "V4"));
		    
		    result_array[10] = 0.0;
		    s = json_object_get_string(json_object_object_get(json_packet, "msg"));
		    if (s != NULL)
		    {
			if (strlen(s) > 0)
			{
			    long int t;

			    if (s[0] == 'P')
			    {
				t = strtol(s + 2, NULL, 10);
			    }
			    else
			    {
				t = strtol(s, NULL, 16);
			    }
		    	    result_array[10] = (double)t;
			    res = 11;
			}
			else
			{
			    res = 10;
			}
		    }
		    
		    sensors[0] = 750010000;
		    sensors[1] = 440070000;
		    sensors[2] = 710020000;
		    sensors[3] = 720020000;
		    sensors[4] = 330130000;
		    sensors[5] = 740020000;
		    
		    sensors[6] = 730020000;
		    sensors[7] = 660020000;
		    sensors[8] = 730030000;
		    sensors[9] = 670040000;
		    
		    sensors[10] = 680020000;
		    
		    *type = VALUES_TYPE_OBS;
	    
		    vidimte_json.json_packet_no++;
		    vidimte_json.json_status = STATUS_POS;*/
		    

		    result_array[0] = (double)json_object_get_int(json_object_object_get(json_packet, "speed"));
		    
		    result_array[1] = (double)json_object_get_int(json_object_object_get(json_packet, "V1"));
		    result_array[2] = (double)json_object_get_int(json_object_object_get(json_packet, "V2")) / 10.0;
		    result_array[3] = (double)json_object_get_int(json_object_object_get(json_packet, "V3"));
		    result_array[4] = (double)json_object_get_int(json_object_object_get(json_packet, "V4"));
		    
		    result_array[5] = 0.0;
		    s = json_object_get_string(json_object_object_get(json_packet, "msg"));
		    if (s != NULL)
		    {
			if (strlen(s) > 0)
			{
			    long int t;

			    if (s[0] == 'P')
			    {
				t = strtol(s + 2, NULL, 10);
			    }
			    else
			    {
				t = strtol(s, NULL, 16);
			    }
		    	    result_array[5] = (double)t;
			    res = 6;
			}
			else
			{
			    res = 5;
			}
		    }
		    
		    sensors[0] = 440070000;
    
		    sensors[1] = 730020000;
		    sensors[2] = 660020000;
		    sensors[3] = 730030000;
		    sensors[4] = 670040000;
		    
		    sensors[5] = 680020000;
		    
		    *type = VALUES_TYPE_OBS;
	    
		    vidimte_json.json_packet_no++;
		    vidimte_json.json_status = STATUS_POS;

		    if ((json_object_get_int(json_object_object_get(json_packet, "airdistance")) == 0) || (json_object_get_int(json_object_object_get(json_packet, "V2")) == 0))		//totacky nebo airspeed 0 vyhazujeme
		    {
		        feederLog(LOG_WARNING, "vidimte: airdistance or V2 zero val\n");
			res = 10000;
		    }
		}
		break;
		default:
		break;

    	    }
	    *id = (uint32_t)json_object_get_int(json_object_object_get(json_unit, "unitid"));
	    *tm = (uint32_t)json_object_get_int(json_object_object_get(json_packet, "time"));
	}
	else
	{
	    if (json_object_array_length(json_object_object_get(vidimte_json.json_unitdata, "data")) == 0)
	    {
		feederLog(LOG_DEBUG, "vidimte: no new data\n");
	    }
	    
	    if (json_object_get_boolean(json_object_object_get(vidimte_json.json_unitdata, "limitused")))
	    {
		sprintf(param, "data={\"unitid\":%u,\"from\":%u}", 
		5370,
	        json_object_get_int(json_object_object_get(vidimte_json.json_unitdata, "nextpackettime")));
	    
/*		sprintf(param, "data={\"unitid\":%u,\"from\":%u,\"to\":%u}", 
		5867,
	        json_object_get_int(json_object_object_get(vidimte_json.json_unitdata, "nextpackettime")),
	        1493574400);
*/

	        
		json_object_put(vidimte_json.json_unitdata);
		vidimte_json.json_unitdata = NULL;
		
    		if (fetch((char *)"http://api.vidimte.cz", (char *)"unitdata", param, &json) == 0)
	        {
//    	    	    vidimte_json.json_unitdata = json_object_object_get(json, "data");
	    	    vidimte_json.json_unitdata = json;
	    	    feederLog(LOG_DEBUG, "vidimte: %d packets downloaded\n", json_object_array_length(json_object_object_get(vidimte_json.json_unitdata, "data")));
	    	    vidimte_json.json_packet_no = 0;
	    	    vidimte_json.json_status = STATUS_POS;
		}
	    }
	    else
	    {
		json_object_put(vidimte_json.json_unitdata);
		vidimte_json.json_unitdata = NULL;
	    }
	
	    res = 10000;
	    
	}
    }
    return res;
}

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

    feederLog(LOG_DEBUG, "vidimte: init\n");

    curl_global_init(CURL_GLOBAL_DEFAULT);
    
    from_start = 1;

//    printf("Curl version: %s \n", curl_version());

    return 0;
}
