mud++0.35/etc/
mud++0.35/etc/guilds/
mud++0.35/help/propert/
mud++0.35/mudC/
mud++0.35/player/
mud++0.35/src/interface/
mud++0.35/src/os/cygwin32/
mud++0.35/src/os/win32/
mud++0.35/src/os/win32/bcppbuilder/
mud++0.35/src/osaddon/
mud++0.35/src/util/
/*
....[@@@..[@@@..............[@.................. 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@hom.net 
MUD++ development mailing list    mudpp@van.ml.org
------------------------------------------------------------------------------
edittext.cc
*/

#include "config.h"
#include "string.h"
#include "llist.h"
#include "index.h"
#include "room.h"
#include "hash.h"
#include "server.h"
#include "bit.h"
#include "edit.h"
#include "pc.h"

// The edit object can be used like a char * for copy text from
// the object.
const String & TextEditor::asStr()
{
	output.clr();
	for( int i = 0; i < lines; i++ )
		output << text[i] << "\r\n";

	return output;
}


// The edit object can be used like an array of strings by providing
// the [] index operator. Returns string at text[i]
const String & TextEditor::operator [] (int i)
{
   if( i >= 0 && i < MAX_LINES )
      return text[i];
   else return text[MAX_LINES]; // dummy string
}


// Show the edit buffer in line format.
const String & TextEditor::format()
{
	output.clr();
	for( int i=0; i < lines; i++ )
		output << i+1 << "] " << text[i] << "\r\n"; 
 
	return output;
}


// Clear the edit buffer out.
void TextEditor::clr()
{
	for( int i=0; i < lines; i++ )
		text[i].clr();
	lines = 0;
	current = 0;
}


// Append a line onto the text.
void TextEditor::append( const char *str )
{
	text[current] = str;
	text[current].rtrim();
	current++;
	lines++;
}

// Append a line onto the text.
void TextEditor::append( const String & str )
{
	text[current] = str;
	text[current].rtrim();
	current++;
	lines++;
}


// Clear the line but do not delete.
// Can be undone.
void TextEditor::clrLine( int i )
{
	clipped = 1;
	clipboard[0] = text[i];
	text[i].clr();
}


// Insert a line at line i. All lines >= i are shifted down.
// Can be undone.
void TextEditor::insertLine( const String &, int )
{

}


// Delete line i and shift the text up.
// Can be undone.
// i is 1 - lines so subtract 1 before delete
void TextEditor::cutLine( int i )
{
	if( i > lines )
		return;

	i--;
	// Discard the clipboard
	clipped = 0;
	for( int j = i; j < lines; j++ )
		text[j] = text[j+1];	
	lines--;
}


// Replace line i with str.
// Can be undone.
void TextEditor::replaceLine( const String & str, int i )
{
	if( i >= MAX_LINES || i < 0 )
		return;

	clipped = 1;
	clipboard[0] = text[i];
	text[i] = str;
}


// Cut a block of text.
// Can be used to paste/copy sections of text.
// Can be undone.
void TextEditor::cutLines( int first, int last )
{
	if( first > last || first >= lines || last >= lines
		|| first < 0      || last < 0      )
		return;

	int i, j;

	clipped = last - first + 1;	
	for( i = first; i <= last; i++ )
		clipboard[i-first] = text[i];

	i = first;
	j = last+1;

	while( (bool)text[j] )
		text[i++] = text[j++];

	text[i].clr();
	lines -= (last - first);
}


// Paste the clipboard back into the text buffer at line i.
// Can be undone.
void TextEditor::pasteLines( int )
{

}


// Text editor master function. Called from main()
// Player must be in a edit state.
void TextEditor::command( const String & arg )
{
	String arg1;
	String arg2;

	if( !(bool)arg )
	{
		pc->out( "Null arg.\n\r" );
		return;
	}

	int line1;
	if( state == ED_TEXT_APPEND )
	{
		if( arg[0] == '~' || arg[0] == '@' )
		{
			state = 0;
			setPrompt( "\n\rText Editor >" );
			return;
		}
		else if( arg[0] == '.' )
		{
			if( arg[1] == 'c' )
			{
				clr();
				pc->out( "\n\rBuffer cleared.\n\r" );
				pc->out( format() );
			}
			else pc->out( "\n\rUnknown dot command.\n\r" );
			return;
		}  

		append( arg );
		return;      
	}

	if( isdigit( arg[0] ) )
	{
		arg.startArgs();
		arg1 = arg.getArg();
		arg2 = arg.getArgRest();
		line1 = arg1.asInt();

		if( line1 <= 0 || line1 > lines )
		{
			pc->out( "\n\rInvalid line number.\n\r" );
			return;
		}

		if( !(bool)arg2 )
		{
			pc->out( text[line1-1] );
			pc->out( "\n\r" );
			return;
		} 
     
		replaceLine( arg2, line1-1 );
		return;
	}
 
	arg.startArgs();
	arg1 = arg.getArg();
	arg2 = arg.getArgRest();

	switch( tolower( arg[0] ) )
	{
		case 'a':
				pc->out( "Entering append mode.\n\r" );
				pc->out( "Enter '~' or '@' on blank line to exit.\n\r" );
				pc->out( format() );
				state = TASK_EDIT_APPEND;
				return;
		case 'c':
				line1 = arg2.asInt();
				if( line1 <= 0 )
					pc->out( "\n\rUsage:    c <line #>\n\r" );
				else
				{
					text[ line1-1 ].clr();
					pc->out( "Line cleared.\n\r" );
				}
				return; 
		case 'd':
				line1 = arg2.asInt();
				if( line1 <= 0 )
					pc->out( "\n\rUsage:    d <line #>\n\r" );
				else
				{
					cutLine( line1 );
					pc->out( "Line cut.\n\r" );
				}
				return; 
		case '?':
		case 'h':
				pc->view( "../help/editor.hlp" );
				return;
		case 'l':
				pc->out( format() );
				return;
		// Save and leave append
		case 'x':
		case 'q':
				state = ED_DONE;
				pc->out( format() );
				pc->out( "Saving buffer.\n\r" );
				return;
		case '!':
				state = ED_CANCEL;
				pc->out( "Exiting without saving.\n\r" );
				return;
		default:
				return;
	}
}


const String & TextEditor::getPrompt()
{
	if(  state == ED_TEXT_APPEND )
	{
		prompt.clr();
		prompt << ( current + 1 ) << "] ";
	}

	return prompt;
}