/*
\\		Dispatcher for editor class
//
\\		V1.1 (23/9/95)
*/

	#define	EDITOR_VERSION	1		/* Value returned on version query */

	#include "Editor.h"
	#include <math.h>

static SAVEDS ULONG m_new( struct IClass *cl, Object *obj, struct opSet *msg )
{
	/* Parse Taglist for instance data, Allocate buffer */

	struct InstanceData *Data;

	if( !(obj = (Object *) DoSuperMethodA( cl, obj, msg ) ) )
		return( NULL );
	Data = INST_DATA( cl, obj );

	NewMinList( &Data->LineList );
        
	Data->Obj = obj;
	Data->Lines = 0;
        
	if( (Data->LinePool = CreatePool( MEMF_CLEAR|MEMF_PUBLIC, 32768, 32768 )) &&
			AddLine( Data, 0, 0 ) )
	{
		Data->cookie	        = EDITOR_COOKIE;
		Data->textcol	        = GetTagData( MUIA_Editor_TextCol,      1,      msg->ops_AttrList );
		Data->backcol	        = GetTagData( MUIA_Editor_BackCol,      0,      msg->ops_AttrList );
		Data->seltextcol        = GetTagData( MUIA_Editor_SelTextCol,   0,      msg->ops_AttrList );
		Data->selbackcol        = GetTagData( MUIA_Editor_SelBackCol,   1,      msg->ops_AttrList );
		Data->curstextcol       = GetTagData( MUIA_Editor_CursTextCol,  2,      msg->ops_AttrList );
		Data->cursbackcol       = GetTagData( MUIA_Editor_CursBackCol,  3,      msg->ops_AttrList );
                
		Data->TabSize           = GetTagData( MUIA_Editor_TabSize,      3,      msg->ops_AttrList );
		Data->TabHook           = GetTagData( MUIA_Editor_TabHook,      NULL,   msg->ops_AttrList );
		Data->InputHook         = GetTagData( MUIA_Editor_InputHook,    NULL,   msg->ops_AttrList );
		Data->RenderHook        = GetTagData( MUIA_Editor_RenderHook,   NULL,   msg->ops_AttrList );
		Data->SuppliedFont      = GetTagData( MUIA_Editor_Font,         NULL,   msg->ops_AttrList );
		if( GetTagData( MUIA_Editor_FollowCurs, TRUE,   msg->ops_AttrList ) ) Data->Flags |= FOLLOWCURSOR;
		if( GetTagData( MUIA_Editor_FollowVis,  TRUE,   msg->ops_AttrList ) ) Data->Flags |= FOLLOWVISIBLE;
		if( GetTagData( MUIA_Editor_UseSysKeys, FALSE,  msg->ops_AttrList ) ) Data->Flags |= USESYSKEYS;
		if( GetTagData( MUIA_Editor_AutoIndent, FALSE,  msg->ops_AttrList ) ) Data->Flags |= AUTOINDENT;
		if( GetTagData( MUIA_Editor_FloatCursor,FALSE,  msg->ops_AttrList ) ) Data->Flags |= FREEFLOAT;
                
		Data->oldy = Data->oldx = -1;

		InitRastPort( &Data->RastPort );		// Our dummy rastport for rendering 
		Data->RastPort.TmpRas = &Data->TempRaster;	// A temporary raster for safer operation 
		Data->RastPort.BitMap = NULL;			// No bitmap yet... 

		return( (ULONG) obj );
	}

	CoerceMethod( cl, obj, OM_DISPOSE );
	return( NULL );
}


static SAVEDS ULONG m_dispose( struct IClass *cl, Object *obj, Msg msg )
{
	/* Deallocate buffers */

	struct InstanceData *Data = INST_DATA( cl, obj );
	ULONG Returner;

	if( Data->RasterPort.BitMap )	FreeBitMap( Data->RasterPort.BitMap );
	if( Data->TempRaster.RasPtr )	FreeVec( Data->TempRaster.RasPtr );     // Watch This!
	if( Data->LinePool )		DeletePool( Data->LinePool );

	Returner = DoSuperMethodA( cl, obj, msg );
	return( Returner );
}

static SAVEDS ULONG m_setup( struct IClass *cl, Object *obj, struct MUIP_Setup *msg )
{
	/* Setup misc values, request IDCMP messages */

	struct TextAttr RomFont = 
                {
                  "topaz.font", 8, 
                  NULL, FPF_ROMFONT 
                };
                
	struct InstanceData *Data = INST_DATA( cl, obj );

	if( !DoSuperMethodA( cl, obj, msg ) )
		return( FALSE );

	SetFont( Data, Data->SuppliedFont );			/* NULL means _font(obj) */
	if( !Data->Font )					/* What no font? */
		Data->Font = OpenFont( &RomFont );	        /* Glack!!! */
	UpdateRenderArea( Data );

	MUI_RequestIDCMP( obj, IDCMP_MOUSEBUTTONS|IDCMP_VANILLAKEY|IDCMP_RAWKEY );

	return( TRUE );
}

static SAVEDS ULONG m_cleanup( struct IClass *cl, Object *obj, Msg msg )
{
	/* Reject IDCMP messages */

	struct InstanceData *Data = INST_DATA( cl, obj );
	ULONG Returner;

	MUI_RejectIDCMP( obj, IDCMP_MOUSEBUTTONS|IDCMP_VANILLAKEY|IDCMP_RAWKEY );

	SetFont( Data, NULL );			                // Close any fonts opened
	if( Data->RasterPort.BitMap )
	{
		FreeBitMap( Data->RasterPort.BitMap );
		Data->RasterPort.BitMap = NULL;
	}

	Returner = DoSuperMethodA( cl, obj, msg );
	return( retval );
}

