/*
    Copyright (c) 2007 SIEGE Development Team
    All rights reserved.
    
    This file is part of libSIEGE.
    
    This software is copyrighted work licensed under the terms of the
    2-clause BSD license. Please consult the file "license.txt" for
    details.
    
    If you did not recieve the file with this program, please email
    Tim Chas <darkuranium@gmail.com>.
*/

#include "event.h"

typedef struct EventData
{
    PyObject* data;
    PyObject* func;
} EventData;

SGbool SG_EXPORT _cbCall(void* data, void* args)
{
    EventData* ed = data;
    PyObject** pargs = args;
    PyObject* a = pargs[0];
    PyObject* ka = pargs[1];

    PyTuple_SetItem(a, 0, ed->data);
    PyObject* ret = PyObject_Call(ed->func, a, ka);

    int t = PyObject_IsTrue(ret);
    Py_DECREF(ret);

    return t;
}

static void pysEventDealloc(PysEvent* self)
{
    EventData* ed = self->event->data;

    Py_DECREF(ed->data);
    Py_DECREF(ed->func);
    free(ed);

    sgEventDestroy(self->event);
    self->ob_type->tp_free(self);
}
static PyObject* pysEventNew(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
    PysEvent* self = (PysEvent*)type->tp_alloc(type, 0);
    if(self != NULL)
        self->event = NULL;
    return (PyObject*)self;
}
static int pysEventInit(PysEvent* self, PyObject* args, PyObject* kwargs)
{
    float priority;
    SGuint type;
    PyObject* data;
    PyObject* func;
    if(!PyArg_ParseTuple(args, "fIOO", &priority, &type, &data, &func))
        return -1;

    Py_INCREF(data);
    Py_INCREF(func);
    EventData* ed = malloc(sizeof(EventData));
    ed->data = data;
    ed->func = func;

    self->event = sgEventCreate(priority, type, ed, _cbCall);

    return 0;
}

static PyObject* pysEventCall(PyObject* self, PyObject* args, PyObject* kwargs)
{
    if(PyTuple_GET_SIZE(args) == 0)
        return NULL;

    SGenum type = PyInt_AsLong(PyTuple_GET_ITEM(args, 0));

    PyObject* a[] = {args, kwargs};
    sgEventCall(type, a);

    Py_RETURN_NONE;
}

static PyObject* pysEventStop(PyObject* self)
{
    sgEventStop();

    Py_RETURN_NONE;
}

static PyMethodDef PysEventMethods[] = {
    {"call", (PyCFunction)pysEventCall, METH_KEYWORDS | METH_STATIC, ""},
    {"stop", (PyCFunction)pysEventStop, METH_NOARGS | METH_STATIC, ""},
    {NULL, NULL, 0, NULL}
};

static PyMemberDef PysEventMembers[] = {
    {NULL, 0, 0, 0, NULL}
};

static PyTypeObject PysEventType = {
    PyObject_HEAD_INIT(NULL)
    0,                         /*ob_size*/
    "siege.core.Event",        /*tp_name*/
    sizeof(PysEvent),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)pysEventDealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_compare*/
    0,                         /*tp_repr*/
    0,                         /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
    "",                        /* tp_doc */
    0,		                   /* tp_traverse */
    0,		                   /* tp_clear */
    0,		                   /* tp_richcompare */
    0,		                   /* tp_weaklistoffset */
    0,		                   /* tp_iter */
    0,		                   /* tp_iternext */
    PysEventMethods,          /* tp_methods */
    PysEventMembers,          /* tp_members */
    0,                         /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    (initproc)pysEventInit,   /* tp_init */
    0,                         /* tp_alloc */
    pysEventNew,                 /* tp_new */
};

