-- ColorVersatecInterpOutputImpl.mesa
-- Copyright (C) 1984, Xerox Corporation.  All rights reserved.
-- Michael Plass, October 31, 1984 12:56:16 pm PST

DIRECTORY Environment, PDFileFormat, PDInterpBasic, PDInterpOutput, PDInterpBitmap, PDDeviceDriver, PDQueue, PDInterpSysCalls, Process, ProcessorFace, PDTextBitmap, PDRemoteStream;

ColorVersatecInterpOutputImpl: PROGRAM
	IMPORTS PDInterpBitmap, PDDeviceDriver, PDInterpSysCalls, PDQueue, PDTextBitmap, PDRemoteStream
	EXPORTS PDInterpOutput
= BEGIN

bitsPerWord: NAT = Environment.bitsPerWord;
currentHerald: PDFileFormat.Herald;
currentStartImage: PDFileFormat.StartImage;
currentBandNumber: NAT ← 0;
bandWords: INT ← 0;
band: PDInterpBitmap.BitmapDesc ← [sOrigin: 0, fOrigin: 0, sMin: 0, fMin: 0, sSize: 0, fSize: 0, pointer: NIL, rast: 0, lines: 0];
bandWordsAllocated: INT ← 0;
extraBands: NAT ← 12;
fontFileName: LONG STRING ← "[Indigo]<Peach>Fonts>TimesRoman36B.ks";
leadingTitleBlockBands: NAT ← 4;

CurrentBandDesc: PROC RETURNS [PDInterpBitmap.BitmapDesc] = {
	band.sOrigin ← currentHerald.bandSSize*(currentBandNumber+currentStartImage.passBands);
	PDInterpBitmap.Clear[band];
	RETURN [band]
	};
	
StartImage: PUBLIC PROC [herald: PDFileFormat.Herald, startImage: PDFileFormat.StartImage, request: PDQueue.Request]
	RETURNS [PDInterpBitmap.BitmapDesc] = {
	rast: NAT = (--startImage.fSizePage-- 8000 +bitsPerWord-1)/bitsPerWord;
	lines: INT = herald.bandSSize;
	words: INT = rast*lines;
	color: PDDeviceDriver.Color ← SELECT startImage.toner FROM
		black => Black,
		cyan => Cyan,
		magenta => Magenta,
		yellow => Yellow,
		ENDCASE => ERROR;
	currentHerald ← herald;
	currentStartImage ← startImage;
	currentBandNumber ← 0;
	IF words > bandWordsAllocated THEN {
		IF band.pointer # NIL THEN PDInterpSysCalls.FreeSpace[band.pointer];
		band.pointer ← PDInterpSysCalls.AllocateSpace[words];
		bandWordsAllocated ← words;
		};
	band.sOrigin ← 0;
	band.fOrigin ← 0; -- startImage.fMinPage;
	band.sMin ← 0;
	band.fMin ← 0;
	band.sSize ← herald.bandSSize;
	band.fSize ← rast*bitsPerWord;
	band.rast ← rast;
	band.lines ← herald.bandSSize;
	bandWords ← words;
	IF currentStartImage.feed THEN {
		passBands ← ALL[LAST[NAT]];
		nBands ← ALL[0];
		};
	passBands[color] ← currentStartImage.passBands;
	nBands[color] ← currentStartImage.nBands;
	RETURN [CurrentBandDesc[]]
	};
	
EndBand: PUBLIC PROC RETURNS [PDInterpBitmap.BitmapDesc] = {
	PDDeviceDriver.StoreBand[
		sourcePtr: band.pointer,
		destOffset: bandWords*currentBandNumber,
		wordCount: bandWords,
		color: SELECT currentStartImage.toner FROM
			black => Black,
			cyan => Cyan,
			magenta => Magenta,
			yellow => Yellow,
			ENDCASE => ERROR
		];
	currentBandNumber ← currentBandNumber + 1;
	RETURN [CurrentBandDesc[]]
	};
	
