/*
....[@@@..[@@@..............[@.................. MUD++ is a written from
....[@..[@..[@..[@..[@..[@@@@@....[@......[@.... scratch multi-user swords and
....[@..[@..[@..[@..[@..[@..[@..[@@@@@..[@@@@@.. sorcery game written in C++.
....[@......[@..[@..[@..[@..[@....[@......[@.... This server is an ongoing
....[@......[@..[@@@@@..[@@@@@.................. development project.  All 
................................................ contributions are welcome. 
....Copyright(C).1995.Melvin.Smith.............. Enjoy. 
------------------------------------------------------------------------------
Melvin Smith (aka Fusion)         msmith@falcon.mercer.peachnet.edu 
MUD++ development mailing list    mudpp-list@spice.com
------------------------------------------------------------------------------
pc_wiz.cc
*/

#include "string.h"
#include "llist.h"
#include "room.h"
#include "repop.h"
#include "indexable.h"
#include "server.h"
#include "area.h"
#include "bit.h"
#include "screen.h"
#include "pc.h"

#include "global.h"

// This is a utility function which I change often just for debuggin
// things
void PC::do_debug( String & )
{
	int i;
	String strOut;
	char buf[ 4096 ];
	char buf2[ 4096 ];
	String str( 4096 );
	static timeval avg;
	timeval tin1, tout1, dif1;
	timeval tin2, tout2, dif2, dif3;

	strcpy( buf2, "testing dfasdfkjsadhfklasdfhasdlkfsdfkljh" );

	gettimeofday( &tin1, 0 );
	for( i = 0; i < 100000; i++ )
	{
		strcpy( buf, buf2 );
	}
	gettimeofday( &tout1, 0 );

	dif1.tv_sec = tout1.tv_sec - tin1.tv_sec;
	dif1.tv_usec = tout1.tv_usec - tin1.tv_usec;
	if( dif1.tv_usec < 0 )
	{
		dif1.tv_sec--;
		dif1.tv_usec += 1000000;
	}

	strOut.sprintf( "char time: secs(%ld) usec(%ld)\n\r",
			dif1.tv_sec, dif1.tv_usec );

	out( strOut );

	gettimeofday( &tin2, 0 );
	for( i = 0; i < 100000; i++ )
	{
		str = buf2;
	}
	gettimeofday( &tout2, 0 );

	dif2.tv_sec = tout2.tv_sec - tin2.tv_sec;
	dif2.tv_usec = tout2.tv_usec - tin2.tv_usec;
	if( dif2.tv_usec < 0 )
	{
		dif2.tv_sec--;
		dif2.tv_usec += 1000000;
	}

	strOut.sprintf( "Str time: secs(%ld) usec(%ld)\n\r",
			dif2.tv_sec, dif2.tv_usec );

	out( strOut );

	dif3.tv_sec = dif2.tv_sec - dif1.tv_sec;
	dif3.tv_usec = dif2.tv_usec - dif1.tv_usec;
	if( dif3.tv_usec < 0 )
	{
		dif3.tv_sec--;
		dif3.tv_usec += 1000000;
	}

	strOut.sprintf( "Diff: secs(%ld) usec(%ld)\n\r",
			dif3.tv_sec, dif3.tv_usec );

	out( strOut );
}


// Just a test to get ident working. Will do non-blocking when
// this is done.
void PC::do_ident( String & arg )
{
	char ip[ 256 ];
	char buf[ 256 ];

	PC *pc;
	Socket *socket;

	if( !( pc = getPCWorld( arg ) ) )
	{
		out( "No such player connected.\n\r" );
		return;
	}

	strcpy( ip, pc->getSock()->getHostName() );

	socket = new Socket( ip, 113 );

	if( socket->error() )
	{
		out( "Socket error.\n\r" );
		delete socket;
		return;
	}

	if( socket->connect() == -1 )
	{
		out( "Connect error.\n\r" );
		delete socket;
		return;
	}

	out( "Connected to ident server on " );
	out( socket->getHostName() );
	out( "\n\r" );

	int foreign_port = pc->getSock()->getPort();
	int size = sprintf( buf, "%d , %d\n\r", foreign_port, 4000 );

	socket->write( buf, size );
	*buf = 0;
	while( !*buf )
		socket->read( buf );

	delete socket;

	out( buf );
}


