/*	XGPrinter.cpp
 *
 *		Handle the XGPrinter declaration
 */

/*  YAAF - Yet another application framework
 *  Copyright (C) 1997, 1998 William Edward Woody
 *  
 *  This library is free software; you can redistribute it
 *  and/or modify it under the terms of the GNU Library
 *  General Public License as published by the Free Software
 *  Foundation; either version 2 of the License, or any
 *  later version.
 *  
 *  This library is distributed in the hope that it will be
 *  useful, but WITHOUT ANY WARRANTY; without even the implied
 *  warranty of MERCHANTABIILITY or FITNESS FOR A PARTICULAR
 *  PURPOSE. See the GNU Library General Public License for
 *  more details.
 *  
 *  You should have received a copy of the GNU Library General
 *  Public License along with this library; if not, write to the
 *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 *  Boston, MA 02111-1307, USA.
 *  
 *  To contact the author, either e-mail me at woody@pandawave.com, 
 *	or write to
 *  
 *          William Edward Woody
 *          In Phase Consulting
 *          1545 Ard Eevin Avenue
 *          Glendale, CA 91202
 *
 *	Or visit us on the web at http://www.pandawave.com
 */


#include <XApplication.h>
#include <XPrinter.h>
#include <XError.h>

#include <stdlib.h>
#include <string.h>

/************************************************************************/
/*																		*/
/*	Global Objects														*/
/*																		*/
/************************************************************************/

XGPrinter GPrinter;							// Global printer object

#if OPT_MACOS == 1

/*	_abs
 *
 *		Absolute value. I define my own local version so I don't have
 *	to rely on the C libraries in that way...
 */

static int _abs(int x)
{
	return (x < 0) ? -x : x;
}

#endif

#if OPT_WINOS == 1

extern "C" {
	extern HWND _GMainWindow;
	extern HINSTANCE _GInstance;
}

#endif

/************************************************************************/
/*																		*/
/*	XGPrinter Construction/Destruction									*/
/*																		*/
/************************************************************************/

// @G"Construction/Destruction"

/*	@F"XGPrinter::XGPrinter" @I
 *
 *		Allocate memory and fill in reasonable defaults for the THPrint
 *	handle
 */

XGPrinter::XGPrinter()
{
#if OPT_MACOS == 1
	int err;
	
	/*
	 *	Allocate a print handle and initialize it, if there is a printer
	 *	port available.
	 */
	
	fHPrint = (THPrint)::NewHandle(sizeof(TPrint));
	if (fHPrint == NULL) throw XGPostError(KXGOutMemory);

	::PrOpen();								// Assure printer driver is okay
	if (0 == (err = ::PrError())) {
		fPrinter = true;
		::PrintDefault(fHPrint);			// Create a valid one of these
		::PrClose();
	} else {
		fPrinter = false;
	}
	
	fPort = NULL;
	fWindow = NULL;
#endif

#if OPT_WINOS == 1
	fPrintDC = NULL;
	
	::memset(&fPrintData,0,sizeof(PRINTDLG));
	fPrintData.lStructSize = sizeof(PRINTDLG);
	
	fPrintData.Flags |= PD_RETURNDEFAULT;
	::PrintDlg(&fPrintData);
#endif
}

/*	@F"XGPrinter::~XGPrinter" @I
 *
 *		Release memory
 */

XGPrinter::~XGPrinter()
{
#if OPT_MACOS == 1
	if (fHPrint) ::DisposeHandle((Handle)fHPrint);
#endif
}

/************************************************************************/
/*																		*/
/*	XGPrinter Parameters												*/
/*																		*/
/************************************************************************/

// @G"Page Settings"

/*	@F"XGPrinter::PageSize" @I
 *
 *		Get the size of this page
 */

Rect XGPrinter::PageSize()
{
	Rect r;

#if OPT_MACOS == 1	
	if (fPrinter && fHPrint) return (**fHPrint).rPaper;
	else {
		r.left = -36;
		r.top = -36;
		r.right = 612;
		r.bottom = 792;				// 8.5 x 11
		return r;
	}
#endif

#if OPT_WINOS == 1
	if (fPrintDC) {
		r.left = 0;
		r.top = 0;
		r.right = ::GetDeviceCaps(fPrintDC,HORZRES);
		r.bottom = ::GetDeviceCaps(fPrintDC,VERTRES);
	} else {
		r.left = 0;
		r.top = 0;
		r.right = 648;
		r.bottom = 828;				// 8.5 x 11
	}
	
	return r;
#endif
}

