/*
 * This file contains all sorts of utility functions used
 * all sorts of places in the code.
 */
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>

/* include main header file */
#include "mud.h"

/*
 * Check to see if a given name is
 * legal, returning FALSE if it
 * fails our high standards...
 */
bool check_name(const char *name)
{
  int size, i;

  if ((size = strlen(name)) < 3 || size > 12)
    return FALSE;

  for (i = 0 ;i < size; i++)
    if (!isalpha(name[i])) return FALSE;

  return TRUE;
}

void clear_mobile(D_MOBILE *dMob)
{
    int i;
    bzero(dMob, sizeof(*dMob));

    dMob->name              = NULL;
    dMob->password          = NULL;
    dMob->is_npc            = FALSE;
    dMob->level             = LEVEL_PLAYER;
    dMob->x                 = 690;
    dMob->y                 = 419;
    dMob->z                 = 1;
    dMob->immortal_flags    = 0;
    dMob->player_flags      = 0;
    dMob->view_x            = 11;
    dMob->view_y            = 7;
    dMob->title             = DEFAULT_TITLE;
    dMob->p_level           = 1;
    dMob->class             = 0;
    dMob->race              = 0;
    dMob->age               = 0;
    dMob->xp                = 0;
    
    /* Clear stats */
    for (i = 0; i <= MAX_STATS; i++)
        dMob->stats[i] = 0;
    /* Clear Attribites */
    for (i = 0; i <= MAX_ATTRIBS; i++)
        dMob->attribs[i] = 0;
    /* Clear Max Attributes */
    for (i = 0; i <= MAX_ATTRIBS; i++)
        dMob->attribs_max[i] = 0;
    /* Clear Talents */
    for (i = 0; i <= MAX_TALENTS; i++)
        dMob->talents[i] = 0;
    /* Clear Skills */
    for (i = 0; i <= MAX_SKILLS; i++)
        dMob->skills[i] = 0;
    /* Clear Knowledge */
    for (i = 0; i <= MAX_KNOW; i++)
        dMob->knowledge[i] = 0;
    /* Clear Talents */
    for (i = 0; i <= MAX_TALENTS; i++)
        dMob->talents_t[i] = 0;
    /* Clear Skills */
    for (i = 0; i <= MAX_SKILLS; i++)
        dMob->skills_t[i] = 0;
    /* Clear Knowledge */
    for (i = 0; i <= MAX_KNOW; i++)
        dMob->knowledge_t[i] = 0;
}

void free_mobile(D_MOBILE *dMob)
{
  D_MOBILE *xMob;

  if (dMob == dmobile_list)
    dmobile_list = dMob->next;
  else
  {
    for (xMob = dmobile_list; xMob && xMob->next != dMob; xMob = xMob->next)
      ;

    if (xMob == NULL)
    {
      bug("Free_mobile: Mobile not found.");
      return;
    }
    xMob->next = dMob->next;
  }

  /* reset the socket */
  if (dMob->socket)
    dMob->socket->player = NULL;

  ex_free_mob(dMob);
}

void ex_free_mob(D_MOBILE * dMob)
{
  /*
   * clear out all strings,
   * remember NULL strings are OK.
   */
  free(dMob->name);
  free(dMob->password);

  /* put it back in the free list */
  dMob->next   = dmobile_free;
  dmobile_free = dMob;
}

void communicate(D_MOBILE *dMob, char *txt, int range)
{
    D_MOBILE *xMob;
    char buf[MAX_BUFFER];
    char message[MAX_BUFFER];

    switch(range)
    {
        default:
            bug("Communicate: Bad Range %d.", range);
            return;
        break;
        case COMM_LOCAL:  /* everyone is in the same room for now... */
            sprintf(message, "#r%s says '%s'.\n\r", dMob->name, txt);
            sprintf(buf, "#rYou say '%s'.\n\r", txt);
            text_to_mobile(dMob, buf);
            for (xMob = dmobile_list; xMob; xMob = xMob->next)
            {
                if (xMob == dMob) continue;
                text_to_mobile(xMob, message);
            }
        break;
        case COMM_CHAT:  /* everyone is in the same room for now... */
            sprintf(message, "#P[#pCHAT#P]#n %s '%s'.\n\r", dMob->name, txt);
            sprintf(buf, "#P[#pCHAT#P]#n You '%s'.\n\r", txt);
            text_to_mobile(dMob, buf);
            for (xMob = dmobile_list; xMob; xMob = xMob->next)
            {
                if (xMob == dMob) continue;
                text_to_mobile(xMob, message);
            }
        break;
        case COMM_LOG:
            sprintf(message, "[LOG: %s]\n\r", txt);
            for (xMob = dmobile_list; xMob; xMob = xMob->next)
            {
                if (!IS_ADMIN(xMob)) continue;
                text_to_mobile(xMob, message);
            }
        break;
  }
}

