/* SWIG (www.swig.org) interface file for shapelib
 *
 * At the moment (Dec 2000) this file is only useful to generate Python
 * bindings. Invoke swig as follows:
 *
 *	swig -python -shadow shapelib.i
 *
 * to generate shapelib_wrap.c and shapelib.py. shapelib_wrap.c
 * defines a bunch of Python-functions that wrap the appripriate
 * shapelib functions and shapelib.py contains an object oriented
 * wrapper around shapelib_wrap.c.
 *
 * Shapelib, and hence this module too, defines two types of objects,
 * shapes and shapefiles.
 */
%module shapelib
/*
 * First, a %{,%}-Block. These blocks are copied verbatim to the
 * shapelib_wrap.c file and are not parsed by SWIG. This is the place to
 * import headerfiles and define helper-functions that are needed by the
 * automatically generated wrappers.
 */
%{
/* import the shapelib headefile. */
#include "shapefil.h"
#include "pyshapelib_api.h"
    
/*
 * Rename a few shapelib functions that are effectively methods with
 * preprocessor macros so that they have the names that swig expects
 * (e.g. the destructor of SHPObject has to be called delete_SHPObject)
 */
#define delete_SHPObject SHPDestroyObject
    
/*
 * The extents() method of SHPObject.
 *
 * Return the extents as a tuple of two 4-element lists with the min.
 * and max. values of x, y, z, m.
 */
static PyObject *
SHPObject_extents(SHPObject *object)
{
    return Py_BuildValue("[dddd][dddd]",
			 object->dfXMin, object->dfYMin, object->dfZMin,
			 object->dfMMin, 
			 object->dfXMax, object->dfYMax, object->dfZMax,
			 object->dfMMax);
}
/*
 * The vertices() method of SHPObject.
 *
 * Return the x and y coords of the vertices as a list of lists of
 * tuples.
 */
static PyObject* build_vertex_list(SHPObject *object, int index, int length);
static PyObject*
SHPObject_vertices(SHPObject *object)
{
    PyObject *result = NULL;
    PyObject *part = NULL;
    int part_idx, vertex_idx;
    int length = 0;
    if (object->nParts > 0)
    {
	/* A multipart shape. Usual for SHPT_ARC and SHPT_POLYGON */
	
	result = PyList_New(object->nParts);
	if (!result)
	    return NULL;
	for (part_idx = 0, vertex_idx = 0; part_idx < object->nParts;
	     part_idx++)
	{
	    if (part_idx < object->nParts - 1)
		length = (object->panPartStart[part_idx + 1]
			  - object->panPartStart[part_idx]);
	    else
		length = object->nVertices - object->panPartStart[part_idx];
	    
	    part = build_vertex_list(object, vertex_idx, length);
	    if (!part)
		goto fail;
	    if (PyList_SetItem(result, part_idx, part) < 0)
		goto fail;
	    vertex_idx += length;
	}
    }
    else
    {
	/* only one part. usual for SHPT_POINT */
	result = build_vertex_list(object, 0, object->nVertices);
    }
    return result;
 fail:
    Py_XDECREF(part);
    Py_DECREF(result);
    return NULL;
}
/* Return the length coordinates of the shape object starting at vertex
 * index as a Python-list of tuples. Helper function for
 * SHPObject_vertices.
 */
static PyObject*
build_vertex_list(SHPObject *object, int index, int length)
{
    int i;
    PyObject * list;
    PyObject * vertex = NULL;
    list = PyList_New(length);
    if (!list)
	return NULL;
    for (i = 0; i < length; i++, index++)
    {
	vertex = Py_BuildValue("dd", object->padfX[index],
			       object->padfY[index]);
	if (!vertex)
	    goto fail;
	if (PyList_SetItem(list, i, vertex) < 0)
	    goto fail;
    }
    return list;
 fail:
    Py_XDECREF(vertex);
    Py_DECREF(list);
    return NULL;
}
/* The constructor of SHPObject. parts is a list of lists of tuples
 * describing the parts and their vertices just likethe output of the
 * vertices() method. part_type_list is the list of part-types and may
 * be NULL. For the meaning of the part-types and their default value
 * see the Shaplib documentation.
 */
SHPObject * new_SHPObject(int type, int id, PyObject * parts,
			  PyObject * part_type_list)
{
    /* arrays to hold thex and y coordinates of the  vertices */
    double *xs = NULL, *ys = NULL;
    /* number of all vertices of all parts */
    int num_vertices;
    /* number of parts in the list parts */
    int num_parts;
    /* start index of in xs and ys of the part currently worked on */
    int part_start;
    /* array of start indices in xs and ys as expected by shapelib */
    int *part_starts = NULL;
    /* generic counter */
    int i;
    /* array of part types. holds the converted content of
     * part_type_list. Stays NULL of part_type_list is NULL
     */
    int *part_types = NULL;
    /* temporary python objects referring to the the list items being
     * worked on.
     */
    PyObject * part = NULL, *tuple = NULL;
    /* The result object */
    SHPObject *result;
    num_parts = PySequence_Length(parts);
    num_vertices = 0; 
    /* parts and part_types have to have the same lengths */
    if (part_type_list
	&& PySequence_Length(parts) != PySequence_Length(part_type_list))
    {
	PyErr_SetString(PyExc_TypeError,
			"parts and part_types have to have the same lengths");
	return NULL;
    }
    /* determine how many vertices there are altogether */
    for (i = 0; i < num_parts; i++)
    {
	PyObject * part = PySequence_GetItem(parts, i);
	if (!part)
	    return NULL;
	num_vertices += PySequence_Length(part);
	Py_DECREF(part);
    }
    /* allocate the memory for the various arrays and check for memory
       errors */
    xs = malloc(num_vertices * sizeof(double));
    ys = malloc(num_vertices * sizeof(double));
    part_starts = malloc(num_parts * sizeof(int));
    if (part_type_list)
	part_types = malloc(num_parts * sizeof(int));
    if (!xs || !ys || !part_starts || (part_type_list && !part_types))
    {
	PyErr_NoMemory();
	goto fail;
    }
    /* convert the part types */
    if (part_type_list)
    {
	for (i = 0; i < num_parts; i++)
	{
	    PyObject * otype = PySequence_GetItem(part_type_list, i);
	    if (!otype)
		return NULL;
	    part_types[i] = PyInt_AsLong(otype);
	    Py_DECREF(otype);
	}
    }
    /* convert the list of parts */
    part_start = 0;
    for (i = 0; i < num_parts; i++)
    {
	int j, length;
	part = PySequence_GetItem(parts, i);
	length = PySequence_Length(part);
	part_starts[i] = part_start;
	for (j = 0; j < length; j++)
	{
	    tuple = PySequence_GetItem(part, j);
	    if (!tuple)
		goto fail;
	    if (!PyArg_ParseTuple(tuple, "dd", xs + part_start + j,
				  ys + part_start + j))
	    {
		goto fail;
	    }
	    Py_DECREF(tuple);
	    tuple = NULL;
	}
	Py_DECREF(part);
	part = NULL;
	part_start += length;
    }
    result = SHPCreateObject(type, id, num_parts, part_starts, part_types,
			     num_vertices, xs, ys, NULL, NULL);
    free(xs);
    free(ys);
    free(part_starts);
    free(part_types);
    return result;
 fail:
    free(xs);
    free(ys);
    free(part_starts);
    free(part_types);
    Py_XDECREF(part);
    Py_XDECREF(tuple);
    return NULL;
}
%}
/*
 * The SWIG Interface definition.
 */
