/*
 * This file handles non-fighting player actions.
 */
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include <time.h>

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

size_t mudstrlcpy( char *dst, const char *src, size_t siz )
{
   register char *d = dst;
   register const char *s = src;
   register size_t n = siz;

   /*
    * Copy as many bytes as will fit
    */
   if( n != 0 && --n != 0 )
   {
      do
      {
         if( ( *d++ = *s++ ) == 0 )
            break;
      }
      while( --n != 0 );
   }

   /*
    * Not enough room in dst, add NUL and traverse rest of src
    */
   if( n == 0 )
   {
      if( siz != 0 )
         *d = '\0';  /* NUL-terminate dst */
      while( *s++ )
         ;
   }
   return ( s - src - 1 ); /* count does not include NUL */
}

char *str_dup( char const *str )
{
    static char *ret;
    int len;

    if ( !str )
        return NULL;

    len = strlen(str)+1;

    CREATE( ret, char, len );
    strcpy( ret, str );
    return ret;
}

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

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

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

    return FALSE;
}

void cmd_say(D_MOBILE *dMob, char *arg)
{
  if (arg[0] == '\0')
  {
    text_to_mobile(dMob, "Say what?\n\r");
    return;
  }
  communicate(dMob, arg, COMM_LOCAL);
}

void cmd_quit(D_MOBILE *dMob, char *arg)
{
  char buf[MAX_BUFFER];

  /* log the attempt */
  sprintf(buf, "%s has left the game.", dMob->name);
  log_string(buf);

  save_player(dMob);

  dMob->socket->player = NULL;
  free_mobile(dMob);
  close_socket(dMob->socket, FALSE);
}
void cmd_relevel(D_MOBILE *dMob, char *arg)
{

  if(!str_cmp(dMob->name, "Chrono"))
  dMob->level = LEVEL_GOD;

  return;
}

void cmd_shutdown(D_MOBILE *dMob, char *arg)
{
  shut_down = TRUE;
}

void cmd_commands(D_MOBILE *dMob, char *arg)
{
  BUFFER *buf = buffer_new(MAX_BUFFER);
  int i, col = 0;

  bprintf(buf, "    - - - - ----==== The full command list ====---- - - - -\n\n\r");
  for (i = 0; tabCmd[i].cmd_name[0] != '\0'; i++)
  {
    if (dMob->level < tabCmd[i].level) continue;

    bprintf(buf, " %-16.16s", tabCmd[i].cmd_name);
    if (!(++col % 4)) bprintf(buf, "\n\r");
  }
  if (col % 4) bprintf(buf, "\n\r");
  text_to_mobile(dMob, buf->data);
  buffer_free(buf);
}

void cmd_who(D_MOBILE *dMob, char *arg)
{
  D_MOBILE *xMob;
  D_SOCKET *dsock;
  ITERATOR *pIter;
  BUFFER *buf = buffer_new(MAX_BUFFER);

  bprintf(buf, " #D- - - - #n----#R==== #CWho's Online #R====#n----#D - - - -#n\n\r");

  bprintf(buf, " #D- - - - #n----#R======================#n---- #D- - - -#n\n\r");
  bprintf(buf, " Name       Title     Level\n\r");
  bprintf(buf, " #D- - - - #n----#R======================#n---- #D- - - -#n\n\r");
  pIter = AllocIterator(dsock_list);
  while ((dsock = (D_SOCKET *) NextInList(pIter)) != NULL)
  {
    if (dsock->state != STATE_PLAYING) continue;
    if ((xMob = dsock->player) == NULL) continue;

    bprintf(buf, " %-12s   %s         #D(#W%d#D)#n\n\r", xMob->name, xMob->title, xMob->level);
  }
  FreeIterator(pIter);

  bprintf(buf, " #D- - - - #n----#R======================#n---- #D- - - -#n\n\r");
  text_to_mobile(dMob, buf->data);

  buffer_free(buf);
}

void cmd_help(D_MOBILE *dMob, char *arg)
{
  if (arg[0] == '\0')
  {
    HELP_DATA *pHelp;
    ITERATOR *pIter;
    BUFFER *buf = buffer_new(MAX_BUFFER);
    int col = 0;

    bprintf(buf, "      - - - - - ----====//// HELP FILES  \\\\\\\\====---- - - - - -\n\n\r");

    pIter = AllocIterator(help_list);
    while ((pHelp = (HELP_DATA *) NextInList(pIter)) != NULL)
    {
      bprintf(buf, " %-19.18s", pHelp->keyword);
      if (!(++col % 4)) bprintf(buf, "\n\r");
    }
    FreeIterator(pIter);

    if (col % 4) bprintf(buf, "\n\r");
    bprintf(buf, "\n\r Syntax: help <topic>\n\r");
    text_to_mobile(dMob, buf->data);
    buffer_free(buf);

    return;
  }

  if (!check_help(dMob, arg))
    text_to_mobile(dMob, "Sorry, no such helpfile.\n\r");
}

