/* look at ../docs/COPYING for copyright */
#include "strings.h"
#include "db.h"
#include "config.h"
#include "externs.h"
#include "interface.h"
#include "params.h"

const char *trash_braces(const char *what)
{
  char buff[BUFFER_LEN];
  if(*what == '{' && what[strlen(what) -1] == '}') {
    strcpy(buff, what+1);
    buff[strlen(buff) -1] = '\0';
  }
  else
    return what;
  return buff;
}

char *awptr[10];
struct das {
  dbref who;
  dbref owner;			/* the owner of who... don't execut *
				 * the command if this isn't the same, *
				 * because we might have been recycled. */
  char *command;		/* command.. free this when we're done. */
  dbref trigger;		/* who made us go? */
  char *awptr[10];		/* the %[0-9]'s */
  struct das *next;		/* the next thing in our LinkedList */
};

struct das *que=NULL;
int gotio;			/* flag that game.c sets when we get *
				 * some io in one our sockets... signals *
				 * us to stop. */
#define MINEX 5			/* how many we have to execute minimum */
int que_check() { return (que!=NULL); } /* for interface.c. we check
					   the queue to see if there's
					   anything in there. if there
					   isn't, we wait a whole second
					   for more input. Otherwise,
					   there's stuff in tue queue,
					   so we just quick check input,
					   and then come right back and
					   process some more queued
					   commands. */
int sofar;
static void freer(struct das *what)
{
  register int i;
  if(what->command) free(what->command);
  for(i=0;i<10;i++)
    if(what->awptr[i]) free(what->awptr[i]);
  free(what);
}

static void check_a_wait()
{
  struct das *cur;
  
  if(que == NULL)			/* no junk in the queue, quit */
    return;
  cur = que;
  que = que->next;
  if(!is_ok(cur->who)) {	/* preblie been recycled */
    if(is_ok(cur->owner)) {	/* we HOPE the owner's ok */
      sprintf(buf,"Object #%d no longer exists.");
      notify(cur->owner,buf);
    } else {
      sprintf(buf,"CWAITS: weird object #%d owned by #%d.",
	      cur->who,cur->owner);
      log_status(buf);
    }
    freer(cur);
    return;
  }
  if(OWNER(cur->who) != cur->owner) { /* aack, ownership change! */
    sprintf(buf,"Object %s halted... %s now owns it.",
	    unparse_object(OWNER(cur->who),cur->who), /* old owner should know
						       * what we're talkin bout
						       * even if can't see it..
						       */
	    unparse_object(cur->owner,OWNER(cur->who)));
    notify(cur->owner,buf);
    freer(cur);
    return;
  }

  if(Halted((cur->who))) {
    sprintf(buf,"Attempt to execute command by halted object %s.",
	    unparse_object(cur->owner,cur->who));
    notify(cur->owner,buf);
    freer(cur);
    return;
  }

  if(!payfor(cur->who, TRIGGER_COST)) {
    sprintf(buf, "%s went bankrupt.", unparse_object(cur->owner, cur->who));
    notify(cur->owner, buf);
    freer(cur);
    return;
  }

  if(!cur->command) {		/* hmm.. we can't really do anything. */
    freer(cur);
    return;
  }

  strcpy(buf, cur->command);
  {
    int x;
    for(x = 0; x < 10; x++) {
      awptr[x] = cur->awptr[x];
    }
    printf("Executing queue:%d, trig %d: %s\n", cur->who, cur->trigger,
	   buf);
    process_command(cur->who,
		    trash_braces(pronoun_substitute(cur->trigger,
						    buf, cur->who)),
		    cur->trigger,1);
    for(x = 0; x < 10; x++) {
      awptr[x] = NULL;
    }
  }
  /* Okay, okay, finally we get to execute a command. yay. */
  freer(cur);
}

void check_waits()
{
  sofar = 0;
  wc_every_sec();		/* for @waits.. do this first, so we can do
				 * those this time too. */
  while(que && (sofar++ < MINEX))
    check_a_wait();
}

void queue_command(dbref who, const char *what, dbref trigger)
{
  struct das *x;
  struct das *y;
  int z;
  x = malloc(sizeof(*x));
  x->who = who;
  x->owner = OWNER(who);
  x->command = alloc_string(what);
  x->trigger = trigger;
  for(z = 0; z < 10; z++)
    x->awptr[z] = alloc_string(wptr[z]);
  x->next = NULL;  /* this goes at the end.. ends don't have *
				 * a next. */
  if(!que)
    que = x;			/* well.. this is the only one in the que! */
  else {
    for(y = que; y->next; y = y->next);
    y->next = x;		/* stick it in at the end. */
  }
}

void trigobj(dbref who, const char *what, dbref trig)
{
  char buffer1[BUFFER_LEN+1];
  char *x;
  char *buffer = buffer1 + 1;
  int depth = 0;
  if(!what)
    return;
  if(!*what)
    return;

  if(!is_ok(who))
    return;
  if(Typeof(who) != TYPE_THING && Typeof(who) != TYPE_PLAYER)
    return;
  if(trig == NOTHING)
    trig = global_trigger;
  strcpy(buffer, what);
  for(x = buffer; *x; x++) {
    if(*x == '{') depth++;
    if(*x == '}') depth--;
    if(depth < 0) depth = 0;
    if(*x == ';' && depth == 0) {
      *x = '\0';
      queue_command(who, buffer, trig);
      what += strlen(buffer) + 1;
      strcpy(buffer, what);
      x = buffer - 1;
    }
  }
  if(*buffer != '\0')
    queue_command(who, buffer, trig);
}

void do_trigger(dbref player, const char *thing, const char *args)
{
  dbref who;
  int d;
  int depth;
  char *arg;
  char *p;
  char *x;
  arg = alloc_string(args);
  for(d = 0; d < 10; d++)
    wptr[d] = NULL;
  if(!index(thing,'/')) {
    notify(player, "No match.");
    return;
  }
  {
    strcpy(buf, thing);
    *index(buf,'/') = NULL;
    who = match_controlled(player, buf);
    if(who == NOTHING)
      return;
    x = 1 + index(buf, '\0');
    if(!get_property_class(who, x)) {
      notify(player,"No match.");
      return;
    }
  }
  if(!is_ok(who))
    return;
  d = 0;
  depth = 0;
  p = arg;
  while(arg && *arg) {
    if(*arg == ',' && depth == 0 && d <= 8) {
      *arg = '\0';
      wptr[d++] = alloc_string(trash_braces(p));
      p = arg+1;
    }
    if(*arg == '{')
      depth++;
    if(*arg == '}')
      depth--;
    arg++;
  }
  wptr[d] = alloc_string(p);
  trigobj(who, get_property_class(who,x), player);
  for(d = 0; d < 10; d++)
    if(wptr[d]) { free(wptr[d]); wptr[d]=NULL; }
}