/*
 * mudwide_info()
 *
 * displays mudwide *txt to all players in the game
 */
void mudwide_info(char * txt)
{
    D_MOBILE *xMob;
    char message[MAX_BUFFER];
    
    sprintf(message, "#W[INFO]#n %s\n", txt);
    for (xMob = dmobile_list; xMob; xMob = xMob->next)
    {
        text_to_mobile(xMob, message);
    }
    return;
}

/*
 * Loading of help files, areas, etc, at boot time.
 */
void load_muddata(bool fCopyOver)
{
    log_string ("\n\n Game Starting at %s", ctime (&current_time));
    load_helps();       /* Load notes   */
    load_world_data();  /* Load world   */
    load_time();        /* Load Time    */
    startup_areas();    /* Load Location*/
    
    /* copyover */
    if (fCopyOver)
        copyover_recover();
}

char *get_time()
{
  static char buf[16];
  char *strtime;
  int i;

  strtime = ctime(&current_time);
  for (i = 0; i < 15; i++)   
    buf[i] = strtime[i + 4];
  buf[15] = '\0';

  return buf;
}

/* Recover from a copyover - load players */
void copyover_recover()
{     
  D_MOBILE *dMob;
  D_SOCKET *dsock;
  FILE *fp;
  char name [100];
  char host[MAX_BUFFER];
  int desc;
      
  log_string("Copyover recovery initiated");
   
  if ((fp = fopen(COPYOVER_FILE, "r")) == NULL)
  {  
    log_string("Copyover file not found. Exitting.");
    exit (1);
  }
      
  /* In case something crashes - doesn't prevent reading */
  unlink(COPYOVER_FILE);
    
  for (;;)
  {  
    fscanf(fp, "%d %s %s\n", &desc, name, host);
    if (desc == -1)
      break;

    dsock = malloc(sizeof(*dsock));
    clear_socket(dsock, desc);
  
    dsock->hostname     =  strdup(host);
    dsock->next         =  dsock_list;
    dsock_list          =  dsock;
 
    /* load player data */
    if ((dMob = load_player(name)) != NULL)
    {
      /* attach to socket */
      dMob->socket     =  dsock;
      dsock->player    =  dMob;
  
      /* attach to mobile list */
      dMob->next       =  dmobile_list;
      dmobile_list     =  dMob;  
    }
    else /* ah bugger */
    {
      close_socket(dsock, FALSE);
      continue;
    }
   
    /* Write something, and check if it goes error-free */
    if (!text_to_socket(dsock, "\n\r <*>  And before you know it, everything has changed  <*>\n\r"))
    { 
      close_socket(dsock, FALSE);
      continue;
    }
  
    /* make sure the socket can be used */
    dsock->bust_prompt    =  TRUE;
    dsock->lookup_status  =  TSTATE_DONE;
    dsock->state          =  STATE_PLAYING;

    /* negotiate compression */
    text_to_buffer(dsock, (char *) compress_will2);
    text_to_buffer(dsock, (char *) compress_will);
  }
  fclose(fp);
}     

D_MOBILE *check_reconnect(char *player)
{
  D_MOBILE *dMob;

  for (dMob = dmobile_list; dMob; dMob = dMob->next)
  {
    if (compares(dMob->name, player))
    {
      if (dMob->socket)
        close_socket(dMob->socket, TRUE);
      return dMob;
    }
  }
  return NULL;
}

D_MOBILE * get_dmob_world (D_MOBILE * dMob, char *name)
{
    D_MOBILE *xMob;
    D_SOCKET *dsock;
    
    for (dsock = dsock_list; dsock; dsock = dsock->next)
    {
        if (dsock->state != STATE_PLAYING) continue;
        if ((xMob = dsock->player) == NULL) continue;
        
        if (compares (xMob->name, name))
            return xMob;
    }
    return NULL;
}

bool str_prefix (const char *astr, const char *bstr)
{
    if (astr == NULL)
    {
        bug ("Strn_cmp: null astr.", 0);
        return TRUE;
    }

    if (bstr == NULL)
    {
        bug ("Strn_cmp: null bstr.", 0);
        return TRUE;
    }

    for (; *astr; astr++, bstr++)
    {
        if (LOWER (*astr) != LOWER (*bstr))
            return TRUE;
    }

    return FALSE;
}

void smash_tilde (char *str)
{
    for (; *str != '\0'; str++)
    {
        if (*str == '~')
            *str = '-';
    }

    return;
}

void smash_space(char *str)
{
    for (; *str != '\0'; str++)
    {
        if (*str == ' ')
            *str = '-';
    }

    return;
}

void tail()
{}