///////////////////////////////////////////////////////////
///////////////// Have an itch? Scratch it! ///////////////
///////////////////////// SCRATCH /////////////////////////
/////////////////////  A MUD  Server   ////////////////////
///////////////////// By: Jared Devall ////////////////////
/////////////////////      Thanks:     ////////////////////
/////////////////////  DIKU/Merc/ROM   ////////////////////
///////////////////// Aetas/Deus Gang  ////////////////////
/////////////////////       Beej       ////////////////////
///////////////////////////////////////////////////////////

#include "handler.h"
#include "avatar.h"
#include "world.h"
#include "stringutil.h"
#include "commandTable.h"
#include "timestamp.h"
#include "room.h"
//#include <arpa/telnet.h>
#include <iostream>
#include <cstring>
#include <list>

using namespace std;

void GetNameHandler::Enter( Avatar * avatar )
{
}
void GetNameHandler::Exit( Avatar * avatar )
{
	delete this;
	return;
}


void GetNameHandler::Handle( Avatar * avatar, const string &input) {
	if ( input.empty() )
		return;
		
	if ( !avatar->SetName( input ) ) {
		avatar->Send( "Names must be 3-15 characters in length.\n\r" );
		return;
	}
		
    avatar->ReplaceHandler( new CheckNameHandler );

}


string GetNameHandler::Prompt( Avatar * avatar ) {
  return "Give us a name: ";
}

void InputHandler::Enter( Avatar * avatar )
{
    // put in the initial room
    Room *r = NULL;

    if ( (r = World::Instance().FindRoom(avatar->Get("last_room"))) == NULL )
      r = World::Instance().FindRoom(ROOM_LIMBO);

    r->InsertAvatar(avatar,true);
}
void InputHandler::Exit( Avatar * avatar ) {
	delete this;
}


void InputHandler::Handle( Avatar * avatar, const string &input )
{
	if ( input.empty() )
		return;
		
	CommandTable::Instance().Execute( avatar, input );
}


string InputHandler::Prompt( Avatar * avatar )
{
	string buf;
	string prompt;
	
	prompt = avatar->Get( "prompt" );

    if ( prompt.empty() )
    	prompt = "%R> ";

    for ( string::iterator cChar = prompt.begin(); cChar != prompt.end(); ++cChar ) { 
        if ( (*cChar) == '%' )
        {
        	++cChar;
        	switch ( (*cChar) )
            {
        		case 'R':
                    if ( avatar->_room )
            		    buf << avatar->_room->Get("name");
                    else
                        buf << "The Void";
        		   break;
        		case 'T':
        		   buf << Timestamp::Instance().GetTime();
        		   break;
        		case 's':
        		   buf << ' ';
        		   break;
        		case 'c':
        		   buf << "\n\r";
        		   break;
        		case '%':
        		   buf << '%';
        		   break;
        		default:
        		   string buf2;
        		   buf2 << "Invalid escape code: " << (*cChar) << "\n\r";
        		   avatar->Send( buf2 );        		   
            }
        } else
        {
            buf << (*cChar);
        }
    }	
    buf << "{x";
    return buf;
}
///////////////////// checkNameHandler ///////////////////////

void CheckNameHandler::Enter( Avatar * avatar )
{
    if ( !avatar->Load() )
    	avatar->Send( "That username does not exist.\n\r" );
    else
    {
		string name;
        
        avatar->Send( "Username found.\n\r" );
        avatar->ReplaceHandler( new GetPasswordHandler );
	}    
}

void CheckNameHandler::Exit( Avatar * avatar )
{
	delete this;
}


void CheckNameHandler::Handle( Avatar * avatar, const string &input)
{
	if ( input.empty() )
		return;

    switch ( input[0] ) {
	case 'Y':
    case 'y':
    	avatar->Send( "User created.\n\r" );
        avatar->ReplaceHandler( new GetPasswordHandler );
        break;

    case 'n':
    case 'N':
      avatar->Send( "User not created.\n\r" );
      avatar->ReplaceHandler( new GetNameHandler );
      break; 
  }

}