static SAVEDS ULONG m_askminmax( struct IClass *cl, Object *obj, struct MUIP_AskMinMax *msg )
{
	/* Return details of min, def, max sizes */

	struct InstanceData *Data = INST_DATA( cl, obj );

	DoSuperMethodA( cl, obj, (APTR) msg );

	msg->MinMaxInfo->MinWidth	+= Data->Font->tf_XSize+1;
	msg->MinMaxInfo->DefWidth	+=	600;
	msg->MinMaxInfo->MaxWidth	+= MUI_MAXMAX;
	msg->MinMaxInfo->MinHeight	+= Data->Font->tf_YSize+1;
	msg->MinMaxInfo->DefHeight	+=	200;
	msg->MinMaxInfo->MaxHeight	+= MUI_MAXMAX;

	return( 0 );
}

static SAVEDS ULONG m_set( struct IClass *cl, Object *obj, struct opSet *msg )
{
	/* Set variables */
	/* SYSSET is set only within dispatcher, and allows changing of protected variables */

	struct ClassData *data = INST_DATA( cl, obj );
	struct TagItem *tag, *tstate;
	ULONG temp, retval;
	struct linedata *stemp;

	tstate = msg->ops_AttrList;
	while( tag = NextTagItem( &tstate ) )
	{
		switch( tag->ti_Tag )
		{
			case MUIA_Editor_VisibleY:	temp = tag->ti_Data;
												if( temp == MUIV_Editor_Max )			temp = data->lines - 1;
												else if( temp == MUIV_Editor_Next )	temp = min( data->lines-1, data->topvisy+1 );
												else if( (temp == MUIV_Editor_Prev) && data->topvisy ) temp = data->topvisy - 1;
												stemp = findvisloc( data, min( data->lines-1, temp ) );
												if( stemp && (stemp != data->topvisloc) )
												{
													data->topvisloc = stemp;
													data->topvisy   = temp;
													correctcurrpos( data, FALSE );
													data->flags |= DRAWSCROLL;
													MUI_Redraw( obj, MADF_DRAWUPDATE );
												}
												break;
			case MUIA_Editor_TextCol:	data->textcol = tag->ti_Data;
												data->flags |= DRAWALL;
												MUI_Redraw( obj, MADF_DRAWUPDATE );
												break;
			case MUIA_Editor_BackCol:	data->backcol = tag->ti_Data;
												data->flags |= DRAWALL;
												fillborders( data );
												MUI_Redraw( obj, MADF_DRAWUPDATE );
												break;
			case MUIA_Editor_SelTextCol:	data->seltextcol = tag->ti_Data;
												if( data->flags & MARKING )
												{
													data->flags |= DRAWALL;
													MUI_Redraw( obj, MADF_DRAWUPDATE );
												}
												break;
			case MUIA_Editor_SelBackCol:	data->selbackcol = tag->ti_Data;
												if( data->flags & MARKING )
												{
													data->flags |= DRAWALL;
													MUI_Redraw( obj, MADF_DRAWUPDATE );
												}
												break;
			case MUIA_Editor_CurrX:		temp = translatexval( data, tag->ti_Data, -1 );
												if( temp != data->currx )
												{
													if( temp <= data->buffersize )
														data->oldx = data->currx;
													data->currx = temp;
													correctcurrpos( data, TRUE );
													if( !(data->flags & KEEPIDEALX) )
														set( obj, MUIA_Editor_IdealX, calcxpos( data, data->linebuffer, data->currx ) );
													data->flags |= DRAWLINE;
													MUI_Redraw( obj, MADF_DRAWUPDATE );
												}
												break;
			case MUIA_Editor_CurrY:		temp = translateyval( data, tag->ti_Data );
												if( temp != data->curry )
												{
													data->quietcount++;
													storebuffer( data );
													if( data->oldy == -1 ) data->oldy = data->curry;
													data->curry = temp;
													data->currline = NULL;
													data->currline = findvisloc( data, data->curry );
													getbuffer( data );
													data->flags |= KEEPIDEALX;
													temp = correctxpos( data, data->linebuffer, data->idealx );
													set( obj, MUIA_Editor_CurrX, (temp<data->buffersize)?temp:MUIV_Editor_Max );
													data->flags &= ~KEEPIDEALX;
													if( data->quietcount && (data->flags&DRAWINSERT) && (data->flags&DRAWREMOVE) )
														data->flags |= DRAWALL;	/* Prevents corruption after `quiet' */
													else data->flags |= (data->flags & MARKING)?DRAWMARKED:DRAWLINE;
													correctcurrpos( data, TRUE );
													data->quietcount--;
													MUI_Redraw( obj, MADF_DRAWUPDATE );
												}
												break;
			case MUIA_Editor_Lines:		if( data->syssetcount )
													data->lines = tag->ti_Data;
												break;
			case MUIA_Editor_VisibleX:	if( data->topvisx != tag->ti_Data )
												{
													data->topvisx = tag->ti_Data;
													correctcurrpos( data, FALSE );
													data->flags |= DRAWALL;
													MUI_Redraw( obj, MADF_DRAWUPDATE );
												}
												break;
			case MUIA_Editor_VisLines:	if( data->syssetcount );
													data->linesvisible = tag->ti_Data;
													correctcurrpos( data, TRUE );
												break;
			case MUIA_Editor_CursTextCol:	data->curstextcol = tag->ti_Data;
												data->flags |= DRAWLINE;
												MUI_Redraw( obj, MADF_DRAWUPDATE );
												break;
			case MUIA_Editor_CursBackCol: data->cursbackcol = tag->ti_Data;
												data->flags |= DRAWLINE;
												MUI_Redraw( obj, MADF_DRAWUPDATE );
												break;
			case MUIA_Editor_MarkX:		temp	= tag->ti_Data;
												stemp	= findvisloc( data, data->marky );
												if( temp == MUIV_Editor_Max )			temp = stemp->len;
												else if( temp == MUIV_Editor_Next )	temp = min( data->markx+1, stemp->len );
												else if( (temp == MUIV_Editor_Prev) && data->markx ) temp = data->markx - 1;
												data->markx = temp;
												if( data->flags & MARKING )
												{
													data->flags |= DRAWLINE;
													MUI_Redraw( obj, MADF_DRAWUPDATE );
												}
												break;
			case MUIA_Editor_MarkY:		temp = tag->ti_Data;
												if( temp == MUIV_Editor_Max )			temp = data->lines - 1;
												else if( temp == MUIV_Editor_Next )	temp = min( data->lines - 1, data->curry + 1 );
												else if( (temp == MUIV_Editor_Prev) && data->curry )	temp = data->curry - 1;
												else if( temp >= data->lines )		temp = data->lines - 1;
												data->marky = temp;
												if( data->flags & MARKING )
												{
													data->flags |= DRAWMARKED;
													MUI_Redraw( obj, MADF_DRAWUPDATE );
												}
												break;
			case MUIA_Editor_Quiet:		if( !tag->ti_Data && data->quietcount )
												{
													data->quietcount--;
													MUI_Redraw( obj, MADF_DRAWUPDATE );
												}
												else data->quietcount++;
												break;
			case MUIA_Editor_FollowCurs:
												if( tag->ti_Data )
													data->flags |= FOLLOWCURSOR;
												else data->flags &= ~FOLLOWCURSOR;
												break;
			case MUIA_Editor_TabSize:	if( tag->ti_Data != data->tabsize )
												{
													data->tabsize = tag->ti_Data;
													data->flags |= DRAWALL;
													MUI_Redraw( obj, MADF_DRAWUPDATE );
												}
												break;
			case MUIA_Editor_Changed:	if( tag->ti_Data && data->syssetcount )
													data->flags |= CHANGED;
												else data->flags &= ~CHANGED;
												break;
			case MUIA_Editor_CurrColumn:
												temp = correctxpos( data, data->linebuffer, tag->ti_Data );
												if( temp != data->currx )
													set( obj, MUIA_Editor_CurrX, temp );
												break;
			case MUIA_Editor_VisCols:	if( data->syssetcount )
												{
													data->colsvisible = tag->ti_Data;
													updaterenderarea( data );
													correctcurrpos( data, TRUE );
												}
												break;
			case MUIA_Editor_TabHook:	data->tabhook = (struct Hook *) tag->ti_Data;
												break;
			case MUIA_Editor_InputHook:data->inputhook = (struct Hook *) tag->ti_Data;
												break;
			case MUIA_Editor_UseSysKeys:
												/* if( tag->ti_Data )	THIS DOESN'T WORK!!!!
													data->flags |= USESYSKEYS;
												else */ data->flags &= ~USESYSKEYS;
												break;
			case MUIA_Editor_LastCode:	if( data->syssetcount )
													data->lastcode = tag->ti_Data;
												break;
			case MUIA_Editor_FollowVis:if( tag->ti_Data )
													data->flags |= FOLLOWVISIBLE;
												else data->flags &= ~FOLLOWVISIBLE;
												break;
			case MUIA_Editor_IsEmpty:	if( data->syssetcount )
												{
													if( tag->ti_Data )
														data->flags |= ISEMPTY;
													else data->flags &= ~ISEMPTY;
												}
												break;
			case MUIA_Editor_Font:		setfont( data, (struct TextAttr *) tag->ti_Data );
												data->quietcount++;
												updaterenderarea( data );
												correctcurrpos( data, TRUE );
												data->flags |= DRAWALL;
												data->quietcount--;
												MUI_Redraw( obj, MADF_DRAWUPDATE );
												break;
			case MUIA_Editor_RenderHook:
												if( data->renderhook != (struct Hook *) tag->ti_Data )
												{
													data->renderhook = (struct Hook *) tag->ti_Data;
													data->flags |= DRAWALL;
													MUI_Redraw( obj, MADF_DRAWUPDATE );
												}
												break;
			case MUIA_Editor_AutoIndent:
												if( tag->ti_Data )
													data->flags |= AUTOINDENT;
												else data->flags &= ~AUTOINDENT;
												break;
			case MUIA_Editor_IdealX:	if( data->syssetcount )
													data->idealx = tag->ti_Data;
												break;
			case MUIA_Editor_ClickColumn:
												if( data->syssetcount )
													data->clickcolumn = tag->ti_Data;
												break;
			case MUIA_Editor_Marking:	if( ((BOOL) tag->ti_Data) != ((BOOL)data->flags & MARKING))
												{
													if( tag->ti_Data )
														data->flags |= MARKING;
													else data->flags &= ~MARKING;
													data->flags |= DRAWALL;
													MUI_Redraw( obj, MADF_DRAWUPDATE );
												}
												break;
			case MUIA_Editor_FloatCursor:
												if( tag->ti_Data )
													data->flags |= FREEFLOAT;
												else data->flags &= ~FREEFLOAT;
												break;
		}
	}

	retval = DoSuperMethodA( cl, obj, msg );
	return( retval );
}

