/*
    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 "surface.h"

static void pysSurfaceDealloc(PysSurface* self)
{
    sgSurfaceDestroy(self->surface);
    self->ob_type->tp_free(self);
}
static PyObject* pysSurfaceNew(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
    PysSurface* self = (PysSurface*)type->tp_alloc(type, 0);
    if(self != NULL)
        self->surface = NULL;
    return (PyObject*)self;
}
static int pysSurfaceInit(PysSurface* self, PyObject* args, PyObject* kwargs)
{
    PyObject* fwidth;
    SGuint height = (SGuint)-1;
    SGenum bpp = (SGuint)-1;
    PyObject* data = NULL;
    if(!PyArg_ParseTuple(args, "O|IIO", &fwidth, &height, &bpp, &data));
        return -1;

    if(data != NULL)
    {
        if(!PyByteArray_Check(data))
            return -1;
        SGuint width = PyInt_AsLong(fwidth);
        if(width == (SGuint)-1) // -1 is an illegal value anyways - no need for PyErr_Occured()
            return -1;

        /// \todo Check data length
        self->surface = sgSurfaceCreateData(width, height, bpp, PyByteArray_AS_STRING(data));
    }
    else if(bpp != (SGenum)-1)
    {
        SGuint width = PyInt_AsLong(fwidth);
        if(width == (SGuint)-1) // -1 is an illegal value anyways - no need for PyErr_Occured()
            return -1;
        self->surface = sgSurfaceCreate(width, height, bpp);
    }
    else if(height == (SGuint)-1) // height must not be provided if bpp isn't!
    {
        char* fname = PyString_AsString(fwidth);
        if(fname == NULL)
            return -1;
        self->surface = sgSurfaceCreateFile(fname);
    }

    return 0;
}

/*
    x,y,z,xscale,yscale,oxffset,yoffset,angle
    x,y,xscale,yscale,xoffset,yoffset,angle
    x,y,z,xscale,yscale,angle
    x,y,xscale,yscale,angle
    x,y,z,angle
    x,y,angle
*/
static PyObject* pysSurfaceDrawRads(PysSurface* self, PyObject* args)
{
    float x, y, z;
    float xscale, yscale;
    float xoffset, yoffset;
    float rads;

    size_t size = PyTuple_Size(args);
    if(size == 8)
    {
        if(!PyArg_ParseTuple(args, "ffffffff", &x, &y, &z, &xscale, &yscale, &xoffset, &yoffset, &rads))
            return NULL;
        sgSurfaceDrawRads3f2f2f1f(self->surface, x, y, z, xscale, yscale, xoffset, yoffset, rads);
    }
    else if(size == 7)
    {
        if(!PyArg_ParseTuple(args, "fffffff", &x, &y, &xscale, &yscale, &xoffset, &yoffset, &rads))
            return NULL;
        sgSurfaceDrawRads2f2f2f1f(self->surface, x, y, xscale, yscale, xoffset, yoffset, rads);
    }
    else if(size == 6)
    {
        if(!PyArg_ParseTuple(args, "ffffff", &x, &y, &z, &xscale, &yscale, &rads))
            return NULL;
        sgSurfaceDrawRads3f2f1f(self->surface, x, y, z, xscale, yscale, rads);
    }
    else if(size == 5)
    {
        if(!PyArg_ParseTuple(args, "fffff", &x, &y, &xscale, &yscale, &rads))
            return NULL;
        sgSurfaceDrawRads2f2f1f(self->surface, x, y, xscale, yscale, rads);
    }
    else if(size == 4)
    {
        if(!PyArg_ParseTuple(args, "ffff", &x, &y, &z, &rads))
            return NULL;
        sgSurfaceDrawRads3f1f(self->surface, x, y, z, rads);
    }
    else if(size == 3)
    {
        if(!PyArg_ParseTuple(args, "fff", &x, &y, &rads))
            return NULL;
        sgSurfaceDrawRads2f1f(self->surface, x, y, rads);
    }
    else
        return NULL;
    Py_RETURN_NONE;
}

