/* The Other Realm Account Code */

#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#include "include.h"
#include "channel.h"

extern const struct	acnt_cmdfun_type acnt_cmdfun_table[];
extern std::list<Channel *> chanList;
void account_gen(DESCRIPTOR_DATA *d, char *arg )
{	ACCOUNT *pAcnt;
	char buf[MSL];
	while(isspace(*arg)) arg++;

	if(d->account) pAcnt = d->account;
	switch(d->connected)
	{	case CON_GET_ACCOUNT_NAME:
			if(!check_parse_name(arg) )
			{	write_to_buffer(d, "Illegal name. Try another.\n\r", 0 );
				return;
			}
			if( ( pAcnt = load_account(d, arg ) ) == NULL )
			{	sprintf(buf, "{DWelcome to The Other Realm. The account by the name {r'{W%s{r'{D\r\n" 
							 "was not found. Would you like to create a new one?{r[{WY{D/{WN{r]{x\n\r", capitalize(arg) );
				write_to_buffer(d, buf, 0 );
				pAcnt = account_new();
				pAcnt->name = str_dup(capitalize(arg) );
				d->account	= pAcnt;
				pAcnt->desc = d;
				d->connected = CON_CONFIRM_ACCOUNT_NAME;
				return;
			}


			write_to_buffer(d, "{DPlease enter your password\n\r{W-->", 0 );
			d->connected = CON_CHECK_ACCOUNT_PASSWORD;
			return;
		case CON_CONFIRM_ACCOUNT_NAME:
			switch(UPPER(arg[0] ) )
			{	case 'Y':
					sprintf(buf, "{W%s{D it is! Welcome. Now, we require a password for your account\n\r{W-->{x", pAcnt->name );
					write_to_buffer(d, buf, 0);
					d->connected = CON_GET_ACCOUNT_PASSWORD;
					break;
				case 'N':
					write_to_buffer(d, "{DOk then. What shall your name be?{x\n\r", 0);
					free_account(pAcnt);
					d->connected = CON_GET_ACCOUNT_NAME;
					break;
				default:
					write_to_buffer(d, "{DPlease choose either {WY{Des, or {WN{Do{x.\n\r",0);
					break;
			}
			break;
		case CON_GET_ACCOUNT_PASSWORD:
			if(arg[0] == '\0' )
			{	write_to_buffer(d, "{DWhat type of password is that!? Please choose another\n\r{W-->",0);
				return;
			}
			pAcnt->password = str_dup(arg);
			write_to_buffer(d, "{DPlease retype so that we can confirm your password.\n\r{W-->", 0 );
			d->connected = CON_CONFIRM_ACCOUNT_PASSWORD;
			return;
		case CON_CONFIRM_ACCOUNT_PASSWORD:
			if(!strcmp(pAcnt->password, arg ) )
			{	write_to_buffer(d, "{DPassword confirmed.\n\r", 0);
				write_to_buffer(d, "From which MUD do you hail? (We just want the name of the mud, no url/ports please!)\n\r", 0);
				d->connected = CON_GET_MUD;
				return;
			}
			free_string(pAcnt->password);
			write_to_buffer(d, "{DPasswords did not match. What would you like your password to be?\n\r{W-->", 0 );
			d->connected = CON_GET_ACCOUNT_PASSWORD;
			return;
		case CON_CHECK_ACCOUNT_PASSWORD:
			if(!strcmp(arg, pAcnt->password ) )
			{	if(check_reconnect(pAcnt) )
					return;
				if(pAcnt->initLogin == 0)
				{   write_to_buffer(d, "Welcome to MUD-Con V!\n\r",0);
				    pAcnt->sendChanHelp();
				}
				else
				{   sprintf(buf, "{DWelcome back to MUD-Con V, {W%s{D.\n\r", pAcnt->name);
				    write_to_buffer(d, buf, 0);
				}
				d->connected = CON_OOC_CHAT;
				infoChan("%s has entered the MUD-Con.", pAcnt->name);
				return;
			}
			write_to_buffer(d, "{DSorry, that password was incorrect.\n\r",0 );
			close_socket(d);
			free_account(pAcnt);
			return;
		case CON_ACCOUNT_MENU:
			if(arg[0] == '\0' )
			{	send_accnt_menu(pAcnt);
				return;
			}

			switch (arg[0])
			{	case '1':
					write_to_buffer(d, "{DWelcome to The Other Realm Chat Room, for OOC chatter.\n\r",0);
					d->connected = CON_OOC_CHAT;
					infoChan("%s has entered the MUD-Con.", pAcnt->name);
					break;
				case '2':
					write_to_buffer(d, "The Forums havn't been written!\n\r", 0 );
  				return;
			  default: send_accnt_menu(pAcnt);
			  					break;
			}
			break;
		case CON_ASK_RECONNECT:
			switch(UPPER(arg[0]) )
			{	case 'Y':
					reconnect_account(pAcnt);
					d->connected = CON_OOC_CHAT;
					infoChan("%s has re-entered the MUD-Con.", pAcnt->name);
					break;
				case 'N':
					free_account(pAcnt);
					d->account = NULL;
					d->connected = CON_GET_ACCOUNT_NAME;
					write_to_buffer(d, "Ok then! What name shall you use?\n\r",0);
					break;
				default:
					ptc(pAcnt, "Yes, or no?\n\r");
					break;
			}
			break;
		case CON_GET_MUD:
			if(arg[0] == '\0' )
			{	write_to_buffer(d, "What kind of mud name is that!?\n\r",0);
				break;
			}
			free_string(pAcnt->mud);
			pAcnt->mud = str_dup(arg);
			write_to_buffer(d, "What is the URL for this MUD? (You can include a port)\n\r",0);
			d->connected = CON_GET_URL;
			break;
		case CON_GET_URL:
			if(arg[0] == '\0' )
			{	write_to_buffer(d, "What kind of URL is that?\n\r",0);
				break;
			}
			free_string(pAcnt->url);
			pAcnt->url = str_dup(arg);
			write_to_buffer(d, "All your information are belong to us. Thanks for coming by MudCon! Please converse... NOW!\n\r",0);
			addAttendant(pAcnt);
			d->connected = CON_OOC_CHAT;
			infoChan("%s has entered the MUD-Con.", pAcnt->name);
			pAcnt->sendChanHelp();
			break;
			
		default: write_to_buffer(d, "You suck\n\r",0); break;
	}
	return;
			
}


