#ifdef PLAYER_LIST

#include "copyright.h"

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

#define PLAYER_LIST_SIZE (1 << 12)      /* must be a power of 2 */

static dbref hash_function_table[256];
static int hft_initialized = 0;

#define DOWNCASE(x) (isupper((int)x) ? tolower((int)x) : (x))

static void init_hft (void)
{
  int i;

  for (i = 0; i < 256; i++) {
    hash_function_table[i] = OS_RAND () & (PLAYER_LIST_SIZE - 1);
  }
  hft_initialized = 1;
}

static dbref hash_function (const char *string)
{
  dbref hash;

  if (!hft_initialized)
    init_hft ();
  hash = 0;
  for (; *string; string++) {
    hash ^= ((hash >> 1) ^ hash_function_table[DOWNCASE (*string)]);
  }
  return (hash);
}

struct pl_elt {
  dbref player;                 /* pointer to player */
  /* key is db[player].name */
  struct pl_elt *next;
};

static struct pl_elt *player_list[PLAYER_LIST_SIZE];
static int pl_used = 0;

void clear_players (void)
{
  int i;
  struct pl_elt *e;
  struct pl_elt *next;

  for (i = 0; i < PLAYER_LIST_SIZE; i++) {
    if (pl_used) {
      for (e = player_list[i]; e; e = next) {
        next = e->next;
        free ((void *) e);
      }
    }
    player_list[i] = 0;
  }
  pl_used = 1;
}

void add_player (dbref player)
{
  dbref hash;
  struct pl_elt *e;

  hash = hash_function (db[player].name);

  e = (struct pl_elt *) malloc (sizeof (struct pl_elt));
  e->player = player;
  e->next = player_list[hash];
  player_list[hash] = e;
}

dbref lookup_player (const char *name)
{
  struct pl_elt *e;

  for (e = player_list[hash_function (name)]; e; e = e->next) {
    if (!string_compare (db[e->player].name, name))
      return e->player;
  }
  return NOTHING;
}

void delete_player (dbref player)
{
  dbref hash;
  struct pl_elt *prev;
  struct pl_elt *e;

  hash = hash_function (db[player].name);
  if ((e = player_list[hash]) == 0) {
    return;
  } else if (e->player == player) {
    /* it's the first one */
    player_list[hash] = e->next;
    free ((void *) e);
  } else {
    for (prev = e, e = e->next; e; prev = e, e = e->next) {
      if (e->player == player) {
        /* got it */
        prev->next = e->next;
        free ((void *) e);
        break;
      }
    }
  }
}

#endif /* PLAYER_LIST */