/****************************************************************************
 * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |   \\._.//   *
 * -----------------------------------------------------------|   (0...0)   *
 * SMAUG 1.4 (C) 1994, 1995, 1996, 1998  by Derek Snider      |    ).:.(    *
 * -----------------------------------------------------------|    {o o}    *
 * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |   / ' ' \   *
 * Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek,      |~'~.VxvxV.~'~*
 * Tricops and Fireblade                                      |             *
 * ------------------------------------------------------------------------ *
 * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael        *
 * Chastain, Michael Quan, and Mitchell Tse.                                *
 * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,          *
 * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.     *
 * ------------------------------------------------------------------------ *
 *			         Hotboot support code                             *
 ****************************************************************************/

#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include "mud.h"
#ifdef USE_IMC
  #include "imc.h"
  #include "icec.h"
#endif

// bool write_to_descriptor( DESCRIPTOR_DATA *d, char *txt, int length );
bool write_to_descriptor( int desc, char *txt, int length );
bool write_to_descriptor_old( int desc, char *txt, int length );

#ifdef MCCP
#define TELOPT_COMPRESS 85
#define TELOPT_COMPRESS2 86
bool    compressStart   args( ( DESCRIPTOR_DATA *d, unsigned char telopt ) );
bool    compressEnd     args( ( DESCRIPTOR_DATA *d ) );
const   char    compress2_on_str_2 [] = { '\xFF', '\xFB', TELOPT_COMPRESS2, '\0' };
#endif

extern int		    control;		/* Controlling descriptor	*/

/* Used by hotboot code */
void save_areas( void )
{
   AREA_DATA   *tarea;
   char         filename[256];

   for( tarea = first_build; tarea; tarea = tarea->next )
   {
      if( !IS_SET( tarea->status, AREA_LOADED ) )
         continue;
      sprintf( filename, "%s%s", BUILD_DIR, tarea->filename );
      fold_area( tarea, filename, FALSE );
   }
   return;
}
/*
 * Check to see if people are busy doing stuff that they wouldn't
 * want a hotboot to off during it  -Goku
 */
bool isSafeToHotboot(CHAR_DATA *ch)
{
	ROOM_INDEX_DATA *tRoom;

	/* Check for people in the HBTC */
	tRoom = get_room_index(ROOM_HBTC);
	if (tRoom->first_person)
	{
		send_to_char( "The HBTC is in use, hotboot aborted.\n\r", ch );
		return FALSE;
	}

	/* we could check for other stuff as well  -Goku */

	return TRUE;
}

/*  Warm reboot stuff, gotta make sure to thank Erwin for this :) */
void do_hotboot( CHAR_DATA *ch, char *argument )
{
    FILE *fp;
    DESCRIPTOR_DATA *d, *de_next;
    char buf [100], buf2[100]/*, buf3[100], buf4[100], buf5[100]*/;
	char arg [MAX_STRING_LENGTH];
    
    one_argument(argument, arg);
    
    /* typing "hotboot force" will force a hotboot */
    if (str_cmp(arg, "force"))
    	if (!isSafeToHotboot(ch))
    		return;

    sprintf( log_buf, "Hotboot initiated by %s.", ch->name );
    log_string( log_buf );

    fp = fopen( HOTBOOT_FILE, "w" );

    if( !fp )
    {
      send_to_char( "Hotboot file not writeable, aborted.\n\r", ch );
	sprintf( log_buf, "Could not write to hotboot file: %s. Hotboot aborted.", HOTBOOT_FILE );
	log_string( log_buf );
      perror( "do_copyover:fopen" );
      return;
    }

    /* Consider changing all loaded prototype areas here, if you use OLC */
    log_string( "Saving modified area files..." );
    save_areas();
    log_string( "Saving hiscore file..." );
    save_hiscores();

#ifdef USE_IMC
    log_string( "Initiating IMC2 shutdown...." );
    imc_shutdown(); /* shut down IMC */
    log_string( "IMC2 shutdown completed." );
#endif


    log_string( "Saving player files and connection states...." );
    if( ch && ch->desc )
        write_to_descriptor( ch->desc->descriptor, "\e[0m", 0 );
    sprintf( buf, "\n\rThe flow of time is halted momentarily as the world is reshaped!\n\r" );

    if ( auction->item )
    {
      sprintf(buf, "Sale of %s has been stopped by mud.\n\r",
          auction->item->short_descr);
      talk_auction(buf);
      obj_to_char(auction->item, auction->seller);
      auction->item = NULL;
      if ( auction->buyer && auction->buyer != auction->seller )
      {
        auction->buyer->gold += auction->bet;
        send_to_char("Your money has been returned.\n\r", auction->buyer);
      }
    }

    /* For each playing descriptor, save its state */
    for( d = first_descriptor; d ; d = de_next )
    {
        CHAR_DATA * och = CH(d);
        de_next = d->next; /* We delete from the list , so need to save this */
        if( !d->character || d->connected < CON_PLAYING ) /* drop those logging on */
        {
            write_to_descriptor( d->descriptor, "\n\rSorry, we are rebooting. Come back in a few minutes.\n\r", 0 );
            close_socket( d, FALSE ); /* throw'em out */
        }
        else
        {
            fprintf( fp, "%d %d %d %d %d %s %s %s\r",
                     d->descriptor,
#ifdef MCCP
                     (int)d->compressing,
#else
                     0,
#endif
                     och->in_room->vnum, d->port, d->idle, och->name, d->user, d->host );
            save_char_obj( och );
#ifdef I3
		I3_close_char( d );
#endif
            write_to_descriptor( d->descriptor, buf, 0 );
#ifdef MCCP
            compressEnd( d );
#endif
        }
    }
    fprintf( fp, "-1 0 0 0 0 x x x\r" );
    FCLOSE( fp );

#ifdef I3
    log_string( "Initiating Intermud-3 shutdown...." );
    I3_shutdown( 0 );
    log_string( "Intermud-3 shutdown completed." );
#endif

    log_string( "Executing hotboot...." );
    /* Close reserve and other always-open files and release other resources */
    FCLOSE( fpReserve );
    FCLOSE( fpLOG );

    /* exec - descriptors are inherited */
    sprintf( buf,  "%d", port );
    sprintf( buf2, "%d", control );

//    execl( EXE_FILE, "dbsaga", buf, "hotboot",  buf2, buf3, buf4, buf5, (char *)NULL );
    execl( EXE_FILE, "dbsaga", buf, "hotboot", buf2, (char *)NULL );
    /* Failed - sucessful exec will not return */
    perror( "do_hotboot: execl" );

    /* Here you might want to reopen fpReserve */
    /* Since I'm a neophyte type guy, I'll assume this is a good idea and cut and past from main()  */

    if( ( fpReserve = fopen( NULL_FILE, "r" ) ) == NULL )
    {
        perror( NULL_FILE );
        exit( 1 );
    }
    if( ( fpLOG = fopen( NULL_FILE, "r" ) ) == NULL )
    {
        perror( NULL_FILE );
        exit( 1 );
    }
    log_string( "Hotboot execution failed!!" );
    send_to_char( "Hotboot FAILED!\n\r", ch );
}

