//*****************************************************************//
//																						 //
// MARTINS READER V1.3 (Jan 24 1996)										 //
// ^^^^^^^^^^^^^^^^^^^															 //
//																						 //
// Description:																	 //
//   This is an AutoDoc reader that uses MUI 3.1						 //
//																						 //
// Legal:																			 //
//   This program is PUBLIC DOMAIN, you may use it and modify it	 //
//   and publish it if you give a reference to me, the				 //
//																						 //
// Author:																			 //
//   Dirk Holtwick																 //
//   Karlstr 59																	 //
//   47119 Duisburg /GERMANY													 //
//   dirco@uni-duisburg.de														 //
//																						 //
//*****************************************************************//

#include <dos/dos.h>
#include <wbstartup.h>
#include <libraries/mui.h>
#include <clib/alib_protos.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/muimaster_protos.h>
#include <clib/gadtools_protos.h>
#include <clib/asl_protos.h>
#include <pragma/exec_lib.h>
#include <pragma/dos_lib.h>
#include <pragma/muimaster_lib.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

// MUI STUFF
#define MAKE_ID(a,b,c,d) ((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d))
#define TOC "TABLE OF CONTENTS"

struct Library *MUIMasterBase;

// INDEX STRUCTURE
struct IndexData {
	struct IndexData *succ;
	char	*name[80];
	char	*text;
} *base=0, *last=0;

// MUI OBJECTS
APTR
	app,
	window,
	dirlist,
	caplist,
	textlist,
	strip,
	drawer,
	dirgr,
	bal;

// TEXT BUFFER
char	
	*text=0, 
	name[200], 
	wtitle[200];

// THE ONLY MENU CONSTANT
enum{Dummy, MEN_INFO, MEN_PRINT};

// SIMPLE MENU STRUCTURE
struct NewMenu Menu[] = {
	{ NM_TITLE, "Project",			0	,0,0,		(APTR)0            },
	{ NM_ITEM , "Info",				"I",0,0,		(APTR)MEN_INFO     },
	{ NM_ITEM , "Print",				"P",0,0,		(APTR)MEN_PRINT    },
	{ NM_ITEM , NM_BARLABEL, 		0	,0,0,		(APTR)0            },
	{ NM_ITEM , "Quit",				"Q",0,0,		(APTR)MUIV_Application_ReturnID_Quit },
	{ NM_END  , NULL,					0	,0,0,		(APTR)0            },
};

// MUI ERROR?
static VOID fail(APTR app,char *str){
	if (app)	MUI_DisposeObject(app);
   if (MUIMasterBase) CloseLibrary(MUIMasterBase);
   if (str){
      puts(str);
   	exit(20);
   }
	exit(0);
}

// STANDARD INTI FUNCTION FOR MUI
static VOID init(VOID){
	if (!(MUIMasterBase = OpenLibrary(MUIMASTER_NAME,MUIMASTER_VMIN-1)))
		fail(NULL,"Failed to open "MUIMASTER_NAME".");
}

// OPENS INFO WINDOW
void info(){
	MUI_RequestA(app,window,0,"Info","*\033b_O\033bK",
		"\033c\n\033bMartinsReader 1.3\n\033n\033iWritten by Dirk Holtwick, 1995/96.\n\n\033n"
		"'Happy Birthday Martin, this\ntool has been written for you.'\n\n"
		"This program is PUBLIC\nDOMAIN and you may use and\nmodify it how you like to.\n"
		"Just insert a note in the\nmodified program that the\ninitial release was done bye me.\n",0);	
}

// FIND NEXT LINE
char *findlf(char *s){
	while(*s && (*s!='\n') && (*s!='\f')) s++;
	return(++s);
}

// Get (Chapter)line
char *getline(char *d, char *s){
	while(*s && (*s!='\n') && (*s!='\f')) *d++=*s++;
	*d=0;
	if(*s=='\f') return(s);
	return(++s);
}

// FREE INDEX LIST
void freeindex(){
	struct IndexData *a,*b;

	if(base){
		a=base;
		while(a){
			b=a->succ;
			free(a);
			a=b;
		}
		base=0;
		last=0;
	}
}

// DISPLAY ROUTINE FOR CHAPTERS
void display (register __a2 char **array, register __a1 struct IndexData *act){
	*array	= (void *)act->name;
}

// ADD ITEM TO CHAPTER INDEX
void addindex(char *name, char *text){
	struct	IndexData	*act;

	if(act=malloc(sizeof(struct IndexData))){
		if(base) last->succ=act; 
		else base=act;
		last=act;
		strcpy((char *)(act->name), name);
		act->text=text;
		DoMethod (caplist, MUIM_List_InsertSingle, act, MUIV_List_Insert_Bottom);
	}else puts("Index mem");
}

// DOUBLECLICK IN CHAPTER
void cap_found(){
	long		num;
	struct	IndexData	*id;

	set(app, MUIA_Application_Sleep, TRUE);
	get(caplist, MUIA_List_Active, &num);
	DoMethod (caplist, MUIM_List_GetEntry, num, &id);
	set(textlist, MUIA_Floattext_Text, id->text);	
	set(app, MUIA_Application_Sleep, FALSE);
}

