#include "config.h"
#include "object.h"
#include "instr.h"
#include "construct.h"
#include "compile.h"
#include "interp.h"
#include "operproto.h"
#include "interface.h"
#include "dbhandle.h"
#include "globals.h"
#include "cache.h"

int s_random(struct object *caller, struct object *obj, struct object
             *player, struct var_stack **rts) {
  struct var tmp;

  if (pop(&tmp,rts,obj)) return 1;
  if (tmp.type!=NUM_ARGS) {
    clear_var(&tmp);
    return 1;
  }
  if (tmp.value.num!=1) return 1;
  if (popint(&tmp,rts,obj)) return 1;
  if (tmp.value.integer<=0) {
    tmp.value.integer=0;
    push(&tmp,rts);
    return 0;
  }
  tmp.value.integer=(rand() % tmp.value.integer);
  push(&tmp,rts);
  return 0;
}

int s_time(struct object *caller, struct object *obj, struct object
           *player, struct var_stack **rts) {
  struct var tmp;

  if (pop(&tmp,rts,obj)) return 1;
  if (tmp.type!=NUM_ARGS) {
    clear_var(&tmp);
    return 1;
  }
  if (tmp.value.num!=0) return 1;
  tmp.type=INTEGER;
  tmp.value.integer=now_time;
  push(&tmp,rts);
  return 0;
}

int s_mktime(struct object *caller, struct object *obj, struct object
             *player, struct var_stack **rts) {
  struct var tmp;
  time_t int_time;
  char *buf;

  if (pop(&tmp,rts,obj)) return 1;
  if (tmp.type!=NUM_ARGS) {
    clear_var(&tmp);
    return 1;
  }
  if (tmp.value.num!=1) return 1;
  if (popint(&tmp,rts,obj)) return 1;
  int_time=int2time(tmp.value.integer);
  buf=ctime(&int_time);
  if (!buf) {
    tmp.type=INTEGER;
    tmp.value.integer=0;
    push(&tmp,rts);
    return 0;
  }
  tmp.type=STRING;
  tmp.value.string=buf;
  push(&tmp,rts);
  return 0;
}

int s_typeof(struct object *caller, struct object *obj, struct object
             *player, struct var_stack **rts) {
  struct var tmp;
  int result;

  if (pop(&tmp,rts,obj)) return 1;
  if (tmp.type!=NUM_ARGS) {
    clear_var(&tmp);
    return 1;
  }
  if (tmp.value.num!=1) return 1;
  if (pop(&tmp,rts,obj)) return 1;
  result=tmp.type;
  clear_var(&tmp);
  tmp.type=INTEGER;
  tmp.value.integer=result;
  push(&tmp,rts);
  return 0;
}

int s_command(struct object *caller, struct object *obj, struct object
              *player, struct var_stack **rts) {
  struct var tmp;

  if (pop(&tmp,rts,obj)) return 1;
  if (tmp.type!=NUM_ARGS) {
    clear_var(&tmp);
    return 1;
  }
  if (tmp.value.num!=1) return 1;
  if (pop(&tmp,rts,obj)) return 1;
  if (tmp.type==INTEGER && tmp.value.integer==0) {
    tmp.type=STRING;
    tmp.value.string=copy_string("");
  }
  if (tmp.type!=STRING) {
    clear_var(&tmp);
    return 1;
  }
  queue_command(obj,tmp.value.string);
  clear_var(&tmp);
  tmp.type=INTEGER;
  tmp.value.integer=0;
  push (&tmp,rts);
  return 0;
}

