/***********************************************************
Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
The Netherlands.

                        All Rights Reserved

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the names of Stichting Mathematisch
Centrum or CWI not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior permission.

STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

******************************************************************/

#include "Python.h"
#include "abstract.h"

#ifdef __cplusplus
extern "C" {
#endif
#include "avl.h"
#ifdef __cplusplus
}
#endif

static PyObject *ErrorObject;

/* ----------------------------------------------------- */

/* Declarations for objects of type manager */

typedef struct {
  PyObject_HEAD
  avl_tree * tree;
} managerobject;

typedef struct {
  int top, left, right, bottom;
  PyObject * ob;
} regman_item;

staticforward PyTypeObject Managertype;

int
compare_regman_items (avl_tree * tree,
		      regman_item * a,
		      regman_item * b)
{
  if ((a->ob)<(b->ob)) {
    return -1;
  } else if ((a->ob)>(b->ob)) {
    return 1;
  } else {
    return 0;
  }
}

int
free_regman_item (regman_item * a)
{
  Py_DECREF (a->ob);
  free (a);
  return 0;
}

/* ---------------------------------------------------------------- */

static char manager_insert__doc__[] = 
""
;

static PyObject *
manager_insert(managerobject *self, PyObject *args)
{
  regman_item * item;
  int result;

  item = (regman_item *) malloc (sizeof (regman_item));
  if (!item) {
    return PyErr_NoMemory();
  } else if (!PyArg_ParseTuple(args,
			       "O(iiii):rm.insert(object, (left,top,right,bottom))",
			       &item->ob,
			       &item->left,
			       &item->top,
			       &item->right,
			       &item->bottom)) {
    return NULL;
  }

  result = insert_by_key (self->tree, item);
  if (result) {
    free (item);
    return PyErr_NoMemory();
  } else {
    Py_INCREF (item->ob);
    Py_INCREF(Py_None);
    return Py_None;
  }
}

static char manager_delete__doc__[] = 
""
;

static PyObject *
manager_delete(managerobject *self, PyObject *args)
{
  regman_item ri;

  if (!PyArg_ParseTuple(args, "O", &(ri.ob))) {
    return NULL;
  }

  return (Py_BuildValue ("i", remove_by_key (self->tree,
					     &ri,
					     (avl_free_key_fun_type) free_regman_item)));
}

typedef struct {
  int x,y;
  PyListObject * list;
} mip_helper;

int
mip_iter_fun (regman_item * rmi,
	      mip_helper * mh)
{
  if ((mh->x >= rmi->left) &&
      (mh->x <= rmi->right) &&
      (mh->y >= rmi->top) &&
      (mh->y <= rmi->bottom)) {
    PyList_Append ((PyObject *)mh->list, rmi->ob);
  }

  return 0;
}

static char manager_intersect_point__doc__[] = 
""
;

static PyObject *
manager_intersect_point(managerobject *self, PyObject *args)
{
  mip_helper m;
  
  m.list = (PyListObject *) PyList_New(0);
  if (!m.list) {
    return PyErr_NoMemory();
  }
  if (!PyArg_ParseTuple(args, "ii",&m.x,&m.y)) {
    return NULL;
  }

  iterate_inorder (self->tree, (avl_iter_fun_type) mip_iter_fun, &m);

  return (PyObject *) m.list;
}


typedef struct {
  int l,t,r,b;
  PyListObject * list;
} mir_helper;

int
mir_iter_fun (regman_item * rmi,
	      mir_helper * mh)
{
  if ((mh->r >= rmi->left) &&
      (mh->l <= rmi->right) &&
      (mh->b >= rmi->top) &&
      (mh->t <= rmi->bottom)) {
    PyList_Append ((PyObject *) mh->list, rmi->ob);
    Py_INCREF (rmi->ob);
  }
  return 0;
}

static char manager_intersect_rect__doc__[] = 
""
;

static PyObject *
manager_intersect_rect(managerobject *self, PyObject *args)
{
  mir_helper m;
  
  m.list = (PyListObject *) PyList_New(0);
  if (!m.list) {
    return PyErr_NoMemory();
  }
  if (!PyArg_ParseTuple(args, "(iiii)",&m.l, &m.t, &m.r, &m.b)) {
    return NULL;
  }

  iterate_inorder (self->tree,
		   (avl_iter_fun_type) mir_iter_fun,
		   (void *)&m);

  return (PyObject *) m.list;
}