static SAVEDS ULONG m_get( struct IClass *cl, Object *obj, struct opGet *msg )
{
	/* Get variable values */

	struct ClassData *data = INST_DATA( cl, obj );
	ULONG *ptr = msg->opg_Storage;
	ULONG retval;

	switch( msg->opg_AttrID )	/* Find the message */
	{
		case MUIA_Editor_TextCol:		*ptr = data->textcol;					return( TRUE );
		case MUIA_Editor_BackCol:		*ptr = data->backcol;					return( TRUE );
		case MUIA_Editor_SelTextCol:	*ptr = data->seltextcol;				return( TRUE );
		case MUIA_Editor_SelBackCol:	*ptr = data->selbackcol;				return( TRUE );
		case MUIA_Editor_CurrY:			*ptr = data->curry;						return( TRUE );
		case MUIA_Editor_CurrX:			*ptr = data->currx;						return( TRUE );
		case MUIA_Editor_Lines:			*ptr = data->lines;						return( TRUE );
		case MUIA_Editor_VisLines: 	*ptr = data->linesvisible;				return( TRUE );
		case MUIA_Editor_VisibleY:		*ptr = data->topvisy;					return( TRUE );
		case MUIA_Editor_VisibleX:		*ptr = data->topvisx;					return( TRUE );
		case MUIA_Editor_CursTextCol:	*ptr = data->curstextcol;				return( TRUE );
		case MUIA_Editor_CursBackCol:	*ptr = data->cursbackcol;				return( TRUE );
		case MUIA_Editor_MarkX:			*ptr = data->markx;						return( TRUE );
		case MUIA_Editor_MarkY:			*ptr = data->marky;						return( TRUE );
		case MUIA_Editor_Quiet:			*ptr = data->quietcount;				return( TRUE );
		case MUIA_Editor_FollowCurs:	*ptr = (data->flags&FOLLOWCURSOR);	return( TRUE );
		case MUIA_Editor_TabSize:		*ptr = data->tabsize;					return( TRUE );
		case MUIA_Editor_Changed:		*ptr = (data->flags & CHANGED);		return( TRUE );
		case MUIA_Editor_Version:		*ptr = EDITOR_VERSION;					return( TRUE );
		case MUIA_Editor_CurrColumn:	*ptr = calcxpos( data, data->linebuffer, data->currx );return( TRUE );
		case MUIA_Editor_VisCols:		*ptr = data->colsvisible;				return( TRUE );
		case MUIA_Editor_TabHook:		*ptr = (ULONG) data->tabhook;			return( TRUE );
		case MUIA_Editor_InputHook:	*ptr = (ULONG) data->inputhook;		return( TRUE );
		case MUIA_Editor_LastCode:		*ptr = data->lastcode;					return( TRUE );
		case MUIA_Editor_IsEmpty:		*ptr = (data->flags&ISEMPTY);			return( TRUE );
		case MUIA_Editor_FollowVis:	*ptr = (data->flags&FOLLOWVISIBLE);	return( TRUE );
		case MUIA_Editor_Font:			*ptr = (ULONG) data->font;				return( TRUE );
		case MUIA_Editor_RenderHook:	*ptr = (ULONG) data->renderhook;		return( TRUE );
		case MUIA_Editor_AutoIndent:	*ptr = (data->flags&AUTOINDENT);		return( TRUE );
		case MUIA_Editor_IdealX:		*ptr = data->idealx;						return( TRUE );
		case MUIA_Editor_ClickColumn:	*ptr = data->clickcolumn;				return( TRUE );
		case MUIA_Editor_Marking:		*ptr = data->flags & MARKING;			return( TRUE );
		case MUIA_Editor_FloatCursor:	*ptr = data->flags & FREEFLOAT;		return( TRUE );
	}

	retval = DoSuperMethodA( cl, obj, msg );	/* We didn't recognise it... */
	return( retval );
}

