/**
 * PyStorageVisitor.cpp --
 *
 *	This file contains the storage-visitor defintion.
 *
 *	Authors: Mike Krimerman.
 *		 hemkond@yahoo.com
 *
 * Copyright (c) 2003, Mike Krimerman.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE, EVEN IF
 * MIKE KRIMERMAN IS MADE AWARE OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "e4py.h"
#include <new>

/** Helpers */

/** PyStorageVisitor_New.
 * A helper function for object creation from C.
 */
PyObject* PyStorageVisitor_New()
{
	PyStorageVisitor* result = PyObject_NEW(PyStorageVisitor, &PyStorageVisitorType);
	if (result)
		new(&result->visitor) e4_StorageVisitor();		//Placement new
	return (PyObject*)result;
}

/** PyStorageVisitor_FromStorageVisitor.
 * A helper function for object creation from C.
 */
PyObject* PyStorageVisitor_FromStorageVisitor(e4_StorageVisitor visitor)
{
	PyStorageVisitor* result = PyObject_NEW(PyStorageVisitor, &PyStorageVisitorType);
	if (result)
		new(&result->visitor) e4_StorageVisitor(visitor);		//Placement new
	return (PyObject*)result;
}

/** PyStorageVisitor_AsStorageVisitor.
 *
 */
e4_StorageVisitor& PyStorageVisitor_AsStorageVisitor(PyObject* self)
{
	return ((PyStorageVisitor*)self)->visitor;
}

/** Methods */

/** PyStorageVisitor_Next.
 *
 */
static PyObject* PyStorageVisitor_Next(PyStorageVisitor* self)
{
	e4_Storage storage;
	if (!self->visitor.NextStorage(storage)) {
		PyErr_SetString(e4pyExc_APIFailure, "Next: No more storages to visit");
		return 0;
	}

	return PyStorage_FromStorage(storage);
}

/** PyStorageVisitor_CurrentAndAdvance.
 *
 */
static PyObject* PyStorageVisitor_CurrentAndAdvance(PyStorageVisitor* self)
{
	e4_Storage storage;
	if (!self->visitor.CurrentStorageAndAdvance(storage)) {
		PyErr_SetString(e4pyExc_APIFailure, "CurrentAndAdvance: No more storages to visit");
		return 0;
	}

	return PyStorage_FromStorage(storage);
}


/** Method doc */

static char doc_Next[] = "\
Next() -> Storage\n\
Advances to the next storage to be visited and returns the storage";

static char doc_CurrentAndAdvance[] = "\
CurrentAndAdvance() -> Storage\n\
Returns the storage currently being visited, advances to the next storage to be visited.";

/** Method list */
static PyMethodDef PyStorageVisitorMethods[] = {
	{"Next", (PyCFunction)PyStorageVisitor_Next, METH_NOARGS, doc_Next},
	{"CurrentAndAdvance", (PyCFunction)PyStorageVisitor_CurrentAndAdvance, METH_NOARGS, doc_CurrentAndAdvance},
	{0, 0, 0, 0}
};


/** Attributes */

/** PyStorageVisitor_get_current.
 *
 */
static PyObject* PyStorageVisitor_get_current(PyStorageVisitor* self, void *)
{
	e4_Storage storage;
	if (!self->visitor.CurrentStorage(storage)) {
		PyErr_SetString(e4pyExc_APIFailure, "current: No current storage");
		return 0;
	}

	return PyStorage_FromStorage(storage);
}

/** PyStorageVisitor_get_done.
 *
 */
static PyObject* PyStorageVisitor_get_done(PyStorageVisitor* self, void *)
{
	return PyInt_FromLong(self->visitor.IsDone());
}

/** PyStorageVisitor_get_valid.
 *
 */
static PyObject* PyStorageVisitor_get_valid(PyStorageVisitor* self, void *)
{
	return PyInt_FromLong(1); //self->visitor.IsValid());
}

/** Attribute doc */

static char doc_current[] = "\
Returns the currently visited storage.";

static char doc_done[] = "\
Returns true if there are no more storages to visit.";

