/* clearq.c */

#include "config.h"
#include "object.h"
#include "dbhandle.h"
#include "construct.h"
#include "interp.h"
#include "cache.h"
#include "globals.h"
#include "edit.h"

/* functions for clearing the queues */

void handle_destruct() {
  struct destq *curr_dest;
  struct object *prev_obj,*curr_obj,*next_obj;
  struct proto *prev_proto,*curr_proto;
  signed long num_globals,loop;
  struct ref_list *curr_ref;
  struct verb *next_verb,*curr_verb;
  struct cmdq *curr_cmd,*prev_cmd,*tmp_cmd;
  struct alarmq *curr_alarm,*prev_alarm;

  while (dest_list) {
    curr_dest=dest_list;
    dest_list=dest_list->next;
    curr_cmd=cmd_head;
    prev_cmd=NULL;
    if (curr_dest->obj->devnum!=(-1))
      immediate_disconnect(curr_dest->obj->devnum);
    while (curr_cmd) {
      if (curr_cmd->obj==curr_dest->obj) {
        if (prev_cmd)
          prev_cmd->next=curr_cmd->next;
        if (cmd_head==curr_cmd)
          cmd_head=curr_cmd->next;
        if (cmd_tail==curr_cmd)
          cmd_tail=prev_cmd;
        tmp_cmd=curr_cmd;
        curr_cmd=curr_cmd->next;
        FREE(tmp_cmd);
      } else {
        prev_cmd=curr_cmd;
        curr_cmd=curr_cmd->next;
      }
    }
    curr_alarm=alarm_list;
    prev_alarm=NULL;
    while (curr_alarm) {
      if (curr_alarm->obj==curr_dest->obj) {
        if (prev_alarm)
          prev_alarm->next=curr_alarm->next;
        else
          alarm_list=curr_alarm->next;
        FREE(curr_alarm->funcname);
        FREE(curr_alarm);
        if (prev_alarm)
          curr_alarm=prev_alarm->next;
        else
          curr_alarm=alarm_list;
      } else {
        prev_alarm=curr_alarm;
        curr_alarm=curr_alarm->next;
      }
    }
    num_globals=curr_dest->obj->parent->funcs->num_globals;
    if (curr_dest->obj->flags & PROTOTYPE) {
      curr_obj=curr_dest->obj->next_child;
      while (curr_obj) {
        queue_for_destruct(curr_obj);
        curr_obj=curr_obj->next_child;
      }
      handle_destruct();
      free_code(curr_dest->obj->parent->funcs);
      prev_proto=ref_to_obj(0)->parent;
      curr_proto=prev_proto->next_proto;
      while (curr_proto) {
        if (curr_proto==curr_dest->obj->parent) {
          prev_proto->next_proto=curr_proto->next_proto;
          break;
        }
        prev_proto=curr_proto;
        curr_proto=curr_proto->next_proto;
      }
    } else {
      prev_obj=curr_dest->obj->parent->proto_obj;
      curr_obj=prev_obj->next_child;
      while (curr_obj) {
        if (curr_obj==curr_dest->obj) {
          prev_obj->next_child=curr_dest->obj->next_child;
          break;
        }
        prev_obj=curr_obj;
        curr_obj=curr_obj->next_child;
      }
    }
    load_data(curr_dest->obj);
    loop=0;
    while (loop<num_globals) {
      clear_global_var(curr_dest->obj,loop);
      loop++;
    }
    curr_ref=curr_dest->obj->refd_by;
    while (curr_ref) {
      load_data(curr_ref->ref_obj);
      curr_ref->ref_obj->obj_state=DIRTY;
      curr_ref->ref_obj->globals[curr_ref->ref_num].type=INTEGER;
      curr_ref->ref_obj->globals[curr_ref->ref_num].value.integer=0;
      curr_ref=curr_ref->next;
    }
    unload_object(curr_dest->obj);
    if (curr_dest->obj->flags & PROTOTYPE)
      FREE(curr_dest->obj->parent);
    curr_obj=curr_dest->obj->contents;
    while (curr_obj) {
      curr_obj->location=curr_dest->obj->location;
      next_obj=curr_obj->next_object;
      if (curr_obj->location) {
        curr_obj->next_object=curr_obj->location->contents;
        curr_obj->location->contents=curr_obj;
      } else
        curr_obj->next_object=NULL;
      curr_obj=next_obj;
    }
    curr_dest->obj->contents=NULL;
    if (curr_dest->obj->location) {
      prev_obj=NULL;
      curr_obj=curr_dest->obj->location->contents;
      while (curr_obj) {
        if (curr_obj==curr_dest->obj) {
          if (prev_obj)
            prev_obj->next_object=curr_obj->next_object;
          else
            curr_dest->obj->location->contents=curr_obj->next_object;
          break;
        }
        prev_obj=curr_obj;
        curr_obj=curr_obj->next_object;
      }
    }
    curr_dest->obj->location=NULL;
    if (curr_dest->obj->flags & IN_EDITOR)
      remove_from_edit(curr_dest->obj);
    if (curr_dest->obj->flags & CONNECTED)
      disconnect_device(curr_dest->obj);
    curr_verb=curr_dest->obj->verb_list;
    while (curr_verb) {
      FREE(curr_verb->verb_name);
      FREE(curr_verb->function);
      next_verb=curr_verb->next;
      FREE(curr_verb);
      curr_verb=next_verb;
    }
    curr_dest->obj->devnum=-1;
    curr_dest->obj->flags=GARBAGE;
    curr_dest->obj->parent=NULL;
    curr_dest->obj->next_child=NULL;
    curr_dest->obj->location=NULL;
    curr_dest->obj->contents=NULL;
    curr_dest->obj->next_object=free_obj_list;
    curr_dest->obj->globals=NULL;
    curr_dest->obj->refd_by=NULL;
    curr_dest->obj->verb_list=NULL;
    free_obj_list=curr_dest->obj;
    FREE(curr_dest);
  }
}

