#include <eter/__py_tinker_func.h>

namespace py_tinker {

extern PyTypeObject PyCppFunc_Type;

struct PyCppFunc_SObject
{
	PyObject_HEAD
	IFunction* fn_cpp_functor;

	PyObject* operator() (PyObject* self, PyObject* args)
	{PYTINKER_CALL(return (*fn_cpp_functor)(self, args))}

};

void PyCppFunc_Destruct(PyCppFunc_SObject* func)
{
	if (func->fn_cpp_functor)
	{
		delete func->fn_cpp_functor;
		func->fn_cpp_functor = NULL;
	}
}

PyObject* PyCppFunc_FromFunction(IFunction* cpp_functor)
{
	PyCppFunc_SObject* func = (PyCppFunc_SObject*)PyType_GenericAlloc(&PyCppFunc_Type, 0);
	func->fn_cpp_functor = cpp_functor;
	return (PyObject*)func;	
}

extern "C"
{

static PyObject *
PyCppFunc_Call(PyObject* self, PyObject* args, PyObject* kw)
{
	PYTINKER_CALL(return (*((PyCppFunc_SObject*)self))(self, args))
}

static PyObject *
PyCppFunc_Repr(PyCppFunc_SObject* func)
{
	char repr[256];
	snprintf(repr, sizeof(repr)-1, "<%s %s at 0x%p>", func->ob_type->tp_name, func->fn_cpp_functor->GetName().c_str(), func);
	return PyString_FromString(repr);
}

static void
PyCppFunc_Dealloc(PyCppFunc_SObject* func)
{
	PyCppFunc_Destruct(func);
	
	func->ob_type->tp_free(func);	
}

static PyObject *
PyCppFunc_DescrGet(PyObject* self, PyObject* obj, PyObject* type)
{
	Py_INCREF(self);
	return self;
}

static PyObject* 
PyCppFunc_GetDoc(PyObject* self, void*)
{
    return Py_BuildValue("s", "none");	
}

static int 
PyCppFunc_SetDoc(PyObject* self, PyObject* doc, void*)
{
    return 0;
}

static PyObject* 
PyCppFunc_GetName(PyObject* self, void*)
{
	return Py_BuildValue("s", "none");	
}

static PyGetSetDef PyCppFunc_getsetlist[] = {
    {"__name__",	(getter)PyCppFunc_GetName, 0 },
    {"func_name",	(getter)PyCppFunc_GetName, 0 },
    {"__doc__",		(getter)PyCppFunc_GetDoc, (setter)PyCppFunc_SetDoc},
    {"func_doc",	(getter)PyCppFunc_GetDoc, (setter)PyCppFunc_SetDoc},
    {NULL}
};

PyTypeObject PyCppFunc_Type = {
    PyObject_HEAD_INIT(&PyType_Type)
    0,
    "py_tinker.cpp.function",
    sizeof(PyCppFunc_Type),
    0,
    (destructor)PyCppFunc_Dealloc,       /* tp_dealloc */
    0,                                  /* tp_print */
    0,                                  /* tp_getattr */
    0,                                  /* tp_setattr */
    0,                                  /* tp_compare */
    (reprfunc)PyCppFunc_Repr,      /* tp_repr */
    0,                                  /* tp_as_number */
    0,                                  /* tp_as_sequence */
    0,                                  /* tp_as_mapping */
    0,                                  /* tp_hash */
    PyCppFunc_Call,                              /* tp_call */
    0,                                  /* tp_str */
    0, // PyObject_GenericGetAttr,            /* tp_getattro */
    0, // PyObject_GenericSetAttr,            /* tp_setattro */
    0,                                  /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT /* | Py_TPFLAGS_HAVE_GC */,/* tp_flags */
    0,                                  /* tp_doc */
    0, // (traverseproc)func_traverse,          /* tp_traverse */
    0,                                  /* tp_clear */
    0,                                  /* tp_richcompare */
    0, //offsetof(PyFunctionObject, func_weakreflist), /* tp_weaklistoffset */
    0,                                  /* tp_iter */
    0,                                  /* tp_iternext */
    0,                                  /* tp_methods */
    0, // func_memberlist,              /* tp_members */
    PyCppFunc_getsetlist,                /* tp_getset */
    0,                                  /* tp_base */
    0,                                  /* tp_dict */
    PyCppFunc_DescrGet,                 /* tp_descr_get */
    0,                                  /* tp_descr_set */
    0, //offsetof(PyFunctionObject, func_dict),      /* tp_dictoffset */
    0,                                      /* tp_init */
    0,									/* tp_alloc */
    0,										/* tp_new */
    PyObject_Del,									/* tp_free */                                       
};


} // end of extern "C"


} // py_tinker