/*****************************************************************************
 * $Id: mod_pony_python_ifc.cc,v 1.2 2006/11/25 21:29:23 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	Module Pony and World interfaces from C++ to Python.
 * @remarks Python extension functions have the form:
 *          PyExt(PyObject* self, PyObject* args)
 *          I write PyExt(nil,args) because in fact self will be NULL
 *          (except for the esoteric "Python extension types").
 *          A few of my extensions need self which my Python code passes as
 *          the first arg which appears on the C++ side as the first element
 *          in the tuple passed as "args" to PyExt(self,args).
 *//*
 * LEGAL:	COPYRIGHT (C) 2005 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 *****************************************************************************/

#ifndef NO_PYTHON

#include <Python.h>
#define MOD_PONY_PYTHON_IFC_CC 1
#include "mod_pony_common.hh"
#include "mod_base_craft.hh"
#include "mod_base_combat.hh"
#include "mod_pony_view.hh"
#include "mod_pony_craft.hh"
#include "mod_pony_python_ifc.hh"

//==============================================================================
// Some PYTHON* macros are multi-line macros, enclose them in braces!
//==============================================================================

////////////////////////////////////////////////////////////////////////////////
//////////////////////  Python interface (Module)  /////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/*****************************************************************************
 * @return String of the file directory containing Palomino Python modules.
 * args[0] = none
 *****************************************************************************/
static PyObject*
PonyPy_GetPythonDir( PyObject* nil )
{
	return PYTHON_STRING( gModule.GetPythonDir() );
}

/*****************************************************************************
 * @return String of the file directory containing Palomino 3D models.
 * args[0] = none
 *****************************************************************************/
static PyObject*
PonyPy_GetModelDir( PyObject* nil )
{
	return PYTHON_STRING( gModule.GetModelDir() );
}

/*****************************************************************************
 * @return Pointer to player's C++ Craft object.
 * args[0] = player number (1 or 2)
 *****************************************************************************/
static PyObject*
PonyPy_GetPlayer( PyObject* nil, PyObject* args )
{
	int playerNum;
    if ( PyArg_ParseTuple( args, "i", &playerNum ) )
	{
		if ( playerNum == 1 )
		{
			return PYTHON_PYOBJECT_FROM_CPTR( GET_PTR(gModule.mPlayer1Craft) );
		}
		else if ( playerNum == 2 )
		{
			return PYTHON_PYOBJECT_FROM_CPTR( GET_PTR(gModule.mPlayer2Craft) );
		}
		// Error, wrong player num, fall thru.
	}
	PYTHON_RETURN_BAD_OBJECT_ERROR
}

/*****************************************************************************
 * @return Append Craft to list.
 * args[0]     = (Craft*) craft
 *****************************************************************************/
static PyObject*
PonyPy_CraftListAppend( PyObject* nil, PyObject* args )
{
	CptrArg		cptrCraft;
	if ( PyArg_ParseTuple( args, PYTHON_CPTR_FORMAT, &cptrCraft ) )
	{
		Craft_FROM_CPTR_OR_ERROR( craft, cptrCraft );
		gModule.mCraftDlist.Append( craft );
		PYTHON_RETURN_NONE
	}
Error: PYTHON_RETURN_BAD_OBJECT_ERROR
}

/*****************************************************************************
 * @return Pointer to a new DynaModelTarget.
 * args[0]     = (Quadrant*) quadrant
 * args[1,2,3] = (float)     x,y,z
 * args[4]     = (char*)     Palomino model name
 *****************************************************************************/
static PyObject*
PonyPy_DynaModelTargetNew( PyObject* nil, PyObject* args )
{
	CptrArg		cptrQuadrant;
	float		x, y, z;
	char*		modelName;
	if ( PyArg_ParseTuple( args, PYTHON_CPTR_FORMAT "fffs", &cptrQuadrant, &x, &y, &z, &modelName ) )
	{
		Quadrant_FROM_CPTR_OR_ERROR( quadrant, cptrQuadrant );
		Position pos( x, y, z );
        vector<string> modelNameVec; modelNameVec.push_back( modelName );
		return PYTHON_PYOBJECT_FROM_CPTR( new DynaModelTarget( quadrant, pos, modelNameVec ) );
	}
Error: PYTHON_RETURN_BAD_OBJECT_ERROR
}

