#ifndef OBJECT_MODEL_H
#define OBJECT_MODEL_H

// K-3D
// Copyright (c) 1995-2004, Timothy M. Shead
//
// Contact: tshead@k-3d.com
//
// 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

/** \file
		\brief Declares classes for implementing a scripting object model in Python
		\author Anders Dahnielson (anders@dahnielson.com)
		\author Romain Behar (romainbehar@yahoo.com)
*/

#include "python.h"

#include <k3dsdk/mesh.h>
#include <k3dsdk/result.h>

// Forward declarations ...
namespace k3d { template<typename> class ibezier_channel; }
namespace k3d { class icommand_node; }
namespace k3d { class idocument; }
namespace k3d { class iobject; }
namespace k3d { class iobject_collection; }
namespace k3d { class iproperty; }
namespace k3d { class iplugin_factory; }
namespace k3d { class irender_frame; }
namespace k3d { class irender_job; }
namespace k3d { class iuser_interface; }

/////////////////////////////////////////////////////////////////////////////
// Python skeleton

// template for implementing a scripting object model in Python
template<class InterfaceType, class BaseType>
class PythonSkeleton
{
public:
	typedef PythonSkeleton<InterfaceType, BaseType> Skeleton;
	typedef BaseType Owner;

	static PyMethodDef Methods[];

	static PyObject* Create(InterfaceType* const Interface)
	{
		// Sanity checks ...
		assert_warning(Interface);

		// Wrap the 'Interface' into a PyCObject
		return PyCObject_FromVoidPtr(Interface, NULL);
	}

	static InterfaceType* Interface(PyObject *object)
	{
		// Unwrap the 'Interface' from the PyCObject
		if (PyCObject_Check(object))
			return reinterpret_cast<InterfaceType*>(PyCObject_AsVoidPtr(object));
		else
			return 0;
	}

	template<class NewInterfaceType, class NewActualType>
	static PyObject* DynamicCast(PyObject* const Object)
	{
		NewInterfaceType* const i = dynamic_cast<NewInterfaceType*>(Interface(Object));
		return_val_if_fail(i, PYVAL_FALSE);

		return NewActualType::Create(i);
	}
};

/////////////////////////////////////////////////////////////////////////////
// CPythonObject

class CPythonObject :
	public PythonSkeleton<k3d::iobject, CPythonObject>
{
public:
	static PyObject* GetDocument(PyObject *self, PyObject *args);
	static PyObject* GetFactory(PyObject *self, PyObject *args);
	static PyObject* get_name(PyObject *self, PyObject *args);
	static PyObject* set_name(PyObject *self, PyObject *args);
	static PyObject* get_mesh(PyObject *self, PyObject *args);
	static PyObject* EditObject(PyObject *self, PyObject *args);
};

/////////////////////////////////////////////////////////////////////////////
// CPythonBezierChannel

class CPythonBezierChannel :
	public PythonSkeleton<k3d::ibezier_channel<void>, CPythonBezierChannel>
{
public:
	static PyObject* GetCurve(PyObject *self, PyObject *args);
	static PyObject* SetCurve(PyObject *self, PyObject *args);
};

/////////////////////////////////////////////////////////////////////////////
// CPythonDocument

class CPythonDocument :
	public PythonSkeleton<k3d::idocument, CPythonDocument>
{
public:
	static PyObject* GetApplication(PyObject *self, PyObject *args);
	static PyObject* GetPath(PyObject *self, PyObject *args);
	static PyObject* Import(PyObject *self, PyObject *args);
	static PyObject* Export(PyObject *self, PyObject *args);
	static PyObject* Save(PyObject *self, PyObject *args);
	static PyObject* StartStateChangeSet(PyObject *self, PyObject *args);
	static PyObject* FinishStateChangeSet(PyObject *self, PyObject *args);
	static PyObject* RedrawAll(PyObject *self, PyObject *args);

	// ObjectCollection
	static PyObject* CreateObject(PyObject *self, PyObject *args);
	static PyObject* Objects(PyObject *self, PyObject *args);
	static PyObject* GetObject(PyObject *self, PyObject *args);
	static PyObject* DeleteObject(PyObject *self, PyObject *args);
	static PyObject* get_frozen_meshes(PyObject *self, PyObject *args);
	static PyObject* get_mesh_instances(PyObject *self, PyObject *args);
	static PyObject* get_objects_by_name(PyObject *self, PyObject *args);
};

/////////////////////////////////////////////////////////////////////////////
// CPythonProperty

class CPythonProperty :
	public PythonSkeleton<k3d::iproperty, CPythonProperty>
{
public:
	static PyObject* GetName(PyObject *self, PyObject *args);
	static PyObject* GetDescription(PyObject *self, PyObject *args);
	static PyObject* GetReadOnly(PyObject *self, PyObject *args);
};

/////////////////////////////////////////////////////////////////////////////
// CPythonCommandNode