void send_accnt_menu(ACCOUNT *pAcnt )
{	write_to_buffer(pAcnt->desc, "{D*****************************************************\n\r",0 ); 
	write_to_buffer(pAcnt->desc, "{D* * * * * * * * * * * * * * * * * * * * * * * * * * *\n\r",0 ); 
	write_to_buffer(pAcnt->desc, "{D*****************************************************\n\r",0 ); 
	write_to_buffer(pAcnt->desc, "{D* *{W          Other Realm Account Menu             {D* *\n\r",0 ); 
	write_to_buffer(pAcnt->desc, "{D*{r*{D*{W Please choose one of the Following Options    {D*{r*{D*\n\r",0 ); 
	write_to_buffer(pAcnt->desc, "{D* ************************************************* *\n\r",0 ); 
	write_to_buffer(pAcnt->desc, "{D*{r*{D* * * * * * * * * * * * * * * * * * * * * * * * *{r*{D*\n\r",0 ); 
	write_to_buffer(pAcnt->desc, "{D* ************************************************* *\n\r",0 );
  write_to_buffer(pAcnt->desc, "{D* {r({D1{r){w Log into Chat           {r({D2{r){w Check MUD-Forum   {D*\n\r",0 );
	write_to_buffer(pAcnt->desc, "{D*****************************************************\n\r",0 ); 
	write_to_buffer(pAcnt->desc, "{D* * * * * * * * * * * * * * * * * * * * * * * * * * *\n\r",0 ); 
	write_to_buffer(pAcnt->desc, "{D*****************************************************\n\r",0 ); 
	write_to_buffer(pAcnt->desc, "{D\n\rPlease choose an option\n\r{W-->", 0 );
	return;
}



void interp_acnt_cmd(ACCOUNT *pAcnt, char *argument )
{	ACNT_CMD *pCmd;
	char cmd[MSL];
	char *orig;
	Channel *chan;
	orig = str_dup(argument);
	while(isspace(*argument)) argument++;
	if(argument[0] == '\0' )
		return;
	argument = one_argument(argument,cmd);
	if( (chan = Channel::find(cmd) ) )
	{	chan->interpret(pAcnt, argument);
		return;
	}
	for(pCmd = acnt_cmd_list ; pCmd ; pCmd = pCmd->next )
	{	if (LOWER(cmd[0]) == LOWER(pCmd->name[0])
        &&  !str_prefix( cmd,pCmd->name))
        {	if(pCmd->level > pAcnt->level )
				break;
			( *pCmd->do_fun ) (pAcnt, argument );
			return;
		}
	}
	logfp(LOG_CMD, "%s:%s", pAcnt->name, orig);
	if(pAcnt->lastfun)
	{	(*pAcnt->lastfun) (pAcnt, orig);
		free_string(orig);
		return;
	}
	free_string(orig);
	write_to_buffer(pAcnt->desc, "That isn't a valid command.\n\r",0 );
	return;
}