string CheckNameHandler::Prompt( Avatar * avatar ) {
  return "Create a new User? [Y/N] ";
}

///////////////////// GetPasswordHandler ///////////////////////
string thePassword;
int tries = 0;
void GetPasswordHandler::Enter( Avatar * avatar ) {	
//     static const char echo_off[] = {IAC, WILL, TELOPT_ECHO, '\0'};
//     avatar->Send( echo_off );
     //avatar->GetSocket()->FlushInput( );
}

void GetPasswordHandler::Exit( Avatar * avatar ) {
//	static const char echo_on[] = {IAC, WONT, TELOPT_ECHO, '\0'};
//    avatar->Send( echo_on );
	delete this;
}

void GetPasswordHandler::Handle( Avatar * avatar, const string &input )
{
	list< Avatar *>::iterator a_it;
	
	if ( input.empty() )
		return;

	thePassword = avatar->Get( "password" );
	if ( thePassword.empty() )
    {
    	if ( avatar->Set( "password", avatar->EncryptPassword( input ) ) )
    		avatar->Send( "Password Acceptable.\n\r" );
    }
    else
    {
    	if ( avatar->VerifyPassword( input ) )
        {
    		avatar->Send( "Passwords match.\n\r\n\r" );
    		avatar->Set( "login", Timestamp::Instance().GetDateTime() );
    		avatar->Save();
    		avatar->Load();  //reload?
    		
    		for ( a_it = World::Instance()._avatarList.begin(); a_it != World::Instance()._avatarList.end(); ++a_it ) {
        		if ( ( (*a_it) != avatar ) && ( (*a_it)->GetStatus() == CONNECTED ) && ( (*a_it)->Get( "name" ) == avatar->Get( "name" ) ) ) {
        			int previous_descriptor = (*a_it)->GetSocket()->GetDescriptor();
        			(*a_it)->GetSocket()->SetDescriptor( avatar->GetSocket()->GetDescriptor() );
 			   	avatar->GetSocket()->SetDescriptor( previous_descriptor );
 			   	avatar->SetDisconnected( true ); 			   	
 			   	(*a_it)->Send( "You have reconnected.\n\r" );
 			   	(*a_it)->Set( "login", Timestamp::Instance().GetDateTime() );
 			   	string buf;
 			   	buf << "## " << avatar->Get( "name" ) << " has reconnected.\n\r";
					World::Instance().Broadcast( buf, WCONNECTED );					
					cout << avatar->Get( "name" ) << " has reconnected @ " << Timestamp::Instance().GetDateTime() << "\n\r";
 			   	return;
 				}           
	    	}
	    	
	    	string buf;
			avatar->SetStatus( CONNECTED );			
			buf << "## " << avatar->Get( "name" ) << " has connected.\n\r";
			World::Instance().Broadcast( buf, WCONNECTED );
			cout << avatar->Get( "name" ) << " has connected @ " << Timestamp::Instance().GetDateTime() << "\n\r";
			
            avatar->ReplaceHandler( new InputHandler );
    	}
        else
        {
    		tries++;
    		avatar->Send( "Passwords do not match.\n\r" );
    		thePassword.erase();    		
       	    switch ( tries )
            {
      	      default:
    	    	case 3: 
    	    		avatar->Send( "No more chances.\n\r" ); 
    	    		avatar->ClearPassword();
    	    		avatar->ReplaceHandler( new GetNameHandler ); 
    	    		tries = 0;
    	    		break;
    	    	case 2: avatar->Send( "1 more chance.\n\r" ); break;
    	    	case 1: avatar->Send( "2 more chances.\n\r" ); break;
    	    	case 0: avatar->Send( "3 more chances.\n\r" ); break;
    	   } 	
    	   	
    	}
    }

}


string GetPasswordHandler::Prompt( Avatar * avatar )
{
  return "Enter password: ";
}