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

#include "Global.h"
#include "postlib.h"

/*#define DEBUG*/

struct Library *PostBase;

STATIC struct PSparm	 PSparm;
STATIC struct BitMap	*BitMap;
STATIC PLANEPTR		 Plane;
STATIC LONG		 ActivationRecord,
			 PlaneSize;
STATIC BOOL		 Transferred;

#ifdef DEBUG
STATIC struct Screen	*LocalScreen;
STATIC struct Window	*LocalWindow;
#endif	/* DEBUG */

extern void insertftrap(void);
extern void deleteftrap(void);

STATIC VOID __saveds
CopyPage(VOID)
{
	CopyMem(Plane,BitMap -> Planes[0],PlaneSize);

	Transferred = TRUE;

#ifdef DEBUG
	if(LocalScreen)
	{
		struct IntuiMessage *IntuiMessage;

		CopyMem(Plane,LocalScreen -> RastPort . BitMap -> Planes[0],LocalScreen -> RastPort . BitMap -> BytesPerRow * LocalScreen -> RastPort . BitMap -> Rows);

		ScreenToFront(LocalScreen);

		WaitPort(LocalWindow -> UserPort);

		while(IntuiMessage = (struct IntuiMessage *)GetMsg(LocalWindow -> UserPort))
			ReplyMsg(IntuiMessage);
	}
#endif	/* DEBUG */
}

void __saveds sigfpe(void)
{
	PSsignalfpe(ActivationRecord);
}

void __saveds sigint(void)
{
	PSsignalint(ActivationRecord,1);
}