void PC::do_cat( String & arg )
{
	if( !arg )
		return;

	view( arg.chars() );
}


void PC::do_users( String & )
{
	String str;
	PC *pc;
	LList<PC> tlist = pcs;
	tlist.reset();

	str = "Name       Host          Foreign Port\n\r";
	
	while( ( pc = tlist.peek() ) )
	{
		tlist.next();

		str.sprintfAdd( "%13s%20s%-7d\n\r", pc->getName().chars(),
				pc->getSock()->getHostName(),
				pc->getSock()->getPort() );
	}

	out( str );
}


void PC::do_echo( String & arg )
{
	String str;

	str <<  "\n\n\r" << arg << "\n\r";

	outAllCharExcept( str, 0, 0 );
}


void PC::do_immtalk( String & arg )
{
	PC *ch;
	LList<PC> tlist = pcs;

	String str;
	str << BYELLOW << name << " : " << arg << "\n\r" << NTEXT;

	tlist.reset();

	while( ( ch = tlist.peek() ) )
	{
		if( ch != this )
			ch->out( "\n\r" );

		ch->out( str );
		tlist.next();
	}
}


void PC::do_advance ( String & arg )
{
	if( classnow != CLASS_IMM )
	{
		out("You wish you were this powerful.\n\r");
		return;
	}

	arg.startArgs();

	String argName	= arg.getArg();
	String argLevel	= arg.getArg();

	if( !argName || !argLevel )
	{
		out( "Usage: advance <person> <level>\n\r" );
		return;
	}

	PC *plr = in_room->getPC( argName );
	if( !plr )
	{
		out( "No one here by that name.\n\r" );
		return;
	}

	int lev = argLevel.asInt();
	if( lev < 1 )
	{
		out( "No can do.\n\r" );
		return;
	}

	// Need to check levels here.
	plr->advance( lev );
}


void PC::do_memory( String & )
{
	out( "\n\r[disabled for now  --Fusion]\n\r" );
}


void PC::do_invis( String & )
{
	char buf[ BUF ];
/*if( IsInvisible() )
 
	{
		out( "You fade into existence.\n\r" );
		sprintf( buf, "\n\n\r%s fades into existence.\n\r", name.chars() ); 
	}
	else
	{
		out( "You suddenly vanish.\n\r" );
		sprintf( buf, "\n\n\r%s suddenly vanishes into thin air.\n\r", name.chars() );
	}
*/ 
//TOGGLE_BIT( obj_flags, OBJ_INVISIBLE );
//	in_room->outAllCharExcept( buf, this, NULL ); 
}

void PC::do_goto( String & arg )
{
	String str;
	Char *ch;
	Room *to;

	// Search players first, then NPCs
	if( !( ch = getPCWorld( arg ) ) )
		ch = getNPCWorld( arg );

	if( ch && ch->inRoom() )
		to = ch->inRoom();
	else
	{
		// Now try rooms in this area unless scope: was specified
		Index x( arg );
		if( !x.getScope() )
			x.setScope( in_room->getArea()->getKey() );

		if( !( to = lookupRoom( x ) ) )
		{
			// Now try global (no scope)
			x.setScope( "" );
			to = lookupRoom( x );
		}
	}

	if( !to )
	{
		out("No such location.\n\r");
		return;
	}

	if( to == in_room )
		return;

	str << "\n\r" << name << " disappears in a puff of smoke.\n\r";
	in_room->outAllCharExcept( str, this, NULL );

	// We can use simple out() since character not in room yet.

	in_room->rmCharInv( this );
	str.clr();
	str << "\n\r" << name << " appears with an ear-splitting BANG!!\n\r";
	to->out( str );
	to->addCharInv( this );
	do_look( "" ); 
}