/*	@F"XGPrinter::PrintSize" @I
 *
 *		Get the printing area of this page
 */

Rect XGPrinter::PrintSize()
{
#if OPT_MACOS == 1
	Rect r;
	
	if (fPrinter && fHPrint) return (**fHPrint).prInfo.rPage;
	else {
		r.left = 0;
		r.top = 0;
		r.right = 576;
		r.bottom = 756;				// 8 x 10.5
		return r;
	}
#endif

#if OPT_WINOS == 1
	return PageSize();				//###TODO: Fix this 
#endif
}

/*	@F"XGPrinter::Resolution" @I
 *
 *		Get the horizontal, vertical resolution of this page
 */

Point XGPrinter::Resolution()
{
	Point pt;

#if OPT_MACOS == 1	
	if (fPrinter && fHPrint) {
		pt.h = (**fHPrint).prInfo.iHRes;
		pt.v = (**fHPrint).prInfo.iVRes;
	} else {
		pt.h = 72;
		pt.v = 72;
	}
#endif

#if OPT_WINOS == 1
	if (fPrintDC) {
		pt.h = ::GetDeviceCaps(fPrintDC,LOGPIXELSX);
		pt.v = ::GetDeviceCaps(fPrintDC,LOGPIXELSY);
	} else {
		pt.h = 72;
		pt.v = 72;
	}
#endif

	return pt;
}

/************************************************************************/
/*																		*/
/*	Set Resolutions														*/
/*																		*/
/************************************************************************/

/*	@F"XGPrinter::SetResolution" @I
 *
 *		Set various resolutions for this thing
 */

void XGPrinter::SetResolution(short flags)
{
#if OPT_MACOS == 1
	int i;
	int j;
	long max;
	long measure;
	
	TGetRslBlk getRes;
	TSetRslBlk setRes;
	
	if (!fPrinter || !fHPrint) return;
	
	getRes.iOpCode = getRslDataOp;
	getRes.iError = 0;
	getRes.lReserved = 0;
	::PrGeneral((Ptr)&getRes);
	if (getRes.iError) return;					// Not implemented
	
	setRes.iOpCode = setRslOp;
	setRes.iError = 0;
	setRes.lReserved = 0;
	setRes.hPrint = fHPrint;
	
	max = 0;									// Make compiler happy

	if (flags == KTPDefault) {
		setRes.iXRsl = 0;
		setRes.iYRsl = 0;
	} else {
		if (getRes.xRslRg.iMin == 0) {
			/*
			 *  Descrete resolution printer
			 */
		
			j = -1;
			for (i = 0; i < getRes.iRslRecCnt; i++) {
				if (flags & KTPSquareResolution) {
					if (getRes.rgRslRec[i].iXRsl != getRes.rgRslRec[i].iYRsl) continue;
				}
				if (flags & KTPMaxResolution) {
					measure = getRes.rgRslRec[i].iXRsl * getRes.rgRslRec[i].iYRsl;
					if ((j == -1) || (max < measure)) {
						j = i;
						max = measure;
					}
				} else {
					measure = _abs(72 - getRes.rgRslRec[i].iXRsl) + _abs(72 - getRes.rgRslRec[i].iYRsl);
					if ((j == -1) || (max > measure)) {
						j = i;
						max = measure;
					}
				}
			}
			
			if (j == -1) {
				setRes.iXRsl = 0;
				setRes.iYRsl = 0;
			} else {
				setRes.iXRsl = getRes.rgRslRec[j].iXRsl;
				setRes.iYRsl = getRes.rgRslRec[j].iYRsl;
			}
		} else {
			if (flags & KTPMaxResolution) {
				if (flags & KTPSquareResolution) {
					j = getRes.xRslRg.iMax;
					if (j > getRes.yRslRg.iMax) j = getRes.yRslRg.iMax;
					setRes.iXRsl = j;
					setRes.iYRsl = j;
				} else {
					setRes.iXRsl = getRes.xRslRg.iMax;
					setRes.iYRsl = getRes.yRslRg.iMax;
				}
			} else {
				setRes.iXRsl = 72;
				setRes.iYRsl = 72;
			}
		}
	}
	
	::PrGeneral((Ptr)&setRes);
#endif

#if OPT_WINOS == 1
	#ifdef __MWERKS__
		#pragma unused(flags)
	#endif
#endif
}

/************************************************************************/
/*																		*/
/*	Dialog Stuff														*/
/*																		*/
/************************************************************************/

// @G"Dialogs"

/*	@F"XGPrinter::PageSetup" @I
 *
 *		Run the page setup dialog box. Return -1 if there was a problem
 */

