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

#include <Python.h>

#include "libcommon/config.h"

//{ single value functions
PyObject *wrap_config_get_int(PyObject* self, PyObject* args)
{
	int val, usedef = 0, def = 1;
	const char* key;
	int ok = PyArg_ParseTuple(args, "s|i", &key, &def);
	if(!ok) return PyExc_NameError;

	// use default?
	// compare with two initial values to make sure it changes
	// (to make sure we didn't initialize to the desired value)
	if(def != 1) usedef = 1;
	else { // make sure we didn't miss it
		def = 2;
		PyArg_ParseTuple(args, "s|i", &key, &def);
		if(def != 2) usedef = 1;
	}

	// get config
	Config * cfg = config_parse_default();
	if(!usedef){
		ok = config_get_int(cfg, key, &val);
		if(ok != 0) return PyExc_KeyError;
	} else {
		val = config_get_int_or_default(cfg, key, def);
	}
	config_free(cfg);

	return Py_BuildValue("i", val);
}

PyObject *wrap_config_get_boolean(PyObject* self, PyObject* args)
{
	int val, usedef = 0, def = 1;
	const char* key;
	int ok = PyArg_ParseTuple(args, "s|i", &key, &def);
	if(!ok) return PyExc_NameError;

	// use default?
	// compare with two initial values to make sure it changes
	// (to make sure we didn't initialize to the desired value)
	if(def != 1) usedef = 1;
	else { // make sure we didn't miss it
		def = 2;
		PyArg_ParseTuple(args, "s|i", &key, &def);
		if(def != 2) usedef = 1;
	}

	// get config
	Config * cfg = config_parse_default();
	if(!usedef){
		ok = config_get_boolean(cfg, key, &val);
		if(ok != 0) return PyExc_KeyError;
	} else {
		val = config_get_boolean_or_default(cfg, key, def);
	}
	config_free(cfg);

	return Py_BuildValue("b", val);
}

PyObject *wrap_config_get_double(PyObject* self, PyObject* args)
{
	int usedef = 0;
	double val, def = 1.0;
	const char* key;
	int ok = PyArg_ParseTuple(args, "s|d", &key, &def);
	if(!ok) return PyExc_NameError;

	// use default?
	// compare with two initial values to make sure it changes
	// (to make sure we didn't initialize to the desired value)
	if(def > 1.0) usedef = 1;
	else { // make sure we didn't miss it
		def = 2.0;
		PyArg_ParseTuple(args, "s|d", &key, &def);
		if(def < 2.0) usedef = 1;
	}

	// get config
	Config * cfg = config_parse_default();
	if(!usedef){
		ok = config_get_double(cfg, key, &val);
		if(ok != 0) return PyExc_KeyError;
	} else {
		val = config_get_double_or_default(cfg, key, def);
	}
	config_free(cfg);

	return Py_BuildValue("f", val);
}

PyObject *wrap_config_get_string(PyObject* self, PyObject* args)
{ 
	char* str;
	char* def = NULL;
	const char* key;
	int ok = PyArg_ParseTuple(args, "s|s", &key, &def);
	if(!ok) return PyExc_NameError;

	// get config
	// compare with two initial values to make sure it changes
	// (to make sure we didn't initialize to the desired value)
	Config * cfg = config_parse_default();
	if(def == NULL){
		ok = config_get_string(cfg, key, &str);
		if(ok != 0) return PyExc_KeyError;
	} else {
		str = config_get_string_or_default(cfg, key, def);
	}
	PyObject * res = Py_BuildValue("s", str);
	config_free(cfg);

	return res;
}
//} single values

//{ array functions
PyObject *wrap_config_get_int_array(PyObject* self, PyObject* args)
{
	int* a;
	int len;
	const char* key;
	int ok = PyArg_ParseTuple(args, "s", &key);
	if(!ok) return PyExc_NameError;

	// get config
	Config * cfg = config_parse_default();

	// get array
	len = config_get_array_len(cfg, key);
	a = malloc(sizeof(int)*len);
	ok = config_get_int_array(cfg, key, a, len);

	// raise exception on read error
	if(ok < 0) return PyExc_KeyError;

	// build list for returning
	PyObject *res, *item;
	res = PyList_New(len);
	for(int i=0; i<len; i++){
		item = Py_BuildValue("i",a[i]);
		PyList_SetItem(res, i, item);
	}

	config_free(cfg);
	free(a);

	return res;
}

PyObject *wrap_config_get_boolean_array(PyObject* self, PyObject* args)
{
	int* a;
	int len;
	const char* key;
	int ok = PyArg_ParseTuple(args, "s", &key);
	if(!ok) return PyExc_NameError;

	// get config
	Config * cfg = config_parse_default();

	// get array
	len = config_get_array_len(cfg, key);
	a = malloc(sizeof(int)*len);
	ok = config_get_boolean_array(cfg, key, a, len);

	// raise exception on read error
	if(ok < 0) return PyExc_KeyError;

	// build list for returning
	PyObject *res, *item;
	res = PyList_New(len);
	for(int i=0; i<len; i++){
		item = Py_BuildValue("b",a[i]);
		PyList_SetItem(res, i, item);
	}

	config_free(cfg);
	free(a);

	return res;
}

PyObject *wrap_config_get_double_array(PyObject* self, PyObject* args)
{
	double* a;
	int len;
	const char* key;
	int ok = PyArg_ParseTuple(args, "s", &key);
	if(!ok) return PyExc_NameError;

	// get config
	Config * cfg = config_parse_default();

	// get array
	len = config_get_array_len(cfg, key);
	a = malloc(sizeof(double)*len);
	ok = config_get_double_array(cfg, key, a, len);

	// raise exception on read error
	if(ok < 0) return PyExc_KeyError;

	// build list for returning
	PyObject *res, *item;
	res = PyList_New(len);
	for(int i=0; i<len; i++){
		item = Py_BuildValue("d",a[i]);
		PyList_SetItem(res, i, item);
	}

	config_free(cfg);
	free(a);

	return res;
}
//} arrays

static PyMethodDef configMethods[] = 
{
	{ "getInt",
		(PyCFunction)wrap_config_get_int,
		METH_VARARGS,
		"getInt(string [, default]) gets integer from config file"},
	{ "getBoolean",
		(PyCFunction)wrap_config_get_boolean,
		METH_VARARGS,
		"getBoolean(string [, default]) gets boolean from config file"},
	{ "getDouble",
		(PyCFunction)wrap_config_get_double,
		METH_VARARGS,
		"getDouble(string [, default]) gets double from config file"},
	{ "getString",
		(PyCFunction)wrap_config_get_string,
		METH_VARARGS,
		"getString(string [, default]) gets string from config file"},
	{ "getIntArray",
		(PyCFunction)wrap_config_get_int_array,
		METH_VARARGS,
		"getIntArray(string) get int array from config file"},
	{ "getBooleanArray",
		(PyCFunction)wrap_config_get_boolean_array,
		METH_VARARGS,
		"getBooleanArray(string) get bool array from config file"},
	{ "getDoubleArray",
		(PyCFunction)wrap_config_get_double_array,
		METH_VARARGS,
		"getDoubleArray(string) get double array from config file"},
//	{ "getStringArray",
//		(PyCFunction),
//		METH_VARARGS,
//		""},
//	{ "getStringArrayAlloc",
//		(PyCFunction),
//		METH_VARARGS,
//		""},
	{NULL, NULL, 0, NULL}
};

void initlibconfig(void)
{
	PyObject *m;
	m = Py_InitModule4(
				"libconfig",
				configMethods,
				"Config methods",
				0,
				PYTHON_API_VERSION);
	return;
}