int pysEventCheck(PyObject* o)
{
    return PyObject_TypeCheck(o, &PysEventType);
}
void sgpyInitCoreEvent(PyObject* parent)
{
    PyModule_AddIntConstant(parent, "EV_INTERNAL", SG_EV_INTERNAL);

    // EventClient types -- these should be OR'd together
    PyModule_AddIntConstant(parent, "EVT_MODULE", SG_EVT_MODULE);
    PyModule_AddIntConstant(parent, "EVT_CORE", SG_EVT_CORE);
    PyModule_AddIntConstant(parent, "EVT_WINDOW", SG_EVT_WINDOW);
    PyModule_AddIntConstant(parent, "EVT_MOUSE", SG_EVT_MOUSE);
    PyModule_AddIntConstant(parent, "EVT_KEYBOARD", SG_EVT_KEYBOARD);
    PyModule_AddIntConstant(parent, "EVT_JOYSTICK", SG_EVT_JOYSTICK);
    PyModule_AddIntConstant(parent, "EVT_NETWORK", SG_EVT_NETWORK);
    PyModule_AddIntConstant(parent, "EVT_PHYSICS", SG_EVT_PHYSICS);
    PyModule_AddIntConstant(parent, "EVT_LEVEL", SG_EVT_LEVEL);
    PyModule_AddIntConstant(parent, "EVT_ALL", SG_EVT_ALL);

    // EventClient functions -- used in calls
    PyModule_AddIntConstant(parent, "EVF_INIT", SG_EVF_INIT);
    PyModule_AddIntConstant(parent, "EVF_DEINIT", SG_EVF_DEINIT);

    PyModule_AddIntConstant(parent, "EVF_START", SG_EVF_START);
    PyModule_AddIntConstant(parent, "EVF_EXIT", SG_EVF_EXIT);
    PyModule_AddIntConstant(parent, "EVF_TICK", SG_EVF_TICK);
    PyModule_AddIntConstant(parent, "EVF_TICKB", SG_EVF_TICKB);
    PyModule_AddIntConstant(parent, "EVF_TICKE", SG_EVF_TICKE);
    PyModule_AddIntConstant(parent, "EVF_DRAW", SG_EVF_DRAW);

    PyModule_AddIntConstant(parent, "EVF_WINOPEN", SG_EVF_WINOPEN);
    PyModule_AddIntConstant(parent, "EVF_WINCLOSE", SG_EVF_WINCLOSE);
    PyModule_AddIntConstant(parent, "EVF_WINRESIZE", SG_EVF_WINRESIZE);

    /*
        H: held
        P: press
        R: release
        A: repeat ("again")
    */

    PyModule_AddIntConstant(parent, "EVF_MOUSEBUTH", SG_EVF_MOUSEBUTH);
    PyModule_AddIntConstant(parent, "EVF_MOUSEBUTP", SG_EVF_MOUSEBUTP);
    PyModule_AddIntConstant(parent, "EVF_MOUSEBUTR", SG_EVF_MOUSEBUTR);
    PyModule_AddIntConstant(parent, "EVF_MOUSEBUTLH", SG_EVF_MOUSEBUTLH);
    PyModule_AddIntConstant(parent, "EVF_MOUSEBUTLP", SG_EVF_MOUSEBUTLP);
    PyModule_AddIntConstant(parent, "EVF_MOUSEBUTLR", SG_EVF_MOUSEBUTLR);
    PyModule_AddIntConstant(parent, "EVF_MOUSEBUTRH", SG_EVF_MOUSEBUTRH);
    PyModule_AddIntConstant(parent, "EVF_MOUSEBUTRP", SG_EVF_MOUSEBUTRP);
    PyModule_AddIntConstant(parent, "EVF_MOUSEBUTRR", SG_EVF_MOUSEBUTRR);
    PyModule_AddIntConstant(parent, "EVF_MOUSEBUTMH", SG_EVF_MOUSEBUTMH);
    PyModule_AddIntConstant(parent, "EVF_MOUSEBUTMP", SG_EVF_MOUSEBUTMP);
    PyModule_AddIntConstant(parent, "EVF_MOUSEBUTMR", SG_EVF_MOUSEBUTMR);
    PyModule_AddIntConstant(parent, "EVF_MOUSEMOVE", SG_EVF_MOUSEMOVE);
    PyModule_AddIntConstant(parent, "EVF_MOUSEWHEEL", SG_EVF_MOUSEWHEEL);

    PyModule_AddIntConstant(parent, "EVF_KEYKEYH", SG_EVF_KEYKEYH);
    PyModule_AddIntConstant(parent, "EVF_KEYKEYP", SG_EVF_KEYKEYP);
    PyModule_AddIntConstant(parent, "EVF_KEYKEYR", SG_EVF_KEYKEYR);
    PyModule_AddIntConstant(parent, "EVF_KEYKEYA", SG_EVF_KEYKEYA);
    //PyModule_AddIntConstant(parent, "EVF_KEYCHARH", SG_EVF_KEYCHARH);
    PyModule_AddIntConstant(parent, "EVF_KEYCHARP", SG_EVF_KEYCHARP);
    //PyModule_AddIntConstant(parent, "EVF_KEYCHARR", SG_EVF_KEYCHARR);
    PyModule_AddIntConstant(parent, "EVF_KEYCHARA", SG_EVF_KEYCHARA);

    PyModule_AddIntConstant(parent, "EVF_JOYSTICKBUTH", SG_EVF_JOYSTICKBUTH);
    PyModule_AddIntConstant(parent, "EVF_JOYSTICKBUTP", SG_EVF_JOYSTICKBUTP);
    PyModule_AddIntConstant(parent, "EVF_JOYSTICKBUTR", SG_EVF_JOYSTICKBUTR);
    PyModule_AddIntConstant(parent, "EVF_JOYSTICKMOVE", SG_EVF_JOYSTICKMOVE);

    //PyModule_AddIntConstant(parent, "EVF_NET", SG_EVF_NET);

    PyModule_AddIntConstant(parent, "EVF_PHYSCOLH", SG_EVF_PHYSCOLH);
    PyModule_AddIntConstant(parent, "EVF_PHYSCOL1", SG_EVF_PHYSCOL1);
    PyModule_AddIntConstant(parent, "EVF_PHYSCOL2", SG_EVF_PHYSCOL2);
    PyModule_AddIntConstant(parent, "EVF_PHYSCOLBH", SG_EVF_PHYSCOLBH);
    PyModule_AddIntConstant(parent, "EVF_PHYSCOLB1", SG_EVF_PHYSCOLB1);
    PyModule_AddIntConstant(parent, "EVF_PHYSCOLB2", SG_EVF_PHYSCOLB2);
    PyModule_AddIntConstant(parent, "EVF_PHYSCOLEH", SG_EVF_PHYSCOLEH);
    PyModule_AddIntConstant(parent, "EVF_PHYSCOLE1", SG_EVF_PHYSCOLE1);
    PyModule_AddIntConstant(parent, "EVF_PHYSCOLE2", SG_EVF_PHYSCOLE2);
    PyModule_AddIntConstant(parent, "EVF_PHYSCOLRH", SG_EVF_PHYSCOLRH);
    PyModule_AddIntConstant(parent, "EVF_PHYSCOLR1", SG_EVF_PHYSCOLR1);
    PyModule_AddIntConstant(parent, "EVF_PHYSCOLR2", SG_EVF_PHYSCOLR2);

    PyModule_AddIntConstant(parent, "EVF_LVLSTART", SG_EVF_LVLSTART);
    PyModule_AddIntConstant(parent, "EVF_LVLEND", SG_EVF_LVLEND);

    PysEventType.tp_new = PyType_GenericNew;
    if(PyType_Ready(&PysEventType) < 0)
        return;

    Py_INCREF(&PysEventType);
    PyModule_AddObject(parent, "Event", (PyObject*)&PysEventType);
}