void load_accnt_cmds()
{	FILE *fp;
	ACNT_CMD *pCmd;
	char *word;
	char buf[MSL];

	sprintf(buf, "%s%s%s", DATA_DIR, CMD_DIR, ACNT_CMD_FILE );
	if( ( fp = fopen(buf, "r") ) == NULL )
	{	perror(buf);
		return;
	}

	for(word = fread_word(fp); strcasecmp(word, END_CHAR); word = fread_word(fp) )
	{	if(!strcasecmp(word, "name" ) )
		{	pCmd = acnt_cmd_new();
			if(!acnt_cmd_list)
				acnt_cmd_list = pCmd;
	
			if(acnt_cmd_last)
				acnt_cmd_last->next = pCmd;

			acnt_cmd_last = pCmd;
			SREAD(pCmd->name);
			continue;
		}
		if(!strcasecmp(word, "dofun" ) )
		{	if( (pCmd->do_fun = acntdofun_lookup(fread_string(fp)) ) == NULL ) //When I get a logging function. Gotta be added here.
			{	logfp(LOG_BUG, "CmdFun not found: %s", word);
				break;
			}
			continue;
		}

		IREAD("Lvl", pCmd->level );
		

		//Another logging function here to state that something wasn't valid.
	}
	fclose(fp);
	return;
}

AC_CMD * acntdofun_lookup( const char *name )
{	int cmd;
	for( cmd = 0; acnt_cmdfun_table[cmd].name != NULL; cmd++ )
	{	if(LOWER(name[0]) == LOWER(acnt_cmdfun_table[cmd].name[0])
		&& !str_prefix(name, acnt_cmdfun_table[cmd].name ) )
			return acnt_cmdfun_table[cmd].do_fun;
	}
	return NULL;
}

void save_account(ACCOUNT *pAcnt )
{	FILE *fp;
	char buf[MSL];

	sprintf(buf, "%s%s", ACCOUNT_DIR, pAcnt->name );
	if( ( fp = fopen(buf, "w" ) ) == NULL )
	{	logfp(LOG_BUG, "SAVE_ACCOUNT: Failed on Fopen, %s\n", pAcnt->name );
		return;
	}

	fprintf(fp, "Name %s~\n", pAcnt->name );
	fprintf(fp, "Pswd %s~\n", pAcnt->password );
	fprintf(fp, "Lvl  %d\n", pAcnt->level );
	fprintf(fp, "CmnF " ); save_flags(common_table, fp, COMMON_MAX, pAcnt->common_flags );
	fprintf(fp, "ChnF " ); save_flags(channel_table, fp, CHANNEL_MAX, pAcnt->channel );
	if(IS_SET(pAcnt->common_flags, COMMON_AFK ) )
		fprintf(fp, "AfkS %s~\n", pAcnt->afk_string );
	fprintf(fp, "Read %s~\n", pAcnt->read );
	fprintf(fp, "Mud %s~\n", pAcnt->mud );
	fprintf(fp, "Url %s~\n", pAcnt->url );
	fprintf(fp, "CPst %s~\n", pAcnt->custPost);
	fprintf(fp, "CTpc %s~\n", pAcnt->custTopic);
	fprintf(fp, "CRpl %s~\n", pAcnt->custReply);
	fprintf(fp, "MMade 1\n");
	std::list<Topic *>::iterator i;
	std::list<Channel *>::iterator ch;	
	for(ch = chanList.begin(); ch != chanList.end() ; ++ch)
	{	if( pAcnt->ignore[(*ch)->bit].size() <= 0)
			continue;
		for( i = pAcnt->ignore[(*ch)->bit].begin() ; i != pAcnt->ignore[(*ch)->bit].end() ;++i)
			fprintf(fp, "Ign %d %s\n\r", (*i)->id, (*ch)->name);
	
	}
	fprintf(fp, "%s\n", END_CHAR );
	fclose(fp);
	return;
}

