nakedmudv3.8.1/
nakedmudv3.8.1/html/
nakedmudv3.8.1/html/tutorials/
nakedmudv3.8.1/html/tutorials/building_extras/
nakedmudv3.8.1/html/tutorials/c/
nakedmudv3.8.1/html/tutorials/reference/
nakedmudv3.8.1/html/tutorials/scripting/
nakedmudv3.8.1/html/tutorials/scripting_extras/
nakedmudv3.8.1/lib/
nakedmudv3.8.1/lib/help/A/
nakedmudv3.8.1/lib/help/B/
nakedmudv3.8.1/lib/help/C/
nakedmudv3.8.1/lib/help/D/
nakedmudv3.8.1/lib/help/G/
nakedmudv3.8.1/lib/help/H/
nakedmudv3.8.1/lib/help/J/
nakedmudv3.8.1/lib/help/L/
nakedmudv3.8.1/lib/help/M/
nakedmudv3.8.1/lib/help/O/
nakedmudv3.8.1/lib/help/P/
nakedmudv3.8.1/lib/help/R/
nakedmudv3.8.1/lib/help/S/
nakedmudv3.8.1/lib/help/W/
nakedmudv3.8.1/lib/logs/
nakedmudv3.8.1/lib/misc/
nakedmudv3.8.1/lib/players/
nakedmudv3.8.1/lib/txt/
nakedmudv3.8.1/lib/world/
nakedmudv3.8.1/lib/world/zones/examples/
nakedmudv3.8.1/lib/world/zones/examples/mproto/
nakedmudv3.8.1/lib/world/zones/examples/oproto/
nakedmudv3.8.1/lib/world/zones/examples/reset/
nakedmudv3.8.1/lib/world/zones/examples/rproto/
nakedmudv3.8.1/lib/world/zones/examples/trigger/
nakedmudv3.8.1/lib/world/zones/limbo/
nakedmudv3.8.1/lib/world/zones/limbo/room/
nakedmudv3.8.1/lib/world/zones/limbo/rproto/
nakedmudv3.8.1/src/alias/
nakedmudv3.8.1/src/dyn_vars/
nakedmudv3.8.1/src/editor/
nakedmudv3.8.1/src/example_module/
nakedmudv3.8.1/src/help2/
nakedmudv3.8.1/src/set_val/
nakedmudv3.8.1/src/socials/
nakedmudv3.8.1/src/time/
//*****************************************************************************
//
// olc_extender.c
//
// A structure for helping in the extension of OLC functions. Allows for the
// registration of new commands, menu displays, parsers, and execution 
// functions.
//
//*****************************************************************************
#include "../mud.h"
#include "../socket.h"
#include "olc.h"
#include "olc_extender.h"



//*****************************************************************************
// mandatory modules
//*****************************************************************************
#include "../scripts/scripts.h"
#include "../scripts/pyplugs.h"



//*****************************************************************************
// local variables, structures, and functions
//*****************************************************************************

// what kind of extension is this?
#define OLCEXT_C        0
#define OLCEXT_PY       1

// what is the minimum ID we use?
#define MIN_CHOICE_ID   10000

typedef struct olc_extender_data {
  // what type of extension is this?
  int type;

  // C functions
  void       (* menu)(SOCKET_DATA *sock, void *data);
  int (* choose_exec)(SOCKET_DATA *sock, void *data);
  bool (* parse_exec)(SOCKET_DATA *sock, void *data, const char *arg);
  void (* from_proto)(void *data);
  void   (* to_proto)(void *data, BUFFER *buf);

  // Python functions
  PyObject   *pymenu;
  PyObject *pychoose;
  PyObject  *pyparse;
  PyObject *pyfrompr;
  PyObject   *pytopr;
} OLC_EXT_DATA;

struct olc_extender {
  HASHTABLE *opt_hash;
  void *(* borrow_py)(void *data);
};

OLC_EXT_DATA *newOLCExt(void *menu, void *choose_exec, void *parse_exec,
			void *from_proto, void *to_proto) {
  OLC_EXT_DATA *ext = calloc(1, sizeof(OLC_EXT_DATA));
  ext->menu         = menu;
  ext->choose_exec  = choose_exec;
  ext->parse_exec   = parse_exec;
  ext->from_proto   = from_proto;
  ext->to_proto     = to_proto;
  ext->type = OLCEXT_C;
  return ext;
}

