/*
 * $Id: Constraint.c 16519 2008-09-14 12:41:42Z aligorith $
 *
 * ***** BEGIN GPL LICENSE BLOCK *****
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
 * All rights reserved.
 *
 * This is a new part of Blender.
 *
 * Contributor(s): Joseph Gilbert, Ken Hughes, Joshua Leung
 *
 * ***** END GPL LICENSE BLOCK *****
 */

#include "Constraint.h" /*This must come first*/

#include "DNA_armature_types.h"
#include "DNA_object_types.h"
#include "DNA_effect_types.h"
#include "DNA_vec_types.h"
#include "DNA_curve_types.h"
#include "DNA_text_types.h"

#include "BKE_main.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_constraint.h"
#include "BLI_blenlib.h"
#include "BIF_editconstraint.h"
#include "BIF_keyframing.h"
#include "BIF_poseobject.h"
#include "BSE_editipo.h"
#include "MEM_guardedalloc.h"
#include "butspace.h"
#include "blendef.h"
#include "mydevice.h"

#include "IDProp.h"
#include "Object.h"
#include "NLA.h"
#include "Text.h"
#include "gen_utils.h"

enum constraint_constants {
	EXPP_CONSTR_XROT = 0,
	EXPP_CONSTR_YROT = 1,
	EXPP_CONSTR_ZROT = 2,
	EXPP_CONSTR_XSIZE = 10,
	EXPP_CONSTR_YSIZE = 11,
	EXPP_CONSTR_ZSIZE = 12,
	EXPP_CONSTR_XLOC = 20,
	EXPP_CONSTR_YLOC = 21,
	EXPP_CONSTR_ZLOC = 22,

	EXPP_CONSTR_MAXX = TRACK_X,
	EXPP_CONSTR_MAXY = TRACK_Y,
	EXPP_CONSTR_MAXZ = TRACK_Z,
	EXPP_CONSTR_MINX = TRACK_nX,
	EXPP_CONSTR_MINY = TRACK_nY,
	EXPP_CONSTR_MINZ = TRACK_nZ,

	EXPP_CONSTR_TARGET = 100,
	EXPP_CONSTR_STRETCH,
	EXPP_CONSTR_ITERATIONS,
	EXPP_CONSTR_BONE,
	EXPP_CONSTR_CHAINLEN,
	EXPP_CONSTR_POSWEIGHT,
	EXPP_CONSTR_ROTWEIGHT,
	EXPP_CONSTR_ROTATE,
	EXPP_CONSTR_USETIP,

	EXPP_CONSTR_ACTION,
	EXPP_CONSTR_START,
	EXPP_CONSTR_END,
	EXPP_CONSTR_MIN,
	EXPP_CONSTR_MAX,
	EXPP_CONSTR_KEYON,

	EXPP_CONSTR_TRACK,
	EXPP_CONSTR_UP,

	EXPP_CONSTR_RESTLENGTH,
	EXPP_CONSTR_VOLVARIATION,
	EXPP_CONSTR_VOLUMEMODE,
	EXPP_CONSTR_PLANE,

	EXPP_CONSTR_FOLLOW,
	EXPP_CONSTR_OFFSET,
	EXPP_CONSTR_FORWARD,

	EXPP_CONSTR_LOCK,

	EXPP_CONSTR_MINMAX,
	EXPP_CONSTR_STICKY,

	EXPP_CONSTR_COPY,
	EXPP_CONSTR_LIMIT,
	EXPP_CONSTR_CLAMP,
	
	EXPP_CONSTR_MODE,
	
	EXPP_CONSTR_LIMXMIN = LIMIT_XMIN,
	EXPP_CONSTR_LIMXMAX = LIMIT_XMAX,
	EXPP_CONSTR_LIMYMIN = LIMIT_YMIN,
	EXPP_CONSTR_LIMYMAX = LIMIT_YMAX,
	EXPP_CONSTR_LIMZMIN = LIMIT_ZMIN,
	EXPP_CONSTR_LIMZMAX = LIMIT_ZMAX,
	
	EXPP_CONSTR_LIMXROT = LIMIT_XROT,
	EXPP_CONSTR_LIMYROT = LIMIT_YROT,
	EXPP_CONSTR_LIMZROT = LIMIT_ZROT,
	
	EXPP_CONSTR_CLAMPCYCLIC,
	
	EXPP_CONSTR_XMIN,
	EXPP_CONSTR_XMAX,
	EXPP_CONSTR_YMIN,
	EXPP_CONSTR_YMAX,
	EXPP_CONSTR_ZMIN,
	EXPP_CONSTR_ZMAX,
	
	EXPP_CONSTR_SCRIPT,
	EXPP_CONSTR_PROPS,
	
	EXPP_CONSTR_FROM,
	EXPP_CONSTR_TO,
	EXPP_CONSTR_EXPO,
	EXPP_CONSTR_FROMMINX,
	EXPP_CONSTR_FROMMAXX,
	EXPP_CONSTR_FROMMINY,
	EXPP_CONSTR_FROMMAXY,
	EXPP_CONSTR_FROMMINZ,
	EXPP_CONSTR_FROMMAXZ,
	EXPP_CONSTR_TOMINX,
	EXPP_CONSTR_TOMAXX,
	EXPP_CONSTR_TOMINY,
	EXPP_CONSTR_TOMAXY,
	EXPP_CONSTR_TOMINZ,
	EXPP_CONSTR_TOMAXZ,
	EXPP_CONSTR_MAPX,
	EXPP_CONSTR_MAPY,
	EXPP_CONSTR_MAPZ,
	
	EXPP_CONSTR_OWNSPACE,
	EXPP_CONSTR_TARSPACE,
		
	EXPP_CONSTR_RB_TYPE,
	EXPP_CONSTR_RB_BALL,
	EXPP_CONSTR_RB_HINGE,
	EXPP_CONSTR_RB_GENERIC6DOF,
	EXPP_CONSTR_RB_VEHICLE,
	EXPP_CONSTR_RB_PIVX,
	EXPP_CONSTR_RB_PIVY,
	EXPP_CONSTR_RB_PIVZ,
	EXPP_CONSTR_RB_AXX,
	EXPP_CONSTR_RB_AXY,
	EXPP_CONSTR_RB_AXZ,
	EXPP_CONSTR_RB_MINLIMIT0,
	EXPP_CONSTR_RB_MINLIMIT1,
	EXPP_CONSTR_RB_MINLIMIT2,
	EXPP_CONSTR_RB_MINLIMIT3,
	EXPP_CONSTR_RB_MINLIMIT4,
	EXPP_CONSTR_RB_MINLIMIT5,
	EXPP_CONSTR_RB_MAXLIMIT0,
	EXPP_CONSTR_RB_MAXLIMIT1,
	EXPP_CONSTR_RB_MAXLIMIT2,
	EXPP_CONSTR_RB_MAXLIMIT3,
	EXPP_CONSTR_RB_MAXLIMIT4,
	EXPP_CONSTR_RB_MAXLIMIT5,
	EXPP_CONSTR_RB_EXTRAFZ,
	EXPP_CONSTR_RB_FLAG,
	
};

/*****************************************************************************/
/* Python BPy_Constraint methods declarations:                               */
/*****************************************************************************/
static PyObject *Constraint_getName( BPy_Constraint * self );
static int Constraint_setName( BPy_Constraint * self, PyObject *arg );
static PyObject *Constraint_getType( BPy_Constraint * self );
static PyObject *Constraint_getInfluence( BPy_Constraint * self );
static int Constraint_setInfluence( BPy_Constraint * self, PyObject * arg );

static PyObject *Constraint_insertKey( BPy_Constraint * self, PyObject * arg );

static PyObject *Constraint_getData( BPy_Constraint * self, PyObject * key );
static int Constraint_setData( BPy_Constraint * self, PyObject * key, 
		PyObject * value );

/*****************************************************************************/
/* Python BPy_Constraint methods table:                                      */
/*****************************************************************************/
static PyMethodDef BPy_Constraint_methods[] = {
	/* name, method, flags, doc */
	{"insertKey", ( PyCFunction ) Constraint_insertKey, METH_O,
	 "Insert influence keyframe for constraint"},
	{NULL, NULL, 0, NULL}
};

/*****************************************************************************/
/* Python BPy_Constraint attributes get/set structure:                       */
/*****************************************************************************/
static PyGetSetDef BPy_Constraint_getseters[] = {
	{"name",
	(getter)Constraint_getName, (setter)Constraint_setName,
	 "Constraint name", NULL},
	{"type",
	(getter)Constraint_getType, (setter)NULL,
	 "Constraint type (read only)", NULL},
	{"influence",
	(getter)Constraint_getInfluence, (setter)Constraint_setInfluence,
	 "Constraint influence", NULL},
	{NULL,NULL,NULL,NULL,NULL}  /* Sentinel */
};

/*****************************************************************************/
/* Python Constraint_Type Mapping Methods table:                             */
/*****************************************************************************/
static PyMappingMethods Constraint_as_mapping = {
	NULL,                               /* mp_length        */
	( binaryfunc ) Constraint_getData,	/* mp_subscript     */
	( objobjargproc ) Constraint_setData,	/* mp_ass_subscript */
};

/*****************************************************************************/
/* Python Constraint_Type callback function prototypes:                      */
/*****************************************************************************/
static PyObject *Constraint_repr( BPy_Constraint * self );
static int Constraint_compare( BPy_Constraint * a, BPy_Constraint * b );

/*****************************************************************************/
/* Python Constraint_Type structure definition:                              */
/*****************************************************************************/
PyTypeObject Constraint_Type = {
	PyObject_HEAD_INIT( NULL )  /* required py macro */
	0,                          /* ob_size */
	/*  For printing, in format "<module>.<name>" */
	"Blender Constraint",         /* char *tp_name; */
	sizeof( BPy_Constraint ),     /* int tp_basicsize; */
	0,                          /* tp_itemsize;  For allocation */

	/* Methods to implement standard operations */

	NULL,						/* destructor tp_dealloc; */
	NULL,                       /* printfunc tp_print; */
	NULL,                       /* getattrfunc tp_getattr; */
	NULL,                       /* setattrfunc tp_setattr; */
	( cmpfunc ) Constraint_compare, /* cmpfunc tp_compare; */
	( reprfunc ) Constraint_repr, /* reprfunc tp_repr; */

	/* Method suites for standard classes */

	NULL,                       /* PyNumberMethods *tp_as_number; */
	NULL,                       /* PySequenceMethods *tp_as_sequence; */
	&Constraint_as_mapping,       /* PyMappingMethods *tp_as_mapping; */

	/* More standard operations (here for binary compatibility) */

	NULL,                       /* hashfunc tp_hash; */
	NULL,                       /* ternaryfunc tp_call; */
	NULL,                       /* reprfunc tp_str; */
	NULL,                       /* getattrofunc tp_getattro; */
	NULL,                       /* setattrofunc tp_setattro; */

	/* Functions to access object as input/output buffer */
	NULL,                       /* PyBufferProcs *tp_as_buffer; */

  /*** Flags to define presence of optional/expanded features ***/
	Py_TPFLAGS_DEFAULT,         /* long tp_flags; */

	NULL,                       /*  char *tp_doc;  Documentation string */
  /*** Assigned meaning in release 2.0 ***/
	/* call function for all accessible objects */
	NULL,                       /* traverseproc tp_traverse; */

	/* delete references to contained objects */
	NULL,                       /* inquiry tp_clear; */

  /***  Assigned meaning in release 2.1 ***/
  /*** rich comparisons ***/
	NULL,                       /* richcmpfunc tp_richcompare; */

  /***  weak reference enabler ***/
	0,                          /* long tp_weaklistoffset; */

  /*** Added in release 2.2 ***/
	/*   Iterators */
	NULL,                       /* getiterfunc tp_iter; */
	NULL,                       /* iternextfunc tp_iternext; */

  /*** Attribute descriptor and subclassing stuff ***/
	BPy_Constraint_methods,       /* struct PyMethodDef *tp_methods; */
	NULL,                       /* struct PyMemberDef *tp_members; */
	BPy_Constraint_getseters,     /* struct PyGetSetDef *tp_getset; */
	NULL,                       /* struct _typeobject *tp_base; */
	NULL,                       /* PyObject *tp_dict; */
	NULL,                       /* descrgetfunc tp_descr_get; */
	NULL,                       /* descrsetfunc tp_descr_set; */
	0,                          /* long tp_dictoffset; */
	NULL,                       /* initproc tp_init; */
	NULL,                       /* allocfunc tp_alloc; */
	NULL,                       /* newfunc tp_new; */
	/*  Low-level free-memory routine */
	NULL,                       /* freefunc tp_free;  */
	/* For PyObject_IS_GC */
	NULL,                       /* inquiry tp_is_gc;  */
	NULL,                       /* PyObject *tp_bases; */
	/* method resolution order */
	NULL,                       /* PyObject *tp_mro;  */
	NULL,                       /* PyObject *tp_cache; */
	NULL,                       /* PyObject *tp_subclasses; */
	NULL,                       /* PyObject *tp_weaklist; */
	NULL
};

/*****************************************************************************/
/* Python BPy_Constraint methods:                                            */
/*****************************************************************************/

/*
 * return the name of this constraint
 */

static PyObject *Constraint_getName( BPy_Constraint * self )
{
	if( !self->con )
		return EXPP_ReturnPyObjError( PyExc_RuntimeError,
				"This constraint has been removed!" );
	
	return PyString_FromString( self->con->name );
}

/*
 * set the name of this constraint
 */

static int Constraint_setName( BPy_Constraint * self, PyObject * attr )
{
	char *name = PyString_AsString( attr );
	if( !name )
		return EXPP_ReturnIntError( PyExc_TypeError, "expected string arg" );

	if( !self->con )
		return EXPP_ReturnIntError( PyExc_RuntimeError,
				"This constraint has been removed!" );
	
	BLI_strncpy( self->con->name, name, sizeof( self->con->name ) );

	return 0;
}

/*
 * return the influence of this constraint
 */

static PyObject *Constraint_getInfluence( BPy_Constraint * self )
{
	if( !self->con )
		return EXPP_ReturnPyObjError( PyExc_RuntimeError,
				"This constraint has been removed!" );
	
	return PyFloat_FromDouble( (double)self->con->enforce );
}

/*
 * set the influence of this constraint
 */

static int Constraint_setInfluence( BPy_Constraint * self, PyObject * value )
{
	if( !self->con )
		return EXPP_ReturnIntError( PyExc_RuntimeError,
				"This constraint has been removed!" );

	return EXPP_setFloatClamped( value, &self->con->enforce, 0.0, 1.0 );
}

