#define __USE_SYSBASE

#include <exec/types.h>
#include <exec/execbase.h>
#include <exec/memory.h>
#include <dos/rdargs.h>
#include <dos/dosextens.h>
#include <graphics/text.h>
#include <support/types.h>
#include <support/exec.h>

#include <string.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/diskfont.h>
#include <proto/graphics.h>

#include "changefont.rev.h"

#define DOS_NAME			"dos.library"
#define DOS_VERN 			37L
#define GFX_NAME			"graphics.library"
#define GFX_VERN			0L
#define DISKFONT_NAME	"diskfont.library"
#define DISKFONT_VERN	36L

#define STD_NAME			"topaz.font"
#define STD_STYLE			FS_NORMAL
#define STD_FLAGS			(FPF_ROMFONT | FPF_DESIGNED)

#define REPLACE_FLAGS	(FPF_DISKFONT | FPF_DESIGNED)

#define FLAGS_MASK		(FPF_REVPATH | FPF_TALLDOT | FPF_WIDEDOT | FPF_PROPORTIONAL | FPF_DESIGNED)

#define TEMPLATE			"NAME/A,SIZE/N/M,QUIET/S"

STATIC CONST TEXT VersionString[]=
	VERSION(PROG_NAME,PROG_VERSION,PROG_REVISION,PROG_DATE);

#define MSG_REPLACED			"  Replaced\n"
#define MSG_NOT_REPLACED	"  Not Replaced"
#define INFO_TEMPLATE			"%s %d"

#define FONT_EXT			".font"

#define OPT_NAME		0
#define OPT_SIZE		1
#define OPT_QUIET		2
#define OPT_COUNT		3

#define NAME_SIZE		36		/* Size of name buffer */
#define BASE_SIZE		25		/* Max allowed length of font's name w/o extension */
#define EXT_SIZE		5			/* Size of font extension */

STATIC BOOL Match(struct TextFont *srcFont, struct TextFont *destFont);
STATIC VOID CopyAttrs(struct TextFont *srcFont, struct TextFont *destFont);

ULONG ChangeFont(VOID)
{
	struct ExecBase *SysBase=*((struct ExecBase **)4);
	struct DosLibrary *DOSBase;
	struct GfxBase *GfxBase;
	struct Library *DiskfontBase;

	STATIC CONST LONG Default8=8,Default9=9;
	STATIC CONST LONG * CONST DefaultSizes[]={&Default8,&Default9,NULL};

	LONG Opts[OPT_COUNT];
	ULONG RC=RETURN_FAIL,FontError;
	struct TextAttr StdAttr,ReplaceAttr;
	struct TextFont *StdFont,*ReplaceFont;
	CHAR FontName[NAME_SIZE];
	LONG **SizesPtr,*TempPtr;
	struct RDArgs *Args;
	BOOL ErrOccured=FALSE;

	unless(DOSBase=(struct DosLibrary *)OpenLibrary(DOS_NAME,DOS_VERN))
	{
		SetResult2(ERROR_INVALID_RESIDENT_LIBRARY);
		goto InvalidDOS;
	}

	unless(GfxBase=(struct GfxBase *)OpenLibrary(GFX_NAME,GFX_VERN))
	{
		PrintFault(IoErr(),NULL);								/* Inform user */
		goto InvalidGfx;
	}

	unless(DiskfontBase=OpenLibrary(DISKFONT_NAME,DISKFONT_VERN))
	{
		PrintFault(IoErr(),NULL);								/* Inform user */
		goto InvalidDiskfont;
	}

	clear(&Opts);															/* Clear out args buffer */
	unless(Args=ReadArgs(TEMPLATE,Opts,NULL))
	{
		PrintFault(IoErr(),NULL);								/* Inform user */
		goto NoArgs;
	}

	StdAttr.ta_Name=STD_NAME;
	StdAttr.ta_Flags=STD_FLAGS;

	ReplaceAttr.ta_Name=FontName;
	ReplaceAttr.ta_Flags=REPLACE_FLAGS;

	ReplaceAttr.ta_Style=StdAttr.ta_Style=STD_STYLE;

	SizesPtr=Opts[OPT_SIZE] ? (LONG **)Opts[OPT_SIZE] : DefaultSizes;
	while(TempPtr=*SizesPtr++)
	{
		FontError=ERROR_OBJECT_NOT_FOUND;	/* Possible error: fon not found */
		ReplaceAttr.ta_YSize=StdAttr.ta_YSize=*TempPtr;
		unless(StdFont=OpenDiskFont(&StdAttr))
			goto NoStdFont;

		clear(&FontName);
		strncpy(FontName,(STRPTR)Opts[OPT_NAME],NAME_SIZE-EXT_SIZE-1);
		unless(ReplaceFont=OpenDiskFont(&ReplaceAttr))
		{
			if(strlen(FontName)>BASE_SIZE)	/* Name too long */
				goto NoReplaceFont;
			strcat(FontName,FONT_EXT);			/* Now try concatenating ".font" */
			unless(ReplaceFont=OpenDiskFont(&ReplaceAttr))
				goto NoReplaceFont;
		}

		FontError=ERROR_OBJECT_WRONG_TYPE;	/* Possible error: wrong type of font */	
		if(Match(ReplaceFont,StdFont))			/* Fonts match themselves */
		{
			Forbid();
			CopyAttrs(ReplaceFont,StdFont);
			Permit();
			unless(Opts[OPT_QUIET])
				VPrintf(INFO_TEMPLATE MSG_REPLACED,&StdAttr);
			continue;
		}
		CloseFont(ReplaceFont);
NoReplaceFont:
		CloseFont(StdFont);
NoStdFont:
		VPrintf(INFO_TEMPLATE,&StdAttr);
		PrintFault(FontError,MSG_NOT_REPLACED);
		SetIoErr(FontError);
		ErrOccured=TRUE;
	}
	RC=ErrOccured ? RETURN_ERROR : RETURN_OK;

	FreeArgs(Args);
NoArgs:
	CloseLibrary(DiskfontBase);
InvalidDiskfont:
	CloseLibrary((struct Library *)GfxBase);
InvalidGfx:
	CloseLibrary((struct Library *)DOSBase);
InvalidDOS:
	return(RC);
}

STATIC BOOL Match(struct TextFont *srcFont, struct TextFont *destFont)
{
	return((BOOL)(srcFont->tf_YSize==destFont->tf_YSize &&
								srcFont->tf_Style==destFont->tf_Style &&
								(srcFont->tf_Flags & FLAGS_MASK)==
									(destFont->tf_Flags & FLAGS_MASK) &&
								srcFont->tf_XSize==destFont->tf_XSize &&
								srcFont->tf_Baseline==destFont->tf_Baseline));
}

STATIC VOID CopyAttrs(struct TextFont *srcFont, struct TextFont *destFont)
{
	destFont->tf_BoldSmear=srcFont->tf_BoldSmear;
	destFont->tf_Modulo=srcFont->tf_Modulo;
	destFont->tf_LoChar=srcFont->tf_LoChar;
	destFont->tf_HiChar=srcFont->tf_HiChar;
	destFont->tf_CharData=srcFont->tf_CharData;
	destFont->tf_CharLoc=srcFont->tf_CharLoc;
	destFont->tf_CharSpace=srcFont->tf_CharSpace;
	destFont->tf_CharKern=srcFont->tf_CharKern;
}
