#include "rpmsystem-py.h"

#include <rpm/rpmdb.h>
#include <rpm/rpmtd.h>

#include "rpmtd-py.h"
#include "rpmii-py.h"
#include "header-py.h"

/** \ingroup python
 * \class Rpmii
 * \brief A python rpm.ii key iterator object represents the keys of a
 *	database index.
 *
 * The rpm.ii class conains the following methods:
 * - next() -> key		Return the next key.
 *
 * To obtain a rpm.ii object to query the database used by a transaction,
 * the ts.dbIndex(tag) method is used.
 *
 * Here's an example that prints the name of all installed packages:
 * \code
 *	import rpm
 *	ts = rpm.TransactionSet()
 *	for name in ts.dbIndex("conflictname"):
 *	    print(name)
 * \endcode
 *
 * ts.dbIndex() can be used to get the packages containing the keys of interest
 */

/** \ingroup python
 * \name Class: Rpmii
 */

struct rpmiiObject_s {
    PyObject_HEAD
    PyObject *md_dict;		/*!< to look like PyModuleObject */
    PyObject *ref;		/* for db/ts refcounting */
    rpmdbIndexIterator ii;
    rpmtd keytd;
};

static PyObject *
rpmii_iternext(rpmiiObject * s)
{
    PyObject *keyo = NULL;

    if (s->ii != NULL) {
	if (rpmdbIndexIteratorNextTd(s->ii, s->keytd) == 0) {
	    /* The keys must never be arrays so rpmtd_AsPyObj() wont work */
	    keyo = rpmtd_ItemAsPyobj(s->keytd, rpmtdClass(s->keytd));
	    rpmtdFreeData(s->keytd);
	} else {
	    s->ii = rpmdbIndexIteratorFree(s->ii);
	}
    }

    return keyo;
};

static PyObject *
rpmii_instances(rpmiiObject * s)
{
    int entries = rpmdbIndexIteratorNumPkgs(s->ii);
    PyObject * list = PyList_New(entries);
    PyObject * tuple;
    for (int i = 0; i < entries; i++) {
        tuple = PyTuple_New(2);
        PyTuple_SET_ITEM(tuple, 0,
                         PyLong_FromLong(rpmdbIndexIteratorPkgOffset(s->ii, i)));
        PyTuple_SET_ITEM(tuple, 1,
                         PyLong_FromLong(rpmdbIndexIteratorTagNum(s->ii, i)));
	PyList_SET_ITEM(list, i, tuple);
    }
    return list;
}

static struct PyMethodDef rpmii_methods[] = {
    {"instances", (PyCFunction) rpmii_instances, METH_NOARGS, NULL},
    {NULL,		NULL}		/* sentinel */
};

static void rpmii_dealloc(rpmiiObject * s)
{
    s->ii = rpmdbIndexIteratorFree(s->ii);
    rpmtdFree(s->keytd);
    Py_DECREF(s->ref);
    Py_TYPE(s)->tp_free((PyObject *)s);
}

static int rpmii_bool(rpmiiObject *s)
{
    return (s->ii != NULL);
}

static PyNumberMethods rpmii_as_number = {
	0, /* nb_add */
	0, /* nb_subtract */
	0, /* nb_multiply */
	0, /* nb_remainder */
	0, /* nb_divmod */
	0, /* nb_power */
	0, /* nb_negative */
	0, /* nb_positive */
	0, /* nb_absolute */
	(inquiry)rpmii_bool, /* nb_bool/nonzero */
};

static char rpmii_doc[] =
"";

PyTypeObject rpmii_Type = {
	PyVarObject_HEAD_INIT(&PyType_Type, 0)
	"rpm.ii",			/* tp_name */
	sizeof(rpmiiObject),		/* tp_size */
	0,				/* tp_itemsize */
	(destructor) rpmii_dealloc, 	/* tp_dealloc */
	0,				/* tp_print */
	(getattrfunc)0, 		/* tp_getattr */
	0,				/* tp_setattr */
	0,				/* tp_compare */
	0,				/* tp_repr */
	&rpmii_as_number,		/* tp_as_number */
	0,				/* tp_as_sequence */
	0,				/* tp_as_mapping */
	0,				/* tp_hash */
	0,				/* tp_call */
	0,				/* tp_str */
	PyObject_GenericGetAttr,	/* tp_getattro */
	PyObject_GenericSetAttr,	/* tp_setattro */
	0,				/* tp_as_buffer */
	Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,	/* tp_flags */
	rpmii_doc,			/* tp_doc */
	0,				/* tp_traverse */
	0,				/* tp_clear */
	0,				/* tp_richcompare */
	0,				/* tp_weaklistoffset */
	PyObject_SelfIter,		/* tp_iter */
	(iternextfunc) rpmii_iternext,	/* tp_iternext */
	rpmii_methods,			/* 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 */
	0,				/* tp_init */
	0,				/* tp_alloc */
	0,				/* tp_new */
	0,				/* tp_free */
	0,				/* tp_is_gc */
};

PyObject * rpmii_Wrap(PyTypeObject *subtype, rpmdbIndexIterator ii, PyObject *s)
{
    rpmiiObject * iio = (rpmiiObject *)subtype->tp_alloc(subtype, 0);
    if (iio == NULL) return NULL;

    iio->ii = ii;
    iio->ref = s;
    iio->keytd = rpmtdNew();
    Py_INCREF(iio->ref);
    return (PyObject *) iio;
}