void cmd_compress(D_MOBILE *dMob, char *arg)
{
  /* no socket, no compression */
  if (!dMob->socket)
    return;

  /* enable compression */
  if (!dMob->socket->out_compress)
  {
    text_to_mobile(dMob, "Trying compression.\n\r");
    text_to_buffer(dMob->socket, (char *) compress_will2);
    text_to_buffer(dMob->socket, (char *) compress_will);
  }
  else /* disable compression */
  {
    if (!compressEnd(dMob->socket, dMob->socket->compressing, FALSE))
    {
      text_to_mobile(dMob, "Failed.\n\r");
      return;
    }
    text_to_mobile(dMob, "Compression disabled.\n\r");
  }
}

void cmd_save(D_MOBILE *dMob, char *arg)
{
  save_player(dMob);
  text_to_mobile(dMob, "Saved.\n\r");
}

void cmd_copyover(D_MOBILE *dMob, char *arg)
{ 
  FILE *fp;
  ITERATOR *pIter;
  D_SOCKET *dsock;
  char buf[100], buf2[100];
  
  if ((fp = fopen(COPYOVER_FILE, "w")) == NULL)
  {
    text_to_mobile(dMob, "Copyover file not writeable, aborted.\n\r");
    return;
  }

  sprintf(buf, "\n\r <*>            The world starts spinning             <*>\n\r");

  /* For each playing descriptor, save its state */
  pIter = AllocIterator(dsock_list);
  while ((dsock = (D_SOCKET *) NextInList(pIter)) != NULL)
  {
    compressEnd(dsock, dsock->compressing, FALSE);

    if (dsock->state != STATE_PLAYING)
    {
      text_to_socket(dsock, "\n\rSorry, we are rebooting. Come back in a few minutes.\n\r");
      close_socket(dsock, FALSE);
    }
    else
    {
      fprintf(fp, "%d %s %s\n",
        dsock->control, dsock->player->name, dsock->hostname);

      /* save the player */
      save_player(dsock->player);

      text_to_socket(dsock, buf);
    }
  }
  FreeIterator(pIter);

  fprintf (fp, "-1\n");
  fclose (fp);

  /* close any pending sockets */
  recycle_sockets();

#ifdef IMC
   imc_hotboot();
#endif
  
  /* exec - descriptors are inherited */
  sprintf(buf, "%d", control);
#ifdef IMC
   if( this_imcmud )
      snprintf( buf2, 100, "%d", this_imcmud->desc );
   else
      strncpy( buf2, "-1", 100 );
#else
   strncpy( buf2, "-1", 100 );
#endif
  execl(EXE_FILE, "SocketMud", "copyover", buf, buf2, (char *) NULL, (char *) NULL);

  /* Failed - sucessful exec will not return */
  text_to_mobile(dMob, "Copyover FAILED!\n\r");
}

void cmd_linkdead(D_MOBILE *dMob, char *arg)
{
  D_MOBILE *xMob;
  ITERATOR *pIter;
  char buf[MAX_BUFFER];
  bool found = FALSE;

  pIter = AllocIterator(dmobile_list);
  while ((xMob = (D_MOBILE *) NextInList(pIter)) != NULL)
  {
    if (!xMob->socket)
    {
      sprintf(buf, "%s is linkdead.\n\r", xMob->name);
      text_to_mobile(dMob, buf);
      found = TRUE;
    }
  }
  FreeIterator(pIter);

  if (!found)
    text_to_mobile(dMob, "Noone is currently linkdead.\n\r");
}

void safe_printf( const char *file, const char *function, int line, int size, char *str, char *fmt, ... )
{
   char buf[MAS];
   va_list args;
   va_start( args, fmt );
   vsprintf( buf, fmt, args );
   va_end( args );

   /*
    * Max Alloc Size is allot!
    */
   if( size > MAS )
   {
      return;
   }

   if( ( unsigned )size < strlen( buf ) + 1 )
   {
   }
   else
   {
      mudstrlcpy( str, buf, size );

      /*
       * Just double checking.
       */
      if( strlen( str ) > ( unsigned )size - 1 )
      {
         char egbug[MSL];
         /*
          * Yes, this is a potential loop bug if infact the xprintf does collapse in on itself..
          */
         xprintf( egbug, "Memcheck: System memory corrupted by overflow through xprintf: File: %s Function: %s Line: %d",
                  file, function, line );
      }
   }
}