/* Recover from a hotboot - load players */
void hotboot_recover()
{
    DESCRIPTOR_DATA *d = NULL;
    FILE *fp;
    char name[100];
    char host[MAX_STRING_LENGTH];
    char user[MAX_STRING_LENGTH];
    int desc, dcompress, room, dport, idle;
    bool fOld;

    fp = fopen( HOTBOOT_FILE, "r" );

    if (!fp) /* there are some descriptors open which will hang forever then ? */
    {
        perror( "hotboot_recover: fopen" );
        log_string( "Hotboot file not found. Exitting.\n\r" );
        exit( 1 );
    }

    unlink( HOTBOOT_FILE ); /* In case something crashes - doesn't prevent reading */
    for( ; ; )
    {
        d = NULL;

        fscanf( fp, "%d %d %d %d %d %s %s %s\r", &desc, &dcompress, &room, &dport, &idle, name, user, host );

       if (desc == -1 || feof(fp) )
       {
			break;
		}
            
        /* Write something, and check if it goes error-free */
//        if( !dcompress && !write_to_descriptor( desc, "\n\rThe ether swirls in chaos.\n\r", 0 ) )
//        if( !dcompress)
//        {
//bug("desc:%d dcompress:%d - %d %d %d %s %s %s", desc,dcompress, room, dport, idle, name, user, host );
//        	if (!write_to_descriptor( desc, "\n\rThe ether swirls in chaos.\n\r", 0 ) )
//        {
//            close( desc ); /* nope */
//            continue;
//        }
//    	}
#ifdef MCCP
        if( !dcompress && !write_to_descriptor_old( desc, "\n\rThe ether swirls in chaos.\n\r", 0 ) )
#else
        if( !write_to_descriptor( desc, "\n\rThe ether swirls in chaos.\n\r", 0 ) )
#endif
        {
            close( desc ); /* nope */
            continue;
        }
        CREATE( d, DESCRIPTOR_DATA, 1 );

        d->next		= NULL;
        d->descriptor	= desc;
        d->connected	= CON_GET_NAME;
        d->outsize	= 2000;
        d->idle		= 0;
        d->lines		= 0;
        d->scrlen		= 24;
        d->newstate	= 0;
        d->prevcolor	= 0x07;
        d->ansi = TRUE;
		d->ifd		= -1;
		d->ipid		= -1;

        CREATE( d->outbuf, char, d->outsize );

        d->user = STRALLOC( user );
        d->host = STRALLOC( host );
        d->port = dport;
        d->idle = idle;
#ifdef MCCP
		/* Start MCCP back up for who ever had it enabled */
		if (dcompress)
			write_to_buffer( d, compress2_on_str_2, 0 );
//			compressStart(d, TELOPT_COMPRESS2);

#endif
        LINK( d, first_descriptor, last_descriptor, next, prev );
        d->connected = CON_COPYOVER_RECOVER; /* negative so close_socket will cut them off */

        /* Now, find the pfile */
        fOld = load_char_obj( d, name, FALSE );

       if( !fOld ) /* Player file not found?! */
        {
            write_to_descriptor( d->descriptor, "\n\rSomehow, your character was lost during hotboot. Contact the immortals ASAP.\n\r", 0 );
            close_socket( d, FALSE );
        }
        else /* ok! */
        {
           write_to_descriptor( d->descriptor, "\n\rTime resumes its normal flow.\n\r", 0 );
            d->character->in_room = get_room_index( room );
            if( !d->character->in_room )
                d->character->in_room = get_room_index( ROOM_VNUM_TEMPLE );

            /* Insert in the char_list */
            add_char( d->character );

            char_to_room( d->character, d->character->in_room );
	      act( AT_MAGIC, "A puff of ethereal smoke disipates around you!", d->character, NULL, NULL, TO_CHAR );
            act( AT_MAGIC, "$n appears in a puff of ethereal smoke!", d->character, NULL, NULL, TO_ROOM );
            d->connected = CON_PLAYING;
            if ( ++num_descriptors > sysdata.maxplayers )
	         sysdata.maxplayers = num_descriptors;
#ifdef I3
	      I3_char_login( d->character );
#endif
        }
    }
    FCLOSE( fp );
    log_string( "Hotboot recovery complete." );
    return;
}
