/*
	This set of routines implements printing of a block of mono-styled text
using a Waste edit
	record.  The code can optionally print a pretty "Page X of Y" header at
the top of each page.

Send comments
to rrwood@mars.execulink.com.	
	
	Variables:
	==========
	
	gErrorMessage
	-------------
		a string variable used to return an informative error message
	
	
	printRecordHandle
	-----------------
		a THPrint handle used to hold the page-setup preferences
	
	
	

	Functions:
	==========
	
	OSErr doPageSetup(void);
	------------------------
		the function that handles the page setup
		
		parameters: 	none
		return code:	noErr indicates success, -1 indicates failure (check
gErrorMessage for further info)
	
	
	
	OSErr printMonostyleText(char *theTextPtr,long theTextLength,short
theFontNum,short theFontSize,Boolean doPageHeader,char *pageHeader);
	---------------------------------------------------------------------------
------------------------------------------------------------
		the function that actually prints the block of text
		
		parameters:		theTextPtr, a pointer to the text to be printed
						theTextLength, the length in bytes of the text to be printed
						theFontNum, the font number of the printed text
						theFontSize, the size of the printed text
						doPageHeader, a boolean indicator controlling whether a header should
be printed at the top of each page
						pageHeader, a string that is prepended to the usual "Page X of Y"
page header (pass in nil if you don't want anything but the standard page
header)
	
		return code:	noErr indicates success, -1 indicates failure (check
gErrorMessage for further info)

*/




#include "Waste.h"


THPrint  				printRecordHandle = nil;	// the page setup preferences



OSErr doPageSetup(void);
OSErr printMonostyleText(char *theTextPtr,long theTextLength,short
theFontNum,short theFontSize,Boolean doPageHeader,char *pageHeader);



//	Do the page setup stuff

OSErr doPageSetup(void)
{
OSErr			errCode = noErr;
	
	
	PrOpen();
	
	if (printRecordHandle == nil)
	{
		printRecordHandle = (THPrint) NewHandle(sizeof(TPrint));
		
		if (printRecordHandle == nil)
		{
			PrClose();
			
			sprintf(gErrorMessage,"doPageSetup: NewHandle(%lu) error %d",(unsigned
long) sizeof(TPrint),(int) MemError());
			errCode = -1;
			goto EXITPOINT;
		}
		
		else
		{
			PrintDefault(printRecordHandle);
			PrValidate(printRecordHandle);
		}
	}
	
	PrStlDialog(printRecordHandle);
	
	PrClose();
	
	
EXITPOINT:

	return(errCode);
}





//	Print out the text with (optionally) a "Page X of Y" header or even a
"<user string>, Page X of Y" header

