#include <stdio.h>
#include "Python.h"
#include "structmember.h"

class BasicObject: public PyObject
{
public:
     BasicObject(int defaultValue=0);
     ~BasicObject();

     /* python specific interfaces */
     static void dealloc(PyObject *obj);
     static PyObject *getattr(PyObject *obj, char *name);
     static int setattr(PyObject *obj, char *name, PyObject *value);

     static PyObject *stringvalue(PyObject *obj, PyObject *args);
     static struct memberlist memberlist[];
     static PyMethodDef methodlist[];
     
     int value;
}; 


BasicObject::~BasicObject()
{
     /* nothing to do here */
}

void
BasicObject::dealloc(PyObject *obj)
{
     delete (BasicObject *) obj;
}

#define     OFF(x)     offsetof(BasicObject, x)

struct memberlist BasicObject::memberlist[] = {
     {"value", T_INT, OFF(value)},
     {NULL}
};

PyObject *
BasicObject::stringvalue(PyObject *obj, PyObject *args)
{
     BasicObject *self = (BasicObject *) obj;
     char text[128];

     if(!PyArg_ParseTuple(args,":stringvalue"))
          return NULL;

     sprintf(text,"value is: %d",self->value);
     return PyString_FromString(text);     
}

PyMethodDef BasicObject::methodlist[] = {
     {"stringvalue",(PyCFunction) BasicObject::stringvalue, METH_VARARGS},
     { NULL, NULL}
};


PyObject *
BasicObject::getattr(PyObject *obj, char *attr)
{
     PyObject *res;
     BasicObject *self = (BasicObject *) obj;

     res = Py_FindMethod(methodlist, (PyObject *) self,attr);
     if(NULL != res)
          return res;
     else {
          PyErr_Clear();
          return PyMember_Get((char *) self, memberlist, attr);
     }
}

int
BasicObject::setattr(PyObject *obj, char *attr, PyObject *value)
{
     BasicObject *self = (BasicObject *) obj;
     if(value == NULL) {
          PyErr_SetString(PyExc_AttributeError,"can't delete attributes");
          return -1;
     }
     return PyMember_Set((char *) self, memberlist, attr, value);
}

PyTypeObject BasicObject_Type = {
     PyObject_HEAD_INIT(&PyType_Type)  /* required header */
     0,                    /* variable object size */
     "basic_object",               /* name of object type */
     sizeof(BasicObject),          /* size of per-instance memory */
     0,                    /* size of per-item element */
     (destructor) BasicObject::dealloc,/* tp_dealloc */
     0,                    /* tp_print aka str */
     (getattrfunc) BasicObject::getattr,/* tp_getattr */
     (setattrfunc) BasicObject::setattr,/* tp_setattr */
};
     
BasicObject::BasicObject(int defaultValue=0)
{

     ob_type = &BasicObject_Type;
     _Py_NewReference(this);

     value = defaultValue;
}


PyObject *
NewBasicObject(PyObject *self, PyObject *args)
     /* return a new instance of basicobject */
{
        int defaultValue = 0;

        if(!PyArg_ParseTuple(args,"|i:BasicObject",&defaultValue))
                return NULL;

        return new BasicObject(defaultValue);
}


static PyMethodDef cplus_functions[] = {
     { "BasicObject", NewBasicObject, METH_VARARGS},
     { NULL, NULL }
};


extern "C"
void
initcplus()
{
     Py_InitModule("cplus",cplus_functions);
}