passBands: ARRAY PDDeviceDriver.Color OF NAT;
nBands: ARRAY PDDeviceDriver.Color OF NAT;

TryToLoadFont: PROC [request: PDQueue.Request] = {
	IF PDTextBitmap.FontAscent[] = 0 THEN {
		ok: BOOL ← FALSE;
		accessError: BOOL ← FALSE;
		ok ← PDTextBitmap.SetFont[fontFileName, request.requestor, request.requestorPassword ! PDRemoteStream.Error => {accessError ← TRUE; CONTINUE}];
		IF NOT ok THEN {
			IF accessError THEN
				PDQueue.LogMessage["Could not access font file for title block:",,request.requestor]
			ELSE
				PDQueue.LogMessage["Invalid font file for title block:",,request.requestor];
			PDQueue.LogMessage[fontFileName];
			RETURN
			};
		};
	};

DoTitleBlock: PROC [request: PDQueue.Request] = {
	ascent: INTEGER ← PDTextBitmap.FontAscent[];
	descent: INTEGER ← PDTextBitmap.FontDescent[];
	topMargin: INTEGER ← (band.sSize-ascent+descent)/2;
	titleBand: PDInterpBitmap.BitmapDesc ← PDInterpBitmap.Reshape[band.pointer, bandWordsAllocated, [-topMargin-ascent, 0, band.sSize, band.fSize]];
	empty: LONG STRING ← [0];
	margin: INTEGER ← ascent;
	tabw: CARDINAL ← MAX[ascent+descent, 1] * 10;
	centeredString: LONG STRING ← IF request.separator.length = 0 THEN request.fileName ELSE request.separator;
	penultimateString: LONG STRING ← IF request.separator.length = 0 THEN request.separator ELSE request.fileName;
	string: ARRAY [0..5) OF LONG STRING ← [request.requestor, request.requestTime, centeredString, penultimateString, request.requestor];
	pos: ARRAY [0..5) OF INTEGER ← ALL[0];
	TryLayout: PROC RETURNS [ok: BOOLEAN] = {
		spaceLeft: INTEGER ← titleBand.fSize;
		wid: ARRAY [0..5) OF INTEGER;
		glue: ARRAY [0..5) OF INTEGER;
		FOR i: NAT IN [0..5) DO
			wid[i] ← PDTextBitmap.TextWidth[string[i]];
			ENDLOOP;
		FOR i: NAT IN [0..5) DO
			glue[i] ← IF wid[i] = 0 THEN 0 ELSE PDTextBitmap.TextWidth["  "];
			ENDLOOP;
		glue[4] ← margin;
		glue[0] ← MAX[glue[0]+wid[0], tabw]-wid[0];
		glue[3] ← IF glue[3]+wid[4] = 0 THEN 0 ELSE MAX[glue[3]+wid[4], tabw]-wid[4];
		spaceLeft ← spaceLeft - margin;
		FOR i: NAT IN [0..5) DO
			spaceLeft ← spaceLeft - wid[i] - glue[i];
			ENDLOOP;
		IF spaceLeft < 0 THEN RETURN [FALSE];
		glue[1] ← glue[1] + spaceLeft/2;
		glue[2] ← glue[2] + (spaceLeft-spaceLeft/2);
		pos[0] ← margin;
		FOR i: NAT IN [0..4) DO
			pos[i+1] ← pos[i]+wid[i]+glue[i];
			ENDLOOP;
		RETURN [TRUE];
		};
	DoLayout: PROC = {
		IF TryLayout[].ok THEN RETURN;
		string[4] ← empty;
		IF TryLayout[].ok THEN RETURN;
		string[3] ← empty;
		IF TryLayout[].ok THEN RETURN;
		string[1] ← empty;
		IF TryLayout[].ok THEN RETURN;
		string[2] ← empty;
		pos[0] ← margin;
		};
	totalBands: NAT ← 0;
	FOR c: PDDeviceDriver.Color IN PDDeviceDriver.Color DO
		IF passBands[c] # NAT.LAST THEN
			totalBands ← MAX[totalBands, passBands[c] + nBands[c]];
		ENDLOOP;
	currentBandNumber ← nBands[Black];
	DoLayout[];
	PDInterpBitmap.Clear[titleBand];
	WHILE passBands[Black] + currentBandNumber < totalBands + extraBands DO
		PDDeviceDriver.StoreBand[
			sourcePtr: titleBand.pointer,
			destOffset: bandWords*currentBandNumber,
			wordCount: bandWords,
			color: Black
			];
		currentBandNumber ← currentBandNumber + 1;
		ENDLOOP;
	PDInterpBitmap.Fill[titleBand, titleBand.Window, 1];
	FOR i: NAT IN [0..5) DO
		PDTextBitmap.TextToBitmap[dest: titleBand.ShiftMap[0, -pos[i]], string: string[i], function: [and, complement]];
		ENDLOOP;
	PDDeviceDriver.StoreBand[
		sourcePtr: titleBand.pointer,
		destOffset: bandWords*currentBandNumber,
		wordCount: bandWords,
		color: Black,
		isSeparatorBand: TRUE
		];
	currentBandNumber ← currentBandNumber + 1;
	nBands[Black] ← currentBandNumber;
	};
	