int s_sysctl(struct object *caller, struct object *obj, struct object *player,
             struct var_stack **rts) {
  struct var tmp;
  struct object *rcv;
  unsigned int old_num_locals;
  struct var *old_locals;
  struct fns *tmp_fns;
  struct var_stack *arg_stack;
  long loop;
  char *buf,*name;
  int num_args;
  struct alarmq *curr_alarmq;
  struct destq *curr_destq;
  struct cmdq *curr_cmdq;

  if (pop(&tmp,rts,obj)) return 1;
  if (tmp.type!=NUM_ARGS) {
    clear_var(&tmp);
    return 1;
  }
  if (tmp.value.num<1) {
    clear_var(&tmp);
    return 1;
  }
  num_args=tmp.value.num-1;
  if (pop(&tmp,rts,obj)) return 1;
  if (tmp.type!=INTEGER) {
    clear_var(&tmp);
    return 1;
  }
  if (tmp.value.integer<0 || tmp.value.integer>9 || (!(obj->flags & PRIV))) {
    tmp.value.integer=1;
    push(&tmp,rts);
    return 0;
  }
  if (player)
    rcv=player;
  else
    rcv=obj;
  switch (tmp.value.integer) {
    case 0:
      if (num_args) return 1;
      if (player) {
        buf=MALLOC(strlen(player->parent->pathname)+strlen(obj->parent->
                   pathname)+(2*ITOA_BUFSIZ)+48);
        sprintf(buf," sysctl: player %s#%ld object %s#%ld attempting "
                "save",player->parent->pathname,
                (long) player->refno,obj->parent->pathname,
                (long) obj->refno);
      } else {
        buf=MALLOC(strlen(obj->parent->pathname)+ITOA_BUFSIZ+39);
        sprintf(buf," sysctl: object %s#%ld attempting save",
                obj->parent->pathname,(long) obj->refno);
      }
      log_sysmsg(buf);
      FREE(buf);
      tmp.value.integer=save_db(save_name);
      push(&tmp,rts);
      if (!tmp.value.integer)
        log_sysmsg(" sysctl: save complete");
      else
        log_sysmsg(" sysctl: save failed");
      return 0;
      break;
    case 1:
      if (num_args) return 1;
      if (player) {
        buf=MALLOC(strlen(player->parent->pathname)+strlen(obj->parent->
                   pathname)+(2*ITOA_BUFSIZ)+48);
        sprintf(buf," sysctl: player %s#%ld object %s#%ld attempting "
                "shutdown",player->parent->pathname,
                (long) player->refno,obj->parent->pathname,
                (long) obj->refno);
      } else {
        buf=MALLOC(strlen(obj->parent->pathname)+ITOA_BUFSIZ+39);
        sprintf(buf," sysctl: object %s#%ld attempting shutdown",
                obj->parent->pathname,(long) obj->refno);
      }
      log_sysmsg(buf);
      FREE(buf);
      tmp.value.integer=save_db(save_name);
      if (tmp.value.integer) {
        log_sysmsg(" sysctl: shutdown failed");
        push(&tmp,rts);
        return 0;
      }
      shutdown_interface();
      log_sysmsg(" sysctl: shutdown complete");
      exit(0);
      break;
    case 2:
      if (num_args) return 1;
      if (player) {
        buf=MALLOC(strlen(player->parent->pathname)+strlen(obj->parent->
                   pathname)+(2*ITOA_BUFSIZ)+48);
        sprintf(buf," sysctl: player %s#%ld object %s#%ld attempting "
                "panic",player->parent->pathname,
                (long) player->refno,obj->parent->pathname,
                (long) obj->refno);
      } else {
        buf=MALLOC(strlen(obj->parent->pathname)+ITOA_BUFSIZ+39);
        sprintf(buf," sysctl: object %s#%ld attempting panic",
                obj->parent->pathname,(long) obj->refno);
      }
      log_sysmsg(buf);
      FREE(buf);
      tmp.value.integer=save_db(panic_name);
      if (tmp.value.integer) {
        push(&tmp,rts);
        log_sysmsg(" sysctl: panic failed");
        return 0;
      }
      shutdown_interface();
      log_sysmsg(" sysctl: panic complete");
      exit(-1);
      break;
    case 3:
      if (num_args) return 1;
      tmp_fns=find_fns("listen",rcv);
      if (!tmp_fns) {
        tmp.value.integer=0;
        push(&tmp,rts);
        return 0;
      }
      curr_alarmq=alarm_list;
      old_locals=locals;
      old_num_locals=num_locals;
      while (curr_alarmq) {
        buf=MALLOC(strlen(curr_alarmq->funcname)+2*ITOA_BUFSIZ+4);
        sprintf(buf,"%ld %s %ld\n",(long) curr_alarmq->obj->refno,
                curr_alarmq->funcname,(long) curr_alarmq->delay);
        tmp.type=STRING;
        tmp.value.string=buf;
        arg_stack=NULL;
        pushnocopy(&tmp,&arg_stack);
        interp(obj,rcv,player,&arg_stack,tmp_fns);
        free_stack(&arg_stack);
        curr_alarmq=curr_alarmq->next;
      }
      locals=old_locals;
      num_locals=old_num_locals;
      tmp.type=INTEGER;
      tmp.value.integer=0;
      push(&tmp,rts);
      return 0;
      break;
    case 4:
      if (num_args) return 1;
      tmp_fns=find_fns("listen",rcv);
      if (!tmp_fns) {
        tmp.value.integer=0;
        push(&tmp,rts);
        return 0;
      }
      curr_cmdq=cmd_head;
      old_locals=locals;
      old_num_locals=num_locals;
      while (curr_cmdq) {
        buf=MALLOC(strlen(curr_cmdq->cmd)+ITOA_BUFSIZ+3);
        sprintf(buf,"%ld %s\n",curr_cmdq->cmd,(long) curr_cmdq->obj->refno);
        tmp.type=STRING;
        tmp.value.string=buf;
        arg_stack=NULL;
        pushnocopy(&tmp,&arg_stack);
        interp(obj,rcv,player,&arg_stack,tmp_fns);
        free_stack(&arg_stack);
        curr_cmdq=curr_cmdq->next;
      }
      locals=old_locals;
      num_locals=old_num_locals;
      tmp.type=INTEGER;
      tmp.value.integer=0;
      push(&tmp,rts);
      return 0;
      break;
    case 5:
      if (num_args) return 1;
      tmp_fns=find_fns("listen",rcv);
      if (!tmp_fns) {
        tmp.value.integer=0;
        push(&tmp,rts);
        return 0;
      }
      old_locals=locals;
      old_num_locals=num_locals;
      curr_destq=dest_list;
      while (curr_destq) {
        buf=MALLOC(ITOA_BUFSIZ+2);
        sprintf(buf,"%ld\n",(long) curr_destq->obj->refno);
        tmp.type=STRING;
        tmp.value.string=buf;
        arg_stack=NULL;
        pushnocopy(&tmp,&arg_stack);
        interp(obj,rcv,player,&arg_stack,tmp_fns);
        free_stack(&arg_stack);
        curr_destq=curr_destq->next;
      }
      locals=old_locals;
      num_locals=old_num_locals;
      tmp.type=INTEGER;
      tmp.value.integer=0;
      push(&tmp,rts);
      return 0;
      break;
    default:
      return 1;
      break;
  }
}