/*
**	SpecialHost for PasTeX
**
**	Copyright © by Olaf Barthel & Georg Heßmann
*/

#include "Global.h"

enum	{	ARG_IFFFILE,ARG_PSFILE,ARG_HSIZE,ARG_VSIZE,ARG_HOFFSET,
		ARG_VOFFSET,ARG_SCALE,ARG_HSCALE,ARG_VSCALE,ARG_ANGLE,ARG_CLIP,ARG_MODE,
		ARG_BRIGHT,ARG_CONTRAST,ARG_GAMMA,ARG_RED,ARG_GREEN,ARG_BLUE,
		ARG_TRANSFER,ARG_RENDERING,ARG_INVERT,ARG_BASEDPI,ARG_THRESHOLD,
		ARG_PATCHCOLOURS,ARG_LLX,ARG_LLY,ARG_URX,ARG_URY,ARG_RWI,ARG_RHI,
		ARG_DITHEROPT,ARG_PSINITSTRING,ARG_PSINITFILE,

		ARGCOUNT
	};

#define TEMPLATE "IMAGE=IFFFILE/K,PSFILE/K,HSIZE/K,VSIZE/K,HOFFSET/K,VOFFSET/K,SCALE/K,HSCALE/K,VSCALE/K,ANGLE/K,CLIP/S,MODE/K,BRIGHT/K,CONTRAST/K,GAMMA/K,RED/K,GREEN/K,BLUE/K,TRANSFER/K,RENDER/K,INVERT/K,BASEDPI/K,THRESHOLD/K,PATCH=PATCHCOLOURS/S,LLX/K,LLY/K,URX/K,URY/K,RWI/K,RHI/K,DITHEROPT/K/N,PSINITSTRING/K,PSINITFILE/K"

STATIC BOOL __regargs
GetDimension(STRPTR Argument,float *Storage,float Unit)
{
	UBYTE LocalBuffer[40];
	LONG Len;

	memcpy(LocalBuffer,Argument,39);

	LocalBuffer[39] = 0;

	Len = strlen(LocalBuffer);

	while(Len > 0 && LocalBuffer[Len - 1] == ' ')
		Len--;

	LocalBuffer[Len] = 0;

	if(Len > 2) /* if(Len > 2 && isalpha(LocalBuffer[Len-1])) */
	{
		STATIC struct { STRPTR Name; float Unit; } UnitTable[] =
		{
			"pt",	72.27,
			"pc",	6.0225,     /* 72.27/12.0 */
			"in",	1.0,
			"bp",	72.0,
			"cm",	2.54,
			"mm",	25.4,
			"dd",	67.54151,   /* 72.27*1157.0/1238.0 */
			"cc",	5.62846,    /* 72.27*1157.0/1238.0/12.0 */
                        "sp",   4736286.7   /* 72.27 * 65536.0 */
		};

		LONG i;

		for(i = 0 ; i < 9 ; i++)
		{
			if(!Stricmp(&LocalBuffer[Len - 2],UnitTable[i] . Name))
			{
				Unit = UnitTable[i] . Unit;

				LocalBuffer[Len - 2] = 0;

				break;
			}
		}
	}

	*Storage = atof(LocalBuffer);

	switch(_FPERR)
	{
		case 0:

			*Storage /= Unit;

			return(TRUE);

		case _FPEUND:

			PrintLine("\33bFloating point underflow \"%s\".\33n",Argument);
			return(FALSE);

		case _FPEOVF:

			PrintLine("\33bFloating point overflow \"%s\".\33n",Argument);
			return(FALSE);

		case _FPEZDV:

			PrintLine("\33bDivision by zero \"%s\".\33n",Argument);
			return(FALSE);

		case _FPENAN:

			PrintLine("\33bInvalid operation \"%s\".\33n",Argument);
			return(FALSE);

		case _FPECOM:

			PrintLine("\33bFloating point value not comparable \"%s\".\33n",Argument);
			return(FALSE);
	}
}

