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

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



typedef struct {
        PyObject_HEAD   /* wymagany naglowek */
        int value;
} BasicObject;


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

static PyObject *
bobject_getattr(BasicObject *self, char *attr)
{
        PyObject *res;

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



static PyObject * PrintString(PyObject *self, PyObject *args)
{
        PyObject *o;

        if(!PyArg_ParseTuple(args,"O:PrintString",&o))
                return NULL;

        if(PyString_Check(o))
                printf("print string: %s\n",PyString_AS_STRING(o));
        else if(PyInt_Check(o))
                printf("print int: %d\n",PyInt_AS_LONG(o));
        else {
                PyErr_SetString(PyExc_TypeError,
                     "invalid type passed to PrintString");
                return NULL;
        }

        Py_INCREF(Py_None);
        return Py_None;
}

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

void initcapi() {
        Py_InitModule("capi",capi_functions);
}

static void bobject_dealloc(BasicObject *self) {
        if(self)
                free(self);
}

PyTypeObject BasicObject_Type = {
        PyObject_HEAD_INIT(&PyType_Type)  /* wymagany naglowek */
        0,                              /* zmienny rozmiar obiektu */
        "basic_object",                 /* nazwa typu obiektu */
        sizeof(BasicObject),            /* rozmiar pamieci dla kazdej kopii */
        0,                              /* rozmiar indywidualnego elementu */
        (destructor) bobject_dealloc,    /* tp_dealloc */
        0,                              /* tp_print, aka str */
        (getattrfunc) bobject_getattr,  /* tp_getattr */
        (setattrfunc) bobject_setattr,  /* tp_setattr */
};

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

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

        obj = PyObject_NEW(BasicObject, &BasicObject_Type);
        if(obj)
                obj->value = defaultValue;
        return (PyObject *) obj;
}


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

static PyObject * bobject_stringvalue(BasicObject *self, PyObject *args)
{
        char text[128];

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

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

static PyMethodDef bobject_methods[] = {
        {"stringvalue",(PyCFunction) bobject_stringvalue, METH_VARARGS},
        { NULL, NULL}
};