struct BitMap * __regargs
ProcessPostscript(struct special_msg *Message,struct special_map *SpecialMap,struct parse_result *Result,LONG *Error)
{
	*Error = 0;

	BitMap = NULL;

	if(PostBase = OpenLibrary("post.library",15))
	{
		BPTR NIL;

		if(NIL = Open("NIL:",MODE_READWRITE))
		{
			LONG	NewWidth,
				NewHeight,
				X_DPI	= Message -> hresolution,
				Y_DPI	= Message -> vresolution;

			memset(&PSparm,0,sizeof(struct PSparm));

			if((Result -> gotcontrol & SUFFICIENT_PS_ARGS) == SUFFICIENT_PS_ARGS)
			{
				LONG	OldWidth	= Result -> urx - Result -> llx + 1,
					OldHeight	= Result -> ury - Result -> lly + 1;

				if(Result -> gotcontrol & GOT_RHI)
				{
					NewWidth	= (Result -> hres * Result -> rhi) / 720;
					NewHeight	= (Result -> vres * Result -> rhi) / 720;

					X_DPI		= (72 * NewWidth) / OldWidth;
					Y_DPI		= (72 * NewHeight) / OldHeight;
				}
				else
				{
					NewWidth	= (Result -> hres * Result -> rwi) / 720;
					NewHeight	= (Result -> vres * OldHeight * Result -> rwi) / (720 * OldWidth);

					X_DPI		= (72 * NewWidth) / OldWidth;
					Y_DPI		= X_DPI;
				}
			}
			else
			{
				NewWidth	= (LONG)(Result -> hsize * (float)Result -> hres + 0.5),
				NewHeight	= (LONG)(Result -> vsize * (float)Result -> vres + 0.5);

				if(Result -> scale > 0.0)
				{
					X_DPI = (LONG)(((float)X_DPI * Result -> scale) + 0.5);
					Y_DPI = (LONG)(((float)Y_DPI * Result -> scale) + 0.5);
				}
				else
				{
					if(Result -> hscale > 0.0)
						X_DPI = (LONG)(((float)X_DPI * Result -> hscale) + 0.5);

					if(Result -> vscale > 0.0)
						Y_DPI = (LONG)(((float)Y_DPI * Result -> vscale) + 0.5);
				}
			}

			PSparm . page . xoff = (LONG)(Result -> hoffset * (float)X_DPI + 0.5);
			PSparm . page . yoff = (LONG)(Result -> voffset * (float)Y_DPI + 0.5);

			SpecialMap -> width	= NewWidth;
			SpecialMap -> height	= NewHeight;

			if(NewWidth > 30000 || NewHeight > 30000)
				*Error = ERR_TOO_LARGE;
			else
			{
				if(NewWidth < 1 || NewHeight < 1)
					*Error = ERR_TOO_SMALL;
				else
				{
					PrintLine("Page size %ld × %ld, %ld × %ld DPI",NewWidth,NewHeight,Message -> hresolution,Message -> vresolution);

					if(BitMap = CreateBitMap(NewWidth,NewHeight,1,NULL,NULL))
					{
						if(Plane = (PLANEPTR)AllocVecPooled(PlaneSize = BitMap -> BytesPerRow * BitMap -> Rows,MEMF_ANY))
						{
							LONG ResultCode;

							insertftrap();

							PSparm . page . depth	= 1;
							PSparm . page . ydir	= -1;
							PSparm . page . xden	= X_DPI;
							PSparm . page . yden	= Y_DPI;
							PSparm . page . xsize	= NewWidth;
							PSparm . page . ysize	= NewHeight;
							PSparm . page . yheight	= NewHeight;
							PSparm . page . xbytes	= BitMap -> BytesPerRow;
							PSparm . page . len	= PSparm . page . xbytes * PSparm . page . ysize;
							PSparm . page . buf[0]	= Plane;

							PSparm . copyfunc	= (APTR)CopyPage;
							PSparm . infh		= NIL;
							PSparm . outfh		= NIL;
							PSparm . errfh		= NIL;

							ActivationRecord = PScreateact(&PSparm);

							if(ActivationRecord <= errmax)
							{
								if(ActivationRecord)
									*Error = 20000 + ActivationRecord;
								else
									*Error = ERR_NO_MEM;
							}
							else
							{
								ULONG Flags = PSFLAGCLEAR | PSFLAGERASE;
#ifdef DEBUG
								if(LocalScreen = OpenScreenTags(NULL,
									SA_Width,	NewWidth,
									SA_Height,	NewHeight,
									SA_Depth,	1,
									SA_DisplayID,	HIRESLACE_KEY,
									SA_Quiet,	TRUE,
									SA_AutoScroll,	TRUE,
									SA_ShowTitle,	FALSE,
									SA_Overscan,	OSCAN_STANDARD,
								TAG_DONE))
								{
									if(!(LocalWindow = OpenWindowTags(NULL,
										WA_Left,	0,
										WA_Top,		0,
										WA_Width,	LocalScreen -> Width,
										WA_Height,	LocalScreen -> Height,
										WA_RMBTrap,	TRUE,
										WA_Backdrop,	TRUE,
										WA_Borderless,	TRUE,
										WA_CustomScreen,LocalScreen,
										WA_Activate,	TRUE,
										WA_IDCMP,	IDCMP_VANILLAKEY,
									TAG_DONE)))
									{
										CloseScreen(LocalScreen);

										LocalScreen = NULL;
									}
								}
#endif	/* DEBUG */
								Transferred = FALSE;

								if(Result -> psinit_file[0] && !(*Error))
								{
									PrintLine("Executing initialization file...");
	
									if(ResultCode = PSintstring(ActivationRecord,Result -> psinit_file,-1,PSFLAGFILE | Flags))
										*Error = 20000 + ResultCode;
									else
										Flags = NULL;
								}

								if(Result -> psinit_string[0] && !(*Error))
								{
									PrintLine("Executing initialization string...");
	
									if(ResultCode = PSintstring(ActivationRecord,Result -> psinit_string,strlen(Result -> psinit_string),PSFLAGSTRING | Flags))
										*Error = 20000 + ResultCode;
									else
										Flags = NULL;
								}
/*
								if(!(*Error))
								{
									PrintLine("Executing file \"%s\"...","TeX:ps/finclude.pro");
	
									if(ResultCode = PSintstring(ActivationRecord,"TeX:ps/finclude.pro",-1,PSFLAGFILE | Flags))
										*Error = 20000 + ResultCode;
									else
										Flags = NULL;
								}

								if(!(*Error))
								{
									PrintLine("Executing file \"%s\"...","TeX:ps/texps.pro");
	
									if(ResultCode = PSintstring(ActivationRecord,"TeX:ps/texps.pro",-1,PSFLAGFILE | Flags))
										*Error = 20000 + ResultCode;
									else
										Flags = NULL;
								}

								if(!(*Error))
								{
									PrintLine("Executing file \"%s\"...","TeX:ps/special.pro");
	
									if(ResultCode = PSintstring(ActivationRecord,"TeX:ps/special.pro",-1,PSFLAGFILE | Flags))
										*Error = 20000 + ResultCode;
									else
										Flags = NULL;
								}

								if(!(*Error))
								{
									PrintLine("Executing file \"%s\"...","TeX:ps/color.pro");
	
									if(ResultCode = PSintstring(ActivationRecord,"TeX:ps/color.pro",-1,PSFLAGFILE | Flags))
										*Error = 20000 + ResultCode;
									else
										Flags = NULL;
								}
*/
								if(!(*Error))
								{
									PrintLine("Executing file \"%s\"...",Result -> psfile);
	
									if(ResultCode = PSintstring(ActivationRecord,Result -> psfile,-1,PSFLAGFILE | Flags))
										*Error = 20000 + ResultCode;
									else
									{
										if(!Transferred)
										{
											if(ResultCode = PSintstring(ActivationRecord,"showpage",8,PSFLAGSTRING))
												*Error = 20000 + ResultCode;
										}										
									}
								}

								PSdeleteact(ActivationRecord);
#ifdef DEBUG
								if(LocalWindow)
								{
									CloseWindow(LocalWindow);

									LocalWindow = NULL;
								}

								if(LocalScreen)
								{
									CloseScreen(LocalScreen);

									LocalScreen = NULL;
								}
#endif	/* DEBUG */
							}

							deleteftrap();

							FreeVecPooled(Plane);
						}
						else
							*Error = ERR_NO_MEM;

						if(*Error)
						{
							DeleteBitMap(BitMap);

							BitMap = NULL;
						}
					}
					else
						*Error = ERR_NO_MEM;
				}
			}

			Close(NIL);
		}
		else
			*Error = ERR_NO_NIL;

		CloseLibrary(PostBase);

		PostBase = NULL;
	}
	else
		*Error = ERR_NO_POST;

	return(BitMap);
}
