/****************************************************************************
 *
 *        IFF_Printer task routines.
 */

#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/memory.h>
#include <exec/tasks.h>
#include <devices/prtbase.h>
#include <devices/printer.h>
#include <dos/dostags.h>
#include <dos/dosextens.h>
#include <iffp/ilbm.h>
#include <iffp/packer.h>
#include <libraries/iffparse.h>

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/iffparse_protos.h>

#include "task.h"

extern BYTE *PackBuf;
extern struct PrinterData *PD;
extern struct PrinterExtendedData *PED;
extern UWORD ColorSize;

int SendMyMsg(int i);
BOOL CreateMyTask(void);
void DeleteMyTask(void);
void MyTaskCode(void);
int OpenMyFile(void);
int WriteMyLine(void);
void CloseMyFile(void);
void CloseOutfile(struct IFFHandle *iff);

	struct IFFHandle *myIFFhandle;
	long linesleft;
	BOOL color_on;
	ULONG PageNumber;
	struct Library *IFFParseBase;
	struct MsgPort *myMsgPort;
	struct Task *firsttask;
	LONG signum;
	ULONG sig;
	BOOL success;

int SendMyMsg(int i) {
	struct MyMsg msg;
	struct MsgPort *myReplyPort;
	
	if ((myReplyPort = CreateMsgPort()) == NULL) return FALSE;
	else {
		msg.my_msg.mn_Node.ln_Type = NT_MESSAGE;
		msg.my_msg.mn_Length = sizeof(struct MyMsg);
		msg.my_msg.mn_ReplyPort = myReplyPort;
		msg.my_value = i;
		PutMsg(myMsgPort,(struct Message *)&msg);
		WaitPort(myReplyPort);
		GetMsg(myReplyPort);
		DeleteMsgPort(myReplyPort);
	}
	return msg.my_value;
}

BOOL CreateMyTask(void) {
	struct Process *task;

	if ((signum = AllocSignal(-1)) == -1) {
		return FALSE;
	}
	else {
		sig = 1L << signum;
		firsttask = FindTask(NULL);
		task = CreateNewProcTags(
			NP_Entry,	&MyTaskCode,
			NP_Name,	"IFF Printer Process");
		if (task == NULL) {
			success = FALSE;
		}
		else {
			Wait(sig);
		}
		FreeSignal(signum);
	}
	return success;
}

void DeleteMyTask(void) {
	SendMyMsg(myCode_Exit);
	DeleteMsgPort(myMsgPort);
}

void MyTaskCode(void) {
	struct MyMsg *msg;
	
	if ((myMsgPort = CreateMsgPort()) == NULL) goto abort_port;
	if ((IFFParseBase = OpenLibrary("iffparse.library",0)) == NULL)
		goto abort_lib;
	/* success */
	success = TRUE;
	Signal(firsttask,sig);

	PageNumber = 1;

	while(1)
	{
		WaitPort(myMsgPort);
		while((msg = (struct MyMsg *)GetMsg(myMsgPort)) != NULL)
		{
			switch(msg->my_value) {
				case myCode_OpenFile:
					msg->my_value = OpenMyFile();
					break;
				case myCode_WriteLine:
					msg->my_value = WriteMyLine();
					break;
				case myCode_CloseFile:
					CloseMyFile();
					msg->my_value = TRUE;
					break;
				case myCode_Exit:
					/* Forbid, reply msg, and Exit
						to remove task */
					CloseLibrary(IFFParseBase);
					Forbid();
					ReplyMsg((struct Message *)msg);
					Exit(0);
			}
			ReplyMsg((struct Message *)msg);
		}
	}

abort_lib:
	DeleteMsgPort(myMsgPort);
abort_port:
	success = FALSE;
	Forbid();
	Signal(firsttask,sig);
	Exit(0);		/* Abort task */
}

