/* Copyright (c) 2001, 2002, 2007 by Intevation GmbH
 * Authors:
 * Bernhard Herzog <bh@intevation.de>
 *
 * This program is free software under the LGPL (>=v2)
 * Read the file COPYING coming with pyshapelib for details.
 */

/* Python wrapper for the shapelib SHPTree */

#include <Python.h>
#include <shapefil.h>

#include "pyshapelib_api.h"

PyShapeLibAPI * api;

typedef struct {
    PyObject_HEAD
    SHPTree * tree; 
} SHPTreeObject;

extern PyTypeObject SHPTreeType;

#define SHPTree_Check(v)		((v)->ob_type == &SHPTreeType)

/* Create a new python wrapper object from a SHPTree pointer */
static PyObject *
SHPTreeObject_FromSHPTree(SHPTree* tree)
{
    SHPTreeObject * self = PyObject_NEW(SHPTreeObject, &SHPTreeType);
    if (!self)
	return NULL;

    self->tree = tree;

    return (PyObject *)self;
}

/* Deallocate the SHPTree wrapper. */
static void
shptree_dealloc(SHPTreeObject * self)
{
    api->SHPDestroyTree(self->tree);
    PyObject_Del(self);
}

/* Return the repr of the wrapper */
static PyObject *
shptree_repr(SHPTreeObject * self)
{
    char buf[1000];
    sprintf(buf, "<SHPTree at %xul>", (unsigned long)self);
    return PyString_FromString(buf);
}

static PyObject *
shptree_find_shapes(SHPTreeObject * self, PyObject * args)
{
    double min[4] = {0, 0, 0, 0};
    double max[4] = {0, 0, 0, 0};
    int count, idx;
    int * ids;
    PyObject * list = NULL, *temp = NULL;

    if (!PyArg_ParseTuple(args, "(dd)(dd)", min + 0, min + 1,
			  max + 0, max + 1))
	return NULL;

    ids = api->SHPTreeFindLikelyShapes(self->tree, min, max, &count);

    list = PyList_New(count);
    if (!list)
	goto fail;

    /* Turn the returned array of indices into a python list of ints. */
    for (idx = 0; idx < count; idx++)
    {
	temp = PyInt_FromLong(ids[idx]);
	if (!temp)
	    goto fail;

	if (PyList_SetItem(list, idx, temp) == -1)
	{
	    /* temp's refcount has already be decreased. Set temp to
	     * NULL so that the fail code doesn't do it again
	     */
	    temp = NULL;
	    goto fail;
	}
    }

    free(ids);
    return list;
    
 fail:
    free(ids);
    Py_XDECREF(list);
    Py_XDECREF(temp);
    return NULL;
}


static struct PyMethodDef shptree_methods[] = {
    {"find_shapes",	(PyCFunction)shptree_find_shapes,	METH_VARARGS},
    {NULL,	NULL}
};

static PyObject *
shptree_getattr(PyObject * self, char * name)
{
    return Py_FindMethod(shptree_methods, self, name);
}


PyTypeObject SHPTreeType = {
	PyObject_HEAD_INIT(NULL)
	0,
	"SHPTree",
	sizeof(SHPTreeObject),
	0,
	(destructor)shptree_dealloc,	/*tp_dealloc*/
	(printfunc)NULL,		/*tp_print*/
	shptree_getattr,		/*tp_getattr*/
	0,				/*tp_setattr*/
	0,				/*tp_compare*/
	(reprfunc)shptree_repr,		/*tp_repr*/
	0,				/*tp_as_number*/
	0,				/*tp_as_sequence*/
	0,				/*tp_as_mapping*/
	0,				/*tp_hash*/
        0,				/*tp_call*/
        0,				/*tp_str*/
	0,				/*tp_getattro*/
	0,				/*tp_setattro*/
	0,				/*tp_as_buffer*/
};



static PyObject *
shptree_from_shapefile(PyObject * self, PyObject * args)
{
    SHPTree * tree;
    SHPHandle handle;
    PyObject * cobject;
    int dimension, max_depth;

    if (!PyArg_ParseTuple(args, "O!ii", &PyCObject_Type, &cobject,
			  &dimension, &max_depth))
	return NULL;

    handle = PyCObject_AsVoidPtr(cobject);

    tree = api->SHPCreateTree(handle, dimension, max_depth, NULL, NULL);

    /* apparently SHPCreateTree doesn't do any error checking, so we
     * have to assume that tree is valid at this point. */
    return SHPTreeObject_FromSHPTree(tree);
}


static PyMethodDef module_functions[] = {
    {"SHPTree",		shptree_from_shapefile,		METH_VARARGS},
    { NULL, NULL }
};


void
initshptree()
{
    SHPTreeType.ob_type = &PyType_Type;

    Py_InitModule("shptree", module_functions);
    PYSHAPELIB_IMPORT_API(api);
}