static SAVEDS ULONG e_clearbuff( struct IClass *cl, Object *obj, Msg msg )
{
	/* Clear memory buffer, set values */

	struct InstanceData *Data = INST_DATA( cl, obj );

	Data->QuietCount++;
	Data->TopVisLoc = 0;
        Data->oldy = 0;
 	Data->Flags &= ~CHANGED;
 	Data->Flags |= DRAWALL;
 	SetAttrs( obj,	MUIA_Editor_CurrY, 0,	/* Set attributes through notification */
			MUIA_Editor_CurrX, 0,
			MUIA_Editor_MarkY, -1,
		TAG_DONE );
        ClearBuffer( Data );
        AddLine( Data, MUIV_Editor_Max, 0 );	/* Add a dummy line */
        Data->curry = 0;
        GetBuffer( Data );
        Data->QuietCount--;
        MUI_Redraw( obj, MADF_DRAWUPDATE );
	return( 0 );
}

static SAVEDS ULONG e_import( struct IClass *cl, Object *obj, struct ImportMSG *msg )
{
	/* Import text from - (BPTR) filehandle, (UWORD) textmode */

	struct InstanceData *Data = INST_DATA( cl, obj );
	ULONG Returner =0;
	struct Hook *hook;

	Data->QuietCount++;
	Data->Flags |= DRAWALL;
	SetAttrs( obj,	MUIA_Editor_MarkY, -1,
			MUIA_Editor_CurrY, 0,
			MUIA_Editor_CurrX, 0,
			TAG_DONE );
	ClearBuffer( Data );
	hook = (msg->ProgHook && (msg->Flags & LF_HOOK))?msg->ProgHook:NULL;
	switch( msg->Flags & LF_LOADMODE )
	{
		case LOADMODE_ASCII:		Returner = LoadASCII( Data, msg->FileHandle, hook );
										break;
		case LOADMODE_FTXT:		Returner = LoadFTXT( Data, msg->FileHandle, hook );
										break;
	}
	Data->Flags &= ~CHANGED;
	GetBuffer( Data );
	Data->Flags |= DRAWALL;
	Data->QuietCount--;
	MUI_Redraw( obj, MADF_DRAWUPDATE );
	return( Returner );
}