// LOAD WHOLE TEXT INTO BUFFER
void loadtext(char *name, LONG len){
	struct	IndexData	*id;
	char		*t;
	FILE		*f;

	// LOAD
	if(text) free(text);
	text=0;
	if(text=malloc(len+10)){
		if(f=fopen(name,"r")){
			fread(text,len,1,f);
			text[len]=0;
			fclose(f);
		}else puts("File error");
	}else puts("No more mem");

	// IS AUTODOC?
	if(!strncmp(text,TOC,strlen(TOC))){
		strcpy(wtitle, FilePart(name));
		set (window, MUIA_Window_Title, wtitle);

		// ANALYSE
		t=text;
		t=findlf(t);
		t=findlf(t);
	
		set (caplist, MUIA_List_Quiet, TRUE);
		DoMethod(caplist, MUIM_List_Clear);
		freeindex();
		while(*t!='\f'){
			getline(name,t);
			addindex(name,0);
			t=findlf(t);
		}
		set (caplist, MUIA_List_Quiet, FALSE);
	
		// FIND OFFSETS
		id=base;
		t=text;
		while(id){
			while(*t && (*t!='\f')) t++;
			if(*t=='\f'){
				*t++=0;
				id->text=t;
			}
			id=id->succ;
		}
	
		// SHOW
		set(textlist, MUIA_Floattext_Text, text);
	}else{
		MUI_RequestA(app,window,0,"Info","*\033b_O\033bK",
			"\nDoesn't seem to be\na real AutoDoc file!\n",0);	
	}
}

// DOUBLECLICK ON A FILE
void dir_found(){
	long		num,len;
	struct	FileInfoBlock	*act;
	struct	IndexData	*id;
	char		*dir,*t;

	set(app, MUIA_Application_Sleep, TRUE);

	get(dirlist, MUIA_List_Active, &num);
	DoMethod (dirlist, MUIM_List_GetEntry, num, &act);
	get(dirlist,MUIA_Dirlist_Directory,&dir);
	strcpy(name,dir);
	AddPart(name,act->fib_FileName,199);
	len=act->fib_Size;

	// Laden
	loadtext(name,len);

	set(app, MUIA_Application_Sleep, FALSE);
}

// PRINT ACTUAL PAGE
void print(){
	char	*text;
	FILE	*prt;

	get(textlist, MUIA_Floattext_Text, &text);
	if(prt=fopen("prt:","w")){
		fputs(text,prt);
		fclose(prt);
	}else puts("Couldn't open printer.");
}

// UPDATE THE DIRECTORA LIST
void change(){
	char	*s;

	get(drawer, MUIA_String_Contents, &s);
	set(dirlist, MUIA_Dirlist_Directory, s);
}