/*
 * return the type of this constraint
 */

static PyObject *Constraint_getType( BPy_Constraint * self )
{
	if( !self->con )
		return EXPP_ReturnPyObjError( PyExc_RuntimeError,
				"This constraint has been removed!" );
	
	return PyInt_FromLong( self->con->type );
}

/*
 * add keyframe for influence
	base on code in add_influence_key_to_constraint_func()
 */
static PyObject *Constraint_insertKey( BPy_Constraint * self, PyObject * value )
{
	bConstraint *con = self->con;
	Object *ob = self->obj;
	bPoseChannel *pchan = self->pchan;
	IpoCurve *icu;
	float cfra = (float)PyFloat_AsDouble(value);
	char actname[32] = "";
	
	if( !self->con )
		return EXPP_ReturnPyObjError( PyExc_RuntimeError,
				"This constraint has been removed!" );

	/* get frame for inserting key */
	if( PyFloat_Check(value) )
		return EXPP_ReturnPyObjError( PyExc_TypeError,
				"expected a float argument" );
	
	/* find actname for locating that action-channel that a constraint channel should be added to */
	if (ob) {
		if (pchan) {
			/* actname is the name of the pchan that this constraint belongs to */
			BLI_strncpy(actname, pchan->name, 32);
		}
		else {
			/* hardcoded achan name -> "Object" (this may change in future) */
			strcpy(actname, "Object");
		}
	}
	else {
		return EXPP_ReturnPyObjError( PyExc_RuntimeError,
				"constraint doesn't belong to anything" );
	}
	icu= verify_ipocurve((ID *)ob, ID_CO, actname, con->name, NULL, CO_ENFORCE, 1);
	
	if (!icu)
		return EXPP_ReturnPyObjError( PyExc_RuntimeError,
				"cannot get a curve from this IPO, may be using libdata" );
	
	if( ob->action )
		insert_vert_icu( icu, get_action_frame(ob, cfra), con->enforce, 0);
	else
		insert_vert_icu( icu, cfra, con->enforce, 0);

	Py_RETURN_NONE;
}

/******************************************************************************/
/* Constraint Space Conversion get/set procedures							  */
/* 		- These are called before/instead of individual constraint 			  */
/*		  get/set procedures when OWNERSPACE or TARGETSPACE are chosen		  */
/*		- They are only called from Constraint_g/setData					  */
/******************************************************************************/

static PyObject *constspace_getter( BPy_Constraint * self, int type )
{
	bConstraint *con= (bConstraint *)(self->con);
	
	/* depends on type being asked for
	 * NOTE: not all constraints support all space types 
	 */
	if (type == EXPP_CONSTR_OWNSPACE) {
		switch (con->type) {
			/* all of these support this... */
			case CONSTRAINT_TYPE_PYTHON:
			case CONSTRAINT_TYPE_LOCLIKE:
			case CONSTRAINT_TYPE_ROTLIKE:
			case CONSTRAINT_TYPE_SIZELIKE:
			case CONSTRAINT_TYPE_TRACKTO:
			case CONSTRAINT_TYPE_LOCLIMIT:
			case CONSTRAINT_TYPE_ROTLIMIT:
			case CONSTRAINT_TYPE_SIZELIMIT:
			case CONSTRAINT_TYPE_TRANSFORM:
				return PyInt_FromLong( (long)con->ownspace );
		}
	}
	else if (type == EXPP_CONSTR_TARSPACE) {
		switch (con->type) {
			/* all of these support this... */
			case CONSTRAINT_TYPE_PYTHON:
			case CONSTRAINT_TYPE_ACTION:
			case CONSTRAINT_TYPE_LOCLIKE:
			case CONSTRAINT_TYPE_ROTLIKE:
			case CONSTRAINT_TYPE_SIZELIKE:
			case CONSTRAINT_TYPE_TRACKTO:
			case CONSTRAINT_TYPE_TRANSFORM:
			{	
				bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
				bConstraintTarget *ct;
				PyObject *tlist=NULL, *val;
				
				if (cti) {
					/* change space of targets */
					if (cti->get_constraint_targets) {
						ListBase targets = {NULL, NULL};
						int num_tars=0, i=0;
						
						/* get targets, and create py-list for use temporarily */
						num_tars= cti->get_constraint_targets(con, &targets);
						if (num_tars) {
							tlist= PyList_New(num_tars);
							
							for (ct=targets.first; ct; ct=ct->next, i++) {
								val= PyInt_FromLong((long)ct->space);
								PyList_SET_ITEM(tlist, i, val);
							}
						}
						
						if (cti->flush_constraint_targets)
							cti->flush_constraint_targets(con, &targets, 1);
					}
				}
				
				return tlist;
			}
		}
	}
	
	/* raise error if failed */
	return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
}

static int constspace_setter( BPy_Constraint *self, int type, PyObject *value )
{
	bConstraint *con= (bConstraint *)(self->con);
	
	/* depends on type being asked for
	 * NOTE: not all constraints support all space types 
	 */
	if (type == EXPP_CONSTR_OWNSPACE) {
		switch (con->type) {
			/* all of these support this... */
			case CONSTRAINT_TYPE_PYTHON:
			case CONSTRAINT_TYPE_LOCLIKE:
			case CONSTRAINT_TYPE_ROTLIKE:
			case CONSTRAINT_TYPE_SIZELIKE:
			case CONSTRAINT_TYPE_TRACKTO:
			case CONSTRAINT_TYPE_LOCLIMIT:
			case CONSTRAINT_TYPE_ROTLIMIT:
			case CONSTRAINT_TYPE_SIZELIMIT:
			case CONSTRAINT_TYPE_TRANSFORM:
			{
				/* only copy depending on ownertype */
				if (self->pchan) {
					return EXPP_setIValueClamped( value, &con->ownspace, 
							CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_PARLOCAL, 'h' );
				}
				else {
					return EXPP_setIValueClamped( value, &con->ownspace, 
							CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, 'h' );
				}
			}
				break;
		}
	}
	else if (type == EXPP_CONSTR_TARSPACE) {
		switch (con->type) {
			/* all of these support this... */
			case CONSTRAINT_TYPE_PYTHON:
			case CONSTRAINT_TYPE_ACTION:
			case CONSTRAINT_TYPE_LOCLIKE:
			case CONSTRAINT_TYPE_ROTLIKE:
			case CONSTRAINT_TYPE_SIZELIKE:
			case CONSTRAINT_TYPE_TRACKTO:
			case CONSTRAINT_TYPE_TRANSFORM:
			{
				bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
				bConstraintTarget *ct;
				int ok= 0;
				
				if (cti) {
					/* change space of targets */
					if (cti->get_constraint_targets) {
						ListBase targets = {NULL, NULL};
						int num_tars=0, i=0;
						
						/* get targets, and extract values from the given list */
						num_tars= cti->get_constraint_targets(con, &targets);
						if (num_tars) {
							if ((PySequence_Check(value) == 0) || (PySequence_Size(value) != num_tars)) {
								char errorstr[64];
								sprintf(errorstr, "expected sequence of %d integer(s)", num_tars);
								return EXPP_ReturnIntError(PyExc_TypeError, errorstr);
							}
							
							for (ct=targets.first; ct; ct=ct->next, i++) {
								if (ct->tar && ct->subtarget[0]) {
									PyObject *val= PySequence_ITEM(value, i);
									
									ok += EXPP_setIValueClamped(val, &ct->space, 
											CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_PARLOCAL, 'h' );
										
									Py_DECREF(val);
								}
								else if (ct->tar) {
									PyObject *val= PySequence_ITEM(value, i);
									
									ok += EXPP_setIValueClamped(val, &ct->space, 
											CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, 'h' );
									
									Py_DECREF(val);
								}
							}
						}
						
						if (cti->flush_constraint_targets)
							cti->flush_constraint_targets(con, &targets, 0);
					}
				}
				
				return ok;
			}
				break;
		}
	}
	
	/* raise error if failed */
	return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
}

/*****************************************************************************/
/* Specific constraint get/set procedures                                    */
/*****************************************************************************/

static PyObject *kinematic_getter( BPy_Constraint * self, int type )
{
	bKinematicConstraint *con = (bKinematicConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET:
		return Object_CreatePyObject( con->tar );
	case EXPP_CONSTR_BONE:
		return PyString_FromString( con->subtarget );
	case EXPP_CONSTR_STRETCH:
		return PyBool_FromLong( (long)( con->flag & CONSTRAINT_IK_STRETCH ) ) ;
	case EXPP_CONSTR_ITERATIONS:
		return PyInt_FromLong( (long)con->iterations );
	case EXPP_CONSTR_CHAINLEN:
		return PyInt_FromLong( (long)con->rootbone );
	case EXPP_CONSTR_POSWEIGHT:
		return PyFloat_FromDouble( (double)con->weight );
	case EXPP_CONSTR_ROTWEIGHT:
		return PyFloat_FromDouble( (double)con->orientweight );
	case EXPP_CONSTR_ROTATE:
		return PyBool_FromLong( (long)( con->flag & CONSTRAINT_IK_ROT ) ) ;
	case EXPP_CONSTR_USETIP:
		return PyBool_FromLong( (long)( con->flag & CONSTRAINT_IK_TIP ) ) ;
	default:
		return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
	}
}

static int kinematic_setter( BPy_Constraint *self, int type, PyObject *value )
{
	bKinematicConstraint *con = (bKinematicConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET: {
		Object *obj = (( BPy_Object * )value)->object;
		if( !BPy_Object_Check( value ) )
			return EXPP_ReturnIntError( PyExc_TypeError, 
					"expected BPy object argument" );
		con->tar = obj;
		return 0;
		}
	case EXPP_CONSTR_BONE: {
		char *name = PyString_AsString( value );
		if( !name )
			return EXPP_ReturnIntError( PyExc_TypeError,
					"expected string arg" );

		BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );

		return 0;
		}
	case EXPP_CONSTR_STRETCH:
		return EXPP_setBitfield( value, &con->flag, CONSTRAINT_IK_STRETCH, 'h' );
	case EXPP_CONSTR_ITERATIONS:
		return EXPP_setIValueClamped( value, &con->iterations, 1, 10000, 'h' );
	case EXPP_CONSTR_CHAINLEN:
		return EXPP_setIValueClamped( value, &con->rootbone, 0, 255, 'i' );
	case EXPP_CONSTR_POSWEIGHT:
		return EXPP_setFloatClamped( value, &con->weight, 0.01f, 1.0 );
	case EXPP_CONSTR_ROTWEIGHT:
		return EXPP_setFloatClamped( value, &con->orientweight, 0.01f, 1.0 );
	case EXPP_CONSTR_ROTATE:
		return EXPP_setBitfield( value, &con->flag, CONSTRAINT_IK_ROT, 'h' );
	case EXPP_CONSTR_USETIP:
		return EXPP_setBitfield( value, &con->flag, CONSTRAINT_IK_TIP, 'h' );
	default:
		return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
	}
}

static PyObject *action_getter( BPy_Constraint * self, int type )
{
	bActionConstraint *con = (bActionConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET:
		return Object_CreatePyObject( con->tar );
	case EXPP_CONSTR_BONE:
		return PyString_FromString( con->subtarget );
	case EXPP_CONSTR_ACTION:
		return Action_CreatePyObject( con->act );
	case EXPP_CONSTR_START:
		return PyInt_FromLong( (long)con->start );
	case EXPP_CONSTR_END:
		return PyInt_FromLong( (long)con->end );
	case EXPP_CONSTR_MIN:
		return PyFloat_FromDouble( (double)con->min );
	case EXPP_CONSTR_MAX:
		return PyFloat_FromDouble( (double)con->max );
	case EXPP_CONSTR_KEYON:
		return PyInt_FromLong( (long)con->type );
	default:
		return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
	}
}

static int action_setter( BPy_Constraint *self, int type, PyObject *value )
{
	bActionConstraint *con = (bActionConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET: {
		Object *obj = (( BPy_Object * )value)->object;
		if( !BPy_Object_Check( value ) )
			return EXPP_ReturnIntError( PyExc_TypeError, 
					"expected BPy object argument" );
		con->tar = obj;
		return 0;
		}
	case EXPP_CONSTR_BONE: {
		char *name = PyString_AsString( value );
		if( !name )
			return EXPP_ReturnIntError( PyExc_TypeError,
					"expected string arg" );

		BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );

		return 0;
		}
	case EXPP_CONSTR_ACTION: {
		bAction *act = (( BPy_Action * )value)->action;
		if( !BPy_Action_Check( value ) )
			return EXPP_ReturnIntError( PyExc_TypeError, 
					"expected BPy action argument" );
		con->act = act;
		return 0;
		}
	case EXPP_CONSTR_START:
		return EXPP_setIValueClamped( value, &con->start, 1, MAXFRAME, 'h' );
	case EXPP_CONSTR_END:
		return EXPP_setIValueClamped( value, &con->end, 1, MAXFRAME, 'h' );
	case EXPP_CONSTR_MIN:
		if (con->type < 10)
			return EXPP_setFloatClamped( value, &con->min, -180.0, 180.0 );
		else if (con->type < 20)
			return EXPP_setFloatClamped( value, &con->min, 0.0001, 1000.0 );
		else 
			return EXPP_setFloatClamped( value, &con->min, -1000.0, 1000.0 );
	case EXPP_CONSTR_MAX:
		if (con->type < 10)
			return EXPP_setFloatClamped( value, &con->max, -180.0, 180.0 );
		else if (con->type < 20)
			return EXPP_setFloatClamped( value, &con->max, 0.0001, 1000.0 );
		else 
			return EXPP_setFloatClamped( value, &con->max, -1000.0, 1000.0 );
	case EXPP_CONSTR_KEYON:
		return EXPP_setIValueRange( value, &con->type,
				EXPP_CONSTR_XROT, EXPP_CONSTR_ZLOC, 'h' );
	default:
		return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
	}
}

static PyObject *trackto_getter( BPy_Constraint * self, int type )
{
	bTrackToConstraint *con = (bTrackToConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET:
		return Object_CreatePyObject( con->tar );
	case EXPP_CONSTR_BONE:
		return PyString_FromString( con->subtarget );
	case EXPP_CONSTR_TRACK:
		return PyInt_FromLong( (long)con->reserved1 );
	case EXPP_CONSTR_UP:
		return PyInt_FromLong( (long)con->reserved2 );
	default:
		return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
	}
}

