#include "copyright.h"

/* commands which set parameters */
//#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "db.h"
#include "config.h"
#include "match.h"
#include "interface.h"
#include "externs.h"

static dbref match_controlled (dbref player, const char *name)
{
  dbref match;

  init_match (player, name, NOTYPE);
  match_everything ();

  match = noisy_match_result ();
  if (match != NOTHING && !controls (player, match)) {
    notify (player, "Permission denied.");
    return NOTHING;
  } else {
    return match;
  }
}

void do_name (dbref player, const char *name, char *newname)
{
  dbref thing;
  void free (void *);
  char *password;

  if ((thing = match_controlled (player, name)) != NOTHING) {
    /* check for bad name */
    if (*newname == '\0') {
      notify (player, "Give it what new name?");
      return;
    }

    /* check for renaming a player */
    if (Typeof (thing) == TYPE_PLAYER) {
      /* split off password */
      for (password = newname; isgraph (*password); password++);

      /* eat whitespace */
      if (*password) {
        *password++ = '\0';     /* terminate name */
        while (*password && isspace (*password))
          password++;
      }

      /* check for null password */
      if (!*password) {
        notify (player,
          "You must specify a password to change a player name.");
        notify (player, "E.g.: name player = newname password");
        return;
      } else if (strcmp (password, db[thing].password)) {
        notify (player, "Incorrect password.");
        return;
      } else if (!payfor (player, LOOKUP_COST)
        || !ok_player_name (newname)) {
        notify (player, "You can't give a player that name.");
        return;
      }
    } else {
      if (!ok_name (newname)) {
        notify (player, "That is not a reasonable name.");
        return;
      }
    }

    /* everything ok, change the name */
    if (db[thing].name) {
      free ((void *) db[thing].name);
    }
    db[thing].name = alloc_string (newname);
    notify (player, "Name set.");
  }
}

void do_describe (dbref player, const char *name, const char *description)
{
  dbref thing;

  if ((thing = match_controlled (player, name)) != NOTHING) {
    if (db[thing].description) {
      free ((void *) db[thing].description);
    }
    db[thing].description = alloc_string (description);
    notify (player, "Description set.");
  }
}

void do_fail (dbref player, const char *name, const char *message)
{
  dbref thing;

  if ((thing = match_controlled (player, name)) != NOTHING) {
    if (db[thing].fail_message) {
      free ((void *) db[thing].fail_message);
    }
    db[thing].fail_message = alloc_string (message);
    notify (player, "Message set.");
  }
}

void do_success (dbref player, const char *name, const char *message)
{
  dbref thing;

  if ((thing = match_controlled (player, name)) != NOTHING) {
    if (db[thing].succ_message) {
      free ((void *) db[thing].succ_message);
    }
    db[thing].succ_message = alloc_string (message);
    notify (player, "Message set.");
  }
}

void do_osuccess (dbref player, const char *name, const char *message)
{
  dbref thing;

  if ((thing = match_controlled (player, name)) != NOTHING) {
    if (db[thing].osuccess) {
      free ((void *) db[thing].osuccess);
    }
    db[thing].osuccess = alloc_string (message);
    notify (player, "Message set.");
  }
}

void do_ofail (dbref player, const char *name, const char *message)
{
  dbref thing;

  if ((thing = match_controlled (player, name)) != NOTHING) {
    if (db[thing].ofail) {
      free ((void *) db[thing].ofail);
    }
    db[thing].ofail = alloc_string (message);
    notify (player, "Message set.");
  }
}

void do_lock (dbref player, const char *name, const char *keyname)
{
  dbref thing;
  dbref key;
  int antilock;

  init_match (player, name, NOTYPE);
  match_everything ();

  switch (thing = match_result ()) {
  case NOTHING:
    notify (player, "I don't see what you want to lock!");
    return;
  case AMBIGUOUS:
    notify (player, "I don't know which one you want to lock!");
    return;
  default:
    if (!controls (player, thing)) {
      notify (player, "You can't lock that!");
      return;
    }
    break;
  }

  /* now we know it's ok to lock */
  if (antilock = (*keyname == NOT_TOKEN)) {
    /* skip past ! and any following whitespace */
    for (keyname++; *keyname && isspace (*keyname); keyname++);
  }

  /* match keyname */
  init_match (player, keyname, TYPE_THING);
  match_neighbor ();
  match_possession ();
  match_me ();
  match_player ();
  if (Wizard (player))
    match_absolute ();

  switch (key = match_result ()) {
  case NOTHING:
    notify (player, "I can't find that key!");
    return;
  case AMBIGUOUS:
    notify (player, "I don't know which key you want!");
    return;
  default:
    if (Typeof (key) != TYPE_PLAYER && Typeof (key) != TYPE_THING) {
      notify (player, "Keys can only be players or things.");
      return;
    }
    break;
  }

  /* everything ok, do it */
  db[thing].key = key;
  if (antilock) {
    db[thing].flags |= ANTILOCK;
    notify (player, "Anti-Locked.");
  } else {
    db[thing].flags &= ~ANTILOCK;
    notify (player, "Locked.");
  }
}

