nakedmud-mod/
nakedmud-mod/html/tutorials/
nakedmud-mod/html/tutorials/building_extras/
nakedmud-mod/html/tutorials/c/
nakedmud-mod/html/tutorials/reference/
nakedmud-mod/html/tutorials/scripting/
nakedmud-mod/html/tutorials/scripting_extras/
nakedmud-mod/lib/
nakedmud-mod/lib/help/A/
nakedmud-mod/lib/help/B/
nakedmud-mod/lib/help/C/
nakedmud-mod/lib/help/D/
nakedmud-mod/lib/help/G/
nakedmud-mod/lib/help/H/
nakedmud-mod/lib/help/J/
nakedmud-mod/lib/help/L/
nakedmud-mod/lib/help/M/
nakedmud-mod/lib/help/O/
nakedmud-mod/lib/help/P/
nakedmud-mod/lib/help/R/
nakedmud-mod/lib/help/S/
nakedmud-mod/lib/help/W/
nakedmud-mod/lib/logs/
nakedmud-mod/lib/misc/
nakedmud-mod/lib/players/
nakedmud-mod/lib/pymodules/polc/
nakedmud-mod/lib/txt/
nakedmud-mod/lib/world/
nakedmud-mod/lib/world/zones/examples/
nakedmud-mod/lib/world/zones/examples/mproto/
nakedmud-mod/lib/world/zones/examples/oproto/
nakedmud-mod/lib/world/zones/examples/reset/
nakedmud-mod/lib/world/zones/examples/rproto/
nakedmud-mod/lib/world/zones/examples/trigger/
nakedmud-mod/lib/world/zones/limbo/
nakedmud-mod/lib/world/zones/limbo/room/
nakedmud-mod/lib/world/zones/limbo/rproto/
nakedmud-mod/src/alias/
nakedmud-mod/src/dyn_vars/
nakedmud-mod/src/editor/
nakedmud-mod/src/example_module/
nakedmud-mod/src/help2/
nakedmud-mod/src/set_val/
nakedmud-mod/src/socials/
nakedmud-mod/src/time/
//*****************************************************************************
//
// pyauxiliary.c
//
// This is a wrapper around the auxiliary data system so python can make use
// of it. Allows python modules to install new auxiliary data on characters,
// rooms, objects, etc...
//
//*****************************************************************************

#include <Python.h>
#include <structmember.h>

#include "../mud.h"
#include "../utils.h"
#include "../storage.h"
#include "../auxiliary.h"

#include "pystorage.h"
#include "pyplugs.h"



//*****************************************************************************
// local variables and datastructures
//*****************************************************************************

// the minimum size of our aux table
#define MIN_AUX_TABLE_SIZE       50

// holds a map from auxiliary data names to their prototype
HASHTABLE *aux_table = NULL;



//*****************************************************************************
// the wrapper layer between python and C auxiliary data
//*****************************************************************************
PyObject *newPyAuxiliaryData(const char *keyword) {
  // look up the prototype
  PyObject *proto = hashGet(aux_table, keyword);
  
  // make sure we've got an OK proto
  if(proto == NULL)
    return NULL;
  else {
    // create a new instance of the proto
    PyObject *instance = PyInstance_New(proto, NULL, NULL);
    if(instance == NULL)
      log_pyerr("Error with Python auxiliary new");
    return instance;
  }
}

void deletePyAuxiliaryData(PyObject *data) {
  Py_XDECREF(data);
}

void pyAuxiliaryDataCopyTo(PyObject *from, PyObject *to) {
  PyObject *retval = PyObject_CallMethod(from, "copyTo", "O", to);
  if(retval == NULL)
    log_pyerr("Error with Python auxiliary copyto");
  Py_XDECREF(retval);
}

PyObject *pyAuxiliaryDataCopy(PyObject *data) {
  PyObject *retval = PyObject_CallMethod(data, "copy", NULL);
  if(retval == NULL)
    log_pyerr("Error with Python auxiliary copy");
  return retval;
}

STORAGE_SET *pyAuxiliaryDataStore(PyObject *data) {
  PyObject  *pyset = PyObject_CallMethod(data, "store", NULL);
  if(pyset == NULL)
    log_pyerr("Error with Python auxiliary store");
  STORAGE_SET *set = NULL;

  // make sure the set exists
  if(pyset == NULL || pyset == Py_None)
    set = new_storage_set();
  else
    set = PyStorageSet_AsSet(pyset);
  Py_XDECREF(pyset);
  return set;
}

