///////////////////////////////////////////////////////////
///////////////// 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 <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 ) {	
}
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':
        		   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();   		
    		
    		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: ";
}