/* unparse.c */

#include <string.h>
#include "config.h"
#include "db.h"
#include "externs.h"
#include "interface.h"

const char *unparse_flags(thing)
    dbref thing;
{
  static char buf[BUFFER_LEN];
  char *p;
  const char *type_codes = "R-EP";


  p = buf;
  if (Typeof(thing) != TYPE_THING)
    *p++ = type_codes[Typeof(thing)];
  if (db[thing].flags & ~TYPE_MASK) {
    /* print flags */
#ifdef DESTROY
    if (db[thing].flags & GOING)
      *p++ = 'G';
#endif	/* DESTROY */
    if (db[thing].flags & WIZARD)
      *p++ = 'W';
    if (db[thing].flags & STICKY)
      *p++ = 'S';
    if (db[thing].flags & DARK)
      *p++ = 'D';
    if (db[thing].flags & HAVEN)
      *p++ = 'H';
    if (db[thing].flags & HALT)
      *p++ = 'h';
    if (db[thing].flags & QUIET)
      *p++ = 'Q';
    if (db[thing].flags & CHOWN_OK)
      *p++ = 'C';
    if (db[thing].flags & ENTER_OK)
      *p++ = 'e';
    if (db[thing].flags & TERSE)
      *p++ = 'x';
    if (db[thing].flags & VISUAL)
      *p++ = 'V';
    if (db[thing].flags & OPAQUE)
      *p++ = 'O';
    if (db[thing].flags & NOSPOOF)
      *p++ = 'N';
#ifdef INHERIT_FLAG
    if (db[thing].flags & INHERIT)
      *p++ = 'I';
#endif
#ifdef ROYALTY_FLAG
    if (db[thing].flags & ROYALTY)
      *p++ = 'r';
#endif
    switch (Typeof(thing)) {
      case TYPE_PLAYER:
#ifdef RESTRICTED_BUILDING
	if (db[thing].flags & PLAYER_BUILD)
	  *p++ = 'B';
#endif
	if (db[thing].flags & PLAYER_GAGGED)
	  *p++ = 'g';
	if (db[thing].flags & PLAYER_SUSPECT)
	  *p++ = 'u';
	if (db[thing].flags & PLAYER_CONNECT)
	  *p++ = 'c';
	if (db[thing].flags & PLAYER_DARK)
	  *p++ = 'U';
	break;
      case TYPE_EXIT:
	if (db[thing].flags & EXIT_TRANSPARENT)
	  *p++ = 't';
	if (db[thing].flags & EXIT_KEY)
	  *p++ = 'K';
	break;
      case TYPE_THING:
	if (db[thing].flags & THING_KEY)
	  *p++ = 'K';
	if (db[thing].flags & THING_SAFE)
	  *p++ = 'X';
	if (db[thing].flags & THING_VERBOSE)
	  *p++ = 'v';
	if (db[thing].flags & THING_IMMORTAL)
	  *p++ = 'i';
	if (db[thing].flags & THING_DEST_OK)
	  *p++ = 'd';
	if (db[thing].flags & THING_PUPPET)
	  *p++ = 'p';
	break;
      case TYPE_ROOM:
	if (db[thing].flags & ROOM_TEMPLE)
	  *p++ = 'T';
	if (db[thing].flags & ROOM_ABODE)
	  *p++ = 'A';
	if (db[thing].flags & LINK_OK)
	  *p++ = 'L';
	if (db[thing].flags & ROOM_JUMP_OK)
	  *p++ = 'J';
	if (db[thing].flags & ROOM_FLOATING)
	  *p++ = 'F';
	if (db[thing].flags & ROOM_NO_TEL)
	  *p++ = 'n';
	break;
    }
  }
  *p = '\0';
  return buf;
}

const char *unparse_object(player, loc)
    dbref player;
    dbref loc;
{
  static char buf[BUFFER_LEN];
  Access(loc);
  switch (loc) {
    case NOTHING:
      return "*NOTHING*";
    case HOME:
      return "*HOME*";
    default:
      if (controls(player, loc) ||
	  can_link_to(player, loc) ||
	  (db[loc].flags & CHOWN_OK) ||
	  ((Typeof(loc) == TYPE_ROOM) && (db[loc].flags & ROOM_JUMP_OK)) ||
#ifdef ROYALTY_FLAG
	  (db[player].flags & ROYALTY) ||
#endif
	  ((Typeof(loc) == TYPE_PLAYER) && (db[loc].flags & VISUAL))) {
	/* show everything */
	sprintf(buf, "%s(#%d%s)", db[loc].name, loc, unparse_flags(loc));
	return buf;
      } else {
	/* show only the name */
	return db[loc].name;
      }
  }
}

static char boolexp_buf[BUFFER_LEN];
static char *buftop;

static void unparse_boolexp1(player, b, outer_type, flag)
    dbref player;
    struct boolexp *b;
    boolexp_type outer_type;
    int flag;    /*  0 is full unparse, 1 is numbers-only */
{
  if (b == TRUE_BOOLEXP) {
    strcpy(buftop, "*UNLOCKED*");
    buftop += strlen(buftop);
  } else {
    switch (b->type) {
      case BOOLEXP_AND:
	if (outer_type == BOOLEXP_NOT) {
	  *buftop++ = '(';
	}
	unparse_boolexp1(player, b->sub1, b->type, flag);
	*buftop++ = AND_TOKEN;
	unparse_boolexp1(player, b->sub2, b->type, flag);
	if (outer_type == BOOLEXP_NOT) {
	  *buftop++ = ')';
	}
	break;
      case BOOLEXP_OR:
	if (outer_type == BOOLEXP_NOT || outer_type == BOOLEXP_AND) {
	  *buftop++ = '(';
	}
	unparse_boolexp1(player, b->sub1, b->type, flag);
	*buftop++ = OR_TOKEN;
	unparse_boolexp1(player, b->sub2, b->type, flag);
	if (outer_type == BOOLEXP_NOT || outer_type == BOOLEXP_AND) {
	  *buftop++ = ')';
	}
	break;
      case BOOLEXP_IND:
	*buftop++ = AT_TOKEN;
	unparse_boolexp1(player, b->sub1, b->type, flag);
	break;
      case BOOLEXP_IS:
	*buftop++ = IS_TOKEN;
	unparse_boolexp1(player, b->sub1, b->type, flag);
	break;
      case BOOLEXP_CARRY:
	*buftop++ = IN_TOKEN;
	unparse_boolexp1(player, b->sub1, b->type, flag);
	break;
      case BOOLEXP_NOT:
	*buftop++ = '!';
	unparse_boolexp1(player, b->sub1, b->type, flag);
	break;
      case BOOLEXP_CONST:
	if (flag)
	  strcpy(buftop, tprintf("#%d", b->thing));
	else
	  strcpy(buftop, unparse_object(player, b->thing));
	buftop += strlen(buftop);
	break;
      case BOOLEXP_ATR:
	sprintf(buftop, "%s:%s", b->atr_lock->name,
		uncompress(b->atr_lock->text));
	buftop += strlen(buftop);
	break;
      default:
	sprintf(buftop, "Bad boolexp type!");
	buftop += strlen(buftop);
	break;
    }
  }
}

const char *unparse_boolexp(player, b, flag)
    dbref player;
    struct boolexp *b;
    int flag;    /*  0 is full unparse, 1 is numbers-only */
{
  buftop = boolexp_buf;
  unparse_boolexp1(player, b, BOOLEXP_CONST, flag);	/* no outer type */
  *buftop++ = '\0';

  return boolexp_buf;
}