/* include some common SWIG type definitions and standard exception
   handling code */
%include typemaps.i
%include exception.i
/*
 *  SHPObject -- Represents one shape
 */
/* Exception typemap for the SHPObject constructor. The constructor the
   the wrapper function defined above which returns NULL in case of
   error. */
   
%typemap(python,except) SHPObject*new_SHPObject {
    $function;
    if (PyErr_Occurred())
	return NULL;
}
/* Define the SHPObject struct for SWIG. This has to have the same name
 * as the underlying C-struct in shapfil.h, but we don't have to repeat
 * all the fields here, only those we want to access directly, and we
 * can define methods for the object oriented interface.
 */
typedef struct {
    /* The shape object has two read-only attributes: */
    /* The type of the shape. In the c-struct defined the field is
     * called 'nSHPType' but for the python bindings 'type' is more
     * appropriate.
     */
    %readonly %name(type) int nSHPType;
    /* The id of the shape. Here 'id' is a better name than 'nShapeId'. */
    %readonly %name(id) int nShapeId;
    /* The methods */
    %addmethods {
	/* the constructor */
	SHPObject(int type, int id, PyObject * parts,
		  PyObject * part_types = NULL);
	/* The destructor */
	~SHPObject();
	/* extents and vertices correspond to the SHPObject_extents and
	 * SHPObject_vertices defined above
	 */
	PyObject *extents();
	PyObject *vertices();
    }
} SHPObject;
/*
 * ShapeFile --  Represents the shape file
 */
