/*  agtdbg.c-- Metacommand debugging output                */
/* Copyright 1996,97    Robert Masenten                    */
/*                                                         */
/* This is part of the source for AGiliTy: the (Mostly) Universal  */
/*       AGT Interpreter                                           */

/* At the moment, these routines all output straight to stderr. */
/* If you're porting this to a platform without I/O redirection, */
/*  then you'll either need to disable debugging or make sure that */
/*  stderr can be pointed to a file. */

#include <stdarg.h>
#include <ctype.h>
#include "agtread.h"

static void dbgprintf(const char *fmt,...)
{
  va_list vp;
  char buff[300];
  
  va_start(vp,fmt);
  vsprintf(buff,fmt,vp);
  va_end(vp);

  debugout(buff);
}


static void print_msg(descr_ptr dp)
{
  int j;
  descr_line *txt;

  txt=read_descr(dp.start,dp.size);
  if (txt!=NULL) 
    for(j=0;txt[j]!=NULL;j++)
      {
	if (j!=0) dbgprintf("\n");
	dbgprintf("%s",txt[j]);
      }
  free_descr(txt);
}



static char *getname(int inum)
/* Name should be 20 chars or less */
{
  if (inum==0) return rstrdup("* 0 *");
  return objname(inum);
}


extern integer dobj, iobj, actor;

void print_special_obj(int i)
     /* This is called by the disassembler in agtdbg.c */
     /* i=0 NOUN, 1 OBJECT, 2 NAME */
{
  int dval;
  char *s;
  switch(i)
    {
    case 0: dval=dobj; dbgprintf("NOUN"); break;
    case 1: dval=iobj; dbgprintf("OBJECT"); break;
    case 2: dval=actor; dbgprintf("NAME"); break;
    }
  if (dbgflagptr==NULL)  
    /* This determines whether we are linked with agtout or agil */
    return;
  s=getname(dval);
  dbgprintf("(=%d:%s)",dval,s);
  rfree(s);
}



#define printval(str,index,ptr) {dbgprintf("[%s%d",str,index);\
				 if (ptr==NULL) dbgprintf("]");\
				 else dbgprintf("=%ld]",(long)ptr[index]);}