bool XGPrinter::PageSetup()
{
#if OPT_MACOS == 1
	int res;
	int err;
	
	if (!fHPrint) return false;
	
	::PrOpen();
	if (0 != (err = ::PrError())) {
		throw XGPostError(KXGPrintChooser);
	}
	if (!fPrinter) ::PrintDefault(fHPrint);
	else ::PrValidate(fHPrint);
	fPrinter = true;
	
	res = ::PrStlDialog(fHPrint);
	::PrClose();
	return res ? true : false;
#endif

#if OPT_WINOS == 1
	fPrintData.lStructSize = sizeof(fPrintData);
	fPrintData.hwndOwner = _GMainWindow;
	fPrintData.Flags = PD_PRINTSETUP;
	
	return ::PrintDlg(&fPrintData) ? true : false;
#endif
}

/*	@F"XGPrinter::PrintJob" @I
 *
 *		Run the print job dialog box. This returns the first page and
 *	the last page to print
 */

bool XGPrinter::PrintJob(short *first, short *last)
{
#if OPT_MACOS == 1
	int res;
	int err;
	
	if (!fHPrint) return false;
	
	::PrOpen();
	if (0 != (err = ::PrError())) {
		throw XGPostError(KXGPrintChooser);
	}
	if (!fPrinter) ::PrintDefault(fHPrint);
	else ::PrValidate(fHPrint);
	fPrinter = true;
	
	res = ::PrJobDialog(fHPrint);
	::PrClose();
	if (res) {
		*first = (**fHPrint).prJob.iFstPage;
		*last = (**fHPrint).prJob.iLstPage;
		(**fHPrint).prJob.iFstPage = 1;
		(**fHPrint).prJob.iLstPage = 9999;
		return true;
	} else {
		return false;
	}
#endif

#if OPT_WINOS == 1
	fPrintData.lStructSize = sizeof(fPrintData);
	fPrintData.hwndOwner = _GMainWindow;
	fPrintData.Flags = PD_RETURNDC | PD_NOSELECTION;
	fPrintData.nMinPage = 1;
	fPrintData.nMaxPage = 0xFFFF;
	fPrintData.nFromPage = 1;
	fPrintData.nToPage = 1;
	
	if (!::PrintDlg(&fPrintData)) return false;			// Error or cancel
	
	if (fPrintData.Flags & PD_PAGENUMS) {
		*first = fPrintData.nFromPage;
		*last = fPrintData.nToPage;
	} else {
		*first = 1;
		*last = 9999;
	}
	
	fPrintDC = fPrintData.hDC;
	
	return true;
#endif
}

/************************************************************************/
/*																		*/
/*	Page Printing Control Operations									*/
/*																		*/
/************************************************************************/

// @G"Printer Core"

/*	@F"XGPrinter::StartJob" @I
 *
 *		Start this printing job. This opens a window with a cancel message
 */

bool XGPrinter::StartJob(char *doc)
{
#if OPT_MACOS == 1
	#pragma unused(doc)
	
	int err;
	if (!fHPrint) return false;

	::PrOpen();
	if (0 != (err = ::PrError())) {
		throw XGPostError(KXGPrintChooser);
	}
	if (!fPrinter) ::PrintDefault(fHPrint);
	else ::PrValidate(fHPrint);
	fPrinter = true;
	
	if (NULL == (fPort = ::PrOpenDoc(fHPrint,NULL,NULL))) {
		throw XGPostError(KXGPrintError);
	}
	OpenWindow();
	return true;
#endif

#if OPT_WINOS == 1
	DOCINFO info;
	int ret;
	static char name[256];
	
	::memset(&info,0,sizeof(info));
	info.cbSize = sizeof(info);
	info.lpszDocName = (doc) ? doc : "Document";
	if (fPrintData.Flags & PD_PRINTTOFILE) {
		/*
		 *	We're printing to a file. This is in the category of
		 *	things I hate about Windows 95/Windows NT.
		 *
		 *	It turns out that with WinNT4 (and perhaps earlier),
		 *	simply passing "FILE:" to StartDoc() no longer pops
		 *	up a standard output file. So I have to run the damned
		 *	dialog myself.
		 *
		 *	Of course this is not document *anywhere* except in
		 *	the source kit for MFC v4.2 (in ViewPrint.cpp) and as
		 *	a footnote to StartDoc()...
		 */
		

		OPENFILENAME ofn;
		char buffer[64];
		char *c;
		
		memset(&ofn,0,sizeof(ofn));
		ofn.lStructSize = sizeof(ofn);
		ofn.hwndOwner = _GMainWindow;
		ofn.hInstance = _GInstance;
		
		strcpy(buffer,"Printer Files (*.prn)|*.PRN|All Files (*.*)|*.*|");
		for (c = buffer; *c; c++) if (*c == '|') *c = '\0';
		ofn.lpstrFilter = buffer;
		ofn.lpstrTitle = "Print To File";
		
		strcpy(name,"Output.prn");		
		ofn.lpstrFile = name;
		ofn.nMaxFile = 256;
		ofn.Flags = OFN_OVERWRITEPROMPT | OFN_LONGNAMES | OFN_HIDEREADONLY;

		if (!GetSaveFileName(&ofn)) return false;
		info.lpszOutput = name;
	} else {
		info.lpszOutput = NULL;
	}

	ret = ::StartDoc(fPrintDC,&info);
	if (SP_ERROR == ret) return false;
	return true;
#endif
}