void PC::do_transfer( String & arg )
{
	Room *src;
	Room *dest = in_room;
	Char *ch = getPCWorld( arg );

	if( !ch )
	{
		ch = getNPCWorld( arg );
		if( !ch )
		{
			out( "No such character, Coolio.\n\r" );
			return;
		}
	}

	if( !( src = ch->inRoom() ) )
	{
		out( "PC::do_transfer() : victim not in a room." );
		return;
	}

	src->outAllCharExcept( ch->getShort(), ch, 0 );
	src->outAllCharExcept( " dissappears in a mushroom cloud.\n\r", ch, 0 );

	ch->inRoom()->rmCharInv( ch );
	ch->out( shortdesc );
	ch->out( " has transferred you!\n\r" );
	dest->outAllCharExcept( ch->getShort(), ch, 0 );
	dest->outAllCharExcept( " arrives from a puff of smoke.\n\r", ch, 0 );
	dest->addCharInv( ch );
	if( ch->isPC() )
		((PC *)ch)->do_look( "" );
}


void PC::do_slay( String & arg )
{
	if( !arg )
	{
		out( "\n\rWho shall we be slaying?\n\r" );
		return;
	}

	Char *ch = in_room->getChar( arg );

	if( !ch )
	{
		out( "\n\rHmm, you must need your eyes checked.\n\r" );
		return;
	}

	if( ch == this )
	{
		out( "\n\rAren't we funny today?\n\r" );
		return;
	}
    
	// OK - Lets build the corpse Object.
	// This stuff is so straighforward I don't make a seperate function.
   
	String str;
	Object *corpse = new Object;

	corpse->setName( "corpse" );
	str << "the corpse of " << ch->getShort();
	corpse->setShort( str );
	str.clr();
	str << "The corpse of " << ch->getShort() << " lies here, rotting.";
	corpse->setLong( str );
	corpse->setWeight( ch->getWeight() );
	corpse->setType( ITEM_CORPSE );
	corpse->setTimer( 2 );

	corpse->toWorld();
	in_room->addObjInv( corpse );
	ch->inRoom()->rmCharInv( ch ); 
	ch->out( "\n\n\r** YOU HAVE BEEN SLAIN!!! **\n\r" );
	out( "\n\rAAAAAHG - Blood everywhere!!!\n\r" );
	str.clr();
	str << "\n\n\r" << name << " chops " << ch->getShort()
		<< " to pieces!!!\n\r*SPLATTER*\n\r";
   
	in_room->outAllCharExcept( str, this, ch );
  
	// Mob corpses are traditional. Transfer the inventory to corpse.
	if( ch->isNPC() )
	{
	}   

	if( ch->isNPC() )
	{
		ch->fromWorld();
		delete ch; 
		return;
	}

	//INCOMPLETE
	((PC*)ch)->setState( STATE_MAIN_MENU );  
}



void PC::do_purge( String & )
{
	Char *ch;
	Object *obj;

	in_room->chars.reset();
	while( ( ch = in_room->chars.peek() ) )
	{
		if( ch->isNPC() )
		{
			out( "Purging " );
			out( ch->getShort() );
			out( ".\n\r" );
			in_room->rmCharInv( ch );
			ch->fromWorld();
			delete ch;
			continue;
		}

		in_room->chars.next();	
	}

	in_room->inv.reset();
	while( ( obj = in_room->inv.remove() ) )
	{
		out( "Purging " );
		out( obj->getShort() );
		out( ".\n\r" );
		obj->fromWorld();
		delete obj;
	}
}



void PC::do_page( String & )
{

}



void PC::do_reboot( String & )
{
	String str;
	DOWN = 1;
	REBOOT = 1;
	str << "\n\rRebooted by " << name << "\n\n\r";
	out( str );
}


void PC::do_shutdown( String & )
{
	String str;
	DOWN = 1;
	str << "\n\rShutdown by " << name << "\n\n\r";
	out( str );
}