static int trackto_setter( BPy_Constraint *self, int type, PyObject *value )
{
	bTrackToConstraint *con = (bTrackToConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET: {
		Object *obj = (( BPy_Object * )value)->object;
		if( !BPy_Object_Check( value ) )
			return EXPP_ReturnIntError( PyExc_TypeError, 
					"expected BPy object argument" );
		con->tar = obj;
		return 0;
		}
	case EXPP_CONSTR_BONE: {
		char *name = PyString_AsString( value );
		if( !name )
			return EXPP_ReturnIntError( PyExc_TypeError,
					"expected string arg" );

		BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );

		return 0;
		}
	case EXPP_CONSTR_TRACK:
		return EXPP_setIValueRange( value, &con->reserved1,
				TRACK_X, TRACK_nZ, 'i' );
	case EXPP_CONSTR_UP:
		return EXPP_setIValueRange( value, &con->reserved2,
				UP_X, UP_Z, 'i' );
	default:
		return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
	}
}

static PyObject *stretchto_getter( BPy_Constraint * self, int type )
{
	bStretchToConstraint *con = (bStretchToConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET:
		return Object_CreatePyObject( con->tar );
	case EXPP_CONSTR_BONE:
		return PyString_FromString( con->subtarget );
	case EXPP_CONSTR_RESTLENGTH:
		return PyFloat_FromDouble( (double)con->orglength );
	case EXPP_CONSTR_VOLVARIATION:
		return PyFloat_FromDouble( (double)con->bulge );
	case EXPP_CONSTR_VOLUMEMODE:
		return PyInt_FromLong( (long)con->volmode );
	case EXPP_CONSTR_PLANE:
		return PyInt_FromLong( (long)con->plane );
	default:
		return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
	}
}

static int stretchto_setter( BPy_Constraint *self, int type, PyObject *value )
{
	bStretchToConstraint *con = (bStretchToConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET: {
		Object *obj = (( BPy_Object * )value)->object;
		if( !BPy_Object_Check( value ) )
			return EXPP_ReturnIntError( PyExc_TypeError, 
					"expected BPy object argument" );
		con->tar = obj;
		return 0;
		}
	case EXPP_CONSTR_BONE: {
		char *name = PyString_AsString( value );
		if( !name )
			return EXPP_ReturnIntError( PyExc_TypeError,
					"expected string arg" );

		BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );

		return 0;
		}
	case EXPP_CONSTR_RESTLENGTH:
		return EXPP_setFloatClamped( value, &con->orglength, 0.0, 100.0 );
	case EXPP_CONSTR_VOLVARIATION:
		return EXPP_setFloatClamped( value, &con->bulge, 0.0, 100.0 );
	case EXPP_CONSTR_VOLUMEMODE:
		return EXPP_setIValueRange( value, &con->volmode,
				VOLUME_XZ, NO_VOLUME, 'h' );
	case EXPP_CONSTR_PLANE: {
		int status, oldcode = con->plane;
		status = EXPP_setIValueRange( value, &con->plane,
				PLANE_X, PLANE_Z, 'h' );
		if( !status && con->plane == PLANE_Y ) {
			con->plane = oldcode;
			return EXPP_ReturnIntError( PyExc_ValueError,
					"value must be either PLANEX or PLANEZ" );
		}
		return status;
		}
	default:
		return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
	}
}

static PyObject *distlimit_getter( BPy_Constraint * self, int type )
{
	bDistLimitConstraint *con = (bDistLimitConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET:
		return Object_CreatePyObject( con->tar );
	case EXPP_CONSTR_BONE:
		return PyString_FromString( con->subtarget );
	case EXPP_CONSTR_RESTLENGTH:
		return PyFloat_FromDouble( (double)con->dist );
	case EXPP_CONSTR_MODE:
		return PyInt_FromLong( (long)con->mode );
	default:
		return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
	}
}

static int distlimit_setter( BPy_Constraint *self, int type, PyObject *value )
{
	bDistLimitConstraint *con = (bDistLimitConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET: {
		Object *obj = (( BPy_Object * )value)->object;
		if( !BPy_Object_Check( value ) )
			return EXPP_ReturnIntError( PyExc_TypeError, 
					"expected BPy object argument" );
		con->tar = obj;
		return 0;
		}
	case EXPP_CONSTR_BONE: {
		char *name = PyString_AsString( value );
		if( !name )
			return EXPP_ReturnIntError( PyExc_TypeError,
					"expected string arg" );

		BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );

		return 0;
		}
	case EXPP_CONSTR_RESTLENGTH:
		return EXPP_setFloatClamped( value, &con->dist, 0.0, 100.0 );
	case EXPP_CONSTR_MODE:
		return EXPP_setIValueRange( value, &con->mode, LIMITDIST_INSIDE, LIMITDIST_ONSURFACE, 'i' );
	default:
		return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
	}
}

static PyObject *followpath_getter( BPy_Constraint * self, int type )
{
	bFollowPathConstraint *con = (bFollowPathConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET:
		return Object_CreatePyObject( con->tar );
	case EXPP_CONSTR_FOLLOW:
		return PyBool_FromLong( (long)( con->followflag & SELECT ) );
	case EXPP_CONSTR_OFFSET:
		return PyFloat_FromDouble( (double)con->offset );
	case EXPP_CONSTR_FORWARD:
		return PyInt_FromLong( (long)con->trackflag );
	case EXPP_CONSTR_UP:
		return PyInt_FromLong( (long)con->upflag );
	default:
		return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
	}
}

static int followpath_setter( BPy_Constraint *self, int type, PyObject *value )
{
	bFollowPathConstraint *con = (bFollowPathConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET: {
		Object *obj = (( BPy_Object * )value)->object;
		if( !BPy_Object_Check( value ) )
			return EXPP_ReturnIntError( PyExc_TypeError, 
					"expected BPy object argument" );
		con->tar = obj;
		return 0;
		}
	case EXPP_CONSTR_FOLLOW:
		return EXPP_setBitfield( value, &con->followflag, SELECT, 'i' );
	case EXPP_CONSTR_OFFSET:
		return EXPP_setFloatClamped( value, &con->offset,
				-MAXFRAMEF, MAXFRAMEF );
	case EXPP_CONSTR_FORWARD:
		return EXPP_setIValueRange( value, &con->trackflag,
				TRACK_X, TRACK_nZ, 'i' );
	case EXPP_CONSTR_UP:
		return EXPP_setIValueRange( value, &con->upflag,
				UP_X, UP_Z, 'i' );
	default:
		return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
	}
}

static PyObject *clampto_getter( BPy_Constraint * self, int type )
{
	bClampToConstraint *con = (bClampToConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET:
		return Object_CreatePyObject( con->tar );
	case EXPP_CONSTR_CLAMP:
		return PyInt_FromLong( (long)con->flag );
	case EXPP_CONSTR_CLAMPCYCLIC:
		return PyBool_FromLong( (long)(con->flag2 & CLAMPTO_CYCLIC) );
	default:
		return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
	}
}

static int clampto_setter( BPy_Constraint *self, int type, PyObject *value )
{
	bClampToConstraint *con = (bClampToConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET: {
		Object *obj = (( BPy_Object * )value)->object;
		if( !BPy_Object_Check( value ) )
			return EXPP_ReturnIntError( PyExc_TypeError, 
					"expected BPy object argument" );
		con->tar = obj;
		return 0;
		}
	case EXPP_CONSTR_CLAMP:
		return EXPP_setIValueRange( value, &con->flag,
				CLAMPTO_AUTO, CLAMPTO_Z, 'i' );
	case EXPP_CONSTR_CLAMPCYCLIC:
		return EXPP_setBitfield( value, &con->flag2, CLAMPTO_CYCLIC, 'i' );
	default:
		return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
	}
}
static PyObject *locktrack_getter( BPy_Constraint * self, int type )
{
	bLockTrackConstraint *con = (bLockTrackConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET:
		return Object_CreatePyObject( con->tar );
	case EXPP_CONSTR_BONE:
		return PyString_FromString( con->subtarget );
	case EXPP_CONSTR_TRACK:
		return PyInt_FromLong( (long)con->trackflag );
	case EXPP_CONSTR_LOCK:
		return PyInt_FromLong( (long)con->lockflag );
	default:
		return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
	}
}

static int locktrack_setter( BPy_Constraint *self, int type, PyObject *value )
{
	bLockTrackConstraint *con = (bLockTrackConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET: {
		Object *obj = (( BPy_Object * )value)->object;
		if( !BPy_Object_Check( value ) )
			return EXPP_ReturnIntError( PyExc_TypeError, 
					"expected BPy object argument" );
		con->tar = obj;
		return 0;
		}
	case EXPP_CONSTR_BONE: {
		char *name = PyString_AsString( value );
		if( !name )
			return EXPP_ReturnIntError( PyExc_TypeError,
					"expected string arg" );

		BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );

		return 0;
		}
	case EXPP_CONSTR_TRACK:
		return EXPP_setIValueRange( value, &con->trackflag,
				TRACK_X, TRACK_nZ, 'i' );
	case EXPP_CONSTR_LOCK:
		return EXPP_setIValueRange( value, &con->lockflag,
				LOCK_X, LOCK_Z, 'i' );
	default:
		return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
	}
}

static PyObject *floor_getter( BPy_Constraint * self, int type )
{
	bMinMaxConstraint *con = (bMinMaxConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET:
		return Object_CreatePyObject( con->tar );
	case EXPP_CONSTR_BONE:
		return PyString_FromString( con->subtarget );
	case EXPP_CONSTR_MINMAX:
		return PyInt_FromLong( (long)con->minmaxflag );
	case EXPP_CONSTR_OFFSET:
		return PyFloat_FromDouble( (double)con->offset );
	case EXPP_CONSTR_STICKY:
		return PyBool_FromLong( (long)( con->flag & MINMAX_STICKY ) ) ;
	default:
		return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
	}
}

static int floor_setter( BPy_Constraint *self, int type, PyObject *value )
{
	bMinMaxConstraint *con = (bMinMaxConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET: {
		Object *obj = (( BPy_Object * )value)->object;
		if( !BPy_Object_Check( value ) )
			return EXPP_ReturnIntError( PyExc_TypeError, 
					"expected BPy object argument" );
		con->tar = obj;
		return 0;
		}
	case EXPP_CONSTR_BONE: {
		char *name = PyString_AsString( value );
		if( !name )
			return EXPP_ReturnIntError( PyExc_TypeError,
					"expected string arg" );

		BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );

		return 0;
		}
	case EXPP_CONSTR_MINMAX:
		return EXPP_setIValueRange( value, &con->minmaxflag,
				EXPP_CONSTR_MAXX, EXPP_CONSTR_MINZ, 'i' );
	case EXPP_CONSTR_OFFSET:
		return EXPP_setFloatClamped( value, &con->offset, -100.0, 100.0 );
	case EXPP_CONSTR_STICKY:
		return EXPP_setBitfield( value, &con->flag, MINMAX_STICKY, 'h' );
	default:
		return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
	}
}

static PyObject *locatelike_getter( BPy_Constraint * self, int type )
{
	bLocateLikeConstraint *con = (bLocateLikeConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET:
		return Object_CreatePyObject( con->tar );
	case EXPP_CONSTR_BONE:
		return PyString_FromString( con->subtarget );
	case EXPP_CONSTR_COPY:
		return PyInt_FromLong( (long)con->flag );
	default:
		return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
	}
}

static int locatelike_setter( BPy_Constraint *self, int type, PyObject *value )
{
	bLocateLikeConstraint *con = (bLocateLikeConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET: {
		Object *obj = (( BPy_Object * )value)->object;
		if( !BPy_Object_Check( value ) )
			return EXPP_ReturnIntError( PyExc_TypeError, 
					"expected BPy object argument" );
		con->tar = obj;
		return 0;
		}
	case EXPP_CONSTR_BONE: {
		char *name = PyString_AsString( value );
		if( !name )
			return EXPP_ReturnIntError( PyExc_TypeError,
					"expected string arg" );

		BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );

		return 0;
		}
	case EXPP_CONSTR_COPY:
		return EXPP_setIValueRange( value, &con->flag,
				0, LOCLIKE_X | LOCLIKE_Y | LOCLIKE_Z | LOCLIKE_X_INVERT | LOCLIKE_Y_INVERT | LOCLIKE_Z_INVERT, 'i' );
	default:
		return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
	}
}

static PyObject *rotatelike_getter( BPy_Constraint * self, int type )
{
	bRotateLikeConstraint *con = (bRotateLikeConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET:
		return Object_CreatePyObject( con->tar );
	case EXPP_CONSTR_BONE:
		return PyString_FromString( con->subtarget );
	case EXPP_CONSTR_COPY:
		return PyInt_FromLong( (long)con->flag );
	default:
		return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
	}
}

static int rotatelike_setter( BPy_Constraint *self, int type, PyObject *value )
{
	bRotateLikeConstraint *con = (bRotateLikeConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET: {
		Object *obj = (( BPy_Object * )value)->object;
		if( !BPy_Object_Check( value ) )
			return EXPP_ReturnIntError( PyExc_TypeError, 
					"expected BPy object argument" );
		con->tar = obj;
		return 0;
		}
	case EXPP_CONSTR_BONE: {
		char *name = PyString_AsString( value );
		if( !name )
			return EXPP_ReturnIntError( PyExc_TypeError,
					"expected string arg" );

		BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );

		return 0;
		}
	case EXPP_CONSTR_COPY:
		return EXPP_setIValueRange( value, &con->flag,
				0, ROTLIKE_X | ROTLIKE_Y | ROTLIKE_Z | ROTLIKE_X_INVERT | ROTLIKE_Y_INVERT | ROTLIKE_Z_INVERT, 'i' );
	default:
		return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
	}
}

static PyObject *sizelike_getter( BPy_Constraint * self, int type )
{
	bSizeLikeConstraint *con = (bSizeLikeConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET:
		return Object_CreatePyObject( con->tar );
	case EXPP_CONSTR_BONE:
		return PyString_FromString( con->subtarget );
	case EXPP_CONSTR_COPY:
		return PyInt_FromLong( (long)con->flag );
	default:
		return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
	}
}