STATIC BOOL __regargs
GetScale(STRPTR Argument,float *Storage, float Unit)
{
	*Storage = atof(Argument);

	switch(_FPERR)
	{
		case 0:

			if(*Storage <= 0.0)
			{
				PrintLine("\33bIllegal scale value \"%s\".\33n",Argument);

				return(FALSE);
			}
			else
			{
				*Storage /= Unit;

				return(TRUE);
			}

		case _FPEUND:

			PrintLine("\33bFloating point underflow \"%s\".\33n",Argument);
			return(FALSE);

		case _FPEOVF:

			PrintLine("\33bFloating point overflow \"%s\".\33n",Argument);
			return(FALSE);

		case _FPEZDV:

			PrintLine("\33bDivision by zero \"%s\".\33n",Argument);
			return(FALSE);

		case _FPENAN:

			PrintLine("\33bInvalid operation \"%s\".\33n",Argument);
			return(FALSE);

		case _FPECOM:

			PrintLine("\33bFloating point value not comparable \"%s\".\33n",Argument);
			return(FALSE);
	}
}

STATIC BOOL __regargs
GetInteger(STRPTR Argument,LONG *Storage,LONG Min,LONG Max)
{
	if(StrToLong(Argument,Storage) < 1)
	{
		PrintLine("\33bIllegal value \"%s\".\33n",Argument);

		return(FALSE);
	}
	else
	{
		if(Min != Max)
		{
			if(*Storage < Min)
				*Storage = Min;
			else
			{
				if(*Storage > Max)
					*Storage = Max;
			}
		}

		return(TRUE);
	}
}

