#include "PostPre.h"
#include "Global.h"
#include <intuition/intuitionbase.h>
#include <utility/hooks.h>

#define	MENU_PROJECT	0
#define	ITEM_NEW			0
#define	ITEM_CLEAR		1
#define	ITEM_OFILE		3
#define	ITEM_RFILE		4
#define	ITEM_LFONT		5
#define	ITEM_SAVEIFF	7
#define	ITEM_PRINT		9
#define	ITEM_ABOUT		11
#define	ITEM_QUIT		13

#define	MENU_CONTROL	1
#define	ITEM_PAUSE		0
#define	ITEM_NEXT		2
#define	ITEM_PREV		3
#define	ITEM_GOTO		4
#define	ITEM_INTERRUPT	6
#define	ITEM_KILL		7
#define	ITEM_INTER		9

#define	MENU_PREFS		2
#define	ITEM_PUB			0
#define	ITEM_CUSTOM		1
#define	ITEM_OPTIONS	2

/* sigintmain() is called when the main programm recieves a CTRL-C */

void __saveds sigintmain()
{
	Signal((struct Task *) rendertask, 1L << SIGBREAKB_CTRL_C);
}

/* sigint() is called when the rendertask recieves a CTRL-C */

void __saveds sigint()
{
	if(arec && !argwindow && running)
	{
		PSsignalint(arec, 1);
		ioerror = errinterrupt;
	}
}

/* sigfpe() is called when a floating point error occurs in the rendertask */

void __saveds sigfpe()
{
	if(arec) PSsignalfpe(arec);
}

/* Send a mesage to the rendering subtask */

void sendmenu(int action, int nop, int from, int to, char *file, char *directory)
{
	struct PSmessage *psmsg;

	if(psmsg = AllocMem(sizeof(struct PSmessage), MEMF_PUBLIC))
	{
		psmsg->action = action;
		if(file) strcpy(psmsg->file, file);
		else psmsg->file[0] = 0;
		if(directory) strcpy(psmsg->directory, directory);
		else psmsg->directory[0] = 0;

/* Save rmsg. In case of action == PSACTAREXX the ARexxMsg is not replied	*
 * immediately. It is replied when the subtask has interpreted the string.	*
 * This way it is possible to synchronise the interpreter with an Arexx 	*
 * script that in turn can react to an error the interpreter generates.		*/

		if(action == PSACTAREXX) psmsg->rmsg = rmsg;
		else psmsg->rmsg = NULL;
		psmsg->numofpages = nop;
		psmsg->from = from;
		psmsg->to	= to;

		psmsg->ExecMessage.mn_ReplyPort = mainport;
		psmsg->ExecMessage.mn_Node.ln_Type = NT_MESSAGE;
		psmsg->ExecMessage.mn_Length = sizeof(struct PSmessage);

		PutMsg(renderport, (struct Message *) psmsg);
	}
}


/* Display a message */

void okmsg(char *string)
{
	struct	Screen *scr;
	struct EasyStruct myES =
	{
		sizeof(struct EasyStruct),
		0,
		"Post Information",
		"",
		"Ok",
	};

	if (IntuitionBase)
	{
		if (Options.Screen.custscreen) scr = custscreen;
		else scr = pubscrcontext.pubscreen;
		if(scr == 0) scr = IntuitionBase->FirstScreen;
		myES.es_TextFormat = string;
		EasyRequest((OutputWnd == 0) ? scr->FirstWindow : OutputWnd, &myES, NULL);
	}
	else puts(string);
}