/* Open IFF File */
int OpenMyFile(void)
{
	static UBYTE monopal[2][3] = {
		{0xFF,0xFF,0xFF},{0x00,0x00,0x00}
	};
	static UBYTE colorpal[8][3] = {
		{0xFF,0xFF,0xFF},{0xFF,0xFF,0x00},
		{0xFF,0x00,0xFF},{0xFF,0x00,0x00},
		{0x00,0xFF,0xFF},{0x00,0xFF,0x00},
		{0x00,0x00,0xFF},{0x00,0x00,0x00}
	};

#define monosize sizeof(monopal)
#define colorsize sizeof(colorpal)

	BitMapHeader bmhd;
	char outfile[32];
	int size, depth;
	UBYTE *pal;
	ULONG w,h;

	w = PED->ped_MaxXDots;
	h = PED->ped_MaxYDots;
	if (myIFFhandle) {
		if ((color_on) == (PD->pd_Preferences.PrintShade ==
			SHADE_COLOR)) return TRUE;
		else return FALSE;
	}
	if (color_on = (PD->pd_Preferences.PrintShade == SHADE_COLOR)) {
		depth = 3;
		size = colorsize;
		pal = (UBYTE *)colorpal;
	}
	else {
		depth = 1;
		size = monosize;
		pal = (UBYTE *)monopal;
	}
	if (!(myIFFhandle = AllocIFF())) return FALSE;
	sprintf(outfile,"Pages:Page.%05lu",PageNumber);
	if (!(myIFFhandle->iff_Stream=Open(outfile,MODE_NEWFILE)))
		goto abortopen;
	InitIFFasDOS(myIFFhandle);
	if (OpenIFF(myIFFhandle,IFFF_WRITE)) goto abortopen;
	
	/* Write header */
	if (PushChunk(myIFFhandle,ID_ILBM,ID_FORM,IFFSIZE_UNKNOWN))
		goto abortopen;
	
/* Write BMHD */
	if (PushChunk(myIFFhandle,ID_ILBM,ID_BMHD,sizeof(BitMapHeader)))
		goto abortopen;
	/* Set BMHD values */
	bmhd.w=bmhd.pageWidth=w;
	bmhd.h=bmhd.pageHeight=h;
	bmhd.x=0;
	bmhd.y=0;
	bmhd.nPlanes=depth;
	bmhd.masking=mskNone;
	bmhd.compression=cmpByteRun1;
	bmhd.reserved1=0;
	bmhd.transparentColor=0;
	if (PED->ped_XDotsInch == PED->ped_YDotsInch) {
		bmhd.xAspect=bmhd.yAspect=1;
	}
	else {
		bmhd.xAspect=22;
		bmhd.yAspect=26;
	}

	if (WriteChunkBytes(myIFFhandle,&bmhd,sizeof(bmhd)) != sizeof(bmhd))
		goto abortopen;
	if (PopChunk(myIFFhandle))
		goto abortopen;
	
/* Write CMAP */
	if (PushChunk(myIFFhandle,ID_ILBM,ID_CMAP,size))
		goto abortopen;
	if (WriteChunkBytes(myIFFhandle,pal,size) != size)
		goto abortopen;
	if (PopChunk(myIFFhandle))
		goto abortopen;
	
/* Write BODY header */
	if (PushChunk(myIFFhandle,ID_ILBM,ID_BODY,IFFSIZE_UNKNOWN))
		goto abortopen;
	linesleft = h;
	return TRUE;

abortopen:
	CloseOutfile(myIFFhandle);
	myIFFhandle=NULL;
	return FALSE;
}

int WriteMyLine(void) {
	char *src_ptr, *dest_ptr;
	int i,j,k;

	/* Pointers are incremented by packrow, so we use a copy */
	src_ptr=PD->pd_PrintBuf;
	dest_ptr=PackBuf;
	k=color_on ? 3 : 1;
	for (i=0, j=0; j<k; j++) {
		i += packrow(&src_ptr,&dest_ptr,ColorSize);
	}
	if (WriteChunkBytes(myIFFhandle,PackBuf,i)!=i)
		return FALSE;
	linesleft--;
	return TRUE;
}

void CloseMyFile(void) {
	BYTE *blankline;
	long row = ColorSize;
	long len = 0;
	
	if (myIFFhandle == NULL) return;
	if ((blankline = AllocMem(((ColorSize+126)/127)*2, MEMF_ANY))
		== NULL) goto aborteject;

	/* Make packed empty line */
	while(row>128) {
		*blankline++ = -127;	/* -n+1 */
		*blankline++ = 0;
		len += 2;
		row -= 128;
	}
	if (row>0) {
		*blankline++ = -(row) + 1;
		*blankline++ = 0;
		len += 2;
	}
	if (color_on) linesleft *= 3;

	/* Write out rest of page */
	for (blankline -= len; linesleft>0; linesleft--) {
		if (WriteChunkBytes(myIFFhandle,blankline,len)!=len)
			goto aborteject;
	}
	FreeMem(blankline,((ColorSize+126)/127)*2);
	
	if(PopChunk(myIFFhandle)) {	/* Close BODY chunk */
		goto aborteject;
	}
	
	if(PopChunk(myIFFhandle)) {	/* Close FORM */
		goto aborteject;
	}

	PageNumber++;

aborteject:
	CloseOutfile(myIFFhandle);
	myIFFhandle=NULL;
}

void CloseOutfile(struct IFFHandle *iff)
{
	if(iff) {
		CloseIFF(iff);
		if (iff->iff_Stream)
			Close(iff->iff_Stream);
		FreeIFF(iff);
	}
}