OLC_EXT_DATA *newPyOLCExt(PyObject *menu, PyObject *choose_exec, 
			  PyObject *parse_exec, PyObject *from_proto,
			  PyObject *to_proto) {
  OLC_EXT_DATA *ext = calloc(1, sizeof(OLC_EXT_DATA));
  ext->pymenu   = menu;        Py_XINCREF(menu);
  ext->pychoose = choose_exec; Py_XINCREF(choose_exec);
  ext->pyparse  = parse_exec;  Py_XINCREF(parse_exec);
  ext->pyfrompr = from_proto;  Py_XINCREF(from_proto);
  ext->pytopr   = to_proto;    Py_XINCREF(to_proto);
  ext->type = OLCEXT_PY;
  return ext;
}

void deleteOLCExt(OLC_EXT_DATA *ext) {
  Py_XDECREF(ext->pymenu);
  Py_XDECREF(ext->pychoose);
  Py_XDECREF(ext->pyparse);
  Py_XDECREF(ext->pyfrompr);
  Py_XDECREF(ext->pytopr);
  free(ext);
}



//*****************************************************************************
// implementation of olc_extender.h
//*****************************************************************************
OLC_EXTENDER *newExtender(void) {
  OLC_EXTENDER *data = calloc(1, sizeof(OLC_EXTENDER));
  data->opt_hash = newHashtable();
  return data;
}

void extenderSetPyFunc(OLC_EXTENDER *ext, void *borrow_py) {
  ext->borrow_py = borrow_py;
}

void extenderDoMenu(SOCKET_DATA *sock, OLC_EXTENDER *ext, void *data) {
  LIST           *keys = hashCollect(ext->opt_hash);
  char            *key = NULL;
  OLC_EXT_DATA  *edata = NULL;

  // display each menu item alphabetically
  listSortWith(keys, strcasecmp);
  LIST_ITERATOR *key_i = newListIterator(keys);
  ITERATE_LIST(key, key_i) {
    // display the menu option
    send_to_socket(sock, "{g%s) ", key);

    // then display the information
    edata = hashGet(ext->opt_hash, key);
    if(edata->type == OLCEXT_C)
      edata->menu(sock, data);
    else if(ext->borrow_py != NULL) {
      PyObject *ret = PyObject_CallFunction(edata->pymenu, "OO", 
					    socketGetPyFormBorrowed(sock), 
					    ext->borrow_py(data));
      if(ret == NULL)
	log_pyerr("Error running Python OLC exention menu function: %s", key);
      Py_XDECREF(ret);
    }
  } deleteListIterator(key_i);

  // free up our garbage
  deleteListWith(keys, free);
}

int extenderDoOptChoice(SOCKET_DATA *sock, OLC_EXTENDER *ext, void *data, 
			char opt) {
  char key[2] = { opt, '\0' };

  // does it exist?
  if(!hashIn(ext->opt_hash, key))
    return MENU_CHOICE_INVALID;

  // pull out the data
  OLC_EXT_DATA *edata = hashGet(ext->opt_hash, key);
  int          retval = MENU_CHOICE_INVALID;

  // is it C data or Python data?
  if(edata->type == OLCEXT_C)
    retval = edata->choose_exec(sock, data);
  else if(ext->borrow_py != NULL) {
    PyObject *ret = 
      PyObject_CallFunction(edata->pychoose, "OO", socketGetPyFormBorrowed(sock), ext->borrow_py(data));
    if(ret == NULL)
      log_pyerr("Error running Python OLC exention choice function: %s", key);
    else if(PyInt_Check(ret))
      retval = (int)PyInt_AsLong(ret);
    Py_XDECREF(ret);
  }

  // did we do a toggle, or enter a submenu?
  if(retval == MENU_NOCHOICE || retval == MENU_CHOICE_INVALID)
    return retval;
  return MIN_CHOICE_ID + opt;
}

