/* 

py/pyext - python script object for PD and Max/MSP

Copyright (c)2002-2005 Thomas Grill (gr@grrrr.org)
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "license.txt," in this distribution.  

*/

#include "pyprefix.h"
#include "pysymbol.h"

inline pySymbol *symbol_newsym(const t_symbol *sym)
{
    pySymbol *self = (pySymbol *)pySymbol_Type.tp_alloc(&pySymbol_Type, 0);
    if(self) self->sym = sym;
    return self;
}

static PyObject *symbol_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    return (PyObject *)symbol_newsym(flext::sym__);
}

static int symbol_init(PyObject *self, PyObject *args, PyObject *kwds)
{
    FLEXT_ASSERT(pySymbol_Check(self));

    PyObject *arg = PySequence_GetItem(args,0); // new reference
    if(!arg) return -1;

    int ret = 0;

    if(pySymbol_Check(arg))
        ((pySymbol *)self)->sym = pySymbol_AS_SYMBOL(arg);
    else if(PyString_Check(arg))
        ((pySymbol *)self)->sym = flext::MakeSymbol(PyString_AS_STRING(arg));
    else
        ret = -1;
    Py_DECREF(arg);

    return ret;
}

static PyObject *symbol_str(PyObject *self)
{
    FLEXT_ASSERT(pySymbol_Check(self));
    return (PyObject *)PyString_FromString(pySymbol_AS_STRING(self));
}

static PyObject *symbol_repr(PyObject *self)
{
    FLEXT_ASSERT(pySymbol_Check(self));
    return (PyObject *)PyString_FromFormat("<Symbol %s>",pySymbol_AS_STRING(self));
}

static PyObject *symbol_richcompare(PyObject *a,PyObject *b,int cmp)
{
    if(pySymbol_Check(a) && pySymbol_Check(b)) {
        const t_symbol *asym = pySymbol_AS_SYMBOL(a);
        const t_symbol *bsym = pySymbol_AS_SYMBOL(a);
        bool ret;
        switch(cmp) {
            case Py_LT: ret = asym < bsym;
            case Py_LE: ret = asym <= bsym;
            case Py_EQ: ret = asym == bsym;
            case Py_NE: ret = asym != bsym;
            case Py_GT: ret = asym > bsym;
            case Py_GE: ret = asym >= bsym;
        }
        return PyBool_FromLong(ret);
    }
	Py_INCREF(Py_NotImplemented);
	return Py_NotImplemented;
}

static long symbol_hash(PyObject *self)
{
    FLEXT_ASSERT(pySymbol_Check(self));
    return (long)pySymbol_AS_SYMBOL(self);
}

PyTypeObject pySymbol_Type = {
    PyObject_HEAD_INIT(NULL)
    0,                         /*ob_size*/
    "Symbol",              /*tp_name*/
    sizeof(pySymbol),          /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    0,                         /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,            /*tp_compare*/
    symbol_repr,               /*tp_repr*/
    0,                         /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    symbol_hash,               /*tp_hash */
    0,                         /*tp_call*/
    symbol_str,                /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT /*| Py_TPFLAGS_BASETYPE*/,   /*tp_flags*/
    "Symbol objects",           /* tp_doc */
    0,		               /* tp_traverse */
    0,		               /* tp_clear */
    symbol_richcompare,	       /* tp_richcompare */
    0,		               /* tp_weaklistoffset */
    0,		               /* tp_iter */
    0,		               /* tp_iternext */
    0,                          /* tp_methods */
    0,                          /* tp_members */
    0,                         /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    symbol_init,            /* tp_init */
    0,                         /* tp_alloc */
    symbol_new,                 /* tp_new */
};

pySymbol *pySymbol__;
pySymbol *pySymbol_bang;
pySymbol *pySymbol_list;
pySymbol *pySymbol_symbol;
pySymbol *pySymbol_float;
pySymbol *pySymbol_int;


void initsymbol()
{
    if(PyType_Ready(&pySymbol_Type) < 0)
        FLEXT_ASSERT(false);
    else
        Py_INCREF(&pySymbol_Type);

    // initialize predefined objects
    pySymbol__ = symbol_newsym(flext::sym__);
    pySymbol_bang = symbol_newsym(flext::sym_bang);
    pySymbol_list = symbol_newsym(flext::sym_list);
    pySymbol_symbol = symbol_newsym(flext::sym_symbol);
    pySymbol_float = symbol_newsym(flext::sym_float);
    pySymbol_int = symbol_newsym(flext::sym_int);
}


PyObject *pySymbol_FromSymbol(const t_symbol *sym)
{
    pySymbol *op;
    if(sym == flext::sym__)
        Py_INCREF(op = pySymbol__);
    else if(sym == flext::sym_bang)
        Py_INCREF(op = pySymbol_bang);
    else if(sym == flext::sym_list)
        Py_INCREF(op = pySymbol_list);
    else if(sym == flext::sym_symbol)
        Py_INCREF(op = pySymbol_symbol);
    else if(sym == flext::sym_float)
        Py_INCREF(op = pySymbol_float);
    else if(sym == flext::sym_int)
        Py_INCREF(op = pySymbol_int);
    else
        op = symbol_newsym(sym);
    return (PyObject *)op;
}