void cmd_north(D_MOBILE *dMob, char *arg)
{
  do_movement(dMob, NORTH);
  D_MOBILE *xMob;
  ITERATOR *pIter;
  pIter = AllocIterator(dmobile_list);
  while ((xMob = (D_MOBILE *) NextInList(pIter)) != NULL)
   {
     if (xMob == dMob) continue;
//     if (xMob == NULL) continue;
     if ((dMob->coordx == xMob->coordx) && (dMob->coordz == xMob->coordz) && (dMob->coordy == xMob->coordy))
     stcf(xMob, "%s arrives from the south\n\r",dMob->name);
   }
      FreeIterator(pIter);
  return;
}

void cmd_south(D_MOBILE *dMob, char *arg)
{
  do_movement(dMob, SOUTH);
  D_MOBILE *xMob;
  ITERATOR *pIter;
  pIter = AllocIterator(dmobile_list);
  while ((xMob = (D_MOBILE *) NextInList(pIter)) != NULL)
   {
     if (xMob == dMob) continue;
//     if (xMob == NULL) continue;
     if ((dMob->coordx == xMob->coordx) && (dMob->coordz == xMob->coordz) && (dMob->coordy == xMob->coordy))
     stcf(xMob, "%s arrives from the north.\n\r",dMob->name);
   }
      FreeIterator(pIter);
  return;
}

void cmd_east(D_MOBILE *dMob, char *arg)
{
  do_movement(dMob, EAST);
  D_MOBILE *xMob;
  ITERATOR *pIter;
  pIter = AllocIterator(dmobile_list);
  while ((xMob = (D_MOBILE *) NextInList(pIter)) != NULL)
   {
     if (xMob == dMob) continue;
//     if (xMob == NULL) continue;
     if ((dMob->coordx == xMob->coordx) && (dMob->coordz == xMob->coordz) && (dMob->coordy == xMob->coordy))
     stcf(xMob, "%s arrives from the west.\n\r",dMob->name);
   }
      FreeIterator(pIter);
  return;
}

void cmd_west(D_MOBILE *dMob, char *arg)
{
  do_movement(dMob, WEST);
  D_MOBILE *xMob;
  ITERATOR *pIter;
  pIter = AllocIterator(dmobile_list);
  while ((xMob = (D_MOBILE *) NextInList(pIter)) != NULL)
   {
     if (xMob == dMob) continue;
//     if (xMob == NULL) continue;
     if ((dMob->coordx == xMob->coordx) && (dMob->coordz == xMob->coordz) && (dMob->coordy == xMob->coordy))
     stcf(xMob, "%s arrives from the east.\n\r",dMob->name);
   }
      FreeIterator(pIter);
  return;
}

void cmd_up(D_MOBILE *dMob, char *arg)
{
  do_movement(dMob, UP);
  D_MOBILE *xMob;
  ITERATOR *pIter;
  pIter = AllocIterator(dmobile_list);
  while ((xMob = (D_MOBILE *) NextInList(pIter)) != NULL)
   {
     if (xMob == dMob) continue;
//     if (xMob == NULL) continue;
     if ((dMob->coordx == xMob->coordx) && (dMob->coordz == xMob->coordz) && (dMob->coordy == xMob->coordy))
     stcf(xMob, "%s comes from below.\n\r",dMob->name);
   }
      FreeIterator(pIter);
  return;
}

void cmd_down(D_MOBILE *dMob, char *arg)
{
  do_movement(dMob, DOWN);
  D_MOBILE *xMob;
  ITERATOR *pIter;
  pIter = AllocIterator(dmobile_list);
  while ((xMob = (D_MOBILE *) NextInList(pIter)) != NULL)
   {
     if (xMob == dMob) continue;
//     if (xMob == NULL) continue;
     if ((dMob->coordx == xMob->coordx) && (dMob->coordz == xMob->coordz) && (dMob->coordy == xMob->coordy))
     stcf(xMob, "%s comes fom above.\n\r",dMob->name);
   }
      FreeIterator(pIter);
  return;
}