void handle_alarm() {
  struct alarmq *curr_alarm;
  struct fns *func;
  struct var tmp;
  struct var_stack *rts;

  while (alarm_list) {
    if (alarm_list->delay>now_time) return;
    curr_alarm=alarm_list;
    alarm_list=alarm_list->next;
    func=find_fns(curr_alarm->funcname,curr_alarm->obj);

#ifdef CYCLE_SOFT_MAX
    soft_cycles=0;
#endif /* CYCLE_SOFT_MAX */

    if (func) {
      rts=NULL;
      tmp.type=NUM_ARGS;
      tmp.value.num=0;
      push(&tmp,&rts);
      interp(NULL,curr_alarm->obj,NULL,&rts,func);
      free_stack(&rts);
    }
    FREE(curr_alarm->funcname);
    FREE(curr_alarm);
    handle_destruct();
  }
}

struct verb *find_vname(struct object *obj, char *vname, int is_second_run) {
  struct verb *curr;

  if (is_second_run)
    curr=obj->parent->proto_obj->verb_list;
  else
    curr=obj->verb_list;
  while (curr) {
    if (!strcmp(curr->verb_name,vname)) return curr;
    curr=curr->next;
  }
  return NULL;
}

int find_verb(struct object *player, struct object *obj, char *vname, char
              *cmd, signed long disp) {
  struct verb *curr_verb;
  struct fns *func;
  struct var_stack *rts;
  struct var tmp;
  int is_match,is_second_run;
  char *string,*cvn;

  if (!obj) return 0;
  if ((obj->flags & INTERACTIVE) && player!=obj) return 0;
  curr_verb=obj->verb_list;
  is_second_run=0;
  if (!curr_verb) {
    curr_verb=obj->parent->proto_obj->verb_list;
    is_second_run=1;
  }
  while (curr_verb) {
    is_match=0;
    cvn=copy_string(curr_verb->verb_name);
    if (curr_verb->is_xverb) {
      if ((!strncmp(curr_verb->verb_name,cmd,strlen(curr_verb->verb_name)))
          || (!(*(curr_verb->verb_name)))) {
        rts=NULL;
        func=find_fns(curr_verb->function,obj);
        if (func) {
          tmp.type=STRING;
          tmp.value.string=&(cmd[strlen(curr_verb->verb_name)]);
          if ((*(tmp.value.string))=='\0') {
            tmp.type=INTEGER;
            tmp.value.integer=0;
          }
          push(&tmp,&rts);
          tmp.type=NUM_ARGS;
          tmp.value.num=1;
          push(&tmp,&rts);
          if (!interp(NULL,obj,player,&rts,func)) {
            if (!pop(&tmp,&rts,obj)) {
              if (tmp.type!=INTEGER || tmp.value.integer!=0)
                is_match=1;
              clear_var(&tmp);
            }
          }
          free_stack(&rts);
        }
      }
    } else {
      if (!strcmp(curr_verb->verb_name,vname)) {
        rts=NULL;
        func=find_fns(curr_verb->function,obj);
        if (func) {
          tmp.type=STRING;
          tmp.value.string=&(cmd[disp]);
          if ((*(tmp.value.string))=='\0') {
            tmp.type=INTEGER;
            tmp.value.integer=0;
          }
          push(&tmp,&rts);
          tmp.type=NUM_ARGS;
          tmp.value.num=1;
          push(&tmp,&rts);
          if (!interp(NULL,obj,player,&rts,func)) {
            if (!pop(&tmp,&rts,obj)) {
              if (tmp.type!=INTEGER || tmp.value.integer!=0)
                is_match=1;
              clear_var(&tmp);
            }
          }
          free_stack(&rts);
        }
      }
    }
    if (is_match) {
      FREE(cvn);
      return 1;
    }
    curr_verb=find_vname(obj,cvn,is_second_run);
    FREE(cvn);
    if (curr_verb) curr_verb=curr_verb->next;
    if (!curr_verb)
      if (!(obj->flags & PROTOTYPE) && !is_second_run) {
        is_second_run=1;
        curr_verb=obj->parent->proto_obj->verb_list;
      }
  }
  return 0;
}