static SAVEDS ULONG e_export( struct IClass *cl, Object *obj, struct ImportMSG *msg )
{
	/* Export text to - (BPTR) filehandle, (UWORD) textmode */

	struct InstanceData *Data = INST_DATA( cl, obj );
	struct Hook *hook;
	ULONG Returner = 0;

	StoreBuffer( Data );
	hook = (msg->ProgHook && (msg->Flags & LF_HOOK))?msg->ProgHook:NULL;
	switch( msg->Flags & LF_LOADMODE )
	{
		case LOADMODE_ASCII:		Returner  = SaveASCII( Data, msg->FileHandle, hook );
										break;
		case LOADMODE_FTXT:		Returner  = SaveFTXT(Data, msg->FileHandle, hook );
										break;
	}
	if( Returner ) Data->Flags &= ~CHANGED;

	return( Returner );
}

static SAVEDS ULONG e_replace( struct IClass *cl, Object *obj, struct AdjustMSG *msg )
{
	/* Replace line y with specified string */
	/* Will return pointer to line, or NULL */
	
	ULONG y;
	struct InstaceData *Data = INST_DATA( cl, obj );	
	struct LineData *NewLine, *Line;

	StoreBuffer( Data );
	y = Translateyval( Data, msg->y );
	Line = FindVisLoc( Data, y );

	if( !(Line = FindVisLoc( Data, y ) ) )
		return( NULL );
	if( !(NewLine = AddLine( Data, y+1, msg->Size ) ) )
		return( NULL );
	memcpy( NewLine->Data, msg->String, msg->Size );
	RemLine( Data, y );
	GetBuffer( Data );
	return( (ULONG) Line );
}

static SAVEDS ULONG e_insert( struct IClass *cl, Object *obj, struct AdjustMSG *msg )
{
	/* Will insert - string of (ULONG) size */
	/* Will return pointer to line, or NULL */

	struct InstanceData *Data = INST_DATA( cl, obj );
	struct LineData *NewLine, *Line;
        
	UBYTE *src, *src2, *dst;
	ULONG count, x, y;
        
        
	StoreBuffer( Data );
	y = Translateyval( Data, msg->y );
	x = Translatexval( Data, msg->x, msg->y );
	Line = FindVisLoc( Data, y );
	if( x > Line->Length ) 
           x = Line->Length;
	if( !(NewLine = AddLine( Data, y + 1, Line->Length + msg->Size ) ) )
           return( NULL );
	StoreBuffer( Data );
	for( src = Line->Data, dst = NewLine->Data, count = x; count; count-- )
		*dst++ = *src++;	/* Part 1 of orig string */
	for( src2 = msg->String, count = msg->Size; count; count-- )
		*dst++ = *src2++;	/* String to insert */
	for( count = Line->Length - x; count; count-- )
		*dst++ = *src++;	/* Part 2 of orig string */
	RemLine( Data, y );
	GetBuffer( Data );
	if( (y==Data->curry) && (x<=Data->currx) ) set( obj, MUIA_Editor_CurrX, Data->currx+msg->Size );
	Data->Flags |= CHANGED|((y == Data->curry)?DRAWLINE:DRAWALL);
	MUI_Redraw( obj, MADF_DRAWUPDATE );

	if( (Data->Flags & ISEMPTY) && msg->Size )
		set( obj, MUIA_Editor_IsEmpty, FALSE );

	return( (ULONG) NewLine);
}