void	GetNeededPens(struct PubScrContext *pscontext)
{
	LONG	PenNum;
	ULONG r[9] = {0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
					  0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0x00000000},
			g[9] = {0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
					  0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000},
			b[9] = {0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
					  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
			test[27], temp;
	UBYTE ro[9] = {0xf, 0x0, 0xf, 0x0, 0xf, 0x0, 0xf, 0x0, 0x0},
			go[9] = {0xf, 0xf, 0x0, 0x0, 0xf, 0xf, 0x0, 0x0, 0x0},
			bo[9] = {0xf, 0xf, 0xf, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0};
	int	i, j, start, end;
	BOOL	ok = TRUE;
	struct ColorMap *pubsc_cm;

	pscontext->depth = Options.PostOpts.depth;
	if(Options.PostOpts.depth == 1)
	{
		pscontext->got_pens	= FALSE;
		pscontext->pens_ok	= TRUE;
		return;
	}
	else if((pscontext->pubscreen->RastPort.BitMap)->Depth < Options.PostOpts.depth + 1)
	{
		pscontext->got_pens	= FALSE;
		pscontext->pens_ok	= FALSE;
		return;
	}
	pubsc_cm = (&(pscontext->pubscreen)->ViewPort)->ColorMap;
	if(Options.PostOpts.depth == 3)
	{
		start = 8;
		end = 16;
	}
	else
	{
		start = 16;
		end = 25;
	}
	if(os_3 == FALSE)
	{
		for(i=start; i < end; i++)
		{
			temp = GetRGB4(pubsc_cm, i);
/*			printf("temp = %x, %x, %x\n", temp, ((temp >> 8) & 0xf), ro[i-8]);*/
			if( ((temp >> 8) & 0xf) != ro[i-8])
			{
				ok = FALSE;
				break;
			}
			if( ((temp >> 4) & 0xf) != go[i-8])
			{
				ok = FALSE;
				break;
			}
			if( ((temp >> 0) & 0xf) != bo[i-8])
			{
				ok = FALSE;
				break;
			}
		}
		pscontext->got_pens	= FALSE;
		pscontext->pens_ok	= ok;
		return;
	}
	GetRGB32(pubsc_cm, start, end-start, test);
	for(i=0; i < end-start; i++)
	{
/*		printf("test[%2d] = %x, test[%2d] = %x, test[%2d] = %x, %x\n",
					i, test[i], i+1, test[i+1], i+2, test[i+2], r[i]);*/
		if((test[3*i] != r[i]) || (test[3*i+1] != g[i]) ||
			(test[3*i+2] != b[i]))
		{
			ok = FALSE;
			break;
		}
	}
/*	printf("ok = %d\n", ok);*/
	if(ok)
	{
		pscontext->got_pens	= FALSE;
		pscontext->pens_ok	= ok;
		return;
	}
	for(i=0; i < end-start; i++)
	{
		PenNum = ObtainPen(pubsc_cm, i+start, r[i], g[i], b[i], 0);
/*		printf("i = %d\n", i);*/
		if(PenNum == -1)
		{
			for(j=0; j < i; j++)
			{
				ReleasePen(pubsc_cm, j+start);
			}
			pscontext->got_pens	= FALSE;
			pscontext->pens_ok	= FALSE;
			return;
		}
	}
	pscontext->got_pens	= TRUE;
	pscontext->pens_ok	= TRUE;
}

void ReleaseNeededPens(struct PubScrContext *pscontext)
{
	int	i, count, start;
	struct ColorMap *pubsc_cm;

	if(pscontext->got_pens == FALSE) return;
	if(pscontext->depth == 3)
	{
		start = 8;
		count = 8;
	}
	else
	{
		start = 16;
		count = 9;
	}
	pubsc_cm = (&(pscontext->pubscreen)->ViewPort)->ColorMap;
	for(i=0; i < count; i++)
	{
		ReleasePen(pubsc_cm, i+start);
	}
	pscontext->got_pens = FALSE;
}

static	int	numberofpages = 0;

int splitpage(char *file)
{
	FILE	*tempfile, *postfile;
	char	line[256], buffer[30], *postfilebuf;
	BOOL	trailer = FALSE, page = FALSE;

	page_number = 1;
	delete_tempfiles();
	numberofpages = 0;
	postfile = fopen(file, "r");

	if (postfile == NULL)
	{
		okmsg("can't open postscript file");
		return(FALSE);
	}
	if(postfilebuf = malloc(Options.bufsize)) setvbuf(postfile, postfilebuf, _IOLBF, Options.bufsize);
	sprintf(buffer, "%sPrologue%d.ps",  Options.temppath, post_count);
	tempfile = fopen(buffer, "w");
	if (tempfile == NULL)
	{
		okmsg("can't open temporary file");
		fclose(postfile);
		free(postfilebuf);
		return(FALSE);
	}

	fgets(line, 256, postfile);
	if(strncmp(line, "%!PS-Adobe-", strlen("%!PS-Adobe-")))
	{
		fclose(tempfile);
		fclose(postfile);
		free(postfilebuf);
		return(FALSE);
	}
	if(fputs(line, tempfile))
	{
		fclose(tempfile);
		fclose(postfile);
		free(postfilebuf);
		return(FALSE);
	}
	while (fgets(line, 256, postfile))
	{
		if(!strncmp(line, "%%Page:", strlen("%%Page:")))
		{
			page = TRUE;
			numberofpages++;
			fclose(tempfile);
			sprintf(buffer, "%sPage%04d_%d.ps",  Options.temppath, numberofpages, post_count);
			tempfile = fopen(buffer, "w");
			if(tempfile == NULL)
			{
				okmsg("can't open temporary file");
				fclose(postfile);
				free(postfilebuf);
				return(FALSE);
			}
		}
		if(!strncmp(line, "%%Trailer", strlen("%%Trailer")))
		{
			trailer=TRUE;
			fclose(tempfile);
			sprintf(buffer, "%sTrailer%d.ps",  Options.temppath, post_count);
			tempfile = fopen(buffer, "w");
			if(tempfile == NULL)
			{
				okmsg("can't open temporary file");
				fclose(postfile);
				free(postfilebuf);
				return(FALSE);
			}
		}
		if(fputs(line, tempfile))
		{
			fclose(tempfile);
			fclose(postfile);
			free(postfilebuf);
			return(FALSE);
		}
	}
	fclose(tempfile);
	fclose(postfile);
	free(postfilebuf);
	if(trailer && page) return(numberofpages);
	else return(FALSE);
}

void	delete_tempfiles(void)
{
	int	i;
	char	buf[MAXFILENAME];

	sprintf(buf, "%sPrologue%d.ps", Options.temppath, post_count);
	remove(buf);
	sprintf(buf, "%sTrailer%d.ps",  Options.temppath, post_count);
	remove(buf);
	if(numberofpages)
	{
		for(i=0; i < numberofpages; i++)
		{
			sprintf(buf, "%sPage%04d_%d.ps",  Options.temppath, i+1, post_count);
			remove(buf);
		}
	}
}

/* because modeID is defined as APTR __regargs puts it in a1 :-)			*/

ULONG __saveds __regargs ModeIDHook (struct Hook *hook, APTR modeID)
{
	struct DimensionInfo di;

	if(GetDisplayInfoData(FindDisplayInfo((ULONG) modeID), (APTR) &di, sizeof(struct DimensionInfo),
		DTAG_DIMS, (ULONG) modeID))
	{
		if(di.MaxDepth >= Options.PostOpts.depth+1) return(TRUE);
		else return(FALSE);
	}
	else
	{
		return(FALSE);
	}
}

int Menu_ScreenMode( void )
{
	struct ScreenModeRequester *smr;
	struct Hook	modehook;

	modehook.h_Entry = (APTR) ModeIDHook;
	smr = (struct ScreenModeRequester *) AllocAslRequestTags(
									ASL_ScreenModeRequest,
									ASLSM_DoWidth,						TRUE,
									ASLSM_DoHeight,					TRUE,
									ASLSM_DoDepth,						FALSE,
									ASLSM_DoAutoScroll,				TRUE,
									ASLSM_DoOverscanType,			TRUE,
									ASLSM_Window,						(ULONG) OutputWnd,
									ASLSM_InitialDisplayWidth,		Options.Screen.ScrWidth,
									ASLSM_InitialDisplayHeight,	Options.Screen.ScrHeight,
									ASLSM_InitialDisplayID,			Options.Screen.ScrDisplayID,
									ASLSM_InitialAutoScroll,		Options.Screen.ScrAutoScroll,
									ASLSM_InitialOverscanType,		Options.Screen.ScrOverscanType,
									ASLSM_FilterFunc,					(ULONG) &modehook,
/*									ASLSM_PropertyFlags,				DIPF_IS_WB | DIPF_IS_LACE,
									ASLSM_PropertyMask,				DIPF_IS_WB | DIPF_IS_LACE,*/
									TAG_DONE);
	if(smr == NULL)
	{
		okmsg("Can't open Screenmoderequester!");
		return(0);
	}

	if(AslRequest(smr, NULL))
	{
		Options.Screen.ScrWidth = smr->sm_DisplayWidth;
		Options.Screen.ScrHeight = smr->sm_DisplayHeight;
		Options.Screen.ScrDisplayID = smr->sm_DisplayID;
		Options.Screen.ScrOverscanType = smr->sm_OverscanType;
		Options.Screen.ScrAutoScroll = smr->sm_AutoScroll;
		FreeAslRequest(smr);
	}
	else
	{
		FreeAslRequest(smr);
		return(1);
	}
	return(0);
}

void	setmenu(void)
{
	if (!Options.Screen.custscreen)
	{
		menu2->FirstItem->Flags |=  CHECKED;
		menu2->FirstItem->NextItem->Flags &=  ~CHECKED;
	}
	else
	{
		menu2->FirstItem->Flags &= ~CHECKED;
		menu2->FirstItem->NextItem->Flags |=  CHECKED;
	}
	if (pause) menu1->FirstItem->Flags |=  CHECKED;
	else menu1->FirstItem->Flags &= ~CHECKED;

	if(running && paused)
	{
		OnMenu(OutputWnd, MENU_CONTROL | SHIFTITEM(ITEM_NEXT));
	}
	else
	{
		OffMenu(OutputWnd, MENU_CONTROL | SHIFTITEM(ITEM_NEXT));
	}
	if(running && paused && number_of_pages)
	{
		OnMenu(OutputWnd, MENU_CONTROL | SHIFTITEM(ITEM_GOTO));
		OnMenu(OutputWnd, MENU_CONTROL | SHIFTITEM(ITEM_PREV));
	}
	else
	{
		OffMenu(OutputWnd, MENU_CONTROL | SHIFTITEM(ITEM_GOTO));
		OffMenu(OutputWnd, MENU_CONTROL | SHIFTITEM(ITEM_PREV));
	}
	if(running && !paused && !interactive)
	{
		OnMenu(OutputWnd, MENU_CONTROL | SHIFTITEM(ITEM_INTERRUPT));
		OnMenu(OutputWnd, MENU_CONTROL | SHIFTITEM(ITEM_KILL));
	}
	else
	{
		OffMenu(OutputWnd, MENU_CONTROL | SHIFTITEM(ITEM_INTERRUPT));
		OffMenu(OutputWnd, MENU_CONTROL | SHIFTITEM(ITEM_KILL));
	}
	if(interactive)
	{
		OffMenu(OutputWnd, MENU_PROJECT | SHIFTITEM(NOITEM));
		OffMenu(OutputWnd, MENU_PREFS |  SHIFTITEM(NOITEM));
		OffMenu(OutputWnd, MENU_CONTROL | SHIFTITEM(ITEM_INTERRUPT));
		OffMenu(OutputWnd, MENU_CONTROL | SHIFTITEM(ITEM_KILL));
		OffMenu(OutputWnd, MENU_CONTROL | SHIFTITEM(ITEM_INTER));
	}
	else
	{
		OnMenu(OutputWnd, MENU_PROJECT | SHIFTITEM(NOITEM));
		OnMenu(OutputWnd, MENU_PREFS |  SHIFTITEM(NOITEM));
		OnMenu(OutputWnd, MENU_CONTROL | SHIFTITEM(ITEM_INTER));
	}
	if(startup)
	{
		OffMenu(OutputWnd, MENU_PROJECT | SHIFTITEM(NOITEM));
		OffMenu(OutputWnd, MENU_CONTROL | SHIFTITEM(ITEM_PAUSE));
		OffMenu(OutputWnd, MENU_CONTROL | SHIFTITEM(ITEM_INTER));
		OffMenu(OutputWnd, MENU_PREFS | SHIFTITEM(NOITEM));
	}
	else
	{
		OnMenu(OutputWnd, MENU_PROJECT | SHIFTITEM(NOITEM));
		OnMenu(OutputWnd, MENU_CONTROL | SHIFTITEM(ITEM_PAUSE));
		OnMenu(OutputWnd, MENU_CONTROL | SHIFTITEM(ITEM_INTER));
		OnMenu(OutputWnd, MENU_PREFS | SHIFTITEM(NOITEM));
	}
}

BPTR	oldlock, newlock;

void	changedir(char *directory)
{
	newlock = Lock(directory, ACCESS_READ);
	if(newlock)
	{
		oldlock = CurrentDir(newlock);
		if(oldlock) UnLock(oldlock);
	}
}

void	getpath(char *directory, char *fullfilename)
{
	strcpy(directory, fullfilename);
	directory[(ULONG)PathPart(fullfilename) - (ULONG)fullfilename] = '\0';
}

void	getfullfilename(char *fullname, char *dir, char *file)
{
	strcpy(fullname, dir);
	AddPart(fullname, file, 255);
}

void	sendfile(int mode)
{
	saveterminate();
	if(mode == PSACTFILE) number_of_pages = splitpage(Options.lastfile);
	getpath(Options.lastdir, Options.lastfile);
	changedir(Options.lastdir);
	sendmenu(mode, (mode == PSACTFILE) ? number_of_pages : 0, 1, 0,
				Options.lastfile, Options.lastdir);
}