/*	@F"XGPrinter::EndJob" @I
 *
 *		End the printing job. If this job needs to be spooled, spool it
 */

void XGPrinter::EndJob()
{
#if OPT_MACOS == 1
	TPrStatus status;
	OSErr err;
	
	::PrCloseDoc(fPort);
	if ((**fHPrint).prJob.bJDocLoop == bSpoolLoop) {
		::PrPicFile(fHPrint,NULL,NULL,NULL,&status);
	}
	if (fWindow) {
		::CloseWindow(fWindow);
		fWindow = NULL;
	}
	::PrClose();
	err = ::PrError();
	if (err && (err != iPrAbort)) {
		throw XGPostError(KXGPrintError);
	}
#endif

#if OPT_WINOS == 1
	int i;
	
	i = ::EndDoc(fPrintDC);
	::DeleteDC(fPrintDC);
	if (i < 0) {
		throw XGPostError(KXGPrintError);
	}
#endif
}

/*	@F"XGPrinter::StartPage" @I
 *
 *		Start printing in a page
 */

bool XGPrinter::StartPage()
{
#if OPT_MACOS == 1
	::PrOpenPage(fPort,NULL);
	return PrError() ? false : true;
#endif

#if OPT_WINOS == 1
	if (::StartPage(fPrintDC) <= 0) return false;
	return true;
#endif
}

/*	@F"XGPrinter::EndPage" @I
 *
 *		End printing in a page
 */

void XGPrinter::EndPage()
{
#if OPT_MACOS == 1
	::PrClosePage(fPort);
#endif

#if OPT_WINOS == 1
	::EndPage(fPrintDC);
#endif
}

/*	@F"XGPrinter::GetCancelState" @I
 *
 *		Get the current state of the cancel button. If the user
 *	hit the cancel button, this returns true.
 */

bool XGPrinter::GetCancelState()
{
#if OPT_MACOS == 1
	return ::PrError() ? true : false;
#endif

#if OPT_WINOS == 1
	return false;							// ###
#endif
}

/************************************************************************/
/*																		*/
/*	Status Window														*/
/*																		*/
/************************************************************************/

#if OPT_MACOS == 1

/*	XGPrinter::OpenWindow
 *
 *		Open a little status window in the display
 */

void XGPrinter::OpenWindow(void)
{
	Rect r;
	WindowPtr w;
	unsigned char line1[] = "\pPrinting is now in progress";
	unsigned char line2[] = "\pTo cancel, press \021+'.'";
	FontInfo fontInfo;
	int y;
	int dy;
	
	::GetWMgrPort(&w);
	r.left = (w->portRect.right + w->portRect.left - 250) / 2;
	r.right = r.left + 250;
	r.top = (w->portRect.bottom - w->portRect.top) / 3 + w->portRect.top;
	r.bottom = r.top + 50;
	
	fWindow = ::NewWindow(NULL,&r,(unsigned char *)"\p",1,dBoxProc,(WindowPtr)-1L,0,0L);
	if (fWindow != NULL) {
		::SetPort(fWindow);
		::TextFont(0);
		::TextSize(12);
		
		::GetFontInfo(&fontInfo);
		dy = fontInfo.ascent + fontInfo.descent + fontInfo.leading;
		y = (r.bottom - r.top) / 2 - fontInfo.descent;
		
		::MoveTo((r.right - r.left - ::StringWidth((unsigned char *)line1))/2,y);
		::DrawString((unsigned char *)line1);
		::MoveTo((r.right - r.left - ::StringWidth((unsigned char *)line2))/2,y+dy);
		::DrawString((unsigned char *)line2);
	}
}

#endif