static SAVEDS ULONG e_delete( struct IClass *cl, Object *obj, struct AdjustMSG *msg )
{
	/* Will remove - (ULONG) size from current pos */
	/* Will return line pointer, or NULL */

	struct InstanceData *Data = INST_DATA( cl, obj );
	struct LineData *NewLine, *Line;
	UBYTE *src, *dst;
	LONG count, x, y;
	WORD Size;

	y = Translateyval( Data, msg->y );
	if( y == Data->curry )
	{
		StoreBuffer( Data );
		Data->CurrLine = NULL;
	}
	x = Translatexval( Data, msg->x, msg->y );
	if( !(Line = FindVisLoc( Data, y ) ) )
		return( NULL );
	Size = msg->Size;
	if( (x > Line->Length) || (x < 0) ) 
            return( NULL );
	if( Line->Length < (x+Size) ) 
             Size = Line->Length - x;
	if( (Size <= 0) || (Size > 1023) ) 
            return( NULL );

	if( !(NewLine = AddLine( Data, y+1, Line->Length - Size ) ) )
		return( NULL );
	for( src = Line->Data, dst = NewLine->Data, count = x; count > 0; count-- )
		*dst++ = *src++;	/* Part 1 of line */
	for( src += Size, count = Line->Length - x - Size; count > 0; count-- )
		*dst++ = *src++;	/* Part 2 of line */
	RemLine( Data, y );
	if( y == Data->curry ) GetBuffer( Data );

	if( (y==Data->curry) && (x<Data->currx) ) set( obj, MUIA_Editor_CurrX, Data->currx-Size );
	Data->Flags |= CHANGED|((y==data->curry)?DRAWLINE:DRAWALL);
	MUI_Redraw( obj, MADF_DRAWUPDATE );

	if( !(Data->Flags & ISEMPTY) && (Data->Lines <= 1) && (Data->BufferSize==0) )
		set( obj, MUIA_Editor_IsEmpty, TRUE );
	return( (ULONG) NewLine );
}

static SAVEDS ULONG e_getline( struct IClass *cl, Object *obj, struct GetLineMSG *msg )
{
	/* Get position of specified line */

	struct InstanceData *Data = INST_DATA( cl, obj );

	StoreBuffer( Data );
	return( (ULONG) FindVisLoc( Data, Translateyval( Data, msg->Line ) ) );
}

static SAVEDS ULONG e_paste( struct IClass *cl, Object *obj, struct CutPasteMSG *msg )
{
	/* Paste specified clip into text at current cursor pos */
	
	struct InstanceData *Data = INST_DATA( cl, obj );

	StoreBuffer( Data );
	if( Paste( Data, msg->ClipNum ) )	/* Did we actually paste anything? */
	{
		Data->Flags |= CHANGED|DRAWALL;
		MUI_Redraw( obj, MADF_DRAWUPDATE );
		return( -1 );
	}
	return( NULL );
}

static SAVEDS ULONG e_copy( struct IClass *cl, Object *obj, struct CutPasteMSG *msg )
{
	/* Cut/Copy marked area */
	
	struct InstanceData *Data = INST_DATA( cl, obj );
	
	StoreBuffer( Data );
	CutMarked( Data, msg->Flags, msg->ClipNum );
	return( NULL );
}

static SAVEDS ULONG e_addline( struct IClass *cl, Object *obj, struct AddLineMSG *msg )
{
	struct InstanceData *Data = INST_DATA( cl, obj );
	struct LineData *Line;
	ULONG LineNumb;

	LineNumb = (msg->Line==-1)?msg->Line:Translateyval( Data, msg->Line );
	if( !(Line = AddLine( Data, LineNumb, msg->Length ) ) )
		return( NULL );
	memcpy( Line->Data, msg->String, msg->Length );
	return( (ULONG) Line );
}

static SAVEDS ULONG e_remline( struct IClass *cl, Object *obj, struct AddLineMSG *msg )
{
	struct InstanceData *Data = INST_DATA( cl, obj );

	RemLine( Data, Translateyval( Data, msg->Line ) );
	return( NULL );
}

static SAVEDS ULONG e_search( struct IClass *cl, Object *obj, struct SearchMSG *msg )
{
	struct InstanceData *Data = INST_DATA( cl, obj );
	struct LineData *Line;
	LONG LineNumb, endline, maxpos, minpos, currpos, Length;
	BOOL forwards, ended;
	
	forwards = !(msg->Flags & SMODE_REVERSE);
	Length = strlen( msg->Pattern );

	StoreBuffer( Data );
	Line = FindVisLoc( Data, Data->curry );
	for(	LineNumb = Data->curry, endline = forwards?(Data->Lines-1):0, ended = FALSE;
			!ended;
			LineNumb += (forwards?1:-1) )
	{
		if( LineNumb == endline ) ended = TRUE;
		if( forwards )			/* Forwards search mode */
		{
			if( LineNumb == Data->curry ) minpos = Data->currx + 1;
				else minpos = 0;
			maxpos = Line->Length - Length;
			for( currpos = minpos; currpos <= maxpos; currpos++ )
				if(	(((msg->Flags & SMODE_NOCASE) && !Strnicmp( msg->Pattern, Line->Data+currpos, Length )) ||
					(!(msg->Flags & SMODE_NOCASE) && !strncmp( msg->Pattern, Line->Data+currpos, Length ))) )
				{
					*msg->xpos = currpos;
					*msg->ypos = LineNumb;
					return( (ULONG) Line );
				}
		}
		else {					/* Backwards search mode */
			maxpos = Line->Length - Length;
			if( LineNumb == Data->curry )
			maxpos = min( maxpos, Data->currx - 1);
			minpos = 0;
			for( currpos = maxpos; currpos >= minpos; currpos-- )
				if(	(((msg->Flags & SMODE_NOCASE) && !Strnicmp( msg->Pattern, Line->Data+currpos, Length )) ||
					(!(msg->Flags & SMODE_NOCASE) && !strncmp( msg->Pattern, Line->Data+currpos, Length ))) )
				{
					*msg->xpos = currpos;
					*msg->ypos = LineNumb;
					return( (ULONG) Line );
				}
		}
		if( !(Line = NextLine( Data, Line, forwards ) ) )
			ended = TRUE;		/* Abort if we run out of Lines... */
	}
	return( NULL );		/* No more matches found... */
}