bool extenderDoParse(SOCKET_DATA *sock, OLC_EXTENDER *ext, void *data, 
		     int choice, const char *arg) {
  char key[2] = { (char)(choice - MIN_CHOICE_ID), '\0' };

  // pull out the data
  OLC_EXT_DATA *edata = hashGet(ext->opt_hash, key);
  int          retval = FALSE;

  // is it C data or Python data?
  if(edata->type == OLCEXT_C)
    retval = edata->parse_exec(sock, data, arg);
  else if(ext->borrow_py != NULL) {
    PyObject *pyret = 
      PyObject_CallFunction(edata->pyparse, "Os", ext->borrow_py(data), arg);
    if(pyret == NULL)
      log_pyerr("Error running Python OLC exention parse function: %s", key);
    else if(PyObject_IsTrue(pyret))
      retval = TRUE;
    Py_XDECREF(pyret);
  }

  // was it valid?
  return retval;
}

void extenderToProto(OLC_EXTENDER *ext, void *data, BUFFER *buf) {
  LIST           *keys = hashCollect(ext->opt_hash);
  char            *key = NULL;
  OLC_EXT_DATA  *edata = NULL;

  // display each menu item alphabetically
  listSortWith(keys, strcasecmp);
  LIST_ITERATOR *key_i = newListIterator(keys);
  ITERATE_LIST(key, key_i) {
    edata = hashGet(ext->opt_hash, key);

    // is it C data?
    if(edata->type == OLCEXT_C) {
      if(edata->to_proto != NULL)
	edata->to_proto(data, buf);
    }
    // is it Python data?
    else if(ext->borrow_py != NULL) {
      if(edata->pytopr != NULL && edata->pytopr != Py_None) {
	PyObject *ret = PyObject_CallFunction(edata->pytopr, "O",
					      ext->borrow_py(data));
	if(ret == NULL)
	  log_pyerr("Error running Python OLC to_proto function: %s", key);
	else
	  bufferCat(buf, PyString_AsString(ret));
	Py_XDECREF(ret);
      }
    }
  } deleteListIterator(key_i);

  // free up our garbage
  deleteListWith(keys, free);
}

void extenderFromProto(OLC_EXTENDER *ext, void *data) {
  LIST           *keys = hashCollect(ext->opt_hash);
  char            *key = NULL;
  OLC_EXT_DATA  *edata = NULL;

  // display each menu item alphabetically
  listSortWith(keys, strcasecmp);
  LIST_ITERATOR *key_i = newListIterator(keys);
  ITERATE_LIST(key, key_i) {
    edata = hashGet(ext->opt_hash, key);

    // is it C data?
    if(edata->type == OLCEXT_C) {
      if(edata->from_proto != NULL)
	edata->from_proto(data);
    }
    // is it Python data?
    else if(ext->borrow_py != NULL) {
      if(edata->pyfrompr != NULL && edata->pyfrompr != Py_None) {
	PyObject *ret = PyObject_CallFunction(edata->pyfrompr, "O",
					      ext->borrow_py(data));
	if(ret == NULL)
	  log_pyerr("Error running Python OLC from_proto function: %s", key);
	Py_XDECREF(ret);
      }
    }
  } deleteListIterator(key_i);

  // free up our garbage
  deleteListWith(keys, free);
}

void gen_register_opt(OLC_EXTENDER *ext, char opt, OLC_EXT_DATA *data) {
  char key[2] = { opt, '\0' };

  // do we already have this registered? If so, clear it
  if(hashIn(ext->opt_hash, key))
    deleteOLCExt(hashRemove(ext->opt_hash, key));
  hashPut(ext->opt_hash, key, data);
}

void extenderRegisterOpt(OLC_EXTENDER *ext, char opt, 
			 void *menu, void *choice, void *parse, 
			 void *from_proto, void *to_proto) {
  gen_register_opt(ext, opt, newOLCExt(menu,choice,parse,from_proto,to_proto));
}

//
// The same, but takes Python functions instead of C function
void extenderRegisterPyOpt(OLC_EXTENDER *ext, char opt, 
			   void *menu, void *choice, void *parse,
			   void *from_proto, void *to_proto) {
  gen_register_opt(ext,opt,newPyOLCExt(menu,choice,parse,from_proto,to_proto));
}