/*
**
**	textwd.h  Release 1
**
**	Textwd Class, derived from Floattext
**	includes methods for:
**	- loading a textfile by filename
**	- loading a textfile by appmessage
**	- searching a string
**	- remembers current line after window-resizing etc.
**	- scrolling and paging up and down
**
**	©1996 Ctryxx/Trinomic (Stephan Quitzsch)
**
*/

#include <stat.h>
#include <workbench/workbench.h>
#include "exec/memory.h"


#define Textwd_Base 0x4

#define MUIM_Textwd_Load	0x491
#define MUIM_Textwd_Up	0x492
#define MUIM_Textwd_Down	0x493
#define MUIM_Textwd_Back	0x494
#define MUIM_Textwd_Next	0x495
#define MUIM_Textwd_Seek 0x497
#define MUIM_Textwd_Nsk  0x498
#define MUIM_Textwd_Bsk  0x499
#define MUIM_Textwd_App	0x49a
#define MUIM_Textwd_Get	0x49b
#define MUIM_Textwd_Set	0x49c
#define MUIM_Textwd_Draw	0x49d
#define MUIM_Textwd_Scur	0x49e
#define MUIM_Textwd_Prt	0x49f

#define MUIA_Textwd_File	0x471

/*============================================================================*/

struct MUI_CustomClass *CL_Textwd;

/*============================================================================*/

struct MUIP_Textwd_Ld   { ULONG MethodID; char *filename;         };
struct MUIP_Textwd_Seek { ULONG MethodID; char *tosearch;         };
struct MUIP_Textwd_App  { ULONG MethodID; struct AppMessage *am;  };

/*============================================================================*/

char show_text[] =											// Introduction text
"Hello!\n\n\
You just loaded PC-Heini, the MUI-Textviewer by\n\
\n\
 _________________________________\n\
[__    ___________________________]\n\
   |  | ___ ()__ _. __  ___ () ___\n\
   |  | |())||||//||/\\||   ||||  /\n\
   /__\\ ||\\\\|||//|||\\/||_Y_||||__\\\n\
\n\n\
There is a Disk-Button in the upper right corner. You can load a Textfile using this button.\
 You can also load a file by typing pch [-l] <Textfile> into any shell-window. pch -h gives \
you a short help-text.\n\n\
Write comments to Ctryxx:\n\
 Stephan Quitzsch\n\
 Am Wolfswinkel 76\n\
 04416 Markkleeberg\n\n\
Email to:\n\
 wir95ccv@manitu.rz.uni-leipzig.de\n\n\
or IRC me:\n\
 Londo at #Leipzig or #Amigager\n";


/*============================================================================*/
/*= Textwd class                                                             =*/
/*============================================================================*/

struct Textwd_Data
{	char str_fname[256];		// current file loaded
	char str_tosearch[256];		// current string to search for
	int curline;				// current top-line
};


ULONG Textwd_Get( struct IClass *cl, Object *obj, struct opGet *msg )	// Get und Set Attrs...
{
	struct Textwd_Data *data = INST_DATA( cl,obj );

	switch( msg->opg_AttrID )
	{
		case MUIA_Textwd_File:
			*( msg->opg_Storage ) = (ULONG)( data->str_fname );
			return TRUE;
	}
	return (ULONG)DoSuperMethodA( cl,obj,msg );
}


ULONG Textwd_Set( struct IClass *cl, Object *obj, struct opSet *msg )
{
	struct Textwd_Data *data = INST_DATA( cl,obj );
	struct TagItem *tag;

	if ( tag = (struct TagItem*)FindTagItem(MUIA_Textwd_File, msg->ops_AttrList) )
	{
		strcpy( data->str_fname, tag->ti_Data );
	}	

	return (ULONG)DoSuperMethodA( cl,obj,msg );
}