void do_unlock (dbref player, const char *name)
{
  dbref thing;

  if ((thing = match_controlled (player, name)) != NOTHING) {
    db[thing].key = NOTHING;
    db[thing].flags &= ~ANTILOCK;
    notify (player, "Unlocked.");
  }
}

void do_unlink (dbref player, const char *name)
{
  dbref exit;

  init_match (player, name, TYPE_EXIT);
  match_exit ();
  match_here ();
  if (Wizard (player)) {
    match_absolute ();
  }

  switch (exit = match_result ()) {
  case NOTHING:
    notify (player, "Unlink what?");
    break;
  case AMBIGUOUS:
    notify (player, "I don't know which one you mean!");
    break;
  default:
    if (!controls (player, exit)) {
      notify (player, "Permission denied.");
    } else {
      switch (Typeof (exit)) {
      case TYPE_EXIT:
        db[exit].location = NOTHING;
        notify (player, "Unlinked.");
        break;
      case TYPE_ROOM:
        db[exit].location = NOTHING;
        notify (player, "Dropto removed.");
        break;
      default:
        notify (player, "You can't unlink that!");
        break;
      }
    }
  }
}

void do_chown (dbref player, const char *name, const char *newobj)
{
  dbref thing;
  dbref owner;

  if (!Wizard (player)) {
    notify (player, "Permission denied.");
  } else {
    init_match (player, name, NOTYPE);
    match_everything ();

    if ((thing = noisy_match_result ()) == NOTHING) {
      return;
    } else if ((owner = lookup_player (newobj)) == NOTHING) {
      notify (player, "I couldn't find that player.");
    } else if (Typeof (thing) == TYPE_PLAYER) {
      notify (player, "Players always own themselves.");
    } else {
      db[thing].owner = owner;
      notify (player, "Owner changed.");
    }
  }
}

void do_set (dbref player, const char *name, const char *flag)
{
  dbref thing;
  const char *p;
  object_flag_type f;

  /* find thing */
  if ((thing = match_controlled (player, name)) == NOTHING)
    return;

  /* move p past NOT_TOKEN if present */
  for (p = flag; *p && (*p == NOT_TOKEN || isspace (*p)); p++);

  /* identify flag */
  if (*p == '\0') {
    notify (player, "You must specify a flag to set.");
    return;
  } else if (string_prefix ("LINK_OK", p)) {
    f = LINK_OK;
  } else if (string_prefix ("DARK", p)) {
    f = DARK;
  } else if (string_prefix ("STICKY", p)) {
    f = STICKY;
  } else if (string_prefix ("WIZARD", p)) {
    f = WIZARD;
  } else if (string_prefix ("TEMPLE", p)) {
    f = TEMPLE;
#ifdef RESTRICTED_BUILDING
  } else if (string_prefix ("BUILDER", p)) {
    f = BUILDER;
#endif /* RESTRICTED_BUILDING */
  } else {
    notify (player, "I don't recognized that flag.");
    return;
  }

  /* check for restricted flag */
  if (!Wizard (player)
    && (f == WIZARD
#ifdef RESTRICTED_BUILDING
      || f == BUILDER
#endif /* RESTRICTED_BUILDING */
      || f == TEMPLE || f == DARK && Typeof (thing) != TYPE_ROOM)) {
    notify (player, "Permission denied.");
    return;
  }

  /* check for stupid wizard */
  if (f == WIZARD && *flag == NOT_TOKEN && thing == player) {
    notify (player, "You cannot make yourself mortal.");
    return;
  }

  /* else everything is ok, do the set */
  if (*flag == NOT_TOKEN) {
    /* reset the flag */
    db[thing].flags &= ~f;
    notify (player, "Flag reset.");
  } else {
    /* set the flag */
    db[thing].flags |= f;
    notify (player, "Flag set.");
  }
}