void PC::do_rfind( String & arg )
{
	bool global = false;
//	bool wildcard = false;
	String str( BUF * 2 );
	const Room * ptr;
	Area *area = in_room->getArea();

	if( arg == "all" )
	{
		global = true;
		areas.reset();
		while( ( area = areas.peek() ) )
		{
			areas.next();

			str << "\n\r--:" << area->getName() << ":--\n\r";
			area->roomIndex.reset();

			while( ( ptr = area->roomIndex.peek() ) )
			{
				area->roomIndex.next();
     
				str.sprintfAdd( "%-30s%-40s\n\r",
						ptr->getKey().chars(),
						ptr->getName().chars() );
			}

		}
	}
	else
	{
		str << "Rooms in this area:\n\r-----------------------\n\r";
		area->roomIndex.reset();

		while( ( ptr = area->roomIndex.peek() ) )
		{
			area->roomIndex.next();
     
			str.sprintfAdd( "%-30s%-40s\n\r",
					ptr->getKey().chars(),
					ptr->getName().chars() );
		}
	}

	out( str );
}



void PC::do_ofind( String & arg )
{
	String str( BUF * 2 );
	String strName;
	String strArea;
	bool wildcard = false;

	const Object * ptr;
	Area *area;

	bool global = false;

	if( !arg )
	{
		out( "Find what?\n\r" );
		return;
	}

	// Use index object to parse arg
	Index index( arg );
	strName = index.getKey();
	strArea = index.getScope();
	
	IndexList<Object> *objIndex;

	if( strArea && strArea == "*" )
	{
		global = true;
	}

	if( strName == "*" )
	{
		wildcard = true;
	}

	str	<< "Looking up [" << strName << "]\n\r-------------\n\r";

	if( !global )
	{
		if( !strArea )
			objIndex = &in_room->getArea()->objIndex; 
		else
		{
			if( !( area = lookupArea( strArea ) ) )
			{
				str << "Unknown area " << strArea << "\n\r";
				out( str );
				return;
			}
	
			objIndex = &area->objIndex;
		}

		objIndex->reset();
		while( ( ptr = objIndex->peek() ) )
		{
			index = objIndex->getIndex();
			objIndex->next();

			if( !wildcard && !ptr->isName( strName ) )
				continue;
     
			str.sprintfAdd( "%-30s%-40s\n\r",
					index.getKey().chars(),
					ptr->getShort().chars() );
		}
	}
	else
	{
		areas.reset();

		while( ( area = areas.peek() ) )
		{
			areas.next();

			objIndex = &area->objIndex;
			objIndex->reset();

			while( ( ptr = objIndex->peek() ) )
			{
				// Get the index of that object
				index = objIndex->getIndex();

				// Then increment
				objIndex->next();

				if( !wildcard && !ptr->isName( strName ) )
					continue;
			
				str.sprintfAdd( "%17s:%-30s%-31s\n\r",
						area->getKey().chars(),
						index.getKey().chars(),
						ptr->getShort().chars() );
			}
		}
	}

	out( str );
}


void PC::do_owhere( String & arg )
{
	Object *obj;
	String str( BUF );

	if( !arg )
		return;

	objects.reset();
	while( ( obj = objects.peek() ) )
	{
		objects.next();

		if( !obj->isName( arg ) )
			continue;
		else if( obj->inRoom() )
		{
			str.sprintfAdd( "%-20s in room %20s\n",
					obj->getShort().chars(), obj->inRoom()->getName().chars() );
		}
		else if( obj->inChar() )
		{
			str.sprintfAdd( "%-20s carried by %20s\n",
					obj->getShort().chars(), obj->inChar()->getShort().chars() );
		}
		else if( obj->inObj() )
		{
			str.sprintfAdd( "%-20s inside %20s\n",
					obj->getShort().chars(), obj->inObj()->getShort().chars() );
		}
		else
		{
			str.sprintfAdd( "%-20s is just sort of floating around! BUG!\n",
					obj->getShort().chars() );
		}
	}

	if( !str )
		str.sprintf( "Could not find any %s.\n\r", arg.chars() );

	out( str );
}


