#define PY_SSIZE_T_CLEAN
#include <Python.h>

#include "cmunipack.h"
#include "framesetclass.h"
#include "airmasscurveclass.h"

PyObject *cmpack_error(int code);
PyObject *err_closed(void);

static PyObject *
AirMassCurve_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    AirMassCurve *self = (AirMassCurve*)type->tp_alloc(type, 0);
    if (self != NULL) 
		self->t.f = NULL;
    return (PyObject *)self;
}

static void
AirMassCurve_dealloc(AirMassCurve* self)
{
	if (self->t.f) {
		cmpack_tab_destroy(self->t.f);
		self->t.f = NULL;
	}
    self->t.ob_base.ob_type->tp_free((PyObject*)self);
}


static int
AirMassCurve_init(AirMassCurve *self, PyObject *param, PyObject *kwds)
{
	int res, flags;
	const char *objname = NULL, *locname = NULL;
	double ra, dec, lon, lat;
	FrameSet *fset;
	PyObject *frameids = NULL, *object = NULL, *location = NULL;

	static char *kwlist[] = {"fset", "object", "location", "frameids", NULL};
	if (!PyArg_ParseTupleAndKeywords(param, kwds, "O!O!O!|O!", kwlist, &FrameSetType, &fset, 
		&PyTuple_Type, &object, &PyTuple_Type, &location, &PyBool_Type, &frameids))
		return -1;

	if (self->t.f) {
		cmpack_tab_destroy(self->t.f);
		self->t.f = NULL;
	}

	if (!PyArg_ParseTuple(object, "zdd", &objname, &ra, &dec)) {
		PyErr_SetString(PyExc_ValueError, "The 'object' parameter should be in a tuple of (name, ra, dec)");
		return -1;
	}
	if (!PyArg_ParseTuple(location, "zdd", &locname, &lon, &lat)) {
		PyErr_SetString(PyExc_ValueError, "The 'location' parameter should be in a tuple of (name, lon, lat)");
		return -1;
	}

	flags = 0;
	if (frameids==Py_True)
		flags |= CMPACK_LCURVE_FRAME_IDS;
	
	res = cmpack_airmass_curve(fset->f, &self->t.f, objname, ra, dec, 
		locname, lon, lat, flags, NULL);
	if (res!=0) {
		cmpack_error(res);
		return -1;
	}

	return 0;
}

static PyObject *
AirMassCurve_frame_id(AirMassCurve *self, void *data)
{
	int frame_id, column;

	if (!self->t.f)
		return err_closed();

	column = cmpack_tab_find_column(self->t.f, "FRAME");
	if (column<0)
		Py_RETURN_NONE;

	if (cmpack_tab_gtdi(self->t.f, column, &frame_id)!=0)
		Py_RETURN_NONE;

	return PyLong_FromLong(frame_id);
}

static PyObject *
AirMassCurve_go_to(AirMassCurve *self, PyObject *args)
{
	int f, frame_id, res, column;

	if (!self->t.f)
		return err_closed();

	if (!PyArg_ParseTuple(args, "i", &frame_id))
		return NULL;

	column = cmpack_tab_find_column(self->t.f, "FRAME");
	if (column<0)
		Py_RETURN_FALSE;

	res = cmpack_tab_rewind(self->t.f);
	while (res==0) {
		if (cmpack_tab_gtdi(self->t.f, column, &f)==0 && frame_id==f)
			Py_RETURN_TRUE;
		res = cmpack_tab_next(self->t.f);
	}
	Py_RETURN_FALSE;
}

static PyObject *
AirMassCurve_get_mag(Table *self, PyObject *args)
{
	const char *name;
	int j;
	double mag, err;
	PyObject *retval;

	if (!PyArg_ParseTuple(args, "s", &name))
		return NULL;

	if (!self->f)
		return err_closed();

	if (cmpack_tab_eof(self->f))
		Py_RETURN_NONE;

	j = cmpack_tab_find_column(self->f, name);
	if (j<0)
		Py_RETURN_NONE;
	
	retval = PyTuple_New(2);
	if (cmpack_tab_gtdd(self->f, j, &mag)==0)
		PyTuple_SET_ITEM(retval, 0, PyFloat_FromDouble(mag));
	else {
		Py_INCREF(Py_None);
		PyTuple_SET_ITEM(retval, 0, Py_None);
	}
	if (cmpack_tab_gtdd(self->f, j+1, &err)==0)
		PyTuple_SET_ITEM(retval, 1, PyFloat_FromDouble(err));
	else {
		Py_INCREF(Py_None);
		PyTuple_SET_ITEM(retval, 1, Py_None);
	}
	return retval;
}

static PyObject *
AirMassCurve_copy(AirMassCurve *self, PyObject *args)
{
	int res;
	CmpackTable *newf; 

	if (!self->t.f)
		return err_closed();

	newf = cmpack_tab_init(CMPACK_TABLE_AIRMASS);
	if (!newf) {
		PyErr_SetString(PyExc_MemoryError, "Memory allocation error.");
		return NULL;
	}
	res = cmpack_tab_copy(newf, self->t.f);
	if (res!=0) {
		cmpack_tab_destroy(newf);
		return cmpack_error(res);
	}
	return AirMassCurve_FromHandle(self->t.f);
}

static PyGetSetDef AirMassCurve_getset[] = {

	{"frame_id", (getter)AirMassCurve_frame_id, NULL,
	"Get frame identifier from active frame"},

	{NULL}
};

static PyMethodDef AirMassCurve_methods[] = {
	{"copy", (PyCFunction)AirMassCurve_copy, METH_NOARGS,
	"Make copy of the frame set"},

	{"go_to", (PyCFunction)AirMassCurve_go_to, METH_VARARGS,
	"Activate a frame specified by its identifier"},
	{"get_mag", (PyCFunction)AirMassCurve_get_mag, METH_VARARGS,
	"Get magnitude and error estimation from given column"},

    {NULL}  /* Sentinel */
};

PyTypeObject AirMassCurveType = {
    PyObject_HEAD_INIT(NULL)
    .tp_name = "cmpack.AirMassCurve",          /*tp_name*/
	.tp_basicsize = sizeof(AirMassCurve),           /*tp_basicsize*/
    .tp_dealloc = (destructor)AirMassCurve_dealloc,			/*tp_dealloc*/
    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,        /*tp_flags*/
    .tp_doc = "AirMass curve",			/* tp_doc */
    .tp_methods = AirMassCurve_methods,           /* tp_methods */
    .tp_getset = AirMassCurve_getset,            /* tp_getset */
    .tp_base = &TableType,                         /* tp_base */
    .tp_init = (initproc)AirMassCurve_init,      /* tp_init */
    .tp_new = AirMassCurve_new                 /* tp_new */
};

PyObject *
AirMassCurve_FromHandle(CmpackTable *f)
{
	Table *pDoc = PyObject_New(Table, &AirMassCurveType);
	if (pDoc) {
		pDoc->f = f;
	}
	return (PyObject*)pDoc;
}


PyTypeObject *AirMassCurve_Type(void)
{
	return &AirMassCurveType;
}