static int sizelike_setter( BPy_Constraint *self, int type, PyObject *value )
{
	bSizeLikeConstraint *con = (bSizeLikeConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET: {
		Object *obj = (( BPy_Object * )value)->object;
		if( !BPy_Object_Check( value ) )
			return EXPP_ReturnIntError( PyExc_TypeError, 
					"expected BPy object argument" );
		con->tar = obj;
		return 0;
		}
	case EXPP_CONSTR_BONE: {
		char *name = PyString_AsString( value );
		if( !name )
			return EXPP_ReturnIntError( PyExc_TypeError,
					"expected string arg" );

		BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );

		return 0;
		}
	case EXPP_CONSTR_COPY:
		return EXPP_setIValueRange( value, &con->flag,
				0, SIZELIKE_X | SIZELIKE_Y | SIZELIKE_Z, 'i' );
	default:
		return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
	}
}

static PyObject *loclimit_getter( BPy_Constraint * self, int type)
{
	bLocLimitConstraint *con = (bLocLimitConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_LIMIT:
		return PyInt_FromLong( (long)con->flag );
	case EXPP_CONSTR_XMIN:
		return PyFloat_FromDouble( (double)con->xmin );
	case EXPP_CONSTR_XMAX:
		return PyFloat_FromDouble( (double)con->xmax );
	case EXPP_CONSTR_YMIN:
		return PyFloat_FromDouble( (double)con->ymin );
	case EXPP_CONSTR_YMAX:
		return PyFloat_FromDouble( (double)con->ymax );
	case EXPP_CONSTR_ZMIN:
		return PyFloat_FromDouble( (double)con->zmin );
	case EXPP_CONSTR_ZMAX:
		return PyFloat_FromDouble( (double)con->zmax );
	default:
		return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );	
	}
}

static int loclimit_setter( BPy_Constraint *self, int type, PyObject *value )
{
	bLocLimitConstraint *con = (bLocLimitConstraint *)(self->con->data);	
	
	switch( type ) {
	case EXPP_CONSTR_LIMIT:
		return EXPP_setIValueRange( value, &con->flag, 0, 
			LIMIT_XMIN | LIMIT_XMAX | LIMIT_YMIN | LIMIT_YMAX | LIMIT_ZMIN | LIMIT_ZMAX , 'i' );
	case EXPP_CONSTR_XMIN:
		return EXPP_setFloatClamped( value, &con->xmin, -1000.0, 1000.0 );
	case EXPP_CONSTR_XMAX:
		return EXPP_setFloatClamped( value, &con->xmax, -1000.0, 1000.0 );
	case EXPP_CONSTR_YMIN:
		return EXPP_setFloatClamped( value, &con->ymin, -1000.0, 1000.0 );
	case EXPP_CONSTR_YMAX:
		return EXPP_setFloatClamped( value, &con->ymax, -1000.0, 1000.0 );
	case EXPP_CONSTR_ZMIN:
		return EXPP_setFloatClamped( value, &con->zmin, -1000.0, 1000.0 );
	case EXPP_CONSTR_ZMAX:
		return EXPP_setFloatClamped( value, &con->zmax, -1000.0, 1000.0 );
	default:
		return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
	}
}

static PyObject *rotlimit_getter( BPy_Constraint * self, int type )
{
	bRotLimitConstraint *con = (bRotLimitConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_LIMIT:
		return PyInt_FromLong( (long)con->flag );
	case EXPP_CONSTR_XMIN:
		return PyFloat_FromDouble( (double)con->xmin );
	case EXPP_CONSTR_XMAX:
		return PyFloat_FromDouble( (double)con->xmax );
	case EXPP_CONSTR_YMIN:
		return PyFloat_FromDouble( (double)con->ymin );
	case EXPP_CONSTR_YMAX:
		return PyFloat_FromDouble( (double)con->ymax );
	case EXPP_CONSTR_ZMIN:
		return PyFloat_FromDouble( (double)con->zmin );
	case EXPP_CONSTR_ZMAX:
		return PyFloat_FromDouble( (double)con->zmax );
	default:
		return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );	
	}
}

static int rotlimit_setter( BPy_Constraint *self, int type, PyObject *value )
{
	bRotLimitConstraint *con = (bRotLimitConstraint *)(self->con->data);	
	
	switch( type ) {
	case EXPP_CONSTR_LIMIT:
		return EXPP_setIValueRange( value, &con->flag, 0, 
			LIMIT_XROT | LIMIT_YROT | LIMIT_ZROT, 'i' );
	case EXPP_CONSTR_XMIN:
		return EXPP_setFloatClamped( value, &con->xmin, -360.0, 360.0 );
	case EXPP_CONSTR_XMAX:
		return EXPP_setFloatClamped( value, &con->xmax, -360.0, 360.0 );
	case EXPP_CONSTR_YMIN:
		return EXPP_setFloatClamped( value, &con->ymin, -360.0, 360.0 );
	case EXPP_CONSTR_YMAX:
		return EXPP_setFloatClamped( value, &con->ymax, -360.0, 360.0 );
	case EXPP_CONSTR_ZMIN:
		return EXPP_setFloatClamped( value, &con->zmin, -360.0, 360.0 );
	case EXPP_CONSTR_ZMAX:
		return EXPP_setFloatClamped( value, &con->zmax, -360.0, 360.0 );
	default:
		return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
	}
}

static PyObject *sizelimit_getter( BPy_Constraint * self, int type)
{
	bSizeLimitConstraint *con = (bSizeLimitConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_LIMIT:
		return PyInt_FromLong( (long)con->flag );
	case EXPP_CONSTR_XMIN:
		return PyFloat_FromDouble( (double)con->xmin );
	case EXPP_CONSTR_XMAX:
		return PyFloat_FromDouble( (double)con->xmax );
	case EXPP_CONSTR_YMIN:
		return PyFloat_FromDouble( (double)con->ymin );
	case EXPP_CONSTR_YMAX:
		return PyFloat_FromDouble( (double)con->ymax );
	case EXPP_CONSTR_ZMIN:
		return PyFloat_FromDouble( (double)con->zmin );
	case EXPP_CONSTR_ZMAX:
		return PyFloat_FromDouble( (double)con->zmax );
	default:
		return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );	
	}
}

static int sizelimit_setter( BPy_Constraint *self, int type, PyObject *value )
{
	bSizeLimitConstraint *con = (bSizeLimitConstraint *)(self->con->data);	
	
	switch( type ) {
	case EXPP_CONSTR_LIMIT:
		return EXPP_setIValueRange( value, &con->flag, 0, 
			LIMIT_XMIN | LIMIT_XMAX | LIMIT_YMIN | LIMIT_YMAX | LIMIT_ZMIN | LIMIT_ZMAX, 'i' );
	case EXPP_CONSTR_XMIN:
		return EXPP_setFloatClamped( value, &con->xmin, -1000.0, 1000.0 );
	case EXPP_CONSTR_XMAX:
		return EXPP_setFloatClamped( value, &con->xmax, -1000.0, 1000.0 );
	case EXPP_CONSTR_YMIN:
		return EXPP_setFloatClamped( value, &con->ymin, -1000.0, 1000.0 );
	case EXPP_CONSTR_YMAX:
		return EXPP_setFloatClamped( value, &con->ymax, -1000.0, 1000.0 );
	case EXPP_CONSTR_ZMIN:
		return EXPP_setFloatClamped( value, &con->zmin, -1000.0, 1000.0 );
	case EXPP_CONSTR_ZMAX:
		return EXPP_setFloatClamped( value, &con->zmax, -1000.0, 1000.0 );
	default:
		return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
	}
}

static PyObject *script_getter( BPy_Constraint * self, int type )
{
	bPythonConstraint *con = (bPythonConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET:
	case EXPP_CONSTR_BONE:
		{
			bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_PYTHON);
			bConstraintTarget *ct;
			PyObject *tlist=NULL, *val;
			
			if (cti) {
				/* change space of targets */
				if (cti->get_constraint_targets) {
					ListBase targets = {NULL, NULL};
					int num_tars=0, i=0;
					
					/* get targets, and create py-list for use temporarily */
					num_tars= cti->get_constraint_targets(self->con, &targets);
					if (num_tars) {
						tlist= PyList_New(num_tars);
						
						for (ct=targets.first; ct; ct=ct->next, i++) {
							if (type == EXPP_CONSTR_BONE)
								val= PyString_FromString(ct->subtarget);
							else
								val= Object_CreatePyObject(ct->tar);
							PyList_SET_ITEM(tlist, i, val);
						}
					}
					
					if (cti->flush_constraint_targets)
						cti->flush_constraint_targets(self->con, &targets, 1);
				}
			}
			
			return tlist;
		}
	case EXPP_CONSTR_SCRIPT:
		return Text_CreatePyObject( con->text );
	case EXPP_CONSTR_PROPS:
		return BPy_Wrap_IDProperty( NULL, con->prop, NULL);
	default:
		return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
	}
}

static int script_setter( BPy_Constraint *self, int type, PyObject *value )
{
	bPythonConstraint *con = (bPythonConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET:
	case EXPP_CONSTR_BONE:
		{
			bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_PYTHON);
			bConstraintTarget *ct;
			int ok= 0;
			
			if (cti) {
				/* change space of targets */
				if (cti->get_constraint_targets) {
					ListBase targets = {NULL, NULL};
					int num_tars=0, i=0;
					
					/* get targets, and extract values from the given list */
					num_tars= cti->get_constraint_targets(self->con, &targets);
					if (num_tars) {
						if ((PySequence_Check(value) == 0) || (PySequence_Size(value) != num_tars)) {
							char errorstr[64];
							sprintf(errorstr, "expected sequence of %d integer(s)", num_tars);
							return EXPP_ReturnIntError(PyExc_TypeError, errorstr);
						}
						
						for (ct=targets.first; ct; ct=ct->next, i++) {
							PyObject *val= PySequence_ITEM(value, i);
								
							if (type == EXPP_CONSTR_BONE) {
								char *name = PyString_AsString(val);
								
								if (name == NULL) {
									// hrm... should we break here instead?
									ok = EXPP_ReturnIntError(PyExc_TypeError, 
												"expected string arg as member of list");
									Py_DECREF(val);
									
									break;
								}
								
								BLI_strncpy(ct->subtarget, name, sizeof(ct->subtarget));
							}
							else {
								Object *obj = (( BPy_Object * )val)->object;
								
								if ( !BPy_Object_Check(value) ) {
									// hrm... should we break here instead?
									ok = EXPP_ReturnIntError(PyExc_TypeError, 
												"expected BPy object argument as member of list");
									Py_DECREF(val);
									
									break;
								}
								
								ct->tar = obj;
							}
							
							Py_DECREF(val);
						}
					}
					
					/* only flush changes to real constraints if all were successful */
					if ((cti->flush_constraint_targets) && (ok == 0))
						cti->flush_constraint_targets(self->con, &targets, 0);
				}
			}
			
			return ok;
		}
			break;
	case EXPP_CONSTR_SCRIPT: {
		Text *text = (( BPy_Text * )value)->text;
		if( !BPy_Object_Check( value ) )
			return EXPP_ReturnIntError( PyExc_TypeError, 
					"expected BPy text argument" );
		con->text = text;
		return 0;
		}
	case EXPP_CONSTR_PROPS:
		return EXPP_ReturnIntError( PyExc_RuntimeError,
					"setting ID-Properties of PyConstraints this way is not supported" );
	default:
		return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
	}
}


static PyObject *rigidbody_getter( BPy_Constraint * self, int type)
{
	bRigidBodyJointConstraint *con = (bRigidBodyJointConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET:
		return Object_CreatePyObject( con->tar );
	case EXPP_CONSTR_RB_PIVX:
		return PyFloat_FromDouble( (double)con->pivX );
	case EXPP_CONSTR_RB_PIVY:
		return PyFloat_FromDouble( (double)con->pivY );
	case EXPP_CONSTR_RB_PIVZ:
		return PyFloat_FromDouble( (double)con->pivZ );
	case EXPP_CONSTR_RB_AXX:
		return PyFloat_FromDouble( (double)con->axX );
	case EXPP_CONSTR_RB_AXY:
		return PyFloat_FromDouble( (double)con->axY );
	case EXPP_CONSTR_RB_AXZ:
		return PyFloat_FromDouble( (double)con->axZ );
	case EXPP_CONSTR_RB_MINLIMIT0:
		return PyFloat_FromDouble( (double)con->minLimit[0] );
	case EXPP_CONSTR_RB_MINLIMIT1:
		return PyFloat_FromDouble( (double)con->minLimit[1] );
	case EXPP_CONSTR_RB_MINLIMIT2:
		return PyFloat_FromDouble( (double)con->minLimit[2] );
	case EXPP_CONSTR_RB_MINLIMIT3:
		return PyFloat_FromDouble( (double)con->minLimit[3] );
	case EXPP_CONSTR_RB_MINLIMIT4:
		return PyFloat_FromDouble( (double)con->minLimit[4] );
	case EXPP_CONSTR_RB_MINLIMIT5:
		return PyFloat_FromDouble( (double)con->minLimit[5] );
	case EXPP_CONSTR_RB_MAXLIMIT0:
		return PyFloat_FromDouble( (double)con->maxLimit[0] );
	case EXPP_CONSTR_RB_MAXLIMIT1:
		return PyFloat_FromDouble( (double)con->maxLimit[1] );
	case EXPP_CONSTR_RB_MAXLIMIT2:
		return PyFloat_FromDouble( (double)con->maxLimit[2] );
	case EXPP_CONSTR_RB_MAXLIMIT3:
		return PyFloat_FromDouble( (double)con->maxLimit[3] );
	case EXPP_CONSTR_RB_MAXLIMIT4:
		return PyFloat_FromDouble( (double)con->maxLimit[4] );
	case EXPP_CONSTR_RB_MAXLIMIT5:
		return PyFloat_FromDouble( (double)con->maxLimit[5] );
	case EXPP_CONSTR_RB_EXTRAFZ:
		return PyFloat_FromDouble( (double)con->extraFz );		
	case EXPP_CONSTR_LIMIT:
		return PyInt_FromLong( (int)con->flag );
		
	case EXPP_CONSTR_RB_TYPE:
		return PyInt_FromLong( (int)con->type );
	default:
		return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );	
	}
}