class CPythonCommandNode :
	public PythonSkeleton<k3d::icommand_node, CPythonCommandNode>
{
public:
	static PyObject* Command(PyObject *self, PyObject *args);
	static PyObject* GetChild(PyObject *self, PyObject *args);
	static PyObject* GetProperty(PyObject *self, PyObject *args);
	static PyObject* SetProperty(PyObject *self, PyObject *args);
	static PyObject* GetChildren(PyObject *self, PyObject *args);
	static PyObject* GetProperties(PyObject *self, PyObject *args);
};

/////////////////////////////////////////////////////////////////////////////
// CPythonUserInterface

class CPythonUserInterface :
	public PythonSkeleton<k3d::iuser_interface, CPythonUserInterface>
{
public:
	static PyObject* BrowserNavigate(PyObject *self, PyObject *args);
	static PyObject* Message(PyObject *self, PyObject *args);
	static PyObject* ErrorMessage(PyObject *self, PyObject *args);
	static PyObject* QueryMessage(PyObject *self, PyObject *args);
	static PyObject* GetFilePath(PyObject *self, PyObject *args);
};

/////////////////////////////////////////////////////////////////////////////
// CPythonScriptEngines

class CPythonScriptEngines
{
public:
	static PyMethodDef Methods[];

	static PyObject* Create();
	static PyObject* PlayFile(PyObject *self, PyObject *args);
};

/////////////////////////////////////////////////////////////////////////////
// CPythonPluginFactory

class CPythonPluginFactory :
	public PythonSkeleton<k3d::iplugin_factory, CPythonPluginFactory>
{
public:
	static PyMethodDef Methods[];

	static PyObject* GetAttribute(PyObject *self, PyObject *args);
};

/////////////////////////////////////////////////////////////////////////////
// CPythonApplication

class CPythonApplication
{
public:
	static PyMethodDef Methods[];

	static PyObject* GetAttribute(PyObject *self, PyObject *args);
	static PyObject* Close(PyObject *self, PyObject *args);
	static PyObject* NewDocument(PyObject *self, PyObject *args);
	static PyObject* OpenDocument(PyObject *self, PyObject *args);
	static PyObject* CloseDocument(PyObject *self, PyObject *args);
	static PyObject* CommandNode(PyObject *self, PyObject *args);
	static PyObject* Plugins(PyObject *self, PyObject *args);
};

/////////////////////////////////////////////////////////////////////////////
// python_mesh

class python_mesh :
	public PythonSkeleton<k3d::mesh, python_mesh>
{
public:
	static PyMethodDef methods[];

	static PyObject* create_mesh(PyObject* self, PyObject* args);
	static PyObject* create_mesh_object(PyObject* self, PyObject* args);
	static PyObject* create_mesh_instance(PyObject* self, PyObject* args);
	static PyObject* create_point(PyObject* self, PyObject* args);
	static PyObject* get_points(PyObject* self, PyObject* args);
	static PyObject* create_polyhedron(PyObject* self, PyObject* args);
	static PyObject* get_polyhedra(PyObject* self, PyObject* args);
	static PyObject* add_blobby(PyObject* self, PyObject* args);
};

class python_point :
	public PythonSkeleton<k3d::point, python_point>
{
public:
	static PyMethodDef methods[];

	static PyObject* get_position(PyObject* self, PyObject* args);
	static PyObject* set_position(PyObject* self, PyObject* args);
	static PyObject* get_reference(PyObject* self, PyObject* args);
};

class python_polyhedron :
	public PythonSkeleton<k3d::polyhedron, python_polyhedron>
{
public:
	static PyMethodDef methods[];

	static PyObject* create_face(PyObject* self, PyObject* args);
	static PyObject* add_point_to_face(PyObject* self, PyObject* args);
	static PyObject* get_faces(PyObject* self, PyObject* args);
};

class python_face :
	public PythonSkeleton<k3d::face, python_face>
{
public:
	static PyMethodDef methods[];

	static PyObject* get_edge_points(PyObject* self, PyObject* args);
};

class python_blobby_opcode :
	public PythonSkeleton<k3d::blobby::opcode, python_blobby_opcode>
{
public:
	static PyMethodDef methods[];

	static PyObject* create_ellipsoid(PyObject* self, PyObject* args);
	static PyObject* create_segment(PyObject* self, PyObject* args);
	static PyObject* set_color(PyObject* self, PyObject* args);
	static PyObject* add_operation(PyObject* self, PyObject* args);
	static PyObject* mult_operation(PyObject* self, PyObject* args);
	static PyObject* max_operation(PyObject* self, PyObject* args);
	static PyObject* min_operation(PyObject* self, PyObject* args);
	static PyObject* sub_operation(PyObject* self, PyObject* args);
	static PyObject* div_operation(PyObject* self, PyObject* args);
};

#endif // !OBJECT_MODEL_H