ACCOUNT *load_account(DESCRIPTOR_DATA *d, char *name)
{	FILE *fp;
	char buf[MSL];
	char *word;
	ACCOUNT *pAcnt;

	sprintf(buf, "%s%s", ACCOUNT_DIR, capitalize(name) );
	if( ( fp = fopen(buf, "r" ) ) == NULL )
		return NULL;
	pAcnt = account_new();
	for(word = fread_word(fp); strcmp(word, END_CHAR); word = fread_word(fp) )
	{	if(!strcasecmp(word, "Name" ) )
		{	SREAD(pAcnt->name);
			continue;
		}
		if(!strcasecmp(word, "Pswd" ) )
		{	SREAD(pAcnt->password);
			continue;
		}
		if(!strcasecmp(word, "Read") )
		{	SREAD(pAcnt->read);
			continue;
		}
		if(!strcasecmp(word, "CmnF" ) )
		{	load_flags(common_table, fp, COMMON_MAX, pAcnt->common_flags );
			continue;
		}
		if(!strcasecmp(word, "ChnF" ) )
		{	load_flags(channel_table, fp, CHANNEL_MAX, pAcnt->channel );
			continue;
		}
		if(!strcasecmp(word, "CPst" ) )
		{	SREAD(pAcnt->custPost);
			continue;
		}
		if(!strcasecmp(word, "CTpc" ) )
		{	SREAD(pAcnt->custTopic);
			continue;
		}
		if(!strcasecmp(word, "CRpl" ) )
		{	SREAD(pAcnt->custReply);
			continue;
		}
		if(!strcasecmp(word, "AfkS" ) )
		{	SREAD(pAcnt->afk_string );
			continue;
		}
		if(!strcasecmp(word, "Url" ) )
		{	SREAD(pAcnt->url);
			continue;
		}
		if(!strcasecmp(word, "Mud" ) )
		{	SREAD(pAcnt->mud);
			continue;
		}
		if(!strcasecmp(word, "Ign") )
		{	int tid = fread_number(fp);
			char *chan = fread_word(fp);
			Channel *channel;
			Topic *topic;
			if( !(channel = Channel::find(chan) ) )
			{	logfp(LOG_BUG, "Shits gone wrong! No Channel in Account::Load(%s)",chan);
				continue;
			}
			if( !( topic = channel->getTopic(tid) ) )
			{	logfp(LOG_BUG, "No topic %d", tid);
				continue;
			}
			pAcnt->addIgnore(topic, channel->bit);
			continue;
		}
		IREAD("MMade", pAcnt->initLogin);
		IREAD("lvl", pAcnt->level );
		logfp(LOG_BUG, "Unexpected reference in Account file %s: %s\n",name, word );
		continue;
	}
	d->account	= pAcnt;
	pAcnt->desc = d;
	return pAcnt;
}


ACCOUNT * get_account( const char *name )
{	ACCOUNT *pAcnt;
	
	for(pAcnt = account_list; pAcnt ; pAcnt = pAcnt->next )
	{	if(LOWER(pAcnt->name[0]) == LOWER(name[0]) 
		&& !str_prefix(name, pAcnt->name ) )
		return pAcnt;
	}
	return NULL;
}

bool check_reconnect(ACCOUNT *pAcnt )
{	ACCOUNT *acnt;
	for(acnt = account_list ; acnt ; acnt = acnt->next )
	{	if(acnt == pAcnt)
			continue;
		if(LOWER(acnt->name[0]) == LOWER(pAcnt->name[0])
		&& !strcasecmp(acnt->name, pAcnt->name ) )
		{	pAcnt->desc->connected = CON_ASK_RECONNECT;
			ptc(pAcnt, "You are already logged in. Would you like to reconnect?[y/n]\n\r" );
			return true;
		}
	}
	return false;
}
void reconnect_account(ACCOUNT *pAcnt )
{	ACCOUNT *acnt;
	bool found = false;
	for(acnt = account_list ; acnt ; acnt = acnt->next )
	{	if(acnt == pAcnt)
			continue;
		if(LOWER(acnt->name[0]) == LOWER(pAcnt->name[0])
		&& !strcasecmp(acnt->name, pAcnt->name ) )
		{	found = true;
			break;
		}
	}
	if(found)
	{	ptc(acnt, "You have reconnected somewhere else... Bye!\n\r");
		close_socket(acnt->desc);
		free_account(acnt);
	}

	pAcnt->desc->connected = CON_OOC_CHAT;
	ptc(pAcnt, "You have reconnected. Welcome back!\n\r");
	return;
}

const struct acnt_cmdfun_type acnt_cmdfun_table[] =
{	{ "acnt_who",		acnt_who	},
	{ "acnt_chat",		acnt_chat	},
	{ "acnt_save",		acnt_save	},
	{ "acnt_quit",		acnt_quit	},
	{ "acnt_typo",		acnt_typo	},
	{ "acnt_copyover",	acnt_copyover },
	{ "acnt_command",	acnt_command  },
	{ "acnt_afk",		acnt_afk	  },
	{ "acnt_advance",	acnt_advance  },
	{ "acnt_socket",	acnt_socket	  },
	{ "acnt_filecount", acnt_filecount},
	{ "acnt_channels",	acnt_channels	},
	{ "acnt_ignore",	acnt_ignore	},
	{ "acnt_ban",		acnt_ban	},
	{ "acnt_view",		acnt_view	},
	{ "acnt_customize",	acnt_customize  },
	{ "acnt_help",		acnt_help	},
	{ "acnt_credits",	acnt_credits	},
	{ "acnt_ignore",	acnt_ignore	},
	{ "acnt_reply",		acnt_reply	},
	{ "acnt_tell",		acnt_tell	},
	{ NULL,			NULL		}
};