static int rigidbody_setter( BPy_Constraint *self, int type, PyObject *value )
{
	bRigidBodyJointConstraint *con = (bRigidBodyJointConstraint *)(self->con->data);	
	
	switch( type ) {
	case EXPP_CONSTR_TARGET: {
		Object *obj = (( BPy_Object * )value)->object;
		if( !BPy_Object_Check( value ) )
			return EXPP_ReturnIntError( PyExc_TypeError, 
					"expected BPy object argument" );
		con->tar = obj;
		return 0;
		}
	case EXPP_CONSTR_RB_PIVX:
		return EXPP_setFloatClamped( value, &con->pivX , -1000.0, 1000.0 );
	case EXPP_CONSTR_RB_PIVY:
		return EXPP_setFloatClamped( value, &con->pivY , -1000.0, 1000.0 );
	case EXPP_CONSTR_RB_PIVZ:
		return EXPP_setFloatClamped( value, &con->pivZ , -1000.0, 1000.0 );
	case EXPP_CONSTR_RB_AXX:
		return EXPP_setFloatClamped( value, &con->axX , -1000.0, 1000.0 );
	case EXPP_CONSTR_RB_AXY:
		return EXPP_setFloatClamped( value, &con->axY , -1000.0, 1000.0 );
	case EXPP_CONSTR_RB_AXZ:
		return EXPP_setFloatClamped( value, &con->axZ , -1000.0, 1000.0 );
	case EXPP_CONSTR_RB_MINLIMIT0:
		return EXPP_setFloatClamped( value, &con->minLimit[0] , -1000.0, 1000.0 );
	case EXPP_CONSTR_RB_MINLIMIT1:
		return EXPP_setFloatClamped( value, &con->minLimit[1] , -1000.0, 1000.0 );
	case EXPP_CONSTR_RB_MINLIMIT2:
		return EXPP_setFloatClamped( value, &con->minLimit[2] , -1000.0, 1000.0 );
	case EXPP_CONSTR_RB_MINLIMIT3:
		return EXPP_setFloatClamped( value, &con->minLimit[3] , -1000.0, 1000.0 );
	case EXPP_CONSTR_RB_MINLIMIT4:
		return EXPP_setFloatClamped( value, &con->minLimit[4] , -1000.0, 1000.0 );
	case EXPP_CONSTR_RB_MINLIMIT5:
		return EXPP_setFloatClamped( value, &con->minLimit[5] , -1000.0, 1000.0 );
	case EXPP_CONSTR_RB_MAXLIMIT0:
		return EXPP_setFloatClamped( value, &con->maxLimit[0] , -1000.0, 1000.0 );
	case EXPP_CONSTR_RB_MAXLIMIT1:
		return EXPP_setFloatClamped( value, &con->maxLimit[1] , -1000.0, 1000.0 );
	case EXPP_CONSTR_RB_MAXLIMIT2:
		return EXPP_setFloatClamped( value, &con->maxLimit[2] , -1000.0, 1000.0 );
	case EXPP_CONSTR_RB_MAXLIMIT3:
		return EXPP_setFloatClamped( value, &con->maxLimit[3] , -1000.0, 1000.0 );
	case EXPP_CONSTR_RB_MAXLIMIT4:
		return EXPP_setFloatClamped( value, &con->maxLimit[4] , -1000.0, 1000.0 );
	case EXPP_CONSTR_RB_MAXLIMIT5:
		return EXPP_setFloatClamped( value, &con->maxLimit[5] , -1000.0, 1000.0 );
	case EXPP_CONSTR_RB_EXTRAFZ:
		return EXPP_setFloatClamped( value, &con->extraFz , -1000.0, 1000.0 );						
	case EXPP_CONSTR_LIMIT:
		return EXPP_setIValueRange( value, &con->flag, 0, 
			LIMIT_XMIN | LIMIT_XMAX | LIMIT_YMIN | LIMIT_YMAX | LIMIT_ZMIN | LIMIT_ZMAX, 'i' );
	case EXPP_CONSTR_RB_TYPE:
		return EXPP_setIValueRange( value, &con->type, 0, 
			EXPP_CONSTR_RB_BALL | EXPP_CONSTR_RB_HINGE | EXPP_CONSTR_RB_GENERIC6DOF | EXPP_CONSTR_RB_VEHICLE, 'i' );
	default:
		return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
	}
}

static PyObject *childof_getter( BPy_Constraint * self, int type )
{
	bChildOfConstraint *con = (bChildOfConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET:
		return Object_CreatePyObject( con->tar );
	case EXPP_CONSTR_BONE:
		return PyString_FromString( con->subtarget );
	case EXPP_CONSTR_COPY:
		return PyInt_FromLong( (long)con->flag );
	default:
		return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
	}
}

static int childof_setter( BPy_Constraint *self, int type, PyObject *value )
{
	bChildOfConstraint *con = (bChildOfConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET: {
		Object *obj = (( BPy_Object * )value)->object;
		if( !BPy_Object_Check( value ) )
			return EXPP_ReturnIntError( PyExc_TypeError, 
					"expected BPy object argument" );
		con->tar = obj;
		return 0;
		}
	case EXPP_CONSTR_BONE: {
		char *name = PyString_AsString( value );
		if( !name )
			return EXPP_ReturnIntError( PyExc_TypeError,
					"expected string arg" );

		BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );

		return 0;
		}
	case EXPP_CONSTR_COPY:
		return EXPP_setIValueRange( value, &con->flag,
				0, CHILDOF_LOCX| CHILDOF_LOCY | CHILDOF_LOCZ | CHILDOF_ROTX | CHILDOF_ROTY | CHILDOF_ROTZ |
					CHILDOF_SIZEX |CHILDOF_SIZEY| CHILDOF_SIZEZ, 'i' );
	default:
		return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
	}
}

static PyObject *transf_getter( BPy_Constraint * self, int type )
{
	bTransformConstraint *con = (bTransformConstraint *)(self->con->data);

	switch( type ) {
	case EXPP_CONSTR_TARGET:
		return Object_CreatePyObject( con->tar );
	case EXPP_CONSTR_BONE:
		return PyString_FromString( con->subtarget );
	case EXPP_CONSTR_FROM:
		return PyInt_FromLong( (long)con->from );
	case EXPP_CONSTR_TO:
		return PyInt_FromLong( (long)con->to );
	case EXPP_CONSTR_MAPX:
		return PyInt_FromLong( (long)con->map[0] );
	case EXPP_CONSTR_MAPY:
		return PyInt_FromLong( (long)con->map[1] );
	case EXPP_CONSTR_MAPZ:
		return PyInt_FromLong( (long)con->map[2] );
	case EXPP_CONSTR_FROMMINX:
		return PyFloat_FromDouble( (double)con->from_min[0] );
	case EXPP_CONSTR_FROMMAXX:
		return PyFloat_FromDouble( (double)con->from_max[0] );
	case EXPP_CONSTR_FROMMINY:
		return PyFloat_FromDouble( (double)con->from_min[1] );
	case EXPP_CONSTR_FROMMAXY:
		return PyFloat_FromDouble( (double)con->from_max[1] );
	case EXPP_CONSTR_FROMMINZ:
		return PyFloat_FromDouble( (double)con->from_min[2] );
	case EXPP_CONSTR_FROMMAXZ:
		return PyFloat_FromDouble( (double)con->from_max[2] );
	case EXPP_CONSTR_TOMINX:
		return PyFloat_FromDouble( (double)con->to_min[0] );
	case EXPP_CONSTR_TOMAXX:
		return PyFloat_FromDouble( (double)con->to_max[0] );
	case EXPP_CONSTR_TOMINY:
		return PyFloat_FromDouble( (double)con->to_min[1] );
	case EXPP_CONSTR_TOMAXY:
		return PyFloat_FromDouble( (double)con->to_max[1] );
	case EXPP_CONSTR_TOMINZ:
		return PyFloat_FromDouble( (double)con->to_min[2] );
	case EXPP_CONSTR_TOMAXZ:
		return PyFloat_FromDouble( (double)con->to_max[2] );
	case EXPP_CONSTR_EXPO:
		return PyBool_FromLong( (long)con->expo );
	default:
		return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
	}
}

static int transf_setter( BPy_Constraint *self, int type, PyObject *value )
{
	bTransformConstraint *con = (bTransformConstraint *)(self->con->data);
	float fmin, fmax, tmin, tmax;
	
	if (con->from == 2) {
		fmin = 0.0001;
		fmax = 1000.0;
	}
	else if (con->from == 1) {
		fmin = -360.0;
		fmax = 360.0;
	}
	else {
		fmin = -1000.0;
		fmax = 1000.0;
	}
	
	if (con->to == 2) {
		tmin = 0.0001;
		tmax = 1000.0;
	}
	else if (con->to == 1) {
		tmin = -360.0;
		tmax = 360.0;
	}
	else {
		tmin = -1000.0;
		tmax = 1000.0;
	}
	
	switch( type ) {
	case EXPP_CONSTR_TARGET: {
		Object *obj = (( BPy_Object * )value)->object;
		if( !BPy_Object_Check( value ) )
			return EXPP_ReturnIntError( PyExc_TypeError, 
					"expected BPy object argument" );
		con->tar = obj;
		return 0;
		}
	case EXPP_CONSTR_BONE: {
		char *name = PyString_AsString( value );
		if( !name )
			return EXPP_ReturnIntError( PyExc_TypeError,
					"expected string arg" );

		BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );

		return 0;
		}
	case EXPP_CONSTR_FROM:
		return EXPP_setIValueClamped( value, &con->from, 0, 3, 'h' );
	case EXPP_CONSTR_TO:
		return EXPP_setIValueClamped( value, &con->to, 0, 3, 'h' );
	case EXPP_CONSTR_MAPX:
		return EXPP_setIValueClamped( value, &con->map[0], 0, 3, 'h' );
	case EXPP_CONSTR_MAPY:
		return EXPP_setIValueClamped( value, &con->map[1], 0, 3, 'h' );
	case EXPP_CONSTR_MAPZ:
		return EXPP_setIValueClamped( value, &con->map[2], 0, 3, 'h' );
	case EXPP_CONSTR_FROMMINX:
		return EXPP_setFloatClamped( value, &con->from_min[0], fmin, fmax );
	case EXPP_CONSTR_FROMMAXX:
		return EXPP_setFloatClamped( value, &con->from_max[0], fmin, fmax );
	case EXPP_CONSTR_FROMMINY:
		return EXPP_setFloatClamped( value, &con->from_min[1], fmin, fmax );
	case EXPP_CONSTR_FROMMAXY:
		return EXPP_setFloatClamped( value, &con->from_max[1], fmin, fmax );
	case EXPP_CONSTR_FROMMINZ:
		return EXPP_setFloatClamped( value, &con->from_min[2], fmin, fmax );
	case EXPP_CONSTR_FROMMAXZ:
		return EXPP_setFloatClamped( value, &con->from_max[2], fmin, fmax );
	case EXPP_CONSTR_TOMINX:
		return EXPP_setFloatClamped( value, &con->to_min[0], tmin, tmax );
	case EXPP_CONSTR_TOMAXX:
		return EXPP_setFloatClamped( value, &con->to_max[0], tmin, tmax );
	case EXPP_CONSTR_TOMINY:
		return EXPP_setFloatClamped( value, &con->to_min[1], tmin, tmax );
	case EXPP_CONSTR_TOMAXY:
		return EXPP_setFloatClamped( value, &con->to_max[1], tmin, tmax );
	case EXPP_CONSTR_TOMINZ:
		return EXPP_setFloatClamped( value, &con->to_min[2], tmin, tmax );
	case EXPP_CONSTR_TOMAXZ:
		return EXPP_setFloatClamped( value, &con->to_max[2], tmin, tmax );
	case EXPP_CONSTR_EXPO:
		return EXPP_setBitfield( value, &con->expo, 1, 'h' );
	default:
		return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
	}
}

/*
 * get data from a constraint
 */

static PyObject *Constraint_getData( BPy_Constraint * self, PyObject * key )
{
	int setting;

	if( !PyInt_Check( key ) )
		return EXPP_ReturnPyObjError( PyExc_TypeError,
				"expected an int arg" );

	if( !self->con )
		return EXPP_ReturnPyObjError( PyExc_RuntimeError,
				"This constraint has been removed!" );
	
	setting = PyInt_AsLong( key );
	
	/* bypass doing settings of individual constraints, if we're just doing
	 * constraint space access-stuff 
	 */
	if ((setting==EXPP_CONSTR_OWNSPACE) || (setting==EXPP_CONSTR_TARSPACE)) {
		return constspace_getter( self, setting );
	}
	switch( self->con->type ) {
		case CONSTRAINT_TYPE_NULL:
			Py_RETURN_NONE;
		case CONSTRAINT_TYPE_TRACKTO:
			return trackto_getter( self, setting );
		case CONSTRAINT_TYPE_KINEMATIC:
			return kinematic_getter( self, setting );
		case CONSTRAINT_TYPE_FOLLOWPATH:
			return followpath_getter( self, setting );
		case CONSTRAINT_TYPE_ACTION:
			return action_getter( self, setting );
		case CONSTRAINT_TYPE_LOCKTRACK:
			return locktrack_getter( self, setting );
		case CONSTRAINT_TYPE_STRETCHTO:
			return stretchto_getter( self, setting );
		case CONSTRAINT_TYPE_MINMAX:
			return floor_getter( self, setting );
		case CONSTRAINT_TYPE_LOCLIKE:
			return locatelike_getter( self, setting );
		case CONSTRAINT_TYPE_ROTLIKE:
			return rotatelike_getter( self, setting );
		case CONSTRAINT_TYPE_SIZELIKE:
			return sizelike_getter( self, setting );
		case CONSTRAINT_TYPE_ROTLIMIT:
			return rotlimit_getter( self, setting );
		case CONSTRAINT_TYPE_LOCLIMIT:
			return loclimit_getter( self, setting );
		case CONSTRAINT_TYPE_SIZELIMIT:
			return sizelimit_getter( self, setting );
		case CONSTRAINT_TYPE_DISTLIMIT:
			return distlimit_getter( self, setting );
		case CONSTRAINT_TYPE_RIGIDBODYJOINT:
			return rigidbody_getter( self, setting );
		case CONSTRAINT_TYPE_CLAMPTO:
			return clampto_getter( self, setting );
		case CONSTRAINT_TYPE_PYTHON:
			return script_getter( self, setting );
		case CONSTRAINT_TYPE_CHILDOF:
			return childof_getter( self, setting );
		case CONSTRAINT_TYPE_TRANSFORM:
			return transf_getter( self, setting );
		default:
			return EXPP_ReturnPyObjError( PyExc_KeyError,
					"unknown constraint type" );
	}
}