/*
    x,y,z,xscale,yscale,oxffset,yoffset,angle
    x,y,xscale,yscale,xoffset,yoffset,angle
    x,y,z,xscale,yscale,angle
    x,y,xscale,yscale,angle
    x,y,z,angle
    x,y,angle
*/
static PyObject* pysSurfaceDrawDegs(PysSurface* self, PyObject* args)
{
    float x, y, z;
    float xscale, yscale;
    float xoffset, yoffset;
    float degs;

    size_t size = PyTuple_Size(args);
    if(size == 8)
    {
        if(!PyArg_ParseTuple(args, "ffffffff", &x, &y, &z, &xscale, &yscale, &xoffset, &yoffset, &degs))
            return NULL;
        sgSurfaceDrawRads3f2f2f1f(self->surface, x, y, z, xscale, yscale, xoffset, yoffset, degs);
    }
    else if(size == 7)
    {
        if(!PyArg_ParseTuple(args, "fffffff", &x, &y, &xscale, &yscale, &xoffset, &yoffset, &degs))
            return NULL;
        sgSurfaceDrawRads2f2f2f1f(self->surface, x, y, xscale, yscale, xoffset, yoffset, degs);
    }
    else if(size == 6)
    {
        if(!PyArg_ParseTuple(args, "ffffff", &x, &y, &z, &xscale, &yscale, &degs))
            return NULL;
        sgSurfaceDrawRads3f2f1f(self->surface, x, y, z, xscale, yscale, degs);
    }
    else if(size == 5)
    {
        if(!PyArg_ParseTuple(args, "fffff", &x, &y, &xscale, &yscale, &degs))
            return NULL;
        sgSurfaceDrawRads2f2f1f(self->surface, x, y, xscale, yscale, degs);
    }
    else if(size == 4)
    {
        if(!PyArg_ParseTuple(args, "ffff", &x, &y, &z, &degs))
            return NULL;
        sgSurfaceDrawRads3f1f(self->surface, x, y, z, degs);
    }
    else if(size == 3)
    {
        if(!PyArg_ParseTuple(args, "fff", &x, &y, &degs))
            return NULL;
        sgSurfaceDrawRads2f1f(self->surface, x, y, degs);
    }
    else
        return NULL;
    Py_RETURN_NONE;
}

/*
    x,y,z,xscale,yscale,oxffset,yoffset
    x,y,xscale,yscale,xoffset,yoffset
    x,y,z,xscale,yscale
    x,y,xscale,yscale
    x,y,z
    x,y
*/
static PyObject* pysSurfaceDraw(PysSurface* self, PyObject* args)
{
    float x, y, z;
    float xscale, yscale;
    float xoffset, yoffset;

    size_t size = PyTuple_Size(args);
    if(size == 7)
    {
        if(!PyArg_ParseTuple(args, "fffffff", &x, &y, &z, &xscale, &yscale, &xoffset, &yoffset))
            return NULL;
        sgSurfaceDraw3f2f2f(self->surface, x, y, z, xscale, yscale, xoffset, yoffset);
    }
    else if(size == 6)
    {
        if(!PyArg_ParseTuple(args, "ffffff", &x, &y, &xscale, &yscale, &xoffset, &yoffset))
            return NULL;
        sgSurfaceDraw2f2f2f(self->surface, x, y, xscale, yscale, xoffset, yoffset);
    }
    else if(size == 5)
    {
        if(!PyArg_ParseTuple(args, "fffff", &x, &y, &z, &xscale, &yscale))
            return NULL;
        sgSurfaceDraw3f2f(self->surface, x, y, z, xscale, yscale);
    }
    else if(size == 4)
    {
        if(!PyArg_ParseTuple(args, "ffff", &x, &y, &xscale, &yscale))
            return NULL;
        sgSurfaceDraw2f2f(self->surface, x, y, xscale, yscale);
    }
    else if(size == 3)
    {
        if(!PyArg_ParseTuple(args, "fff", &x, &y, &z))
            return NULL;
        sgSurfaceDraw3f(self->surface, x, y, z);
    }
    else if(size == 2)
    {
        if(!PyArg_ParseTuple(args, "ff", &x, &y))
            return NULL;
        sgSurfaceDraw2f(self->surface, x, y);
    }
    else if(size == 0)
        sgSurfaceDraw(self->surface);
    else
        return NULL;
    Py_RETURN_NONE;
}