/* Here we do things a little different. We define a new C-struct that
 * holds the SHPHandle. This is mainly done so we can separate the
 * close() method from the destructor but it also helps with exception
 * handling.
 *
 * After the ShapeFile has been opened or created the handle is not
 * NULL. The close() method closes the file and sets handle to NULL as
 * an indicator that the file has been closed.
 */
/* First, define the C-struct */
%{
    typedef struct {
	SHPHandle handle;
    } ShapeFile;
%}
/* define and use some typemaps for the info() method whose
 * C-implementation has four output parameters that are returned through
 * pointers passed into the function. SWIG already has definitions for
 * common types such as int* and we can use those for the first two
 * parameters:
 */
 
%apply int * OUTPUT { int * output_entities }
%apply int * OUTPUT { int * output_type }
/* for the last two, the 4-element arrays of min- and max-values, we
 * have to define our own typemaps:
 */
%typemap (python,ignore) double * extents(double temp[4]) {
    $target = temp;
}
%typemap (python,argout) double * extents {
    PyObject * list = Py_BuildValue("[dddd]",
				    $source[0], $source[1],
				    $source[2], $source[3]);
    $target = t_output_helper($target,list);
}
%apply double * extents { double * output_min_bounds }
%apply double * extents { double * output_max_bounds }
/* The first argument to the ShapeFile methods is a ShapeFile pointer.
 * We have to check whether handle is not NULL in most methods but not
 * all. In the destructor and the close method, it's OK for handle to be
 * NULL. We achieve this by checking whether the preprocessor macro
 * NOCHECK_$name is defined. SWIG replaces $name with the name of the
 * function for which the code is inserted. In the %{,%}-block below we
 * define the macros for the destructor and the close() method.
 */
%typemap(python,check) ShapeFile *{
    %#ifndef NOCHECK_$name
    if (!$target || !$target->handle)
	SWIG_exception(SWIG_TypeError, "shapefile already closed");
    %#endif
}
%{
#define NOCHECK_delete_ShapeFile
#define NOCHECK_ShapeFile_close
%}
/* An exception handle for the constructor and the module level open()
 * and create() functions.
 *
 * Annoyingly, we *have* to put braces around the SWIG_exception()
 * calls, at least in the python case, because of the way the macro is
 * written. Of course, always putting braces around the branches of an
 * if-statement is often considered good practice.
 */
%typemap(python,except) ShapeFile * {
    $function;
    if (!$source)
    {
    	SWIG_exception(SWIG_MemoryError, "no memory");
    }
    else if (!$source->handle)
    {
	SWIG_exception(SWIG_IOError, "$name failed");
    }
}
/*
 * The SWIG-version of the ShapeFile struct.
 */