static int Constraint_setData( BPy_Constraint * self, PyObject * key, 
		PyObject * arg )
{
	int key_int, result;

	if( !PyNumber_Check( key ) )
		return EXPP_ReturnIntError( PyExc_TypeError,
				"expected an int arg" );
	if( !self->con )
		return EXPP_ReturnIntError( PyExc_RuntimeError,
				"This constraint has been removed!" );
	
	key_int = PyInt_AsLong( key );
	
	/* bypass doing settings of individual constraints, if we're just doing
	 * constraint space access-stuff 
	 */
	if ((key_int==EXPP_CONSTR_OWNSPACE) || (key_int==EXPP_CONSTR_TARSPACE)) {
		result = constspace_setter( self, key_int, arg );
	}
	else {
		switch( self->con->type ) {
		case CONSTRAINT_TYPE_KINEMATIC:
			result = kinematic_setter( self, key_int, arg );
			break;
		case CONSTRAINT_TYPE_ACTION:
			result = action_setter( self, key_int, arg );
			break;
		case CONSTRAINT_TYPE_TRACKTO:
			result = trackto_setter( self, key_int, arg );
			break;
		case CONSTRAINT_TYPE_STRETCHTO:
			result = stretchto_setter( self, key_int, arg );
			break;
		case CONSTRAINT_TYPE_FOLLOWPATH:
			result = followpath_setter( self, key_int, arg );
			break;
		case CONSTRAINT_TYPE_LOCKTRACK:
			result = locktrack_setter( self, key_int, arg );
			break;
		case CONSTRAINT_TYPE_MINMAX:
			result = floor_setter( self, key_int, arg );
			break;
		case CONSTRAINT_TYPE_LOCLIKE:
			result = locatelike_setter( self, key_int, arg );
			break;
		case CONSTRAINT_TYPE_ROTLIKE:
			result = rotatelike_setter( self, key_int, arg );
			break;
		case CONSTRAINT_TYPE_SIZELIKE:
			result = sizelike_setter( self, key_int, arg );
			break;
		case CONSTRAINT_TYPE_ROTLIMIT:
			result = rotlimit_setter( self, key_int, arg );
			break;
		case CONSTRAINT_TYPE_LOCLIMIT:
			result = loclimit_setter( self, key_int, arg );
			break;
		case CONSTRAINT_TYPE_SIZELIMIT:
			result = sizelimit_setter( self, key_int, arg);
			break;
		case CONSTRAINT_TYPE_DISTLIMIT:
			result = distlimit_setter( self, key_int, arg);
			break;
		case CONSTRAINT_TYPE_RIGIDBODYJOINT:
			result = rigidbody_setter( self, key_int, arg);
			break;
		case CONSTRAINT_TYPE_CLAMPTO:
			result = clampto_setter( self, key_int, arg);
			break;
		case CONSTRAINT_TYPE_PYTHON:
			result = script_setter( self, key_int, arg);
			break;
		case CONSTRAINT_TYPE_CHILDOF:
			result = childof_setter( self, key_int, arg);
			break;
		case CONSTRAINT_TYPE_TRANSFORM:
			result = transf_setter( self, key_int, arg);
			break;
		case CONSTRAINT_TYPE_NULL:
			return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
		default:
			return EXPP_ReturnIntError( PyExc_RuntimeError,
					"unsupported constraint setting" );
		}
	}
	if( !result && self->pchan )
		update_pose_constraint_flags( self->obj->pose );
	return result;
}

/*****************************************************************************/
/* Function:    Constraint_compare                                           */
/* Description: This compares 2 constraint python types, == or != only.      */
/*****************************************************************************/
static int Constraint_compare( BPy_Constraint * a, BPy_Constraint * b )
{
	return ( a->con == b->con ) ? 0 : -1;
}

/*****************************************************************************/
/* Function:    Constraint_repr                                              */
/* Description: This is a callback function for the BPy_Constraint type. It  */
/*              builds a meaningful string to represent constraint objects.  */
/*****************************************************************************/

static PyObject *Constraint_repr( BPy_Constraint * self )
{
	bConstraintTypeInfo *cti;

	if (!self->con)
		return PyString_FromString("[Constraint - Removed]");
	else
		cti= constraint_get_typeinfo(self->con);
	
	if (cti) {
		return PyString_FromFormat("[Constraint \"%s\", Type \"%s\"]",
				self->con->name, cti->name);
	}
	else {
		return PyString_FromString("[Constraint \"%s\", Type \"Unknown\"]");
	}
}

/* Three Python Constraint_Type helper functions needed by the Object module: */

/*****************************************************************************/
/* Function:    Constraint_CreatePyObject                                    */
/* Description: This function will create a new BPy_Constraint from an       */
/*              existing Blender constraint structure.                       */
/*****************************************************************************/
PyObject *Constraint_CreatePyObject( bPoseChannel *pchan, Object *obj,
		bConstraint *con )
{
	BPy_Constraint *pycon;
	pycon = ( BPy_Constraint * ) PyObject_NEW( BPy_Constraint,
			&Constraint_Type );
	if( !pycon )
		return EXPP_ReturnPyObjError( PyExc_MemoryError,
					      "couldn't create BPy_Constraint object" );

	pycon->con = con;

	/* one of these two will be NULL */
	pycon->obj = obj;	
	pycon->pchan = pchan;
	return ( PyObject * ) pycon;
}

/*****************************************************************************/
/* Function:    Constraint_FromPyObject                                      */
/* Description: This function returns the Blender constraint from the given  */
/*              PyObject.                                                    */
/*****************************************************************************/
bConstraint *Constraint_FromPyObject( BPy_Constraint * self )
{
	return self->con;
}

/*****************************************************************************/
/* Constraint Sequence wrapper                                               */
/*****************************************************************************/

/*
 * Initialize the interator
 */

static PyObject *ConstraintSeq_getIter( BPy_ConstraintSeq * self )
{
	if( self->pchan )
		self->iter = (bConstraint *)self->pchan->constraints.first;
	else
		self->iter = (bConstraint *)self->obj->constraints.first;
	return EXPP_incr_ret ( (PyObject *) self );
}

/*
 * Get the next Constraint
 */

static PyObject *ConstraintSeq_nextIter( BPy_ConstraintSeq * self )
{
	bConstraint *this = self->iter;
	if( this ) {
		self->iter = this->next;
		return Constraint_CreatePyObject( self->pchan, self->obj, this );
	}

	return EXPP_ReturnPyObjError( PyExc_StopIteration,
			"iterator at end" );
}

/* return the number of constraints */

static int ConstraintSeq_length( BPy_ConstraintSeq * self )
{
	return BLI_countlist( self->pchan ?
		&self->pchan->constraints : &self->obj->constraints );
}

/* return a constraint */

static PyObject *ConstraintSeq_item( BPy_ConstraintSeq * self, int i )
{
	bConstraint *con = NULL;

	/* if index is negative, start counting from the end of the list */
	if( i < 0 )
		i += ConstraintSeq_length( self );

	/* skip through the list until we get the constraint or end of list */

	if( self->pchan )
		con = self->pchan->constraints.first;
	else
		con = self->obj->constraints.first;

	while( i && con ) {
		--i;
		con = con->next;
	}

	if( con )
		return Constraint_CreatePyObject( self->pchan, self->obj, con );
	else
		return EXPP_ReturnPyObjError( PyExc_IndexError,
				"array index out of range" );
}

/*****************************************************************************/
/* Python BPy_ConstraintSeq sequence table:                                  */
/*****************************************************************************/
static PySequenceMethods ConstraintSeq_as_sequence = {
	( inquiry ) ConstraintSeq_length,	/* sq_length */
	( binaryfunc ) 0,	/* sq_concat */
	( intargfunc ) 0,	/* sq_repeat */
	( intargfunc ) ConstraintSeq_item,	/* sq_item */
	( intintargfunc ) 0,	/* sq_slice */
	( intobjargproc ) 0,	/* sq_ass_item */
	( intintobjargproc ) 0,	/* sq_ass_slice */
	( objobjproc ) 0,	/* sq_contains */
	( binaryfunc ) 0,		/* sq_inplace_concat */
	( intargfunc ) 0,		/* sq_inplace_repeat */
};

/*
 * helper function to check for a valid constraint argument
 */

static bConstraint *locate_constr( BPy_ConstraintSeq *self, BPy_Constraint * value )
{
	bConstraint *con;

	/* check that argument is a modifier */
	if (!BPy_Constraint_Check(value))
		return (bConstraint *)EXPP_ReturnPyObjError( PyExc_TypeError,
				"expected a constraint as an argument" );

	/* check whether constraint has been removed */
	if( !value->con )
		return (bConstraint *)EXPP_ReturnPyObjError( PyExc_RuntimeError,
				"This constraint has been removed!" );

	/* verify the constraint is still exists in the stack */
	if( self->pchan )
		con = self->pchan->constraints.first;
	else
		con = self->obj->constraints.first;
	while( con && con != value->con )
	   	con = con->next;

	/* if we didn't find it, exception */
	if( !con )
		return (bConstraint *)EXPP_ReturnPyObjError( PyExc_AttributeError,
				"This constraint is no longer in the object's stack" );

	return con;
}


/* create a new constraint at the end of the list */

static PyObject *ConstraintSeq_append( BPy_ConstraintSeq *self, PyObject *value )
{
	int type = (int)PyInt_AsLong(value);
	bConstraint *con;

	/* type 0 is CONSTRAINT_TYPE_NULL, should we be able to add one of these?
	 * if the value is not an int it will be -1 */
	if( type < CONSTRAINT_TYPE_NULL || type > CONSTRAINT_TYPE_RIGIDBODYJOINT ) 
		return EXPP_ReturnPyObjError( PyExc_ValueError,
				"arg not in int or out of range" );

	con = add_new_constraint( type );
	if( self->pchan ) {
		BLI_addtail( &self->pchan->constraints, con );
		update_pose_constraint_flags( self->obj->pose );
	}
	else
		BLI_addtail( &self->obj->constraints, con );

	return Constraint_CreatePyObject( self->pchan, self->obj, con );
}

/* move the constraint up in the stack */

static PyObject *ConstraintSeq_moveUp( BPy_ConstraintSeq *self, BPy_Constraint *value )
{
	bConstraint *con = locate_constr( self,  value );

	/* if we can't locate the constraint, return (exception already set) */
	if( !con )
		return (PyObject *)NULL;

	const_moveUp( self->obj, con );
	Py_RETURN_NONE;
}

/* move the constraint down in the stack */

static PyObject *ConstraintSeq_moveDown( BPy_ConstraintSeq *self, BPy_Constraint *value )
{
	bConstraint *con = locate_constr( self,  value );

	/* if we can't locate the constraint, return (exception already set) */
	if( !con )
		return (PyObject *)NULL;

	const_moveDown( self->obj, con );
	Py_RETURN_NONE;
}

/* remove an existing constraint */

static PyObject *ConstraintSeq_remove( BPy_ConstraintSeq *self, BPy_Constraint *value )
{
	bConstraint *con = locate_constr(self, value);
	bPoseChannel *active= NULL;

	/* if we can't locate the constraint, return (exception already set) */
	if (!con)
		return (PyObject *)NULL;

	/* check if we need to set temporary 'active' flag for pchan */
	if (self->pchan) {
		active= get_active_posechannel(self->obj);
		
		if (active != self->pchan) {
			if (active) active->bone->flag &= ~BONE_ACTIVE;
			self->pchan->bone->flag |= BONE_ACTIVE;
		}
	}
	
	/* del_constr_func() frees constraint + its data */
	del_constr_func( self->obj, con );

	/* reset active pchan (if applicable) */
	if (self->pchan && self->pchan!=active) {
		if (active) active->bone->flag |= BONE_ACTIVE;
		self->pchan->bone->flag &= ~BONE_ACTIVE;
	}
	
	/* erase the link to the constraint */
	value->con = NULL;

	Py_RETURN_NONE;
}

/*****************************************************************************/
/* Function:    ConstraintSeq_dealloc                                        */
/* Description: This is a callback function for the BPy_ConstraintSeq type.  */
/*              It destroys data when the object is deleted.                 */
/*****************************************************************************/
static void ConstraintSeq_dealloc( BPy_Constraint * self )
{
	PyObject_DEL( self );
}

/*****************************************************************************/
/* Python BPy_ConstraintSeq methods table:                                   */
/*****************************************************************************/
static PyMethodDef BPy_ConstraintSeq_methods[] = {
	/* name, method, flags, doc */
	{"append", ( PyCFunction ) ConstraintSeq_append, METH_O,
	 "(type) - add a new constraint, where type is the constraint type"},
	{"remove", ( PyCFunction ) ConstraintSeq_remove, METH_O,
	 "(con) - remove an existing constraint, where con is a constraint from this object."},
	{"moveUp", ( PyCFunction ) ConstraintSeq_moveUp, METH_O,
	 "(con) - Move constraint up in stack"},
	{"moveDown", ( PyCFunction ) ConstraintSeq_moveDown, METH_O,
	 "(con) - Move constraint down in stack"},
	{NULL, NULL, 0, NULL}
};