static PyObject* pysSurfaceTarget(PysSurface* self)
{
    sgSurfaceTarget(self->surface);
    Py_RETURN_NONE;
}
static PyObject* pysSurfaceUntarget(PysSurface* self)
{
    sgSurfaceUntarget(self->surface);
    Py_RETURN_NONE;
}
static PyObject* pysSurfaceClear(PysSurface* self, PyObject* args)
{
    float r = SG_NAN;
    float g = SG_NAN;
    float b = SG_NAN;
    float a = SG_NAN;
    if(!PyArg_ParseTuple(args, "|ffff", &r, &g, &b, &a))
        return NULL;

    if(r != r) // none
        sgSurfaceClear(self->surface);
    else if(g != g) // r
        sgSurfaceClear1f(self->surface, r);
    else if(b != b) // r,g
        sgSurfaceClear2f(self->surface, r, g);
    else if(a != a) // r,g,b
        sgSurfaceClear3f(self->surface, r, g, b);
    else
        sgSurfaceClear4f(self->surface, r, g, b, a);
    Py_RETURN_NONE;
}

static PyObject* pysSurfaceGetSize(PysSurface* self)
{
    SGuint width, height;
    sgSurfaceGetSize(self->surface, &width, &height);

    return Py_BuildValue("(II)", width, height);
}
static PyObject* pysSurfaceGetWidth(PysSurface* self)
{
    return Py_BuildValue("I", sgSurfaceGetWidth(self->surface));
}
static PyObject* pysSurfaceGetHeight(PysSurface* self)
{
    return Py_BuildValue("I", sgSurfaceGetHeight(self->surface));
}

static PyMethodDef PysSurfaceMethods[] = {
    {"drawRads", (PyCFunction)pysSurfaceDrawRads, METH_VARARGS, ""},
    {"drawDegs", (PyCFunction)pysSurfaceDrawDegs, METH_VARARGS, ""},
    {"draw", (PyCFunction)pysSurfaceDraw, METH_VARARGS, ""},

    {"target", (PyCFunction)pysSurfaceTarget, METH_NOARGS, ""},
    {"untarget", (PyCFunction)pysSurfaceUntarget, METH_NOARGS, ""},
    {"clear", (PyCFunction)pysSurfaceClear, METH_VARARGS, ""},

    {"getSize", (PyCFunction)pysSurfaceGetSize, METH_NOARGS, ""},
    {"getWidth", (PyCFunction)pysSurfaceGetWidth, METH_NOARGS, ""},
    {"getHeight", (PyCFunction)pysSurfaceGetHeight, METH_NOARGS, ""},
    {NULL, NULL, 0, NULL}
};

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

static PyTypeObject PysSurfaceType = {
    PyObject_HEAD_INIT(NULL)
    0,                         /*ob_size*/
    "siege.graphics.Surface",   /*tp_name*/
    sizeof(PysSurface),         /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)pysSurfaceDealloc, /*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 */
    PysSurfaceMethods,          /* tp_methods */
    PysSurfaceMembers,          /* tp_members */
    0,                         /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    (initproc)pysSurfaceInit,   /* tp_init */
    0,                         /* tp_alloc */
    pysSurfaceNew,                 /* tp_new */
};

int pysSurfaceCheck(PyObject* o)
{
    return PyObject_TypeCheck(o, &PysSurfaceType);
}
void sgpyInitGraphicsSurface(PyObject* parent)
{
    PysSurfaceType.tp_new = PyType_GenericNew;
    if(PyType_Ready(&PysSurfaceType) < 0)
        return;

    Py_INCREF(&PysSurfaceType);
    PyModule_AddObject(parent, "Surface", (PyObject*)&PysSurfaceType);
}