/*****************************************************************************
 * @return Pointer to a new CraftF14Tomcat.
 * args[0]     = (Quadrant*) quadrant
 * args[1,2,3] = (float)     x,y,z
 *****************************************************************************/
static PyObject*
PonyPy_CraftF14TomcatNew( PyObject* nil, PyObject* args )
{
	CptrArg		cptrQuadrant;
	float		x, y, z;
	if ( PyArg_ParseTuple( args, PYTHON_CPTR_FORMAT "fff", &cptrQuadrant, &x, &y, &z ) )
	{
		Quadrant_FROM_CPTR_OR_ERROR( quadrant, cptrQuadrant );
		Position pos( x, y, z );
		extern vector<string> gModelNameF14Vec;
		return PYTHON_PYOBJECT_FROM_CPTR( new CraftF14Tomcat( quadrant, pos, gModelNameF14Vec ) );
	}
Error: PYTHON_RETURN_BAD_OBJECT_ERROR
}

//------------------------------------------------------------------------------

// Table of C functions that will be imported as Python functions in a Python module.

// ModuleBase/ModulePony class interface:
static PyMethodDef sMethodsModule[] =
{
	// Func name in Python:		// Func name in C:
    { "GetPythonDir",		(PyCFunction)PonyPy_GetPythonDir,		METH_NOARGS,  "" },
    { "GetModelDir",		(PyCFunction)PonyPy_GetModelDir,		METH_NOARGS,  "" },
    { "GetPlayer",			(PyCFunction)PonyPy_GetPlayer,			METH_VARARGS, "" },
    { "CraftListAppend",	(PyCFunction)PonyPy_CraftListAppend,	METH_VARARGS, "" },
    { "DynaModelTargetNew", (PyCFunction)PonyPy_DynaModelTargetNew,	METH_VARARGS, "" },
    { "CraftF14TomcatNew",	(PyCFunction)PonyPy_CraftF14TomcatNew,	METH_VARARGS, "" },
	{ NULL,					NULL,									0,			  NULL }
};

/*****************************************************************************
 * Create a Python module.
 *****************************************************************************/
bool
PythonModule( void )
{
#define PYMOD1	"cmodule"   // Python module name
#define PYMOD2	"cmodule2"  // this module will hold constants originating from C++

	// Let cmodule combine Module Base and Module Pony.
	if ( gPython.NewModule( PYMOD1, sMethodsModule ) == NULL )
	{
		PRINT_PYTHON_ERROR( "failed to create " PYMOD1 " Python module" );
		return false;
	}

	// Here's why Python variables magically appear in the Python code...
	// Create another Python module, then add definitions to it
	// whose values originate from this C++ source code.
	PyObject* module2 = gPython.NewModule( PYMOD2 );
	if ( module2 == NULL )
	{
		PRINT_PYTHON_ERROR( "failed to create " PYMOD2 " Python module" );
		return false;
	}
	// PyModule*() return 0 if ok
	int definingErrors = \
	  PyModule_AddIntConstant( module2, "eAnimation_NONE",           eAnimation_NONE )
	| PyModule_AddIntConstant( module2, "eAnimation_AUTO_TRANSLATE", eAnimation_AUTO_TRANSLATE )
	| PyModule_AddIntConstant( module2, "eAnimation_PILOT_PURSUE",   eAnimation_PILOT_PURSUE );
	if ( definingErrors )
	{
		PRINT_PYTHON_ERROR( "failed to define objects in " PYMOD2 " Python module" );
		return false;
	}

	// Ok.
	return true;
}

#endif // NO_PYTHON