static SAVEDS ULONG e_swapbuffer( struct IClass *cl, Object *obj, struct SwapBuffMSG *msg )
{
	/* swaps current object buffer with aux, or NULL creates new */
	/* Returns pointer to detached buffer, or NULL for failure */
	
	struct InstanceData *Data = INST_DATA( cl, obj );
	APTR temppool;
	struct AuxBuffer *newbuff;

	if( !(newbuff = AllocPooled( Data->LinePool, sizeof( struct AuxBuffer ) ) ) )
		return( NULL );	/* Couldn't create aux */
	StoreBuffer( Data );
	newbuff->Cookie	= AUX_COOKIE;
	newbuff->PoolHeader = Data->LinePool;
	memcpy( &newbuff->LineList, &Data->LineList, sizeof(struct MinList) );
	newbuff->Lines		= Data->Lines;
	newbuff->curry		= Data->curry;
	newbuff->currx		= Data->currx;
	newbuff->marky		= Data->marky;
	newbuff->markx		= Data->markx;
        // Add An Idea X To This Stuff
	newbuff->topvisy	= Data->topvisy;
	newbuff->topvisx	= Data->topvisx;
	newbuff->Flags		= Data->Flags & (CHANGED|ISEMPTY|MARKING);

	Data->QuietCount++;
	if( msg->Buff && (msg->Buff->Cookie == AUX_COOKIE) )
	{
		Data->LinePool	= msg->Buff->PoolHeader;
		memcpy( &Data->LineList, &msg->Buff->LineList, sizeof(struct MinList) );
		Data->Lines		= msg->Buff->Lines;
		Data->curry		= msg->Buff->curry;
		Data->currx		= msg->Buff->currx;
		Data->marky		= msg->Buff->marky;
		Data->markx		= msg->Buff->markx;
		Data->TopVisLoc = Data->CurrLine = NULL;
		Data->Flags		&= ~(MARKING|CHANGED|ISEMPTY);
		Data->Flags		|= msg->Buff->Flags;
		getbuffer( Data );
		SetAttrs( obj,	MUIA_Editor_Lines, Msg->Buff->Lines,	/* Set the attrs... */
							MUIA_Editor_CurrY, msg->Buff->curry,
							MUIA_Editor_CurrX, msg->Buff->currx,
							MUIA_Editor_Changed, msg->Buff->Flags & CHANGED,
							MUIA_Editor_IsEmpty, msg->Buff->Flags & ISEMPTY,
							MUIA_Editor_Marking, msg->Buff->Flags & MARKING,
							MUIA_Editor_MarkY, msg->Buff->marky,
							MUIA_Editor_MarkX, msg->Buff->markx,
							TAG_DONE );
		SetAttrs( obj,	MUIA_Editor_VisibleY, msg->Fuff->curry,
							MUIA_Editor_VisibleX, msg->Fuff->currx,
							TAG_DONE );
		FreePooled( msg->Buff, sizeof(struct AuxBuffer));
	}
	else {
		if( !(temppool = CreatePool( MEMF_CLEAR|MEMF_PUBLIC, 32768, 32768 ) ) )
		{
			FreePooled( newbuff,sizeof(struct AuxBuffer) );	/* Throw away the new aux */
			Data->QuietCount--;
			return( NULL );		/* Abort */
		}
		Data->LinePool = temppool;
		DoMethod( Data->Obj, MUIM_Editor_ClearBuffer );	// Re-initialize this new buffer
	}
	Data->QuietCount--;
	Data->Flags |= DRAWALL;
	MUI_Redraw( obj, MADF_DRAWUPDATE );
	getbuffer( Data );
	return( (ULONG) newbuff );
}

static SAVEDS ULONG e_killbuffer( struct IClass *cl, Object *obj, struct SwapBuffMSG *msg )
{
	/* Deletes detached buffer */
	
	if( msg->Buff && (msg->Buff->Cookie == AUX_COOKIE) ) 
	{
		DeletePool( msg->Buff->Poolheader );	// auxbuffer struct is IN the pool
		return( TRUE );
	}
	return( FALSE );
}

static SAVEDS ULONG e_importauxbuffer( struct IClass *cl, Object *obj, struct importauxmsg *msg )
{
	/*	Imports Data directly into detached buffer */

	struct InstanceData *Data, *dummy;
	struct auxbuffer *newbuff;
	struct Hook *hook;
	ULONG retval;
	
	Data = INST_DATA( cl, obj );
	e_killbuffer( cl, obj, msg );		// If a buffer is specified... kill it first

	if( !(dummy = AllocVecPooled( Data->linepool, sizeof(struct InstanceData) ) ) )
		return( FALSE );
	if( !(dummy->linepool = CreatePool( MEMF_CLEAR, 32768, 32768 ) ) )
	{
		FreeVecPooled( dummy );
		return( FALSE );
	}
	initlist( &dummy->linelist );
	dummy->quietcount = 1;
	hook = (msg->proghook && (msg->flags&LF_HOOK))?msg->proghook:NULL;
	switch( msg->flags & LF_LOADMODE )
	{
		case LOADMODE_ASCII:	retval = loadascii( dummy, msg->filehandle, hook );	break;
		case LOADMODE_FTXT:	retval = loadftxt( dummy, msg->filehandle, hook );		break;
	}

	newbuff = AllocVecPooled( dummy->linepool, sizeof(struct auxbuffer) );
	if( retval && newbuff )
	{
		newbuff->cookie	= AUX_COOKIE;
		newbuff->poolheader = dummy->linepool;
		memcpy( &newbuff->linelist, &dummy->linelist, sizeof(struct MinList) );
		newbuff->Lines		= dummy->Lines;
	}
	else DeletePool( dummy->linepool );
	FreeVecPooled( dummy );

	return( (ULONG) newbuff );
}