void handle_command() {
  struct cmdq *curr;
  char *vname;
  signed long begin_char,count,loop;
  struct object *curr_obj;
  int done;

  while (cmd_head) {
    curr=cmd_head;
    cmd_head=curr->next;
    if (!cmd_head) cmd_tail=NULL;

#ifdef CYCLE_SOFT_MAX
    soft_cycles=0;
#endif /* CYCLE_SOFT_MAX */

    done=0;
    begin_char=0;
    while (curr->cmd[begin_char]==' ') begin_char++;
    count=begin_char;
    while (curr->cmd[count]!='\0' && curr->cmd[count]!=' ') count++;
    vname=MALLOC(count-begin_char+1);
    loop=begin_char;
    while (loop<count) {
      vname[loop-begin_char]=curr->cmd[loop];
      loop++;
    }
    vname[loop]='\0';
    while (curr->cmd[count]==' ') count++;
    if (find_verb(curr->obj,curr->obj->location,vname,curr->cmd,count)) done=1;
    if (curr->obj->location) {
      curr_obj=curr->obj->location->contents;
      while (curr_obj && !done) {
        if (curr_obj!=curr->obj)
          if (find_verb(curr->obj,curr_obj,vname,curr->cmd,count)) done=1;
        curr_obj=curr_obj->next_object;
      }
    }
    curr_obj=curr->obj->contents;
    while (curr_obj && !done) {
      if (find_verb(curr->obj,curr_obj,vname,curr->cmd,count)) done=1;
      curr_obj=curr_obj->next_object;
    }
    if (!done) find_verb(curr->obj,curr->obj,vname,curr->cmd,count);
    FREE(vname);
    FREE(curr->cmd);
    FREE(curr);
    handle_destruct();
  }
}