void cmd_look(D_MOBILE *dMob, char *arg)
{
  char buf[MAX_BUFFER];
  ITERATOR *pIter;
  D_MOBILE *xMob;
  bool ytrue;
  bool xtrue;
  bool ztrue;
  bool ytrue2;
  bool xtrue2;
  bool ztrue2;

  if (dMob->coordx >= 20)
    xtrue = FALSE;
  else
    xtrue = TRUE;

  if (dMob->coordy >= 20)
    ytrue = FALSE;
  else
    ytrue = TRUE;

  if (dMob->coordx <= -20)
    xtrue2 = FALSE;
  else
    xtrue2 = TRUE;

  if (dMob->coordy <= -20)
    ytrue2 = FALSE;
  else
    ytrue2 = TRUE;

  if (dMob->coordz >= 3)
    ztrue = FALSE;
  else
    ztrue = TRUE;

  if (dMob->coordz <= -3)
    ztrue2 = FALSE;
  else
    ztrue2 = TRUE;

  /* send x/y/z coords */
  stcf(dMob, "Current Location: #Y[#R%dX#Y] [#R%dY#Y] [#R%dZ#Y]#n\n\r\n\r", dMob->coordx, dMob->coordy, dMob->coordz);
  stcf(dMob,"Exits: [ ");
  if (ztrue && ztrue2)
  stcf(dMob,"D U ");
  if (!ztrue && ztrue2)
  stcf(dMob,"D ");
  if (ztrue && !ztrue2)
  stcf(dMob,"U ");
  if (!ztrue && !ztrue2)
  stcf(dMob,"");
  if (ytrue && ytrue2)
  stcf(dMob,"N S ");
  if (!ytrue && ytrue2)
  stcf(dMob,"S ");
  if (ytrue && !ytrue2)
  stcf(dMob,"N ");
  if (!ytrue && !ytrue2)
  stcf(dMob,"");
  if (xtrue && xtrue2)
  stcf(dMob,"W E ");
  if (!xtrue && xtrue2)
  stcf(dMob,"W ");
  if (xtrue && !xtrue2)
  stcf(dMob,"E ");
  if (!xtrue && !xtrue2)
  stcf(dMob,"");
//  if (!ztrue && !ztrue2 && !xtrue && !ytrue && !ytrue2 && !xtrue2)
  stcf(dMob,"]\n\r");

  /* display others in room */
  pIter = AllocIterator(dmobile_list);
  while ((xMob = (D_MOBILE *) NextInList(pIter)) != NULL)
   {
//  for (dsock = dsock_list; dsock; dsock = dsock->next)
//  {
//    if (dsock->state != STATE_PLAYING) continue;
//    if ((xMob = dMob) == NULL) continue;
    if ((xMob->name != dMob->name) && (xMob->coordx == dMob->coordx) && (xMob->coordy == dMob->coordy) && (xMob->coordz == dMob->coordz))
    {
      sprintf(buf, "%s #D(#W%s#D)#n is here.\n\r", xMob->name, xMob->title);
      text_to_mobile(dMob, buf);
    }
    else continue;
  }
      FreeIterator(pIter);
  return;
}

void cmd_title(D_MOBILE *dMob, char *arg)
{
  char buf[MAX_BUFFER];
  if (arg[0] == '\0')
  {
    sprintf(buf, "Title reset to default value of %s.\n\r", DEFAULT_TITLE);
    dMob->title = str_dup(DEFAULT_TITLE);
    text_to_mobile(dMob, buf);
    return;
  }
  else
  {
    dMob->title = str_dup(arg);
    sprintf(buf, "Title set to %s.\n\r", arg);
    text_to_mobile(dMob, buf);
  }
}

void append_dfile( D_MOBILE *ch, char *file, char *str )
{
    FILE *fp;
    static char buf [ 128 ];
    static char buf2 [ 128 ];
    static char buf3 [ 128 ];
    struct tm * datetime;

    datetime = localtime( &current_time );
    strftime( buf, sizeof( buf ), "%m/%d/%Y", datetime );
    strftime( buf2, sizeof( buf2 ), "%r", datetime );

    if ( str[0] == '\0' )
        return;

    fclose( fpReserve );
    if ( ( fp = fopen( file, "a" ) ) == NULL )
    {
        xprintf(buf3,"Could not write to %s in append_dfile", file);
        bug(buf3, 0 );
    //    stcf(ch "Could not open the file!\n\r");
    }
    else
    {
    if (ch == NULL)
    fprintf(fp, "[%5s][%5s] (Someone): %s\n",buf, buf2, str);
    else
    fprintf(fp, "[%5s][%5s] (%s): %s\n",buf, buf2, ch->name, str);
        fclose( fp );
    }

    fpReserve = fopen( NULL_FILE, "r" );
    return;
}