// MAIN PROGRAM
int main(int argc,char *argv[]){
	long		size=50000,locksave;
	struct 	FileInfoBlock  *fileinfo;
	char		token[20];

	// HOOKS
	static const struct Hook dir_foundHook	= { { NULL,NULL },(VOID *)dir_found, NULL,NULL };
	static const struct Hook displayHook	= { { NULL,NULL },(VOID *)display, NULL,NULL };
	static const struct Hook cap_foundHook	= { { NULL,NULL },(VOID *)cap_found, NULL,NULL };
	static const struct Hook InfoHook		= { { NULL,NULL },(VOID *)info, NULL,NULL };
	static const struct Hook printHook		= { { NULL,NULL },(VOID *)print, NULL,NULL };
	static const struct Hook changeHook		= { { NULL,NULL },(VOID *)change, NULL,NULL };

	init();
	ParsePatternNoCase("#?.doc",token,20);

	// MUI (3.1) APPLICATION
	app = ApplicationObject,
		MUIA_Application_Title      , "MartinsReader",
		MUIA_Application_Version    , "$VER: MartinsReader 1.3 ["__DATE__"]",
		MUIA_Application_Copyright  , "Written by Dirk Holtwick, 1996",
		MUIA_Application_Author     , "Dirk Holtwick",
		MUIA_Application_Description, "Simple AutoDoc Reader",
		MUIA_Application_Base       , "MARTINSREADER",

		SubWindow, window = WindowObject,
			MUIA_Window_Title, "MartinsReader 1.3, (W)ritten by Dirk Holtwick 1995/96",
			MUIA_Window_ID   , MAKE_ID('M','W','I','N'),
			MUIA_Window_Menustrip, strip = MUI_MakeObject(MUIO_MenustripNM,Menu,0),

			WindowContents, VGroup,
				Child, textlist = ListviewObject,
					MUIA_ShortHelp,
						"\033cShows the text of the choosen chapter.\n"
						"Activate the listview with ALT+UP.",
					MUIA_CycleChain, 1,
					MUIA_VertWeight, 250,
					MUIA_Font,MUIV_Font_Fixed,
					MUIA_Listview_Input, FALSE,
					MUIA_Listview_List, FloattextObject,
						MUIA_Background, MUII_TextBack,
						MUIA_Frame, MUIV_Frame_InputList,
						End,
					End,
				Child, BalanceObject,
					End,
				Child, HGroup,
					Child, dirgr = VGroup,
						MUIA_ShortHelp,
							"\033cChoose the directory where you've stored\n"
							"your autodoc files and then choose the\n"
							"file you want to have a look at.\n"
							"Activate with ALT+LEFT.",
						Child, dirlist = ListviewObject,
							MUIA_CycleChain, 1,
							MUIA_Listview_DoubleClick, TRUE,
							MUIA_Listview_List, DirlistObject,
								MUIA_Frame, MUIV_Frame_InputList,
								MUIA_Dirlist_AcceptPattern, token,
								MUIA_Dirlist_FilesOnly, TRUE,
								End,
							End,
						Child, PopaslObject,
							MUIA_CycleChain, 1,
							MUIA_Popasl_Type, 0,
							MUIA_Popstring_String, drawer = StringObject,
								StringFrame,
								MUIA_ExportID, 1,
								End,
							MUIA_Popstring_Button, PopButton(MUII_PopDrawer),
							ASLFR_DrawersOnly, TRUE,
							End,
						End,
					Child, bal = BalanceObject,
						End,
					Child, caplist = ListviewObject,
						MUIA_ShortHelp,
							"\033cChoose the chapter you are interested in.\n"
							"Activate with ALT+RIGHT or ALT+DOWN.",
						MUIA_CycleChain, 1,
						MUIA_Listview_DoubleClick, TRUE,
						MUIA_Listview_List, caplist = ListObject,
							MUIA_Frame, MUIV_Frame_InputList,
							MUIA_List_DisplayHook, &displayHook,
							End,
						End,
					End,
				End,
			End,
		End;

	if(!app) fail(app,"Failed to create Application.");

	DoMethod(window,MUIM_Notify,MUIA_Window_CloseRequest,TRUE,
		app,2,MUIM_Application_ReturnID,MUIV_Application_ReturnID_Quit);
	DoMethod(dirlist, MUIM_Notify, MUIA_Listview_DoubleClick, TRUE,
		dirlist, 2, MUIM_CallHook, &dir_foundHook);
	DoMethod(caplist, MUIM_Notify, MUIA_Listview_DoubleClick, TRUE,
		caplist, 2, MUIM_CallHook, &cap_foundHook);
	DoMethod((Object *)
		DoMethod(strip,MUIM_FindUData,MEN_INFO),MUIM_Notify,MUIA_Menuitem_Trigger,MUIV_EveryTime,
		window,3,MUIM_CallHook,&InfoHook,MUIV_TriggerValue);
	DoMethod((Object *)
		DoMethod(strip,MUIM_FindUData,MEN_PRINT),MUIM_Notify,MUIA_Menuitem_Trigger,MUIV_EveryTime,
		window,3,MUIM_CallHook,&printHook,MUIV_TriggerValue);
	DoMethod(drawer,MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime,
		dirlist, 2, MUIM_CallHook, &changeHook);
	DoMethod(window,MUIM_Notify,MUIA_Window_InputEvent, "alt up",
		window,3,MUIM_Set,MUIA_Window_ActiveObject,textlist);
	DoMethod(window,MUIM_Notify,MUIA_Window_InputEvent, "alt left",
		window,3,MUIM_Set,MUIA_Window_ActiveObject,dirlist);
	DoMethod(window,MUIM_Notify,MUIA_Window_InputEvent, "alt down",
		window,3,MUIM_Set,MUIA_Window_ActiveObject,caplist);
	DoMethod(window,MUIM_Notify,MUIA_Window_InputEvent, "alt right",
		window,3,MUIM_Set,MUIA_Window_ActiveObject,caplist);
	DoMethod(app,MUIM_Application_Load,MUIV_Application_Load_ENVARC);
	if(argc==2){
		set(dirgr, MUIA_ShowMe, FALSE);
		set(bal, MUIA_ShowMe, FALSE);
		fileinfo=malloc(sizeof(struct FileInfoBlock));
		if (locksave=Lock(argv[1],ACCESS_READ)){
			if(Examine(locksave,fileinfo)) size=fileinfo->fib_Size;
			UnLock(locksave);
		}
		free(fileinfo);
		loadtext(argv[1],size);
	}else{
		change();
	}
	set(window,MUIA_Window_Open,TRUE);
	DoMethod(window, MUIA_Window_ActiveObject, drawer);

	{
		ULONG sigs = 0;

		while (DoMethod(app,MUIM_Application_NewInput,&sigs) != MUIV_Application_ReturnID_Quit){
			if (sigs){
				sigs = Wait(sigs | SIGBREAKF_CTRL_C);
				if (sigs & SIGBREAKF_CTRL_C) break;
			}
		}
	}

	DoMethod(app,MUIM_Application_Save,MUIV_Application_Save_ENVARC);
	if(text) free(text);
	freeindex();
	set(window,MUIA_Window_Open,FALSE);
	fail(app,NULL);
}