/*****************************************************************************/
/* Python ConstraintSeq_Type structure definition:                           */
/*****************************************************************************/
PyTypeObject ConstraintSeq_Type = {
	PyObject_HEAD_INIT( NULL )  /* required py macro */
	0,                          /* ob_size */
	/*  For printing, in format "<module>.<name>" */
	"Blender.Constraints",      /* char *tp_name; */
	sizeof( BPy_ConstraintSeq ),     /* int tp_basicsize; */
	0,                          /* tp_itemsize;  For allocation */

	/* Methods to implement standard operations */

	( destructor ) ConstraintSeq_dealloc,/* destructor tp_dealloc; */
	NULL,                       /* printfunc tp_print; */
	NULL,                       /* getattrfunc tp_getattr; */
	NULL,                       /* setattrfunc tp_setattr; */
	NULL,                       /* cmpfunc tp_compare; */
	( reprfunc ) NULL,          /* reprfunc tp_repr; */

	/* Method suites for standard classes */

	NULL,                       /* PyNumberMethods *tp_as_number; */
	&ConstraintSeq_as_sequence,        /* PySequenceMethods *tp_as_sequence; */
	NULL,                       /* PyMappingMethods *tp_as_mapping; */

	/* More standard operations (here for binary compatibility) */

	NULL,                       /* hashfunc tp_hash; */
	NULL,                       /* ternaryfunc tp_call; */
	NULL,                       /* reprfunc tp_str; */
	NULL,                       /* getattrofunc tp_getattro; */
	NULL,                       /* setattrofunc tp_setattro; */

	/* Functions to access object as input/output buffer */
	NULL,                       /* PyBufferProcs *tp_as_buffer; */

  /*** Flags to define presence of optional/expanded features ***/
	Py_TPFLAGS_DEFAULT,         /* long tp_flags; */

	NULL,                       /*  char *tp_doc;  Documentation string */
  /*** Assigned meaning in release 2.0 ***/
	/* call function for all accessible objects */
	NULL,                       /* traverseproc tp_traverse; */

	/* delete references to contained objects */
	NULL,                       /* inquiry tp_clear; */

  /***  Assigned meaning in release 2.1 ***/
  /*** rich comparisons ***/
	NULL,                       /* richcmpfunc tp_richcompare; */

  /***  weak reference enabler ***/
	0,                          /* long tp_weaklistoffset; */

  /*** Added in release 2.2 ***/
	/*   Iterators */
	( getiterfunc )ConstraintSeq_getIter, /* getiterfunc tp_iter; */
    ( iternextfunc )ConstraintSeq_nextIter, /* iternextfunc tp_iternext; */

  /*** Attribute descriptor and subclassing stuff ***/
	BPy_ConstraintSeq_methods,         /* struct PyMethodDef *tp_methods; */
	NULL,                       /* struct PyMemberDef *tp_members; */
	NULL,                       /* struct PyGetSetDef *tp_getset; */
	NULL,                       /* struct _typeobject *tp_base; */
	NULL,                       /* PyObject *tp_dict; */
	NULL,                       /* descrgetfunc tp_descr_get; */
	NULL,                       /* descrsetfunc tp_descr_set; */
	0,                          /* long tp_dictoffset; */
	NULL,                       /* initproc tp_init; */
	NULL,                       /* allocfunc tp_alloc; */
	NULL,                       /* newfunc tp_new; */
	/*  Low-level free-memory routine */
	NULL,                       /* freefunc tp_free;  */
	/* For PyObject_IS_GC */
	NULL,                       /* inquiry tp_is_gc;  */
	NULL,                       /* PyObject *tp_bases; */
	/* method resolution order */
	NULL,                       /* PyObject *tp_mro;  */
	NULL,                       /* PyObject *tp_cache; */
	NULL,                       /* PyObject *tp_subclasses; */
	NULL,                       /* PyObject *tp_weaklist; */
	NULL
};

/*****************************************************************************/
/* Function:    PoseConstraintSeq_CreatePyObject                             */
/* Description: This function will create a new BPy_ConstraintSeq from an    */
/*              existing ListBase structure.                                 */
/*****************************************************************************/
PyObject *PoseConstraintSeq_CreatePyObject( bPoseChannel *pchan )
{
	BPy_ConstraintSeq *pyseq;
	Object *ob;

	for( ob = G.main->object.first; ob; ob = ob->id.next ) {
		if( ob->type == OB_ARMATURE ) {
			bPoseChannel *p = ob->pose->chanbase.first;
			while( p ) {
				if( p == pchan ) {
					pyseq = ( BPy_ConstraintSeq * ) PyObject_NEW( 
							BPy_ConstraintSeq, &ConstraintSeq_Type );
					if( !pyseq )
						return EXPP_ReturnPyObjError( PyExc_MemoryError,
								"couldn't create BPy_ConstraintSeq object" );
					pyseq->pchan = pchan;
					pyseq->obj = ob;
					return ( PyObject * ) pyseq;
				} else
					p = p->next;
			}
		}
	}
	return EXPP_ReturnPyObjError( PyExc_RuntimeError,
			"couldn't find ANY armature with the pose!" );

}

/*****************************************************************************/
/* Function:    ObConstraintSeq_CreatePyObject                               */
/* Description: This function will create a new BPy_ConstraintSeq from an    */
/*              existing ListBase structure.                                 */
/*****************************************************************************/
PyObject *ObConstraintSeq_CreatePyObject( Object *obj )
{
	BPy_ConstraintSeq *pyseq;
	pyseq = ( BPy_ConstraintSeq * ) PyObject_NEW( BPy_ConstraintSeq,
			&ConstraintSeq_Type );
	if( !pyseq )
		return EXPP_ReturnPyObjError( PyExc_MemoryError,
					      "couldn't create BPy_ConstraintSeq object" );
	pyseq->obj = obj;
	pyseq->pchan = NULL;
	return ( PyObject * ) pyseq;
}

static PyObject *M_Constraint_TypeDict( void )
{
	PyObject *S = PyConstant_New(  );

	if( S ) {
		BPy_constant *d = ( BPy_constant * ) S;
		PyConstant_Insert( d, "NULL", 
				PyInt_FromLong( CONSTRAINT_TYPE_NULL ) );
		PyConstant_Insert( d, "TRACKTO",
				PyInt_FromLong( CONSTRAINT_TYPE_TRACKTO ) );
		PyConstant_Insert( d, "IKSOLVER", 
				PyInt_FromLong( CONSTRAINT_TYPE_KINEMATIC ) );
		PyConstant_Insert( d, "FOLLOWPATH", 
				PyInt_FromLong( CONSTRAINT_TYPE_FOLLOWPATH ) );
		PyConstant_Insert( d, "COPYROT", 
				PyInt_FromLong( CONSTRAINT_TYPE_ROTLIKE ) );
		PyConstant_Insert( d, "COPYLOC", 
				PyInt_FromLong( CONSTRAINT_TYPE_LOCLIKE ) );
		PyConstant_Insert( d, "COPYSIZE", 
				PyInt_FromLong( CONSTRAINT_TYPE_SIZELIKE ) );
		PyConstant_Insert( d, "ACTION", 
				PyInt_FromLong( CONSTRAINT_TYPE_ACTION ) );
		PyConstant_Insert( d, "LOCKTRACK", 
				PyInt_FromLong( CONSTRAINT_TYPE_LOCKTRACK ) );
		PyConstant_Insert( d, "STRETCHTO", 
				PyInt_FromLong( CONSTRAINT_TYPE_STRETCHTO ) );
		PyConstant_Insert( d, "FLOOR", 
				PyInt_FromLong( CONSTRAINT_TYPE_MINMAX ) );
		PyConstant_Insert( d, "LIMITLOC", 
				PyInt_FromLong( CONSTRAINT_TYPE_LOCLIMIT ) );
		PyConstant_Insert( d, "LIMITROT", 
				PyInt_FromLong( CONSTRAINT_TYPE_ROTLIMIT ) );
		PyConstant_Insert( d, "LIMITSIZE", 
				PyInt_FromLong( CONSTRAINT_TYPE_SIZELIMIT ) );
		PyConstant_Insert( d, "LIMITDIST",
				PyInt_FromLong( CONSTRAINT_TYPE_DISTLIMIT ) );
		PyConstant_Insert( d, "RIGIDBODYJOINT", 
				PyInt_FromLong( CONSTRAINT_TYPE_RIGIDBODYJOINT ) );
		PyConstant_Insert( d, "CLAMPTO", 
				PyInt_FromLong( CONSTRAINT_TYPE_CLAMPTO ) );
		PyConstant_Insert( d, "PYTHON",
				PyInt_FromLong( CONSTRAINT_TYPE_PYTHON ) );
		PyConstant_Insert( d, "CHILDOF",
				PyInt_FromLong( CONSTRAINT_TYPE_CHILDOF ) );
		PyConstant_Insert( d, "TRANSFORM",
				PyInt_FromLong( CONSTRAINT_TYPE_TRANSFORM ) );
	}
	return S;
}