typedef struct
{
    /* Only methods and no attributes here: */ 
    %addmethods {
	/* The constructor. Takes two arguments, the filename and the
	 * optinal mode which are passed through to SHPOpen (due to the
	 * renaming trick)
	 */
	ShapeFile(char *file, char * mode = "rb") {
	    ShapeFile * self = malloc(sizeof(ShapeFile));
	    if (self)
		self->handle = SHPOpen(file, mode);
	    return self;
	}
	/* The destructor. Equivalent to SHPClose */
	~ShapeFile() {
	    if (self->handle)
		SHPClose(self->handle);
	    free(self);
	}
	/* close the shape file and set handle to NULL */
	void close() {
	    if (self->handle)
	    {
		SHPClose(self->handle);
		self->handle = NULL;
	    }
	}
	/* info() -- Return a tuple (NUM_SHAPES, TYPE, MIN, MAX) where
	 * NUM_SHAPES is the number of shapes in the file, TYPE is the
	 * shape type and MIN and MAX are 4-element lists with the min.
	 * and max. values of the data.
	 *
	 * The arguments of the underlying shapelib function SHPGetInfo
	 * are all output parameters. To tell SWIG this, we have defined
	 * some typemaps above
	 */
	void info(int * output_entities, int * output_type,
		  double * output_min_bounds, double *output_max_bounds) {
	    SHPGetInfo(self->handle, output_entities, output_type,
		       output_min_bounds, output_max_bounds);
	}
	/* Return object number i */
	%new SHPObject * read_object(int i) {
	    return SHPReadObject(self->handle, i);
	}
	/* Write an object */
	int write_object(int iShape, SHPObject * psObject) {
	    return SHPWriteObject(self->handle, iShape, psObject);
	}
	/* Return the shapelib SHPHandle as a Python CObject */
	PyObject * cobject() {
	    return PyCObject_FromVoidPtr(self->handle, NULL);
	}
    }
} ShapeFile;
/*
 * Two module level functions, open() and create() that correspond to
 * SHPOpen and SHPCreate respectively. open() is equivalent to the
 * ShapeFile constructor.
 */
%{
    ShapeFile * open_ShapeFile(const char *filename, const char * mode) {
	ShapeFile * self = malloc(sizeof(ShapeFile));
	if (self)
	    self->handle = SHPOpen(filename, mode);
	return self;
    }
%}
%name(open) %new ShapeFile *open_ShapeFile(const char *filename,
					   const char * mode = "rb");
%{
    ShapeFile * create_ShapeFile(const char *filename, int type) {
	ShapeFile * self = malloc(sizeof(ShapeFile));
	if (self)
	    self->handle = SHPCreate(filename, type);
	return self;
    }
%}    
%name(create) %new ShapeFile * create_ShapeFile(const char *filename,
						int type);
    
/* Module level function to expose some of the shapelib functions linked
 * with the shapefile C-module to other Python extension modules. This
 * is a kludge to make a Thuban extension work that reads shapes from
 * shapefiles opened by the shapefile module.
 */
%{
    static PyShapeLibAPI the_api = {
	SHPReadObject,
	SHPDestroyObject,
	SHPCreateTree,
	SHPDestroyTree,
	SHPTreeFindLikelyShapes
    };
    PyObject * c_api() {
	return PyCObject_FromVoidPtr(&the_api, NULL);
    }
%}
PyObject * c_api();
/*
 *  Module Level functions 
 */
/* convert shapefile types to names */
%name(type_name) const char *SHPTypeName(int nSHPType);
%name(part_type_name) const char *SHPPartTypeName(int nPartType);
/*
 * Finally, constants copied from shapefil.h
 */
/* -------------------------------------------------------------------- */
/*      Shape types (nSHPType)                                          */
/* -------------------------------------------------------------------- */
#define SHPT_NULL	0
#define SHPT_POINT	1
#define SHPT_ARC	3
#define SHPT_POLYGON	5
#define SHPT_MULTIPOINT	8
#define SHPT_POINTZ	11
#define SHPT_ARCZ	13
#define SHPT_POLYGONZ	15
#define SHPT_MULTIPOINTZ 18
#define SHPT_POINTM	21
#define SHPT_ARCM	23
#define SHPT_POLYGONM	25
#define SHPT_MULTIPOINTM 28
#define SHPT_MULTIPATCH 31
/* -------------------------------------------------------------------- */
/*      Part types - everything but SHPT_MULTIPATCH just uses           */
/*      SHPP_RING.                                                      */
/* -------------------------------------------------------------------- */
#define SHPP_TRISTRIP	0
#define SHPP_TRIFAN	1
#define SHPP_OUTERRING	2
#define SHPP_INNERRING	3
#define SHPP_FIRSTRING	4
#define SHPP_RING	5