static char doc_valid[] = "\
Returns true if visitor has a current storage being visited.";

/** Attribute list */
static PyGetSetDef PyStorageVisitorGetsets[] = {
    {"current", (getter)PyStorageVisitor_get_current, (setter)NULL, doc_current},
    {"done", (getter)PyStorageVisitor_get_done, (setter)NULL, doc_done},
    {"valid", (getter)PyStorageVisitor_get_valid, (setter)NULL, doc_valid},
    {NULL}
};


/** StorageVisitor access */

/** PyStorageVisitor_new.
 *
 */
/*static*/
PyObject* PyStorageVisitor_new(PyObject* o, PyObject* args)
{
	PyStorageVisitor* result = NULL;
	switch (PyTuple_Size(args)) {
	case 0:
		result = (PyStorageVisitor*)PyStorageVisitor_New();
		break;
	case 1: {
		PyObject *obj;
		if (!PyArg_ParseTuple(args, "O", &obj))
			return 0;
		
		if (PyStorageVisitor_Check(obj)) {
			result = (PyStorageVisitor*)PyStorageVisitor_FromStorageVisitor(PyStorageVisitor_AsStorageVisitor(obj));
		} else {
			PyErr_SetString(PyExc_TypeError, ErrInvalidArgs);
			return 0;
		}
		break;
	}
	default:
		PyErr_SetString(PyExc_TypeError, ErrInvalidArgs);
		break;
	}
	return (PyObject*)result;
}

/** PyStorageVisitor_dealloc.
 *
 */
static void PyStorageVisitor_dealloc(PyStorageVisitor *self)
{
	self->visitor.~e4_StorageVisitor();		//"placement" dtor
	PyObject_DEL(self);
}

/** PyStorageVisitor_compare.
 *
 */
static int PyStorageVisitor_compare(PyStorageVisitor *self, PyObject *rhs)
{
	if (!PyStorageVisitor_Check(rhs))
		return -1;
	return self->visitor == PyStorageVisitor_AsStorageVisitor(rhs) ? 0 : 1;
}

/** PyStorageVisitor_iter.
 *
 */
static PyObject* PyStorageVisitor_iter(PyStorageVisitor *self)
{
	Py_INCREF(self);
	return (PyObject*)self;
}

/** PyStorageVisitor_iternext.
 *
 */
static PyObject* PyStorageVisitor_iternext(PyStorageVisitor *self)
{
	e4_Storage storage;
	if (!self->visitor.CurrentStorageAndAdvance(storage)) {
		PyErr_SetString(PyExc_StopIteration , "next: No more storages to visit");
		return 0;
	}

	return PyStorage_FromStorage(storage);
}

/** Type doc */
static char doc_PyStorageVisitor[] = "\
The StorageVisitor class enables a program to iterate over all open storages.";

/** StorageVisitor type */
PyTypeObject PyStorageVisitorType = {
	PyObject_HEAD_INIT(&PyType_Type)
	0,
	"StorageVisitor",
	sizeof(PyStorageVisitor),		/* tp_basicsize */
	0,					/* tp_itemsize */
	(destructor)PyStorageVisitor_dealloc,	/* tp_dealloc */
	0,//(printfunc)PyStorageVisitor_print, /* tp_print */
	0,					/* tp_getattr */
	0,					/* tp_setattr */
	(cmpfunc)PyStorageVisitor_compare,	/* tp_compare */
	(reprfunc)0,		/* tp_repr */
	0,					/* 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 */
    doc_PyStorageVisitor,	/* tp_doc */
    0,					/* tp_traverse */
    0,					/* tp_clear */
    0,					/* tp_richcompare */
    0,					/* tp_weaklistoffset */
    (getiterfunc)PyStorageVisitor_iter,			/* tp_iter */
    (iternextfunc)PyStorageVisitor_iternext,	/* tp_iternext */
    PyStorageVisitorMethods,		/* tp_methods */
    0,					/* tp_members */
    PyStorageVisitorGetsets,		/* tp_getset */
};