int argout(int dtype, int dval, int optype)
{
  char *s;

  if (dtype&AGT_VAR) dtype=AGT_VAR;

  if ((optype&3)==1) /* variable */
    dtype=AGT_VAR;
  if (optype&2) {/* NOUN or OBJECT */
    if (dtype>=64) 
      dbgprintf("ILL:");
    if (optype==2)
      print_special_obj(0); /* NOUN */
    else 
      print_special_obj(1);  /* OBJECT */
    return 0;
  }

  if (!interp_arg) 
    dbgprintf("%d",dval);
  else {
    if (dtype<64) {
      if (dval==-1) 
	print_special_obj(2); /* NAME */
      else {
	s=getname(dval);
	if (dtype&(AGT_ITEM|AGT_CREAT|AGT_SELF|AGT_WORN)) 
	  dbgprintf("<%d:%s>",dval,s);
	else 
	  dbgprintf("{%d:%s}",dval,s);
	rfree(s);	
      }
    } else if ( (dtype&AGT_VAR)!=0) {
      printval("Var",dval,dbgvarptr);
    } else switch(dtype) 
      {
      case AGT_TIME:
	dbgprintf("%2d:%2d",dval/100,dval%100);
      case AGT_NUM:  /* Numeric */
        dbgprintf("%d",dval);break;
      case AGT_FLAG:  /* Flag */
	printval("Flg",dval,dbgflagptr);break;
      case AGT_ROOMFLAG: /* Roomflag */
        dbgprintf("RoomFlag",dval);break;
      case AGT_QUEST:  /* Question */
	if (dval<=MaxQuestion && dval>=1 && question!=NULL) {
	  dbgprintf("\nQ%d:%s\n",dval,question[dval-1]);
	  dbgprintf("[A:%s]",answer[dval-1]);      
	} else if (quest_ptr!=NULL) {
	  dbgprintf("\nQ%d: ",dval);
	  print_msg(quest_ptr[dval-1]);
	  dbgprintf("[A:");
	  print_msg(ans_ptr[dval-1]);
	}
	break;
      case AGT_MSG: /* Message */
	if (dval>last_message || dval<1 || msg_ptr==NULL) 
	  dbgprintf("ILLEGAL MESSAGE");
	else {
	  dbgprintf("(Msg%d)\n",dval);
	if (!dbg_nomsg) 
	  print_msg(msg_ptr[dval-1]);
	}
	break;
      case AGT_ERR: /* Message */
	if (dval>NUM_ERR || dval<1 || err_ptr==NULL) 
	  dbgprintf("ILLEGAL MESSAGE");
	else {
	  dbgprintf("(Std%d)\n",dval);
	if (!dbg_nomsg) 
	  print_msg(err_ptr[dval-1]);
	}
	break;
      case AGT_STR: /* String */
	if (dval-1>=MAX_USTR || userstr==NULL) 
	  dbgprintf("ILLEGAL STRING");
	else 
	  dbgprintf("\nStr%d:%s",dval,userstr[dval]);
	break;
      case AGT_CNT: /* Counter */
	printval("Cnt",dval,dbgcntptr);break;
      case AGT_DIR: /* Direction */
	if (dval>=0 && dval<=12) 
	  dbgprintf("%s",exitname[dval]);
	else dbgprintf("ILL_DIR(%d)",dval);
	break;
      case AGT_SUB: /* Subroutine */
	dbgprintf("Subroutine %d",dval);break;
      case AGT_PIC: /* Picture */
      case AGT_PIX:
	dbgprintf("Picture #%d",dval);break;
      case AGT_FONT: /* Font */
	dbgprintf("Font #%d",dval);break;
      case AGT_SONG:  /* Song */
	dbgprintf("Song #%d",dval);break;
      case AGT_EXIT:
	if (dval>=exitmsg_base) 
	  argout(AGT_MSG,dval-exitmsg_base,0);
	else 
	  argout(AGT_ROOM,dval,0);
	break;
      default:
	dbgprintf("?+%d",dval);
      }
  }
  return 1;
}

void debug_cmd_out(int ip,integer op,int arg1,int arg2, int optype)
{
  int j;
  const opdef *opdata;

  dbgprintf("  %2d:",ip);

  opdata=get_opdef(op);
  if (opdata==&illegal_def)
    dbgprintf("ILLEGAL %d\n",op);
  else {
    if (op>=END_ACT) dbgprintf("!"); /* "Terminal" Actions */
    else if (op<=MAX_COND) dbgprintf("?"); /* Condition */
    
    dbgprintf("%s",opdata->opcode);
    for(j=0;j<opdata->argnum;j++) {
      dbgprintf("\t");
      (void)argout(j==0 ? opdata->arg1 : opdata->arg2 , j==0 ? arg1 : arg2,
		   optype>>2);
      optype<<=2;
    }
  }
}

void debug_head(int i)
{
  int v, w, a;

  v=verb_code(command[i].verbcmd);
  if (v>=BASE_VERB && v<BASE_VERB+DUMB_VERB && syntbl[synlist[v]]!=0)
    w=syntbl[synlist[v]];
  else w=command[i].verbcmd;
  if (command[i].actor>0) {
    dbgprintf("CMD: ");
    a=command[i].actor;
  } else {
    dbgprintf("REDIR: ");
    a=-command[i].actor;
  }

  if (a==2) 
    dbgprintf("anybody, ");
  else if (a>2) {
    char *name;
    name=objname(a);
    name[0]=toupper(name[0]);
    dbgprintf("%s, ",name);
    rfree(name);
  }
  dbgprintf("%s %s %s %s\n", w==0? "any" : dict[w],
	    dict[command[i].nouncmd],
	    (ver==3)? dict[command[i].prep] : "->" ,
	    dict[command[i].objcmd]);
  
}