OSErr printMonostyleText(char *theTextPtr,long theTextLength,short
theFontNum,short theFontSize,Boolean doPageHeader,char *pageHeader)
{
OSErr			errCode = noErr;
Boolean			printDriverIsOpen = false;
Boolean			printDocIsOpen = false;
Boolean			printPageIsOpen = false;
Boolean			userClickedOkay = false;
Boolean			fractIsEnabled = false;
GrafPtr			oldPort = nil;
TPPrPort		printingPort = nil;
TPrStatus		printingStatus;
long			lineCount,pageHeight,topLine,bottomLine,height,prevHeight;
Rect			updateRect;
LongRect		viewLongRect,pageLongRect;
RgnHandle		updateRegionHandle = nil;
WEHandle		theWEHandle = nil;
TextStyle		theTextStyle;
RGBColor		blackRGB = { 0, 0, 0 };
float			paperWidth,paperHeight;
long			horizIndent,vertIndent;
char			tempString[256];
int				numPages,currentPage;
FontInfo		theFontInfo;


	GetPort(&oldPort);


//	Remember whether fractional font sizes were enabled or not

	fractIsEnabled = LMGetFractEnable();
	
	
//	Open and set up printer info

	PrOpen();
	
	printDriverIsOpen = true;
	

//	Make sure page setup was done already

	if (printRecordHandle == nil)
	{
		printRecordHandle = (THPrint) NewHandle(sizeof(TPrint));
		
		if (printRecordHandle == nil)
		{
			sprintf(gErrorMessage,"printMonostyleText: NewHandle(%lu) error
%d",(unsigned long) sizeof(TPrint),(int) MemError());
			errCode = -1;
			goto EXITPOINT;
		}
		
		else
		{
			PrintDefault(printRecordHandle);
			PrValidate(printRecordHandle);
		}
		
		
		userClickedOkay = PrStlDialog(printRecordHandle);
		
		if (userClickedOkay == false)
		{
			goto EXITPOINT;
		}
	}
	

//	Let the printer driver do its print dialog

	userClickedOkay = PrJobDialog(printRecordHandle);
	
	if (userClickedOkay == false)
	{
		goto EXITPOINT;
	}
	

//	Open the print document
	
	printingPort = PrOpenDoc(printRecordHandle,nil,nil);
	
	errCode = PrError();
	
	if (printingPort == nil || errCode != noErr)
	{
		sprintf(gErrorMessage,"printMonostyleText: PrOpenDoc() %d",(int) errCode);
		errCode = -1;
		goto EXITPOINT;
	}
	
	printDocIsOpen = true;
	
	
	SetPort((GrafPtr) printingPort);


//	Get the page size and calculate a half-inch indent

	WERectToLongRect(&((**printRecordHandle).prInfo.rPage),&pageLongRect);
	
	paperWidth = ((**printRecordHandle).prInfo.rPage.right -
(**printRecordHandle).prInfo.rPage.left) /
(**printRecordHandle).prInfo.iHRes;
	paperHeight = ((**printRecordHandle).prInfo.rPage.bottom -
(**printRecordHandle).prInfo.rPage.top) /
(**printRecordHandle).prInfo.iVRes;

	horizIndent = (float) (pageLongRect.right - pageLongRect.left) * 0.5 /
paperWidth;
	vertIndent = (float) (pageLongRect.bottom - pageLongRect.top) * 0.5 /
paperHeight;
	
	pageLongRect.left += horizIndent;
	pageLongRect.right -= horizIndent;
	pageLongRect.top += vertIndent;
	pageLongRect.bottom -= vertIndent;
	
	
//	Create a new printing WasteRecord with dimensions matching the indented page
	
	errCode = WENew(&pageLongRect,&pageLongRect,0,&theWEHandle);
	
	if (errCode != noErr)
	{
		sprintf(gErrorMessage,"printMonostyleText: WENew() error %d",(int) errCode);
		errCode = -1;
		goto EXITPOINT;
	}
	
	WEFeatureFlag(weFInhibitRecal,weBitSet,theWEHandle);
	WEFeatureFlag(weFInhibitRedraw,weBitSet,theWEHandle);
	
	WEFeatureFlag(weFAutoScroll,weBitClear,theWEHandle);
	WEFeatureFlag(weFOutlineHilite,weBitClear,theWEHandle);
	WEFeatureFlag(weFDrawOffscreen,weBitClear,theWEHandle);
	
	WESetAlignment(weFlushLeft,theWEHandle);


//	Stuff the text into the Waste record

	errCode = WEInsert(theTextPtr,theTextLength,nil,nil,theWEHandle);
	
	if (errCode != noErr)
	{
		sprintf(gErrorMessage,"printMonostyleText: WEInsert(%lu) error
%d",(unsigned long) theTextLength,(int) errCode);
		errCode = -1;
		goto EXITPOINT;
	}
	
	
//	Set the font/face/style/colour of the text
	
	theTextStyle.tsFont = theFontNum;
	theTextStyle.tsFace = 0;
	theTextStyle.tsSize = theFontSize;
	theTextStyle.tsColor = blackRGB;
	
	WESetSelection(0,WEGetTextLength(theWEHandle),theWEHandle);
			
	errCode = WESetStyle(weDoAll,&theTextStyle,theWEHandle);
	
	if (errCode != noErr)
	{
		sprintf(gErrorMessage,"printMonostyleText: WESetStyle() error %d",(int)
errCode);
		errCode = -1;
		goto EXITPOINT;
	}
	
	WEFeatureFlag(weFInhibitRecal,weBitClear,theWEHandle);
	WEFeatureFlag(weFInhibitRedraw,weBitClear,theWEHandle);


//	Recalculate linebreaks, etc.

	WECalText(theWEHandle);

	
//	Get page count

	numPages = 0;

	lineCount = WECountLines(theWEHandle);
	pageHeight = pageLongRect.bottom - pageLongRect.top;
	topLine = 0;
	bottomLine = 0;
	
	for(;;)
	{
		numPages++;
		
		prevHeight = 0;
		height = 0;
		
		for (;;)
		{
			if (bottomLine > lineCount)
			{
				break;
			}
			
			prevHeight = height;
			
			height += WEGetHeight(bottomLine,bottomLine + 1,theWEHandle);
			
			if (height > pageHeight)
			{
				height = prevHeight;
				
				break;
			}
			
			bottomLine++;
		}
		
		
		topLine = bottomLine;
		
		if (topLine >= lineCount)
		{
			break;
		}
	}
	
	
//	Print it....
	
	lineCount = WECountLines(theWEHandle);
	pageHeight = pageLongRect.bottom - pageLongRect.top;
	topLine = 0;
	bottomLine = 0;
	
	currentPage = 0;
	
	for(;;)
	{
		currentPage++;
		
		
		PrOpenPage(printingPort,nil);
		
		errCode = PrError();
		
		if (errCode != noErr)
		{
			sprintf(gErrorMessage,"printMonostyleText: PrOpenPage() error %d",(int)
errCode);
			errCode = -1;
			goto EXITPOINT;
		}

		printPageIsOpen = true;
		
		
		SetPort((GrafPtr) printingPort);
		
		SetFractEnable(true);
		
		EraseRect(&((**printRecordHandle).prInfo.rPage));
		
		
		prevHeight = 0;
		height = 0;
		
		for (;;)
		{
			if (bottomLine > lineCount)
			{
				break;
			}
			
			prevHeight = height;
			
			height += WEGetHeight(bottomLine,bottomLine + 1,theWEHandle);
			
			if (height > pageHeight)
			{
				height = prevHeight;
				
				break;
			}
			
			bottomLine++;
		}
		
		
		WEGetViewRect(&viewLongRect,theWEHandle);
		viewLongRect.bottom = viewLongRect.top + height;
		WESetViewRect(&viewLongRect,theWEHandle);
		
		updateRegionHandle = NewRgn();
		
		if (updateRegionHandle == nil)
		{
			sprintf(gErrorMessage,"printMonostyleText: NewRgn() == nil, error
%d",(int) MemError());
			errCode = -1;
			goto EXITPOINT;
		}
		
		WELongRectToRect(&viewLongRect,&updateRect);
		
		RectRgn(updateRegionHandle,&updateRect);
		
		WEUpdate(updateRegionHandle,theWEHandle);
		
		DisposeRgn(updateRegionHandle);
		updateRegionHandle = nil;
		

//	Did user want a header or not?
		
		if (doPageHeader == true)
		{
			TextFont(courier);
			TextSize(9);
			TextFace(italic);
			
			GetFontInfo(&theFontInfo);

//	Did user specify an extra header string?
			
			if (pageHeader != nil)
			{
				sprintf(tempString,"%s, Page %d of %d",pageHeader,currentPage,numPages);
			}
			
			else
			{
				sprintf(tempString,"Page %d of %d",currentPage,numPages);
			}
			
			CtoPstr(tempString);
			
			MoveTo((**printRecordHandle).prInfo.rPage.right - StringWidth((unsigned
char *) tempString) - horizIndent,(**printRecordHandle).prInfo.rPage.top +
theFontInfo.ascent + theFontInfo.descent);
			
			DrawString((unsigned char *) tempString);
		}


//	Done that page, bring on the next....
		
		PrClosePage(printingPort);
		
		printPageIsOpen = false;
		
		errCode = PrError();
		
		if (errCode != noErr)
		{
			sprintf(gErrorMessage,"printMonostyleText: PrClosePage() %d",(int) errCode);
			errCode = -1;
			goto EXITPOINT;
		}
		

		topLine = bottomLine;
		
		if (topLine >= lineCount)
		{
			break;
		}
		
		WEScroll(0,-height,theWEHandle);
	}


//	Done!
	
	PrCloseDoc(printingPort);
	
	printDocIsOpen = false;
	
	errCode = PrError();
	
	if (errCode != noErr)
	{
		sprintf(gErrorMessage,"printMonostyleText: PrCloseDoc() %d",(int) errCode);
		errCode = -1;
		goto EXITPOINT;
	}
	

//	Spooled or not?

	if ((**printRecordHandle).prJob.bJDocLoop == bSpoolLoop)
	{
		PrPicFile(printRecordHandle,nil,nil,nil,&printingStatus);
	}
	

	errCode = PrError();
	
	PrClose();
	
	printDriverIsOpen = false;
	
	if (errCode == iPrAbort)
	{
		errCode = noErr;
	}
	
	if (errCode != noErr)
	{
		sprintf(gErrorMessage,"printMonostyleText: PrError() %d",(int) errCode);
		errCode = -1;
		goto EXITPOINT;
	}
	

EXITPOINT:

//	Restore old fract setting
	
	SetFractEnable(fractIsEnabled);


//	Make sure we clean up anything that was interrupted
	
	if (printPageIsOpen == true)
	{
		PrClosePage(printingPort);
		
		printPageIsOpen = false;
	}

	
	if (printDocIsOpen == true)
	{
		PrCloseDoc(printingPort);
		
		printDocIsOpen = false;
	}

	
	if (printDriverIsOpen == true)
	{
		PrClose();
		
		printDriverIsOpen = false;
	}


//	Get rid of other allocated stuff
	
	if (theWEHandle != nil)
	{
		WEDispose(theWEHandle);
		theWEHandle = nil;
	}

	
	if (updateRegionHandle != nil)
	{
		DisposeRgn(updateRegionHandle);
		updateRegionHandle = nil;
	}

	
	if (oldPort != nil)
	{
		SetPort(oldPort);
	}

	return(errCode);
}