ULONG Textwd_Seek( struct IClass *cl, Object *obj, struct MUIP_Textwd_Seek *msg )
{	struct Textwd_Data *data = INST_DATA( cl, obj );				// Search a string

	ULONG i;
	ULONG j;
	int lines = 0;
	int select = 0l;

	char *buffer = 0l;
	char found[256];

	strcpy( data->str_tosearch, msg->tosearch );

	get( obj, MUIA_List_Entries, &lines );
	select = MUIV_List_NextSelected_Start;

	for( i=0; i<strlen(data->str_tosearch); i++ )
	{	(data->str_tosearch)[i] = (data->str_tosearch)[i]|32;
	}

	for( i=0; i<lines; i++ )
	{
		DoMethod( obj, MUIM_List_GetEntry, i, &buffer );
		strcpy( found, buffer );

		for( j=0; j<strlen(found); j++ )
		{	found[j] = found[j]|32;
		}


		if( strstr(found, data->str_tosearch) )
		{	DoMethod( obj, MUIM_List_Select, i, MUIV_List_Select_On, 0l );
		}
	}

	return 0l;
}


ULONG Textwd_Nsk( struct IClass *cl, Object *obj, Msg msg )			// Jump to next selected
{
	int visible;
	int vislines;
	int selected = -1;

	get( obj, MUIA_List_Visible, &vislines );
	get( obj, MUIA_List_First, &visible );
	visible += vislines;

	do
	{	DoMethod( obj, MUIM_List_NextSelected, &selected );
	}while( (visible>selected) && (selected!=-1) );

	DoMethod( obj, MUIM_List_Jump, selected );

	return 0l;
}


ULONG Textwd_Bsk( struct IClass *cl, Object *obj, Msg msg )			// ...previous selected
{
	int visible;
	int oldselected = 0;
	int selected = -1;

	get( obj, MUIA_List_First, &visible );

	do
	{	oldselected = selected;
		DoMethod( obj, MUIM_List_NextSelected, &selected );
	}while( (visible>selected) && (selected!=-1) );

	DoMethod( obj, MUIM_List_Jump, oldselected );

	return 0l;
}

														// Icon dropped on Textwd-Class
ULONG Textwd_App( struct IClass *cl, Object *obj, struct MUIP_Textwd_App *msg )
{
	struct WBArg *wba;
	char name[256];

	wba = msg->am->am_ArgList;
	NameFromLock( wba->wa_Lock, name, sizeof(name) );
	AddPart( name, wba->wa_Name, sizeof(name) );

	DoMethod( obj, MUIM_Textwd_Load, name );

	return 0l;
}

														// Load a File
ULONG Textwd_Ld( struct IClass *cl, Object *obj, struct MUIP_Textwd_Ld *msg )
{
	FILE *fl_file;
	size_t tlen;
	char *text;
	
	struct stat filestat;
	struct Textwd_Data *data = INST_DATA( cl, obj );

	set( obj, MUIA_Textwd_File, msg->filename );

	stat( data->str_fname, &filestat );
	tlen = filestat.st_size;

	if( fl_file = fopen(data->str_fname, "r") )
	{
		text = (char*)AllocMem( tlen+1, MEMF_ANY );

		fread( text, 1, tlen, fl_file );
		fclose( fl_file );

		text[tlen] = 0;
		set( obj, MUIA_Floattext_Text, text );

		FreeMem( text, tlen );
	}
	else
	{	set( obj, MUIA_Floattext_Text, "Can't open File");
	}

	return 0l;
}


ULONG Textwd_Up( struct IClass *cl, Object *obj, Msg msg )			// Scroll back
{
	int visfirst;

	get( obj, MUIA_List_First, &visfirst);
	if( visfirst != -1 ) DoMethod( obj, MUIM_List_Jump, visfirst - 1 );

	return 0l;
}


ULONG Textwd_Down( struct IClass *cl, Object *obj, Msg msg )		// Scroll forward
{
	int visfirst;
	int vislines;

	get( obj, MUIA_List_Visible, &vislines);
	get( obj, MUIA_List_First, &visfirst);

	if(visfirst != -1)
	{	DoMethod( obj, MUIM_List_Jump, visfirst+vislines );
	}

	return 0l;
}


ULONG Textwd_Back( struct IClass *cl, Object *obj, Msg msg )		// Jump to last page
{
	int visfirst;
	int vislines;

	get( obj, MUIA_List_Visible, &vislines );
	get( obj, MUIA_List_First, &visfirst );

	if( (vislines != -1) && (visfirst != -1) )
	{	DoMethod( obj, MUIM_List_Jump, ((visfirst-vislines>0)?(visfirst-vislines+1):0) );
	}

	return 0l;
}