void PC::do_mfind( String & arg )
{
	String str( BUF * 2 );
	String strName;
	String strArea;
	char arg1[ 256 ];
	const NPC *ptr;
	Area *area;
	bool global = false;
	bool wildcard = false;

	if( !arg )
	{
		out( "Find what?\n\r" );
		return;
	}

	IndexList<NPC> *npcIndex;

	// Use index constructor to parse the string
	Index index( arg );
	strArea = index.getScope();
	strName = index.getKey();

	if( strArea && strArea == "*" )
	{
		global = true;
	}

	if( strName == "*" )
	{
		wildcard =  true;
	}

	str	<< "Looking up [" << strName << "]\n\r-------------\n\r";

	if( !global )
	{
		if( !strArea )
			npcIndex = &in_room->getArea()->npcIndex; 
		else
		{
			if( !( area = lookupArea( strArea ) ) )
			{
				str << "Unknown area " << strArea << "\n\r";
				out( str );
				return;
			}
	
			npcIndex = &area->npcIndex;
		}

		npcIndex->reset();
		while( ( ptr = npcIndex->peek() ) )
		{
			// Get index for that npc
			index = npcIndex->getIndex();

			// Increment
			npcIndex->next();

			if( !wildcard && !ptr->isName( strName ) )
				continue;
     
			str.sprintfAdd( "%-30s%-40s\n\r",
					index.getKey().chars(),
					ptr->getShort().chars() );
		}
	}
	else
	{
		areas.reset();

		while( ( area = areas.peek() ) )
		{
			areas.next();

			npcIndex = &area->npcIndex;
			npcIndex->reset();

			while( ( ptr = npcIndex->peek() ) )
			{
				// Get index of npc
				index = npcIndex->getIndex();

				// Then increment
				npcIndex->next();

				if( !wildcard && !ptr->isName( strName ) )
					continue;
			
				str.sprintfAdd( "%17s:%-25s%-31s\n\r",
						area->getKey().chars(),
						index.getKey().chars(),
						ptr->getShort().chars() );
			}
		}
	}

	out( str );
}

void PC::do_cset( String & arg )
{
}

void PC::do_grant( String & arg )
{
	PC *ch;
	String person;
	String privilege;
	int bit;

	arg.startArgs();

	privilege	= arg.getArg();
	person		= arg.getArg();

	if( !person || !privilege )
	{
		out( "grant <privilege> <person>\n\r" );
		return;
	}

    ch = getPCWorld( person );
    if( !ch )
    {
        out( "Could not find anyone by that name.\n\r" );
        return;
    }

	if( privilege == "all" )
	{
	}
	else
	{
		bit = getPrivBit( privilege.chars() );
		if( bit == NULLBIT )
		{
			out( "No such privilege to grant.\n\r" );
			return;
		}

		ch->setPrivBit( bit );
		out( "Privilege granted to " );
		out( ch->getName() );
		out( ".\n\r" );
	}
}


void PC::do_revoke( String & arg )
{
	PC *ch;
	int bit;
	String privilege;
	String person;

	arg.startArgs();

	privilege	= arg.getArg();
	person		= arg.getArg();

	if( !person || !privilege )
	{
		out( "revoke <privilege> <person>\n\r" );
		return;
	}

    ch = getPCWorld( person );
    if( !ch )
    {
        out( "Could not find anyone by that name.\n\r" );
        return;
    }

	if( privilege == "all" )
	{
	}
	else
	{
		bit = getPrivBit( privilege.chars() );
		if( bit == NULLBIT )
		{
			out( "No such privilege to revoke.\n\r" );
			return;
		}

		ch->rmPrivBit( bit );
		out( "Privilege revoked from " );
		out( ch->getName() );
		out( ".\n\r" );
	}
}