static struct PyMethodDef manager_methods[] = {
  {"insert",		(PyCFunction)manager_insert,	1,manager_insert__doc__},
  {"delete",		(PyCFunction)manager_delete,	1,manager_delete__doc__},
  {"intersect_point",	(PyCFunction)manager_intersect_point, 1,manager_intersect_point__doc__},
  {"intersect_rect",	(PyCFunction)manager_intersect_rect,  1,manager_intersect_rect__doc__},
  {NULL,		NULL}		/* sentinel */
};

/* ---------- */

static managerobject *
newmanagerobject(void)
{
  managerobject *self;
  
  self = PyObject_NEW(managerobject, &Managertype);
  if (self == NULL) {
    return NULL;
  }
  self->tree = new_avl_tree ((avl_key_compare_fun_type) compare_regman_items, NULL);
  return self;
}

static void
manager_dealloc(managerobject *self)
{
  free_avl_tree (self->tree, (avl_free_key_fun_type) free_regman_item);
  PyMem_DEL(self);
}

static int
manager_print(managerobject *self, FILE *fp, int flags)
{
  fprintf (fp, "<region manager: %d items>",
	   self->tree->length);
  return 0;
}

static PyObject *
manager_getattr(managerobject *self, char *name)
{
  /* XXXX Add your own getattr code here */
  return Py_FindMethod(manager_methods, (PyObject *)self, name);
}

static char Managertype__doc__[] = 
""
;

static PyTypeObject Managertype = {
	PyObject_HEAD_INIT(&PyType_Type)
	0,				/*ob_size*/
	"manager",			/*tp_name*/
	sizeof(managerobject),		/*tp_basicsize*/
	0,				/*tp_itemsize*/
	/* methods */
	(destructor)manager_dealloc,	/*tp_dealloc*/
	(printfunc)manager_print,		/*tp_print*/
	(getattrfunc)manager_getattr,	/*tp_getattr*/
	(setattrfunc)0,	/*tp_setattr*/
	(cmpfunc)0,		/*tp_compare*/
	(reprfunc)0,		/*tp_repr*/
	0,			/*tp_as_number*/
	0,		/*tp_as_sequence*/
	0,		/*tp_as_mapping*/
	(hashfunc)0,		/*tp_hash*/
	(ternaryfunc)0,		/*tp_call*/
	(reprfunc)0,		/*tp_str*/

	/* Space for future expansion */
	0L,0L,0L,0L,
	Managertype__doc__ /* Documentation string */
};

/* End of code for manager objects */
/* -------------------------------------------------------- */


static char regman_regman__doc__[] =
""
;

static PyObject *
regman_regman(PyObject *self, PyObject *args)
	               	/* Not used */
	               
{
  managerobject * man;
  if (!PyArg_ParseTuple (args, "")) {
    return NULL;
  }
  man = (managerobject *) newmanagerobject ();
  if (!man) {
    return PyErr_NoMemory();
  } else {
    return (PyObject *) man;
  }
}

/* List of methods defined in the module */

static struct PyMethodDef regman_methods[] = {
	{"regman",	regman_regman,	1,	regman_regman__doc__},
 
	{NULL,		NULL}		/* sentinel */
};


/* Initialization function for the module (*must* be called initregman) */

static char regman_module_documentation[] = 
""
;

void
initregman(void)
{
  PyObject *m, *d;

  /* Create the module and add the functions */
  m = Py_InitModule4("regman", regman_methods,
		     regman_module_documentation,
		     (PyObject*)NULL,PYTHON_API_VERSION);

  /* Add some symbolic constants to the module */
  d = PyModule_GetDict(m);
  ErrorObject = PyString_FromString("regman.error");
  PyDict_SetItemString(d, "error", ErrorObject);

#if 0
  /*
   * For some reason the new vc40 build is mucking with Py_FatalError
   * in some strange way.
   */
  /* Check for errors */
  if (PyErr_Occurred()) {
    Py_FatalError("can't initialize module regman");
  }
#endif
}

