TinyMAZE/
TinyMAZE/config/
TinyMAZE/doc/
TinyMAZE/run/msgs/
TinyMAZE/src/
TinyMAZE/src/db/
TinyMAZE/src/ident/
TinyMAZE/src/io/
TinyMAZE/src/prog/
TinyMAZE/src/softcode/
TinyMAZE/src/util/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "db.h"
#include "filelist.h"
#include "externs.h"

static OBJ **get_eventrefs(OBJ *obj)
{
  OBJ **list = NULL, *o;
  int ctr = 0;
  FILE *fp;
  char filename[4096];
  char buf[4096];

  if(!obj)
  {
    list = (OBJ **)stack_alloc(sizeof(OBJ *), 0, 0);
    list[0] = NULL;
    return(list);
  }

  sprintf(filename, "eventrefs/%d", obj->dbref);

  if(!(fp = fopen(filename, "r")))
  {
    list = (OBJ **)stack_alloc(sizeof(OBJ *), 0, 0);
    list[0] = NULL;
    return(list);
  }

  while(fgets(buf, sizeof(buf), fp))
  {
    if(!(o = find_object(atoi(buf))))
      continue;
    if(!ctr)
      list = (OBJ **)stack_alloc(sizeof(OBJ), 0, 0);
    else
      list = (OBJ **)stack_realloc_tmp(list, sizeof(OBJ *)*(ctr+2));
    list[ctr++] = o;
  }
  fclose(fp);

  list[ctr] = NULL;

  return(list);
}

static void put_eventrefs(OBJ *obj, OBJ **list)
{
  FILE *fp;
  char filename[4096];
  int i;

  if(!obj)
    return;

  sprintf(filename, "eventrefs/%d", obj->dbref);

  if(!(fp = fopen(filename, "w")))
  {
    log_error(tprintf("Couldn't open \"%s\" for writing!", filename));
    return;
  }

  for(i = 0;list[i];i++)
    putref(fp, list[i]->dbref);

  fclose(fp);

  if(!*list)
    unlink(filename);
}

static void do_eventref_add(OBJ *player, char *arg)
{
  OBJ *obj, *ref;
  char *p;

  if(!power(player, POW_DB))
  {
    notify(player, perm_denied());
    return;
  }

  if(!(p = strchr(arg, ',')))
  {
    notify(player, "Usage: +eventref add=<object>,<reference>");
    return;
  }

  *p++ = '\0';

  if(!(obj = match_object(player, arg, NOTYPE)))
  {
    notify(player, no_match(arg));
    return;
  }

  if(!(ref = match_object(player, p, NOTYPE)))
  {
    notify(player, no_match(p));
    return;
  }

  if(!controls(player, obj, POW_MODIFY))
  {
    notify(player, perm_denied());
    return;
  }

  add_event_ref(obj, ref);

  notify(player, tprintf("Added reference %s to %s",
    unparse_object(player, ref), unparse_object(player, obj)));
}

static void do_eventref_check(OBJ *player, char *arg)
{
  OBJ *obj, *ref;
  char *p;
  int answer;

  if(!power(player, POW_DB))
  {
    notify(player, perm_denied());
    return;
  }

  if(!(p = strchr(arg, ',')))
  {
    notify(player, "Usage: +eventref check=<object>,<reference>");
    return;
  }

  *p++ = '\0';

  if(!(obj = match_object(player, arg, NOTYPE)))
  {
    notify(player, no_match(arg));
    return;
  }

  if(!(ref = match_object(player, p, NOTYPE)))
  {
    notify(player, no_match(p));
    return;
  }

  if(!controls(player, obj, POW_EXAMINE))
  {
    notify(player, perm_denied());
    return;
  }

  answer = chk_event_ref(obj, ref);

  notify(player, tprintf("Is %s event referenced to %s? %s",
    unparse_object(player, ref), unparse_object(player, obj),
    (answer)?"Yes":"No"));
}

static void do_eventref_delete(OBJ *player, char *arg)
{
  OBJ *obj, *ref;
  char *p;

  if(!power(player, POW_DB))
  {
    notify(player, perm_denied());
    return;
  }

  if(!(p = strchr(arg, ',')))
  {
    notify(player, "Usage: +eventref delete=<object>,<reference>");
    return;
  }

  *p++ = '\0';

  if(!(obj = match_object(player, arg, NOTYPE)))
  {
    notify(player, no_match(arg));
    return;
  }

  if(!(ref = match_object(player, p, NOTYPE)))
  {
    notify(player, no_match(p));
    return;
  }

  if(!controls(player, obj, POW_MODIFY))
  {
    notify(player, perm_denied());
    return;
  }

  if(!chk_event_ref(obj, ref))
  {
    notify(player, tprintf("%s isn't an event reference of %s.",
      unparse_object(player, ref), unparse_object(player, obj)));
    return;
  }

  del_event_ref(obj, ref);

  notify(player, tprintf("Deleted reference %s from %s.",
    unparse_object(player, ref), unparse_object(player, obj)));
}