EndImage: PUBLIC PROC [request: PDQueue.Request] = {
	IF currentStartImage.strip THEN {
		minPass: NAT ← LAST[NAT];
		FOR c: PDDeviceDriver.Color IN PDDeviceDriver.Color DO
			minPass ← MIN[passBands[c], minPass];
			ENDLOOP;
		FOR c: PDDeviceDriver.Color IN PDDeviceDriver.Color DO
			IF passBands[c] # NAT.LAST THEN passBands[c] ← passBands[c] - minPass + leadingTitleBlockBands;
			ENDLOOP;
		TryToLoadFont[request];
		IF PDTextBitmap.FontAscent[] # 0 THEN DoTitleBlock[request];
		PrintPage[];
		};
	};
	
PrintPage: PROC = {
	successCode: PDDeviceDriver.SuccessCode;
	scanLineLength: CARDINAL ← band.fSize;
	FOR copyNum: CARDINAL IN [0..currentHerald.copies) DO
		DO 
			s: PDDeviceDriver.PrinterStatus;
			successCode ← PDDeviceDriver.PrintPage[
				passBands: passBands,
				nBands: nBands,
				fourColor: currentStartImage.toner#black
				];
			IF PDQueue.ReprintCancelled[] THEN RETURN;
			SELECT successCode FROM
				warning => EXIT;
				error => {
					WHILE (s←PDDeviceDriver.GetStatus[])#standBy DO
						PDDeviceDriver.DisplayBadStatusInMP[s];
						SELECT s FROM
							registrationJam => PDQueue.LogMessage[" - Registration jam"];
							fuserJam => PDQueue.LogMessage[" - Fuser jam"];
							warming => PDQueue.LogMessage[" - Warming up"];
							feederFault => PDQueue.LogMessage[" - Out of paper"];
							interlockOpen => PDQueue.LogMessage[" - Door open"];
							fuserCold => PDQueue.LogMessage[" - Fuser cold"];
							parityError => PDQueue.LogMessage[" - Parity Error"];
							offLine => PDQueue.LogMessage[" - Offline"];
							ENDCASE => PDQueue.LogMessage[" - Can't feed page"];
						ENDLOOP
					};
				ENDCASE => EXIT; -- ok
			ENDLOOP;
		ENDLOOP;
	};
	
ReprintLastPage: PUBLIC PROC [copies: CARDINAL] = {
	IF currentHerald.password # PDFileFormat.passwordValue THEN RETURN;
	IF PDQueue.ReprintCancelled[] THEN RETURN;
	currentHerald.copies ← copies;
	PrintPage[];
	};
	
END.