PyObject *pyAuxiliaryDataRead(const char *keyword, STORAGE_SET *set) {
  // look up the prototype
  PyObject *proto = hashGet(aux_table, keyword);
  
  // make sure we've got an OK proto
  if(proto == NULL)
    return NULL;
  else {
    // build our arguments and keywords
    PyObject  *pystore = newPyStorageSet(set);
    PyObject     *args = Py_BuildValue("(O)", newPyStorageSet(set));
    PyObject *instance = PyInstance_New(proto, args, NULL);
    if(instance == NULL)
      log_pyerr("Error with Python auxiliary read");
    Py_DECREF(args);
    Py_DECREF(pystore);
    return instance;
  }
}



//*****************************************************************************
//  implementation of the pyauxiliary method 
//*****************************************************************************

//
// install new python auxiliary data. Auxiliary data must be a python CLASS
// OBJECT that has 4 functions:
//   __init__   this function initializes the auxiliary data. It takes an
//              optional argument that is a storage set which should be used
//              to initialize the values of the auxiliary data if it is supplied
//   copy       returns a copy of the auxiliary data
//   copyTo     the values of the auxiliary data to another auxiliary data
//              supplied as an argument to the function
//   store      returns a storage set representation of the auxiliary data
PyObject *PyAuxiliary_install(PyObject *self, PyObject *args) {
  PyObject   *proto = NULL; // the class proto
  char        *name = NULL; // the name of the auxiliary data
  char *installs_on = NULL; // a list of datatypes it installs onto
  bitvector_t  type = 0;    // bitvector representation of we we install on

  // try parsing the install
  if(!PyArg_ParseTuple(args, "sOs", &name, &proto, &installs_on)) {
    PyErr_Format(PyExc_TypeError,
		 "Installed auxiliaries require a name, a proto class, and "
		 "a comma-separated list of datatypes to install onto");
    return NULL;
  }

  // parse the data types that this auxiliary data installs to
  if(is_keyword(installs_on, "character", FALSE) ||
     is_keyword(installs_on, "char",      FALSE))
    SET_BIT(type, AUXILIARY_TYPE_CHAR);
  if(is_keyword(installs_on, "room",      FALSE))
    SET_BIT(type, AUXILIARY_TYPE_ROOM);
  if(is_keyword(installs_on, "object",    FALSE) ||
     is_keyword(installs_on, "obj",       FALSE))
    SET_BIT(type, AUXILIARY_TYPE_OBJ);
  if(is_keyword(installs_on, "account",   FALSE) ||
     is_keyword(installs_on, "acct",      FALSE))
    SET_BIT(type, AUXILIARY_TYPE_ACCOUNT);
  if(is_keyword(installs_on, "socket",    FALSE) ||
     is_keyword(installs_on, "sock",      FALSE))
    SET_BIT(type, AUXILIARY_TYPE_SOCKET);
  // more types to come soon!!
  //***********
  // FINISH ME
  //***********

  // add proto to our table
  Py_INCREF(proto);
  hashPut(aux_table, name, proto);
  AUXILIARY_FUNCS *funcs = newAuxiliaryFuncs(type, 
	newPyAuxiliaryData, deletePyAuxiliaryData,
	pyAuxiliaryDataCopyTo, pyAuxiliaryDataCopy,
	pyAuxiliaryDataStore, pyAuxiliaryDataRead);
  auxiliaryFuncSetIsPy(funcs, TRUE);
					     
  auxiliariesInstall(name, funcs);
  return Py_BuildValue("i", 1);
}

PyMethodDef pyauxiliary_module_methods[] = {
  { "install", PyAuxiliary_install, METH_VARARGS,
    "install(name, AuxClass, installs_on)\n\n"
    "Register new auxiliary data to the given name. Auxiliary data can be\n"
    "installed on: character, object, room, account, socket. Auxiliary data\n"
    "must be a class object of the following form:\n\n"
    "  class ClassName:\n"
    "    def __init__(self, storage_set = None)\n"
    "      ...\n\n"
    "    def copy(self)\n"
    "      ...\n\n"
    "    def copyTo(self, to)\n"
    "      ...\n\n"
    "    def store(self)\n"    
    "      ...\n\n"
    "The Store method returns a storage set representation of the data. If\n"
    "the auxiliary data is not persistent, an empty storage set can be\n"
    "returned. The class's init function must be able to handle reading in\n"
    "data from a storage set, or creating a fresh instance if set = None.\n" },
  {NULL, NULL, 0, NULL}  /* Sentinel */
};


//*****************************************************************************
// implementation of pyauxiliary.h
//*****************************************************************************

// initialize python auxiliary data for use
PyMODINIT_FUNC init_PyAuxiliary(void) {
  aux_table = newHashtableSize(MIN_AUX_TABLE_SIZE);
  Py_InitModule3("auxiliary", pyauxiliary_module_methods,
		 "The module for installing auxiliary data");
}

// returns TRUE if auxiliary data of the given name has been installed by python
bool pyAuxiliaryDataExists(const char *name) {
  return hashIn(aux_table, name);
}