static int list_event_refs(OBJ *player, FILELIST *flist, int type, char *str)
{
  FILELIST *f, *fprev = NULL, *fnext;
  int ctr = 0;
  OBJ *o;

  for(f = flist;f;f = fnext)
  {
    fnext = f->next;

    o = find_object(atoi(f->name));

    if(Typeof(o) == type)
    {
      if(!ctr++)
        notify(player, str);
      notify(player, tprintf("  %s", unparse_object(player, o)));

/* Continuously shrink the list so subsequent calls go faster */
      if(fprev)
        fprev->next = fnext;
      else
        flist = fnext;
    }
    else
      fprev = f;
  }

  return(ctr);
}

static void do_eventref_list(OBJ *player, char *arg)
{
  OBJ **list, *obj = NULL;
  int i, ctr = 0;
  FILELIST *flist;

  if(!power(player, POW_DB))
  {
    notify(player, perm_denied());
    return;
  }

  if(*arg)
  {
    if(!(obj = match_object(player, arg, NOTYPE)))
    {
      notify(player, no_match(arg));
      return;
    }

    if(!controls(player, obj, POW_EXAMINE))
    {
      notify(player, perm_denied());
      return;
    }

    list = get_eventrefs(obj);
    if(!*list)
    {
      notify(player, tprintf("%s has no event references.",
        unparse_object(player, obj)));
      return;
    }

    notify(player, tprintf("|+W|Event references of %s|+W|:",
      unparse_object(player, obj)));

    for(i = 0;list[i];++i)
    {
      notify(player, unparse_object(player, list[i]));
      ctr++;
    }

    notify(player, tprintf("|+C|%d |+B|total event reference%s",
      ctr, check_plural(ctr, "", "s")));

    return;
  }

  if(!(flist = get_filelist("eventrefs", 0)))
  {
    notify(player, "There are no objects with event references.");
    return;
  }

  notify(player, "|+W|Objects with event references:");

  ctr += list_event_refs(player, flist, TYPE_PLAYER, "|+B|Players|+W|:");
  ctr += list_event_refs(player, flist, TYPE_THING, "|+B|Things|+W|:");
  ctr += list_event_refs(player, flist, TYPE_ROOM, "|+B|Rooms|+W|:");
  ctr += list_event_refs(player, flist, TYPE_EXIT, "|+B|Exits|+W|:");

  notify(player,
    tprintf("|+B|There %s |+C|%d |+B|object%s with event references.",
    check_plural(ctr, "is", "are"), ctr, check_plural(ctr, "", "s")));
}

void do_eventref(OBJ *player, char *arg1, char *arg2)
{
  SUBCOMMAND *sc, commands[] =
  {
    { "add",    do_eventref_add,    0 },
    { "check",  do_eventref_check,  0 },
    { "delete", do_eventref_delete, 0 },
    { "list",   do_eventref_list,   0 },
    { NULL }
  };

  if(!(sc = subcommand_match(player, arg1, commands, NULL)))
    subcommand_print(player, "+eventref", commands);
  else
    sc->func(player, arg2);
}

int chk_event_ref(OBJ *obj, OBJ *ref)
{
  OBJ **list;
  int i;

  if(!obj || !ref)
    return(0);

  list = get_eventrefs(obj);

  for(i = 0;list[i];++i)
    if(list[i] == ref)
      return(1);

  return(0);
}

void add_event_ref(OBJ *obj, OBJ *ref)
{
  OBJ **oldlist, **newlist;
  int i;

  if(!obj || !ref)
    return;

  oldlist = get_eventrefs(obj);

  for(i = 0;oldlist[i];i++)
    if(oldlist[i] == ref)
      return;

  newlist = (OBJ **)stack_alloc(sizeof(OBJ *)*(i+2), 0, 0);
  memcpy(newlist, oldlist, sizeof(OBJ *)*i);
  newlist[i] = ref;
  newlist[i+1] = NULL;

  put_eventrefs(obj, newlist);
}

static void _del_event_ref(OBJ *obj, OBJ *ref)
{
  OBJ **list;
  int i, j;

  if(!obj || !ref)
    return;

  list = get_eventrefs(obj);

  for(i = 0;list[i];i++)
    if(list[i] == ref)
      break;

  if(!list[i])
    return;

  for(j = i+1;list[j];++i, ++j)
    list[i] = list[j];
  list[i] = NULL;

  put_eventrefs(obj, list);
}

void del_event_ref(OBJ *obj, OBJ *ref)
{
  FILELIST *flist;

  if(obj)
  {
    if(ref)   /* Delete 1 reference */
      _del_event_ref(obj, ref);
    else      /* Delete all references */
      unlink(tprintf("eventrefs/%d", obj->dbref));

    return;
  }

  if(ref)     /* Delete reference from all objects */
    for(flist = get_filelist("eventrefs", 0);flist;flist = flist->next)
      if(!(flist->flags & FILE_DIRECTORY))
        _del_event_ref(find_object(atoi(flist->name)), ref);
}