BOOL
ParseSpecial(STRPTR OldString,struct parse_result *Result)
{
	STRPTR NewString;
	LONG Len = strlen(OldString);
	BOOL Success = FALSE;

	if(NewString = (STRPTR)AllocVecPooled(Len + 2,MEMF_ANY))
	{
		STRPTR Args[ARGCOUNT];
		struct RDArgs *ArgsPtr;

		memset(Args,0,sizeof(Args));

		while(*OldString == ' ')
			OldString++;

		strcpy(NewString,OldString);

		Len = strlen(NewString);

		while(Len > 0 && NewString[Len - 1] == ' ')
			Len--;

		NewString[Len] = '\n';
		NewString[Len + 1] = 0;

		if(ArgsPtr = (struct RDArgs *)AllocDosObjectTags(DOS_RDARGS,TAG_DONE))
		{
				/* Don't prompt for input! */
	
			ArgsPtr -> RDA_Flags |= RDAF_NOPROMPT;
	
				/* Set up for local parsing. */
	
			ArgsPtr -> RDA_Source . CS_Buffer	= NewString;
			ArgsPtr -> RDA_Source . CS_Length	= Len + 1;
			ArgsPtr -> RDA_Source . CS_CurChr	= 0;
	
				/* Read the arguments. */
	
			if(ReadArgs(TEMPLATE,(LONG *)Args,ArgsPtr))
			{
				BOOL	PostScript;
				float	Unit;
				float	ScaleUnit;

				if(Args[ARG_PATCHCOLOURS])
					Result -> patch_colours = TRUE;

				if(Args[ARG_DITHEROPT])
					Result -> dither_opt = *(LONG *)Args[ARG_DITHEROPT];

				if(Args[ARG_PSINITSTRING])
					strcpy(Result -> psinit_string,Args[ARG_PSINITSTRING]);

				if(Args[ARG_PSINITFILE])
					strcpy(Result -> psinit_file,Args[ARG_PSINITFILE]);

				if(Args[ARG_IFFFILE] && Args[ARG_PSFILE])
					PrintLine("\33bYou can either use \"IFFFILE=...\" or \"PSFILE=...\" but not both.\33n");
				else
				{
					Success = TRUE;

					if(Args[ARG_IFFFILE])
					{
						strcpy(Result -> iffile,Args[ARG_IFFFILE]);

						Unit = 1.0;	// `small points'

						ScaleUnit = 1.0;

						PostScript = FALSE;
					}

					if(Args[ARG_PSFILE])
					{
						strcpy(Result -> psfile,Args[ARG_PSFILE]);

						Unit = 72.0;	// `big points'

						ScaleUnit = 100.0; // percentage unit

						PostScript = TRUE;
					}
				}

				if(Args[ARG_HSIZE])
				{
					if(Success = GetDimension(Args[ARG_HSIZE],&Result -> hsize,Unit))
						Result -> gotcontrol |= GOT_HSIZE;
				}

				if(Args[ARG_VSIZE] && Success)
				{
					if(Success = GetDimension(Args[ARG_VSIZE],&Result -> vsize,Unit))
						Result -> gotcontrol |= GOT_VSIZE;
				}

				if(Args[ARG_HOFFSET] && Success)
				{
					if(Success = GetDimension(Args[ARG_HOFFSET],&Result -> hoffset,Unit))
						Result -> gotcontrol |= GOT_HOFFSET;
				}

				if(Args[ARG_VOFFSET] && Success)
				{
					if(Success = GetDimension(Args[ARG_VOFFSET],&Result -> voffset,Unit))
						Result -> gotcontrol |= GOT_VOFFSET;
				}

				if(Args[ARG_SCALE] && Success)
				{
					if(Success = GetScale(Args[ARG_SCALE],&Result -> scale, 1.0f))
						Result -> gotcontrol |= GOT_SCALE;
				}

				if(Args[ARG_HSCALE] && Success)
				{
					if (Success = GetScale(Args[ARG_HSCALE],&Result -> hscale,ScaleUnit))
						Result -> gotcontrol |= GOT_HSCALE;
				}

				if(Args[ARG_VSCALE] && Success)
				{
					if(Success = GetScale(Args[ARG_VSCALE],&Result -> vscale,ScaleUnit))
						Result -> gotcontrol |= GOT_VSCALE;
				}

				if(Args[ARG_MODE] && Success)
				{
					STATIC struct { STRPTR Name; LONG Mode; } ModeTable[] =
					{
						"bw",		BandW,
						"gray",		FS,
						"fs",		FS,
						"burkes",	Burkes,
						"sierra",	Sierra,
						"jarvis",	JJN,
						"jjn",		JJN,
						"whitenoise",	RandomNoise,
						"bluenoise",	BlueNoise,
						"stucki",	Stucki,
						"ordered",	Ordered,
						"halftone",	Halftone,
						"random",	RandomNoise,
						"bckbrick",	BckBrick,
						"fwdbrick",	FwdBrick,
						"hexagon",	Hexagon,
						"spiraldot",	SpiralDot,
						"horizontal",	Horizontal,
						"stevenson",	StevensonArce,
						"sa",		StevensonArce
					};

					LONG i;

					Success = FALSE;

					for(i = 0 ; i < 20 ; i++)
					{
						if(!Stricmp(Args[ARG_MODE],ModeTable[i] . Name))
						{
							Result -> mode = ModeTable[i] . Mode;

							Success = TRUE;

							break;
						}
					}

					if(!Success)
						PrintLine("\33bUnknown shading mode \"%s\".\33n",Args[ARG_MODE]);
				}

				if(Args[ARG_LLX] && Success)
				{
					if(Success = GetDimension(Args[ARG_LLX],&Result -> llx,Unit))
							Result -> gotcontrol |= GOT_LLX;

				}

				if(Args[ARG_LLY] && Success)
				{
					if(Success = GetDimension(Args[ARG_LLY],&Result -> lly,Unit))
						Result -> gotcontrol |= GOT_LLY;
				}

				if(Args[ARG_URX] && Success)
				{
					if(Success = GetDimension(Args[ARG_URX],&Result -> urx,Unit))
						Result -> gotcontrol |= GOT_URX;
				}

				if(Args[ARG_URY] && Success)
				{
					if(Success = GetDimension(Args[ARG_URY],&Result -> ury,Unit))
						Result -> gotcontrol |= GOT_URY;
				}

				if(Args[ARG_RWI] && Success)
				{
					if(Success = GetDimension(Args[ARG_RWI],&Result -> rwi,Unit))
						Result -> gotcontrol |= GOT_RWI;
				}

				if(Args[ARG_RHI] && Success)
				{
					if(Success = GetDimension(Args[ARG_RHI],&Result -> rhi,Unit))
						Result -> gotcontrol |= GOT_RHI;
				}

				if (PostScript && Args[ARG_ANGLE])
				{
					if(Success = GetDimension(Args[ARG_ANGLE],&Result -> angle,1.0f))
						Result -> gotcontrol |= GOT_ANGLE;
				}

				if (PostScript && Args[ARG_CLIP])
						Result -> gotcontrol |= GOT_CLIP;

				if(Args[ARG_BRIGHT] && Success)
					Success = GetInteger(Args[ARG_BRIGHT],&Result -> bright,-100,100);

				if(Args[ARG_CONTRAST] && Success)
					Success = GetInteger(Args[ARG_CONTRAST],&Result -> contrast,-100,100);

				if(Args[ARG_GAMMA] && Success)
					Success = GetInteger(Args[ARG_GAMMA],&Result -> gamma,-100,100);

				if(Args[ARG_RED] && Success)
					Success = GetInteger(Args[ARG_RED],&Result -> red,0,100);

				if(Args[ARG_GREEN] && Success)
					Success = GetInteger(Args[ARG_GREEN],&Result -> green,0,100);

				if(Args[ARG_BLUE] && Success)
					Success = GetInteger(Args[ARG_BLUE],&Result -> blue,0,100);

				if(Args[ARG_BASEDPI] && Success)
					Success = GetInteger(Args[ARG_BASEDPI],&Result -> base_dpi,0,1000000);

				if(Args[ARG_THRESHOLD] && Success)
					Success = GetInteger(Args[ARG_THRESHOLD],&Result -> threshold,0,100);

				if(Args[ARG_TRANSFER] && Success)
				{
					STATIC struct { STRPTR Name; LONG Mode; } TransferTable[] =
					{
						"memory",	CYID_Transfer_Memory,
						"file",		CYID_Transfer_Disk,
						"none",		CYID_Transfer_None
					};

					LONG i;

					Success = FALSE;

					for(i = 0 ; i < 3 ; i++)
					{
						if(!Stricmp(Args[ARG_TRANSFER],TransferTable[i] . Name))
						{
							Result -> transfer = TransferTable[i] . Mode;

							Success = TRUE;

							break;
						}
					}

					if(!Success)
						PrintLine("\33bUnknown transfer mode \"%s\".\33n",Args[ARG_TRANSFER]);
				}

				if(Args[ARG_RENDERING] && Success)
				{
					STATIC struct { STRPTR Name; LONG Mode; } RenderTable[] =
					{
						"plain",	CYID_Render_None,
						"frame",	CYID_Render_Frame,
						"clear",	CYID_Render_Clear
					};

					LONG i;

					Success = FALSE;

					for(i = 0 ; i < 3 ; i++)
					{
						if(!Stricmp(Args[ARG_RENDERING],RenderTable[i] . Name))
						{
							Result -> rendering = RenderTable[i] . Mode;

							Success = TRUE;

							break;
						}
					}

					if(!Success)
						PrintLine("\33bUnknown render mode \"%s\".\33n",Args[ARG_RENDERING]);
				}

				if(Args[ARG_INVERT] && Success)
				{
					STATIC struct { STRPTR Name; LONG Mode; } InvertTable[] =
					{
						"on",		TRUE,
						"yes",		TRUE,
						"true",		TRUE,
						"1",		TRUE,
						"off",		FALSE,
						"no",		FALSE,
						"false",	FALSE,
						"0",		FALSE
					};

					LONG i;

					Success = FALSE;

					for(i = 0 ; i < 8 ; i++)
					{
						if(!Stricmp(Args[ARG_INVERT],InvertTable[i] . Name))
						{
							Result -> invert = InvertTable[i] . Mode;

							Success = TRUE;

							break;
						}
					}

					if(!Success)
						PrintLine("\33bUnknown invert mode \"%s\".\33n",Args[ARG_INVERT]);
				}

				FreeArgs(ArgsPtr);
			}
			else
			{
				UBYTE LocalBuffer[256];

				Fault(IoErr(),"",LocalBuffer,256);

				PrintLine("\33bParsing error: %s\33n",LocalBuffer + 2);
			}

			FreeDosObject(DOS_RDARGS,ArgsPtr);
		}

		FreeVecPooled(NewString);
	}

	return(Success);
}