ULONG Textwd_Next( struct IClass *cl, Object *obj, Msg msg )		// Jump to next page
{
	int visfirst;
	int vislines;

	get( obj, MUIA_List_Visible, &vislines );
	get( obj, MUIA_List_First, &visfirst );

	if( (vislines != -1) && (visfirst != -1) )
		DoMethod( obj, MUIM_List_Jump, 2*vislines + visfirst - 2 );

	return 0l;
}


ULONG Textwd_Draw( struct IClass *cl, Object *obj, Msg msg )		// After redraw jump to current line
{
	struct Textwd_Data *data = INST_DATA( cl, obj );
	int vislines;

	get( obj, MUIA_List_Visible, &vislines );
	DoMethod( obj, MUIM_List_Jump, data->curline+vislines-1 );

	return (ULONG)DoSuperMethodA( cl,obj,msg );
}


ULONG Textwd_Scur( struct IClass *cl, Object *obj, Msg msg )		// save the current line
{
	struct Textwd_Data *data = INST_DATA( cl, obj );
	get( obj, MUIA_List_First, &(data->curline) );
	return (ULONG)DoSuperMethodA( cl,obj,msg );
}


ULONG Textwd_Prt( struct IClass *cl, Object *obj, Msg msg )		// print text
{
	FILE *fp;
	char *text;

	get( obj, MUIA_Floattext_Text, &text);

	if( fp=fopen("prt:","w") )
	{	fputs(text, fp);
		fputs("\n", fp);
		fclose(fp);
	}

	return 0l;
}


ULONG Textwd_New( struct IClass *cl, Object *obj, Msg msg )
{
	obj = (Object*) DoSuperNew( cl, obj,
		MUIA_Frame, MUIV_Frame_ReadList,
		MUIA_Listview_List, FloattextObject,
			MUIA_Floattext_TabSize, 5,
			MUIA_Floattext_Text, show_text,
		End,
		TAG_DONE
	);
	DoMethod( obj, MUIM_Notify, MUIA_AppMessage, MUIV_EveryTime, obj, 2, MUIM_Textwd_App, MUIV_TriggerValue );

	return (ULONG)obj;
}


__saveds __asm ULONG Textwd_Dispatcher( register __a0 struct IClass *cl, register __a2 Object *obj, register __a1 Msg msg )
{
	switch ( msg->MethodID )
	{
		case OM_NEW:			return( Textwd_New ( cl, obj, (APTR)msg ));
		case OM_GET:			return( Textwd_Get ( cl, obj, (APTR)msg ));
		case OM_SET:			return( Textwd_Set ( cl, obj, (APTR)msg ));
		case MUIM_HandleInput:	return( Textwd_Scur( cl, obj, (APTR)msg ));
		case MUIM_Draw:		return( Textwd_Draw( cl, obj, (APTR)msg ));

		case MUIM_Textwd_Load:	return( Textwd_Ld  ( cl, obj, (APTR)msg ));
		case MUIM_Textwd_Up  :	return( Textwd_Up  ( cl, obj, (APTR)msg ));
		case MUIM_Textwd_Down:	return( Textwd_Down( cl, obj, (APTR)msg ));
		case MUIM_Textwd_Next:	return( Textwd_Next( cl, obj, (APTR)msg ));
		case MUIM_Textwd_Back:	return( Textwd_Back( cl, obj, (APTR)msg ));
		case MUIM_Textwd_Seek:	return( Textwd_Seek( cl, obj, (APTR)msg ));
		case MUIM_Textwd_Nsk:	return( Textwd_Nsk ( cl, obj, (APTR)msg ));
		case MUIM_Textwd_Bsk:	return( Textwd_Bsk ( cl, obj, (APTR)msg ));
		case MUIM_Textwd_App:	return( Textwd_App ( cl, obj, (APTR)msg ));
		case MUIM_Textwd_Prt:	return( Textwd_Prt ( cl, obj, (APTR)msg ));
	}
	return (ULONG)DoSuperMethodA( cl, obj, msg );
}