static SAVEDS ULONG e_exportauxbuffer( struct IClass *cl, Object *obj, struct importauxmsg *msg )
{
	/* Export Data directly from detached buffer */

	struct InstanceData *Data, *dummy;
	struct Hook *hook;
	ULONG retval;
	
	Data = INST_DATA( cl, obj );
	if( !(dummy = AllocVecPooled( Data->linepool, sizeof(struct InstanceData) ) ) )
		return( NULL );
	dummy->linepool	= msg->buff->poolheader;
	memcpy( &dummy->linelist, &msg->buff->linelist, sizeof(struct MinList) );
	dummy->Lines		= msg->buff->Lines;

	hook = (msg->proghook && (msg->flags&LF_HOOK))?msg->proghook:NULL;
	switch( msg->flags & LF_LOADMODE )
	{
		case LOADMODE_ASCII:	retval = saveascii( dummy, msg->filehandle, hook );	break;
		case LOADMODE_FTXT:	retval = saveftxt( dummy, msg->filehandle, hook );		break;
	}
	FreeVecPooled( dummy );
	return( retval );
}

static SAVEDS ULONG dispatcherrouter( struct IClass *cl, Object *obj, Msg msg  )
{
	ULONG r;

	switch( msg->MethodID )		/* Jump to the relevant function */
	{
		case OM_NEW:				r = m_new( cl, obj, (APTR) msg ); break;
		case OM_DISPOSE:			r = m_dispose( cl, obj, (APTR) msg ); break;
		case MUIM_Setup:			r = m_setup( cl, obj, (APTR) msg ); break;
		case MUIM_Cleanup:		r = m_cleanup( cl, obj, (APTR) msg ); break;
		case MUIM_AskMinMax:		r = m_askminmax( cl, obj, (APTR) msg ); break;
		case MUIM_Draw:			r = m_draw( cl, obj, (APTR) msg ); break;
		case MUIM_HandleInput:	r = m_handleinput( cl, obj, (APTR) msg ); break;
 		case OM_SET:				r = m_set( cl, obj, (APTR) msg ); break;
		case OM_GET:				r = m_get( cl, obj, (APTR) msg ); break;

		case MUIM_Editor_ClearBuffer: r = e_clearbuff( cl, obj, (APTR) msg ); break;
		case MUIM_Editor_Import:		r = e_import( cl, obj, (APTR) msg ); break;
		case MUIM_Editor_Export:		r = e_export( cl, obj, (APTR) msg ); break;
		case MUIM_Editor_Replace:		r = e_replace( cl, obj, (APTR) msg ); break;
		case MUIM_Editor_Insert:		r = e_insert( cl, obj, (APTR) msg ); break;
		case MUIM_Editor_Delete:		r = e_delete( cl, obj, (APTR) msg ); break;
		case MUIM_Editor_GetLine:		r = e_getline( cl, obj, (APTR) msg ); break;
		case MUIM_Editor_Paste:			r = e_paste( cl, obj, (APTR) msg ); break;
		case MUIM_Editor_Copy:			r = e_copy( cl, obj, (APTR) msg ); break;
		case MUIM_Editor_AddLine:		r = e_addline( cl, obj, (APTR) msg ); break;
		case MUIM_Editor_RemLine:		r = e_remline( cl, obj, (APTR) msg ); break;
		case MUIM_Editor_Search:		r = e_search( cl, obj, (APTR) msg ); break;
		case MUIM_Editor_SwapBuffer:	r = e_swapbuffer( cl, obj, (APTR) msg ); break;
		case MUIM_Editor_KillBuffer:	r = e_killbuffer( cl, obj, (APTR) msg ); break;
		case MUIM_Editor_ImportAux:	r = e_importauxbuffer( cl, obj, (APTR) msg ); break;
		case MUIM_Editor_ExportAux:	r = e_exportauxbuffer( cl, obj, (APTR) msg ); break;
		default:								r = DoSuperMethodA( cl, obj, msg );
	}
	return( r );
}
extern SAVEDS ASM ULONG _Editor_Dispatcher(	REG(a0) struct IClass *cl,
															REG(a2) Object *obj,
															REG(a1) Msg msg )
{
	struct InstanceData *Data;
	ULONG retval, linetemp;

	Data = INST_DATA( cl, obj );
	if( msg->MethodID != OM_NEW )		// instance Data doesn't exist before OM_NEW...
	{
		linetemp = Data->Lines;			// This should be zero at init...
		if( msg->MethodID != OM_SET )
			Data->syssetcount++;			// Allow setting of protected variables
	}
	if( (msg->MethodID == OM_NEW) || (Data->cookie == EDITOR_COOKIE) )
		retval = dispatcherrouter( cl, obj, msg );
	if( (msg->MethodID != OM_DISPOSE) && (msg->MethodID != OM_NEW) )
	{
		if( Data->Lines != linetemp ) set( obj, MUIA_Editor_Lines, Data->Lines );
		if( msg->MethodID != OM_SET )
			Data->syssetcount--;			// Disable setting of protected variables
	}
	return( retval );
}
