
// NEED TO WRITE:
// function to convert fontname to valid Amiga font name / file name
// function to add/remove sizes from otag file
//

#ifndef T1MANAGER_GST
#include "t1manager.h"
#endif


/*************************************************************/
/* Global Variables */
/*************************************************************/
/* MUI stuff */
struct Library *MUIMasterBase = NULL;
Class *myimagegclass;
static Object *app_obj;			/* Application object */
static Object *window_obj;		/* Window object */
static Object *cycle_obj_dirs;		/* Cycle object - Current font directory */
static Object *listview_obj;		/* Listview object - Already Installed Fonts */
static Object *button_obj_install;	/* Button object - Click To Install Fonts */
static Object *button_obj_remove;	/* Button object - Click to remove fonts */
static Object *cycle_obj_pages;		/* Cycle object - Select page */
static Object *page_obj;		/* Page object */
static Object *image_obj_preview;	/* Page 1: Image Object - Preview */
static Object *image_obj_options;	/* Page 2: Image Object - Options */

#define ID_INSTALL 1
#define ID_CYCLE 2
#define ID_DOUBLECLICK 3
#define ID_REMOVE 4
#define ID_SELECTCHANGE 5

char *fontdirparts[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
char *Pages[] = { "Preview", "Options", NULL };
int sizefontdirparts = (sizeof(fontdirparts) / sizeof(char *));
int numfontdirparts = 0;

struct Hook H_AddManyFonts;

/* Storage for the font preview */
struct BitMap *bitmap = NULL;
struct Image imagerec;
struct Image *image = &imagerec;
int bitmapwidth, bitmapheight;
char currentpreviewfont[80] = "";

int can_use_V39_funcs = 1;


/*************************************************************/
/* Prototypes */
/*************************************************************/
static BOOL InstallFont(APTR ParentWindow, char *destdrawer);
static BOOL RemoveFont(APTR ParentWindow, char *destdrawer, char *fontname);
static BOOL PreviewFont(APTR ParentWindow, char *destdrawer, char *fontname);
static struct BitMap *MyAllocBitMap(int width, int height);
static void MyFreeBitMap(struct BitMap *bitMap, int width, int height);
void AddFontToListview(char *otagname, char *filebuf);


void UpdateDisplay(void)
{
	int x;

	/* Clear the current list of fonts, and update */
	get(cycle_obj_dirs, MUIA_Cycle_Active, &x);

	set (window_obj, MUIA_Window_Sleep, TRUE);
	DoMethod(listview_obj, MUIM_List_Clear, 0);
	DoAllAssigns(fontdirparts[x], &ScanDir, &CheckFile);
	set (window_obj, MUIA_Window_Sleep, FALSE);
}

ULONG __saveds __asm AddManyFonts(register __a0 struct Hook *hook, 
											register __a2 APTR object,
											register __a1 APTR message)
{
	struct AppMessage *AppM = *(struct AppMessage **)message;
	int args,i,x,c=0;
	BPTR olddir;
	char Buffer[32];

	if (AppM)
	{
		args = AppM->am_NumArgs;
		olddir = CurrentDir(AppM->am_ArgList[0].wa_Lock);
		get(cycle_obj_dirs, MUIA_Cycle_Active, &x);
		set(window_obj,MUIA_Window_Activate,TRUE);
		for (i=0; i < args; i++)
		{
			if (AppM->am_ArgList[i].wa_Name && AppM->am_ArgList[i].wa_Name[0])
			{
				c++;
				CurrentDir(AppM->am_ArgList[i].wa_Lock);
				T1_InstallFont(AppM->am_ArgList[i].wa_Name, fontdirparts[x]);
			}
		}
		CurrentDir(olddir);
		UpdateDisplay();
		sprintf(Buffer,"%ld fonts installed.",c);
		MUI_Request(app_obj, NULL, 0L, "Multiple Install", "Ok", Buffer);
	}
	return NULL;
}

/*************************************************************/
/* Main */
/*************************************************************/
int main(int argc, char *argv[])
{
	struct DiskObject *DiskObject = NULL;
	BOOL running = TRUE;
	extern struct ExecBase *SysBase;

	/* check for V37 and fail if anything less */
	if (SysBase->LibNode.lib_Version < 37)
	{
		Write(Output(), "T1Manager requires Kickstart V37 or higher.\n", 44);
		exit(RETURN_FAIL);
	}

	/* check for V39 to see if we can use V39 functions AllocBitMap and FreeBitMap */
	if (SysBase->LibNode.lib_Version < 39)
		can_use_V39_funcs = 0;

	H_AddManyFonts.h_Entry = (HOOKFUNC)AddManyFonts;
	
	/* Create an array of the parts in the fonts: assign */
	DoAllAssigns("FONTS:", &AddFontdir, NULL);

	MUIMasterBase = OpenLibrary("muimaster.library", 0L);
	myimagegclass = Init_myimagegclass();

	/* create GUI stuff */
	app_obj = ApplicationObject,
		MUIA_Application_Title,			"T1Manager",
		MUIA_Application_Version,		"$VER: T1Manager " VERSION " (25.03.94)",
		MUIA_Application_Copyright,		"Copyright © 1993 by Amish S. Dave",
		MUIA_Application_Author,		"Amish S. Dave",
		MUIA_Application_Description,	"Type1 font installer program",
		MUIA_Application_Base,			"T1Manager",
		MUIA_Application_DiskObject,	DiskObject=GetDiskObject("PROGDIR:t1manager"),

		SubWindow, window_obj = WindowObject,
			MUIA_Window_Title,	"T1Manager",
			MUIA_Window_ID,		MAKE_ID('T', '1', 'M', 'A'),
			MUIA_Window_AppWindow, TRUE,
			MUIA_Background, MUII_WindowBack,
			WindowContents, VGroup,

				Child, ColGroup(2),
					Child, Label2("\33lFont Drawer:"),
					Child, cycle_obj_dirs = CycleObject,
						MUIA_Cycle_Entries, fontdirparts,
						MUIA_ExportID, 1,
						End,
					End,

				Child, listview_obj = ListviewObject,
					MUIA_Listview_Input, TRUE,
					MUIA_Background, MUII_ListBack,
					MUIA_Listview_MultiSelect, MUIV_Listview_MultiSelect_Default,
					MUIA_Listview_List, ListObject, ReadListFrame,
						MUIA_List_ConstructHook, MUIV_List_ConstructHook_String,
						MUIA_List_DestructHook, MUIV_List_DestructHook_String,
						End,
					End,

				Child, HGroup,
					Child, button_obj_install = SimpleButton("Install"),

					Child, button_obj_remove = SimpleButton("Remove"),
				End,

				Child, VSpace(4),

				Child, VGroup, GroupFrame,
					MUIA_Background, MUII_GroupBack,
					Child, cycle_obj_pages = Cycle(Pages),
					Child, page_obj = PageGroup,
						MUIA_Background,MUII_BACKGROUND,
						Child, image_obj_preview = MyImageBorder(260, 30, NULL, 0),
						Child, image_obj_options = MyImageBorder(260, 30, NULL, 0),
						End,
					End,
				End,
			End,
		End;

	if (app_obj==NULL)
	{
		if (DiskObject) FreeDiskObject (DiskObject);
		exit (RETURN_FAIL);
	}


	/*
	 * setup stuff for event handling
	 */
	DoMethod (window_obj, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
		app_obj, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);

	DoMethod (button_obj_install, MUIM_Notify, MUIA_Pressed, FALSE,
		app_obj, 2, MUIM_Application_ReturnID, ID_INSTALL);

	DoMethod (button_obj_remove, MUIM_Notify, MUIA_Pressed, FALSE,
		app_obj, 2, MUIM_Application_ReturnID, ID_REMOVE);

	DoMethod (cycle_obj_dirs, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime,
		app_obj, 2, MUIM_Application_ReturnID, ID_CYCLE);

	DoMethod (listview_obj, MUIM_Notify, MUIA_Listview_DoubleClick, TRUE,
		app_obj, 2, MUIM_Application_ReturnID, ID_DOUBLECLICK);

	DoMethod (listview_obj, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime,
		app_obj, 2, MUIM_Application_ReturnID, ID_SELECTCHANGE);

	DoMethod (window_obj, MUIM_Notify, MUIA_AppMessage, MUIV_EveryTime,
		window_obj, 3, MUIM_CallHook, &H_AddManyFonts, MUIV_TriggerValue);

	/* connect page cycle gadget with page group */
	DoMethod (cycle_obj_pages, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime,
		page_obj, 3, MUIM_Set, MUIA_Group_ActivePage, MUIV_TriggerValue);


	/* set cycle chain for keyboard control */
	DoMethod (window_obj, MUIM_Window_SetCycleChain,
		cycle_obj_dirs, listview_obj, button_obj_install, button_obj_remove, cycle_obj_pages, NULL);


	/* Load a previously saved configuration from env: */
	DoMethod(app_obj, MUIM_Application_Load, MUIV_Application_Load_ENV);


	/* init display */
	set (window_obj,MUIA_Window_Open,TRUE);
	set (window_obj,MUIA_Window_ActiveObject, cycle_obj_dirs);


	/* event loop */
	DoAllAssigns(fontdirparts[0], &ScanDir, &CheckFile);

	while (running)
	{
		ULONG signals;

		switch (DoMethod(app_obj, MUIM_Application_Input, &signals))
		{
			case MUIV_Application_ReturnID_Quit:
				running = FALSE;

				/* Save our configuration */
				DoMethod(app_obj, MUIM_Application_Save, MUIV_Application_Save_ENVARC);
				DoMethod(app_obj, MUIM_Application_Save, MUIV_Application_Save_ENV);

				break;

			case ID_INSTALL:
			{
				LONG x;

				/* Get the active font: path from the cycle gad */
				get(cycle_obj_dirs, MUIA_Cycle_Active, &x);

				/* Install a font */
				InstallFont(window_obj, fontdirparts[x]);

				/* Clear the current list of fonts, and update */
//				DoMethod(listview_obj, MUIM_List_Clear, 0);
//				DoAllAssigns(fontdirparts[x], &ScanDir, &CheckFile);
				UpdateDisplay();

				break;
			}

			case ID_REMOVE:
			{
				LONG x = MUIV_List_NextSelected_Start;
				LONG fp;
				char *ch;
				int Mod = 0, Opt = 0;
				char Mess[256];

				/* Get the active font: path from the cycle gad */
				get(cycle_obj_dirs, MUIA_Cycle_Active, &fp);

				/* Find the active entry in the listview */
				for (;;)
				{
					DoMethod(listview_obj, MUIM_List_NextSelected,&x);
					if (x == MUIV_List_NextSelected_End) break;

					DoMethod(listview_obj, MUIM_List_GetEntry, x, &ch);
					if (!Mod || Opt == 1)
					{
						// Remove == 1, Skip = 2, All = 3, Cancel = 0
						sprintf(Mess,"Remove %s?",ch);
						Opt = MUI_Request(app_obj,NULL,0L,"Remove Font","Remove|Skip|Remove All|*Cancel",Mess);
						if (!Opt) break;
						if (Opt == 2)
						{
							Opt = 1;
							continue;
						}
					}

					/* Remove the font */
					if (*ch)
					{
						RemoveFont(window_obj, fontdirparts[fp], ch);
						Mod++;
					}
				}
				if (Mod)
				{
					UpdateDisplay();
					if (Mod > 1)
					{
						sprintf(Mess,"%ld fonts removed.",Mod);
						MUI_Request(app_obj, NULL, 0L, "Multiple Remove", "Ok", Mess);
					}
				}
				break;
			}

			case ID_CYCLE:
			{
//				LONG x;

				/* Get the active font: path from the cycle gad */
//				get(cycle_obj_dirs, MUIA_Cycle_Active, &x);

				/* Clear the current list of fonts, and update */
//				DoMethod(listview_obj, MUIM_List_Clear, 0);
//				DoAllAssigns(fontdirparts[x], &ScanDir, &CheckFile);
				UpdateDisplay();
				break;
			}

			case ID_DOUBLECLICK:
			{
				char *fontname;
				LONG x;

				/* Go to sleep until done rendering */
				set (window_obj, MUIA_Window_Sleep, TRUE);

				/* Get the active font: path from the cycle gad */
				get(cycle_obj_dirs, MUIA_Cycle_Active, &x);

				/* Find the active entry in the listview */
				DoMethod(listview_obj, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &fontname);
				strncpy(currentpreviewfont, fontname, 79);

				/* Do the preview */
				PreviewFont(window_obj, fontdirparts[x], fontname);

				/* Wake up */
				set (window_obj, MUIA_Window_Sleep, FALSE);

				break;
			}

			case ID_SELECTCHANGE:
			{
				/* If a preview is displayed, then remove it */
				if ((bitmap) && (*currentpreviewfont != '\0'))
				{
					set(image_obj_preview, GA_Image, NULL);
				}

				break;
			}
			
		}

		if (running && signals)
			Wait(signals);
	}


	/* free the preview bitmap */
//	if (bitmap) FreeBitMap(bitmap);
	if (bitmap) MyFreeBitMap(bitmap, bitmapwidth, bitmapheight);

	/* remove GUI stuff */
	MUI_DisposeObject(app_obj);
	if (DiskObject) FreeDiskObject(DiskObject);

	/* Close the myimageclass private class */
	Free_myimagegclass(myimagegclass);

	/* free some allocations */
	FreeFontdirparts();

	/* close our libraries */
	CloseLibrary(MUIMasterBase);
	exit (RETURN_OK);
}


#ifdef PARMDEBUG
void DebugBltTemplate(UWORD *SrcTemplate, WORD SrcX, WORD SrcMod, struct RastPort *rp, WORD DstX, WORD DstY, WORD SizeX, WORD SizeY, char ch)
{
	char ReqText[256];

	sprintf(ReqText, "ch='%lc'\nSrcTemplate=%lx\nSrcX=%ld\nSrcMod=%ld\nrp=%lx\nDstX=%ld\nDstY=%ld\nSizeX=%ld\nSizeY=%ld\n", (LONG) ch, (LONG) SrcTemplate, (LONG) SrcX, (LONG) SrcMod, (LONG) rp, (LONG) DstX, (LONG) DstY, (LONG) SizeX, (LONG) SizeY);
	(void)MUI_Request(app_obj, NULL, 0L, "BltTemplate parms", "Ok", ReqText);
}
#endif


/*************************************************************/
/* InstallFont */
/* select a file to install with the asl.library */
/*************************************************************/
static BOOL InstallFont(APTR ParentWindow, char *destdrawer)
{
	struct FileRequester *FileRequester;
	struct Window *window;
	BOOL Result;
	int i;
	BPTR olddir;

	get(ParentWindow, MUIA_Window, &window);
	if (window == NULL) return FALSE;

	if ((FileRequester=(struct FileRequester *) MUI_AllocAslRequestTags(ASL_FileRequest,
			ASLFR_RejectIcons,  	(ULONG) TRUE,
			ASLFR_Window,   	(ULONG) window,
//			ASLFR_InitialDrawer,	(ULONG) "psfonts:",
			ASLFR_DoMultiSelect,	(ULONG) TRUE,
			TAG_DONE))==NULL)
		return FALSE;

	set (ParentWindow,MUIA_Window_Sleep,TRUE);
	Result=MUI_AslRequest((APTR)FileRequester,NULL);

	if (Result)
	{
		olddir = CurrentDir(FileRequester->fr_ArgList[0].wa_Lock);
		for (i=0; i < FileRequester->fr_NumArgs; i++)
		{
			CurrentDir(FileRequester->fr_ArgList[i].wa_Lock);
			T1_InstallFont(FileRequester->fr_ArgList[i].wa_Name, destdrawer);
		}
		CurrentDir(olddir);
	}

	MUI_FreeAslRequest (FileRequester);
	set (ParentWindow,MUIA_Window_Sleep,FALSE);

	return Result;
}


/*************************************************************/
/* RemoveFont */
/* remove an installed font */
/*************************************************************/
static BOOL RemoveFont(APTR ParentWindow, char *destdrawer, char *fontname)
{
	char filename[256], *ch;

//	if (MUI_Request(app_obj, ParentWindow, 0, NULL, "Remove|*Cancel",
//		"Warning: are you sure it is\nokay to remove\n%s\nfrom your system?\n",
//		fontname) == 1)
	{
		/* Construct the name of the bitmap directory */
		strcpy(filename, destdrawer);
		AddPart(filename, fontname, sizeof(filename));

		/* Delete all files in the bitmap directory */
// The following causes problems(E-hits). Most likely because I shouldn't be calling DoAllAssigns
// with a path rather than an assign.  In any event, it isn't really necessary, as I
// certainly don't make bitmaps, and don't plan to anytime soon.  Consider this omission
// a matter of laziness.  I'll get to this someday.
//
//		DoAllAssigns(filename, &ScanDir, &DeleteBitmaps);
//
// Ignore any error code from the following.

		/* Delete the bitmap directory, now that it is empty */
		DeleteFile(filename);

		/* Construct the name of the .font file */
		strcat(filename, ".font");

		/* Delete the .font file */
		DeleteFile(filename);
		/* Construct the name of the .otag file */
		ch = filename;
		while (*ch != '\0') ch++;
		ch -= 5;
		strcpy(ch, ".otag");

		DeleteFile(filename);
		return TRUE;

	}

//	return FALSE;
}


/*************************************************************/
/* PreviewFont */
/* Display a preview of the current font */
/*************************************************************/
static BOOL PreviewFont(APTR ParentWindow, char *destdrawer, char *fontname)
{
	char filename[256];
	LONG leftedge, topedge, width, height;
	ULONG pointheight = 24;
	struct RastPort rp;
	BOOL erasebitmap;

	/* Construct the name of the otag file */
	strcpy(filename, destdrawer);
	AddPart(filename, fontname, sizeof(filename));
	strcat(filename, ".otag");

	/* Get the preview box size */
	get(image_obj_preview, MUIA_LeftEdge, &leftedge);
	get(image_obj_preview, MUIA_TopEdge, &topedge);
	get(image_obj_preview, MUIA_Width, &width);
	get(image_obj_preview, MUIA_Height, &height);

	{
//	char ReqText[256];
//	sprintf(ReqText, "left=%ld\ntop=%ld\nwidth=%ld\nheight=%ld\n", leftedge,topedge, width, height);
//	(void)MUI_Request(app_obj, NULL, 0L, "Object Size", "Ok", ReqText);
	}

	/*
	 * Allocate our bitmap
	 * if it is already allocated, make sure it is the right size
	 */
	if ((bitmap != NULL) && ((bitmapwidth != width) || (bitmapheight != height)))
	{
		MyFreeBitMap(bitmap, width, height);
		bitmap = NULL;
	}
		
	if (bitmap == NULL)
	{
		bitmap = MyAllocBitMap(width, height);
		bitmapwidth = width;
		bitmapheight = height;
		InitBitMap(bitmap, 1, width, height);
		erasebitmap = FALSE;
	}
	else
		erasebitmap = TRUE;


	/*
	 * Set up our image structure
	 */
	image->LeftEdge = image->TopEdge = 0;
	image->Width = width;
	image->Height = height;
	image->Depth = 1;
	image->ImageData = (UWORD *)(bitmap->Planes[0]);
	image->PlanePick = 1;
	image->PlaneOnOff = 0;
	image->NextImage = NULL;

	/* Construct a rastport structure using above bitmap data, for rendering */
	InitRastPort(&rp);
	rp.BitMap = bitmap;
	if (erasebitmap) EraseRect(&rp, 0, 0, width-1, height-1);

	/* Call lower level function to do the rendering */
	RenderPreview(filename, pointheight, &rp, 0, 0, width, height, "(1.2) The quick brown fox");

	/* Update the displayed image */
	set(image_obj_preview, GA_Image, image);

	return TRUE;
}


/*************************************************************/
/* MyErrorMsg */
/* display an error with muimaster.library/MUI_Request */
/*************************************************************/
void MyErrorMsg(char *ErrorMsg)
{
	(void)MUI_Request(app_obj, NULL, 0L, "Error", "Ok", ErrorMsg);
}


/*************************************************************/
/* Add font to listview, given name of otag file and */
/* the memory copy of the otag file */
/*************************************************************/
void AddFontToListview(char *otagname, char *filebuf)
{
	char fontname[256], *ch;

	strcpy(fontname, otagname);
	ch = fontname;
	while (*ch && (*ch != '.')) ch++;
	if (*ch == '.') *ch = '\0';
	ch = fontname;
	DoMethod(listview_obj, MUIM_List_Insert, &ch, 1, MUIV_List_Insert_Sorted);

	return;
}


/*************************************************************/
/* Allocate a signle plane bitmap, using either V39 or V37 */
/* functions as appropriate. */
/* Returns NULL on error */
/*************************************************************/
static struct BitMap *MyAllocBitMap(int width, int height)
{
	struct BitMap *bitMap = NULL;

	if (can_use_V39_funcs == 1)
	{
		bitMap = AllocBitMap(width, height, 1, BMF_CLEAR, NULL);
	}
	else
	{
		bitMap = (struct BitMap *)AllocVec(sizeof(struct BitMap), MEMF_CLEAR);
		if (bitMap)
		{
			InitBitMap(bitMap, 1, width, height);
			bitMap->Planes[0] = (PLANEPTR) AllocRaster(width, height);
			if (bitMap->Planes[0] == NULL)
			{
				FreeVec(bitMap);
				bitMap = NULL;
			}
		}
	}

	return bitMap;
}


/*************************************************************/
/* Free a single plane bitmap, using V39 or V37 functions as */
/* appropriate. Can be called with a NULL input. */
/*************************************************************/
static void MyFreeBitMap(struct BitMap *bitMap, int width, int height)
{
	if (bitMap)
	{
		if (can_use_V39_funcs == 1)
		{
			FreeBitMap(bitMap);
		}
		else
		{
			FreeRaster(bitMap->Planes[0], width, height);
			FreeVec(bitMap);
		}
	}
}

