/*
 * Copyright (C) 2010-2016 jeanfi@gmail.com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */
#include <locale.h>
#include <libintl.h>
#define _(str) gettext(str)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <curl/curl.h>

#include <psensor_json.h>
#include <rsensor.h>
#include <server/server.h>
#include <url.h>

struct ucontent {
	char *data;
	size_t len;
};

static CURL *curl;

static const char *PROVIDER_NAME = "rsensor";

static const char *get_url(struct psensor *s)
{
	return (char *)s->provider_data;
}

static size_t cbk_curl(void *buffer, size_t size, size_t nmemb, void *userp)
{
	size_t realsize;
	struct ucontent *mem;

	realsize = size * nmemb;
	mem = (struct ucontent *)userp;

	mem->data = realloc(mem->data, mem->len + realsize + 1);

	memcpy(&(mem->data[mem->len]), buffer, realsize);
	mem->len += realsize;
	mem->data[mem->len] = 0;

	return realsize;
}

static char *create_api_1_1_sensors_url(const char *base_url)
{
	char *nurl, *ret;
	int n;

	nurl = url_normalize(base_url);
	n = strlen(nurl) + strlen(URL_BASE_API_1_1_SENSORS) + 1;
	ret = malloc(n);

	strcpy(ret, nurl);
	strcat(ret, URL_BASE_API_1_1_SENSORS);

	free(nurl);

	return ret;
}

void rsensor_init(void)
{
	curl = curl_easy_init();
}

void rsensor_cleanup(void)
{
	curl_easy_cleanup(curl);
}

static json_object *get_json_object(const char *url)
{
	struct ucontent chunk;
	json_object *obj;

	obj = NULL;

	if (!curl)
		return NULL;

	chunk.data = malloc(1);
	chunk.len = 0;

	curl_easy_setopt(curl, CURLOPT_URL, url);
	curl_easy_setopt(curl, CURLOPT_VERBOSE, 0);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cbk_curl);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);

	log_fct("%s: HTTP request %s", PROVIDER_NAME, url);

	if (curl_easy_perform(curl) == CURLE_OK)
		obj = json_tokener_parse(chunk.data);
	else
		log_err(_("%s: Fail to connect to: %s"), PROVIDER_NAME, url);

	free(chunk.data);

	return obj;
}

struct psensor **get_remote_sensors(const char *server_url,
				    int values_max_length)
{
	struct psensor **sensors, *s;
	char *url;
	json_object *obj;
	int i, n;

	sensors = NULL;

	url = create_api_1_1_sensors_url(server_url);

	obj = get_json_object(url);

	if (obj) {
		n = json_object_array_length(obj);
		sensors = malloc((n + 1) * sizeof(struct psensor *));

		for (i = 0; i < n; i++) {
			s = psensor_new_from_json
				(json_object_array_get_idx(obj, i),
				 url,
				 values_max_length);
			sensors[i] = s;
		}

		sensors[n] = NULL;

		json_object_put(obj);
	} else {
		log_err(_("%s: Invalid content: %s"), PROVIDER_NAME, url);
	}

	free(url);

	if (!sensors) {
		sensors = malloc(sizeof(struct psensor *));
		*sensors = NULL;
	}

	return sensors;
}

static void remote_psensor_update(struct psensor *s)
{
	json_object *obj;

	obj = get_json_object(get_url(s));

	if (obj) {
		json_object *om;

		json_object_object_get_ex(obj, "last_measure", &om);

		json_object *ov, *ot;
		struct timeval tv;

		json_object_object_get_ex(om, "value", &ov);
		json_object_object_get_ex(om, "time", &ot);

		tv.tv_sec = json_object_get_int(ot);
		tv.tv_usec = 0;

		psensor_set_current_measure
		    (s, json_object_get_double(ov), tv);

		json_object_put(obj);
	} else {
		log_err(_("%s: Invalid JSON: %s"), PROVIDER_NAME, get_url(s));
	}

}

void remote_psensor_list_update(struct psensor **sensors)
{
	struct psensor **cur;

	cur = sensors;
	while (*cur) {
		struct psensor *s = *cur;

		if (s->type & SENSOR_TYPE_REMOTE)
			remote_psensor_update(s);

		cur++;
	}
}