static PyObject *M_Constraint_SettingsDict( void )
{
	PyObject *S = PyConstant_New(  );
	
	if( S ) {
		BPy_constant *d = ( BPy_constant * ) S;
		PyConstant_Insert( d, "XROT",
				PyInt_FromLong( EXPP_CONSTR_XROT ) );
		PyConstant_Insert( d, "YROT",
				PyInt_FromLong( EXPP_CONSTR_YROT ) );
		PyConstant_Insert( d, "ZROT",
				PyInt_FromLong( EXPP_CONSTR_ZROT ) );
		PyConstant_Insert( d, "XSIZE",
				PyInt_FromLong( EXPP_CONSTR_XSIZE ) );
		PyConstant_Insert( d, "YSIZE",
				PyInt_FromLong( EXPP_CONSTR_YSIZE ) );
		PyConstant_Insert( d, "ZSIZE",
				PyInt_FromLong( EXPP_CONSTR_ZSIZE ) );
		PyConstant_Insert( d, "XLOC",
				PyInt_FromLong( EXPP_CONSTR_XLOC ) );
		PyConstant_Insert( d, "YLOC",
				PyInt_FromLong( EXPP_CONSTR_YLOC ) );
		PyConstant_Insert( d, "ZLOC",
				PyInt_FromLong( EXPP_CONSTR_ZLOC ) );

		PyConstant_Insert( d, "UPX",
				PyInt_FromLong( UP_X ) );
		PyConstant_Insert( d, "UPY",
				PyInt_FromLong( UP_Y ) );
		PyConstant_Insert( d, "UPZ",
				PyInt_FromLong( UP_Z ) );

		PyConstant_Insert( d, "TRACKX",
				PyInt_FromLong( TRACK_X ) );
		PyConstant_Insert( d, "TRACKY",
				PyInt_FromLong( TRACK_Y ) );
		PyConstant_Insert( d, "TRACKZ",
				PyInt_FromLong( TRACK_Z ) );
		PyConstant_Insert( d, "TRACKNEGX",
				PyInt_FromLong( TRACK_nX ) );
		PyConstant_Insert( d, "TRACKNEGY",
				PyInt_FromLong( TRACK_nY ) );
		PyConstant_Insert( d, "TRACKNEGZ",
				PyInt_FromLong( TRACK_nZ ) );

		PyConstant_Insert( d, "VOLUMEXZ",
				PyInt_FromLong( VOLUME_XZ ) );
		PyConstant_Insert( d, "VOLUMEX",
				PyInt_FromLong( VOLUME_X ) );
		PyConstant_Insert( d, "VOLUMEZ",
				PyInt_FromLong( VOLUME_Z ) );
		PyConstant_Insert( d, "VOLUMENONE",
				PyInt_FromLong( NO_VOLUME ) );

		PyConstant_Insert( d, "PLANEX",
				PyInt_FromLong( PLANE_X ) );
		PyConstant_Insert( d, "PLANEY",
				PyInt_FromLong( PLANE_Y ) );
		PyConstant_Insert( d, "PLANEZ",
				PyInt_FromLong( PLANE_Z ) );

		PyConstant_Insert( d, "LOCKX",
				PyInt_FromLong( LOCK_X ) );
		PyConstant_Insert( d, "LOCKY",
				PyInt_FromLong( LOCK_Y ) );
		PyConstant_Insert( d, "LOCKZ",
				PyInt_FromLong( LOCK_Z ) );

		PyConstant_Insert( d, "MAXX",
				PyInt_FromLong( EXPP_CONSTR_MAXX ) );
		PyConstant_Insert( d, "MAXY",
				PyInt_FromLong( EXPP_CONSTR_MAXY ) );
		PyConstant_Insert( d, "MAXZ",
				PyInt_FromLong( EXPP_CONSTR_MAXZ ) );
		PyConstant_Insert( d, "MINX",
				PyInt_FromLong( EXPP_CONSTR_MINX ) );
		PyConstant_Insert( d, "MINY",
				PyInt_FromLong( EXPP_CONSTR_MINY ) );
		PyConstant_Insert( d, "MINZ",
				PyInt_FromLong( EXPP_CONSTR_MINZ ) );

		PyConstant_Insert( d, "COPYX",
				PyInt_FromLong( LOCLIKE_X ) );
		PyConstant_Insert( d, "COPYY",
				PyInt_FromLong( LOCLIKE_Y ) );
		PyConstant_Insert( d, "COPYZ",
				PyInt_FromLong( LOCLIKE_Z ) );
		PyConstant_Insert( d, "COPYXINVERT",
				PyInt_FromLong( LOCLIKE_X_INVERT ) );
		PyConstant_Insert( d, "COPYYINVERT",
				PyInt_FromLong( LOCLIKE_Y_INVERT ) );
		PyConstant_Insert( d, "COPYZINVERT",
				PyInt_FromLong( LOCLIKE_Z_INVERT ) );
				
		PyConstant_Insert( d, "PARLOCX",
				PyInt_FromLong( CHILDOF_LOCX ) );
		PyConstant_Insert( d, "PARLOCY",
				PyInt_FromLong( CHILDOF_LOCY ) );
		PyConstant_Insert( d, "PARLOCZ",
				PyInt_FromLong( CHILDOF_LOCZ ) );
		PyConstant_Insert( d, "PARROTX",
				PyInt_FromLong( CHILDOF_ROTX ) );
		PyConstant_Insert( d, "PARROTY",
				PyInt_FromLong( CHILDOF_ROTY ) );
		PyConstant_Insert( d, "PARROTZ",
				PyInt_FromLong( CHILDOF_ROTZ ) );
		PyConstant_Insert( d, "PARSIZEX",
				PyInt_FromLong( CHILDOF_LOCX ) );
		PyConstant_Insert( d, "PARSIZEY",
				PyInt_FromLong( CHILDOF_SIZEY ) );
		PyConstant_Insert( d, "PARSIZEZ",
				PyInt_FromLong( CHILDOF_SIZEZ ) );
				
		PyConstant_Insert( d, "CLAMPAUTO",
				PyInt_FromLong( CLAMPTO_AUTO ) );
		PyConstant_Insert( d, "CLAMPX",
				PyInt_FromLong( CLAMPTO_X ) );
		PyConstant_Insert( d, "CLAMPY",
				PyInt_FromLong( CLAMPTO_Y ) );
		PyConstant_Insert( d, "CLAMPZ",
				PyInt_FromLong( CLAMPTO_Z ) );
		PyConstant_Insert( d, "CLAMPCYCLIC",
				PyInt_FromLong( EXPP_CONSTR_CLAMPCYCLIC ));

		PyConstant_Insert( d, "TARGET",
				PyInt_FromLong( EXPP_CONSTR_TARGET ) );
		PyConstant_Insert( d, "STRETCH", 
				PyInt_FromLong( EXPP_CONSTR_STRETCH ) );
		PyConstant_Insert( d, "ITERATIONS", 
				PyInt_FromLong( EXPP_CONSTR_ITERATIONS ) );
		PyConstant_Insert( d, "BONE", 
				PyInt_FromLong( EXPP_CONSTR_BONE ) );
		PyConstant_Insert( d, "CHAINLEN", 
				PyInt_FromLong( EXPP_CONSTR_CHAINLEN ) );
		PyConstant_Insert( d, "POSWEIGHT", 
				PyInt_FromLong( EXPP_CONSTR_POSWEIGHT ) );
		PyConstant_Insert( d, "ROTWEIGHT", 
				PyInt_FromLong( EXPP_CONSTR_ROTWEIGHT ) );
		PyConstant_Insert( d, "ROTATE", 
				PyInt_FromLong( EXPP_CONSTR_ROTATE ) );
		PyConstant_Insert( d, "USETIP", 
				PyInt_FromLong( EXPP_CONSTR_USETIP ) );

		PyConstant_Insert( d, "ACTION", 
				PyInt_FromLong( EXPP_CONSTR_ACTION ) );
		PyConstant_Insert( d, "START", 
				PyInt_FromLong( EXPP_CONSTR_START ) );
		PyConstant_Insert( d, "END", 
				PyInt_FromLong( EXPP_CONSTR_END ) );
		PyConstant_Insert( d, "MIN", 
				PyInt_FromLong( EXPP_CONSTR_MIN ) );
		PyConstant_Insert( d, "MAX", 
				PyInt_FromLong( EXPP_CONSTR_MAX ) );
		PyConstant_Insert( d, "KEYON", 
				PyInt_FromLong( EXPP_CONSTR_KEYON ) );

		PyConstant_Insert( d, "TRACK", 
				PyInt_FromLong( EXPP_CONSTR_TRACK ) );
		PyConstant_Insert( d, "UP", 
				PyInt_FromLong( EXPP_CONSTR_UP ) );

		PyConstant_Insert( d, "RESTLENGTH",
				PyInt_FromLong( EXPP_CONSTR_RESTLENGTH ) );
		PyConstant_Insert( d, "VOLVARIATION",
				PyInt_FromLong( EXPP_CONSTR_VOLVARIATION ) );
		PyConstant_Insert( d, "VOLUMEMODE",
				PyInt_FromLong( EXPP_CONSTR_VOLUMEMODE ) );
		PyConstant_Insert( d, "PLANE",
				PyInt_FromLong( EXPP_CONSTR_PLANE ) );

		PyConstant_Insert( d, "FOLLOW",
				PyInt_FromLong( EXPP_CONSTR_FOLLOW ) );
		PyConstant_Insert( d, "OFFSET",
				PyInt_FromLong( EXPP_CONSTR_OFFSET ) );
		PyConstant_Insert( d, "FORWARD",
				PyInt_FromLong( EXPP_CONSTR_FORWARD ) );

		PyConstant_Insert( d, "LOCK",
				PyInt_FromLong( EXPP_CONSTR_LOCK ) );
				
		PyConstant_Insert( d, "LIMITMODE",
				PyInt_FromLong( EXPP_CONSTR_MODE ) );
		PyConstant_Insert( d, "LIMIT_INSIDE",
				PyInt_FromLong( LIMITDIST_INSIDE ) );
		PyConstant_Insert( d, "LIMIT_OUTSIDE",
				PyInt_FromLong( LIMITDIST_OUTSIDE ) );
		PyConstant_Insert( d, "LIMIT_ONSURFACE",
				PyInt_FromLong( LIMITDIST_ONSURFACE ) );

		PyConstant_Insert( d, "COPY",
				PyInt_FromLong( EXPP_CONSTR_COPY ) );
		PyConstant_Insert( d, "LIMIT",
				PyInt_FromLong( EXPP_CONSTR_LIMIT ) );
		PyConstant_Insert( d, "CLAMP",
				PyInt_FromLong( EXPP_CONSTR_CLAMP ) );
		
		PyConstant_Insert( d, "LIMIT_XMIN",
				PyInt_FromLong( EXPP_CONSTR_LIMXMIN ) );
		PyConstant_Insert( d, "LIMIT_XMAX",
				PyInt_FromLong( EXPP_CONSTR_LIMXMAX ) );
		PyConstant_Insert( d, "LIMIT_YMIN",
				PyInt_FromLong( EXPP_CONSTR_LIMYMIN ) );
		PyConstant_Insert( d, "LIMIT_YMAX",
				PyInt_FromLong( EXPP_CONSTR_LIMYMAX ) );
		PyConstant_Insert( d, "LIMIT_ZMIN",
				PyInt_FromLong( EXPP_CONSTR_LIMZMIN ) );
		PyConstant_Insert( d, "LIMIT_ZMAX",
				PyInt_FromLong( EXPP_CONSTR_LIMZMAX ) );
		
		PyConstant_Insert( d, "LIMIT_XROT",
				PyInt_FromLong( EXPP_CONSTR_LIMXROT ) );
		PyConstant_Insert( d, "LIMIT_YROT",
				PyInt_FromLong( EXPP_CONSTR_LIMYROT ) );
		PyConstant_Insert( d, "LIMIT_ZROT",
				PyInt_FromLong( EXPP_CONSTR_LIMZROT ) );
		
		PyConstant_Insert( d, "XMIN",
				PyInt_FromLong( EXPP_CONSTR_XMIN ) );
		PyConstant_Insert( d, "XMAX",
				PyInt_FromLong( EXPP_CONSTR_XMAX ) );
		PyConstant_Insert( d, "YMIN",
				PyInt_FromLong( EXPP_CONSTR_YMIN ) );
		PyConstant_Insert( d, "YMAX",
				PyInt_FromLong( EXPP_CONSTR_YMAX ) );
		PyConstant_Insert( d, "ZMIN",
				PyInt_FromLong( EXPP_CONSTR_ZMIN ) );
		PyConstant_Insert( d, "ZMAX",
				PyInt_FromLong( EXPP_CONSTR_ZMAX ) );
				
		PyConstant_Insert( d, "SCRIPT",
				PyInt_FromLong( EXPP_CONSTR_SCRIPT ) );
		PyConstant_Insert( d, "PROPERTIES",
				PyInt_FromLong( EXPP_CONSTR_PROPS ) );
				
		PyConstant_Insert( d, "FROM",
				PyInt_FromLong( EXPP_CONSTR_FROM ) );
		PyConstant_Insert( d, "TO",
				PyInt_FromLong( EXPP_CONSTR_TO ) );
		PyConstant_Insert( d, "EXTRAPOLATE",
				PyInt_FromLong( EXPP_CONSTR_EXPO ) );
		PyConstant_Insert( d, "MAPX",
				PyInt_FromLong( EXPP_CONSTR_MAPX ) );
		PyConstant_Insert( d, "MAPY",
				PyInt_FromLong( EXPP_CONSTR_MAPY ) );
		PyConstant_Insert( d, "MAPZ",
				PyInt_FromLong( EXPP_CONSTR_MAPZ ) );
		PyConstant_Insert( d, "FROM_MINX",
				PyInt_FromLong( EXPP_CONSTR_FROMMINX ) );
		PyConstant_Insert( d, "FROM_MAXX",
				PyInt_FromLong( EXPP_CONSTR_FROMMAXX ) );
		PyConstant_Insert( d, "FROM_MINY",
				PyInt_FromLong( EXPP_CONSTR_FROMMINY ) );
		PyConstant_Insert( d, "FROM_MAXY",
				PyInt_FromLong( EXPP_CONSTR_FROMMAXY ) );
		PyConstant_Insert( d, "FROM_MINZ",
				PyInt_FromLong( EXPP_CONSTR_FROMMINZ ) );
		PyConstant_Insert( d, "FROM_MAXZ",
				PyInt_FromLong( EXPP_CONSTR_FROMMAXZ ) );
		PyConstant_Insert( d, "TO_MINX",
				PyInt_FromLong( EXPP_CONSTR_TOMINX ) );
		PyConstant_Insert( d, "TO_MAXX",
				PyInt_FromLong( EXPP_CONSTR_TOMAXX ) );
		PyConstant_Insert( d, "TO_MINY",
				PyInt_FromLong( EXPP_CONSTR_TOMINY ) );
		PyConstant_Insert( d, "TO_MAXY",
				PyInt_FromLong( EXPP_CONSTR_TOMAXY ) );
		PyConstant_Insert( d, "TO_MINZ",
				PyInt_FromLong( EXPP_CONSTR_TOMINZ ) );
		PyConstant_Insert( d, "TO_MAXZ",
				PyInt_FromLong( EXPP_CONSTR_TOMAXZ ) );
				
		PyConstant_Insert( d, "LOC",
				PyInt_FromLong( 0 ) );
		PyConstant_Insert( d, "ROT",
				PyInt_FromLong( 1 ) );
		PyConstant_Insert( d, "SCALE",
				PyInt_FromLong( 2 ) );
				
		PyConstant_Insert( d, "CONSTR_RB_TYPE",
				PyInt_FromLong( EXPP_CONSTR_RB_TYPE ) );
		PyConstant_Insert( d, "CONSTR_RB_BALL",
				PyInt_FromLong( EXPP_CONSTR_RB_BALL ) );
		PyConstant_Insert( d, "CONSTR_RB_HINGE",
				PyInt_FromLong( EXPP_CONSTR_RB_HINGE ) );
		PyConstant_Insert( d, "CONSTR_RB_GENERIC6DOF",
				PyInt_FromLong( EXPP_CONSTR_RB_GENERIC6DOF ) );
		PyConstant_Insert( d, "CONSTR_RB_VEHICLE",
				PyInt_FromLong( EXPP_CONSTR_RB_VEHICLE ) );
		PyConstant_Insert( d, "CONSTR_RB_PIVX",
				PyInt_FromLong( EXPP_CONSTR_RB_PIVX ) );
		PyConstant_Insert( d, "CONSTR_RB_PIVY",
				PyInt_FromLong( EXPP_CONSTR_RB_PIVY ) );
		PyConstant_Insert( d, "CONSTR_RB_PIVZ",
				PyInt_FromLong( EXPP_CONSTR_RB_PIVZ ) );
		PyConstant_Insert( d, "CONSTR_RB_AXX",
				PyInt_FromLong( EXPP_CONSTR_RB_AXX ) );
		PyConstant_Insert( d, "CONSTR_RB_AXY",
				PyInt_FromLong( EXPP_CONSTR_RB_AXY ) );
		PyConstant_Insert( d, "CONSTR_RB_AXZ",
				PyInt_FromLong( EXPP_CONSTR_RB_AXZ ) );
		PyConstant_Insert( d, "CONSTR_RB_MINLIMIT0",
				PyInt_FromLong( EXPP_CONSTR_RB_MINLIMIT0 ) );
		PyConstant_Insert( d, "CONSTR_RB_MINLIMIT1",
				PyInt_FromLong( EXPP_CONSTR_RB_MINLIMIT1 ) );
		PyConstant_Insert( d, "CONSTR_RB_MINLIMIT2",
				PyInt_FromLong( EXPP_CONSTR_RB_MINLIMIT2 ) );
		PyConstant_Insert( d, "CONSTR_RB_MINLIMIT3",
				PyInt_FromLong( EXPP_CONSTR_RB_MINLIMIT3 ) );
		PyConstant_Insert( d, "CONSTR_RB_MINLIMIT4",
				PyInt_FromLong( EXPP_CONSTR_RB_MINLIMIT4 ) );
		PyConstant_Insert( d, "CONSTR_RB_MINLIMIT5",
				PyInt_FromLong( EXPP_CONSTR_RB_MINLIMIT5 ) );
		PyConstant_Insert( d, "CONSTR_RB_MAXLIMIT0",
				PyInt_FromLong( EXPP_CONSTR_RB_MAXLIMIT0 ) );
		PyConstant_Insert( d, "CONSTR_RB_MAXLIMIT1",
				PyInt_FromLong( EXPP_CONSTR_RB_MAXLIMIT1 ) );
		PyConstant_Insert( d, "CONSTR_RB_MAXLIMIT2",
				PyInt_FromLong( EXPP_CONSTR_RB_MAXLIMIT2 ) );
		PyConstant_Insert( d, "CONSTR_RB_MAXLIMIT3",
				PyInt_FromLong( EXPP_CONSTR_RB_MAXLIMIT3 ) );
		PyConstant_Insert( d, "CONSTR_RB_MAXLIMIT4",
				PyInt_FromLong( EXPP_CONSTR_RB_MAXLIMIT4 ) );
		PyConstant_Insert( d, "CONSTR_RB_MAXLIMIT5",
				PyInt_FromLong( EXPP_CONSTR_RB_MAXLIMIT5 ) );				
		PyConstant_Insert( d, "CONSTR_RB_EXTRAFZ",
				PyInt_FromLong( EXPP_CONSTR_RB_EXTRAFZ ) );
		PyConstant_Insert( d, "CONSTR_RB_FLAG",
				PyInt_FromLong( EXPP_CONSTR_RB_FLAG ) );
				
				
		PyConstant_Insert( d, "OWNERSPACE",
				PyInt_FromLong( EXPP_CONSTR_OWNSPACE ) );
		PyConstant_Insert( d, "TARGETSPACE",
				PyInt_FromLong( EXPP_CONSTR_TARSPACE ) );
				
		PyConstant_Insert( d, "SPACE_WORLD",
				PyInt_FromLong( CONSTRAINT_SPACE_WORLD) );
		PyConstant_Insert( d, "SPACE_LOCAL",
				PyInt_FromLong( CONSTRAINT_SPACE_LOCAL ) );
		PyConstant_Insert( d, "SPACE_POSE",
				PyInt_FromLong( CONSTRAINT_SPACE_POSE) );
		PyConstant_Insert( d, "SPACE_PARLOCAL",
				PyInt_FromLong( CONSTRAINT_SPACE_PARLOCAL ) );
	}
	return S;
}

/*****************************************************************************/
/* Function:              Constraint_Init                                    */
/*****************************************************************************/
PyObject *Constraint_Init( void )
{
	PyObject *submodule;
	PyObject *TypeDict = M_Constraint_TypeDict( );
	PyObject *SettingsDict = M_Constraint_SettingsDict( );

	if( PyType_Ready( &ConstraintSeq_Type ) < 0
			|| PyType_Ready( &Constraint_Type ) < 0 )
		return NULL;

	submodule = Py_InitModule3( "Blender.Constraint", NULL,
			"Constraint module for accessing and creating constraint data" );

	if( TypeDict )
		PyModule_AddObject( submodule, "Type", TypeDict );
	
	if( SettingsDict )
		PyModule_AddObject( submodule, "Settings", SettingsDict );
	
	return submodule;
}
