//	Zinc Application Framework - W_PRINT.CPP
//	COPYRIGHT (C) 1990-1999.  All Rights Reserved.
//	Zinc Software Incorporated.  Pleasant Grove, Utah  USA

#include <w_app.hpp>
#include <z_print.hpp>
#include <z_string.hpp>
#include <z_str1.hpp>
#include <z_utils.hpp>
#if !defined(ZAF_WIN32)
#include <print.h>
#endif

#define ZAF_PRINTER_INFO
#include "gbl_def.cpp"

// Data used for initializing the color table. (see constructor)
static COLORREF ZAF_FARDATA zafColors[] =
{
	RGB(0x00, 0x00, 0x00),	// 0  - ZAF_CLR_BLACK
	RGB(0x00, 0x00, 0x80),	// 1  - ZAF_CLR_BLUE
	RGB(0x00, 0x80, 0x00),	// 2  - ZAF_CLR_GREEN
	RGB(0x00, 0x80, 0x80),	// 3  - ZAF_CLR_CYAN
	RGB(0x80, 0x00, 0x00),	// 4  - ZAF_CLR_RED
	RGB(0x80, 0x00, 0x80),	// 5  - ZAF_CLR_MAGENTA
	RGB(0x80, 0x80, 0x00),	// 6  - ZAF_CLR_BROWN
	RGB(0xC0, 0xC0, 0xC0),	// 7  - ZAF_CLR_LIGHTGRAY
	RGB(0x80, 0x80, 0x80),	// 8  - ZAF_CLR_DARKGRAY
	RGB(0x00, 0x00, 0xFF),	// 9  - ZAF_CLR_LIGHTBLUE
	RGB(0x00, 0xFF, 0x00),	// 10 - ZAF_CLR_LIGHTGREEN
	RGB(0x00, 0xFF, 0xFF),	// 11 - ZAF_CLR_LIGHTCYAN
	RGB(0xFF, 0x00, 0x00),	// 12 - ZAF_CLR_LIGHTRED
	RGB(0xFF, 0x00, 0xFF),	// 13 - ZAF_CLR_LIGHTMAGENTA
	RGB(0xFF, 0xFF, 0x00),	// 14 - ZAF_CLR_YELLOW
	RGB(0xFF, 0xFF, 0xFF),	// 15 - ZAF_CLR_WHITE
	RGB(0xE0, 0xE0, 0xE0),	// 16 - COLOR_3DHILIGHT (Windows Only)
};

// Data used for initializing the pattern table. (see constructor)
static WORD zafSolidData[8] = { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF };
static WORD zafInterleaveData[8] = { 0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555, 0xAAAA };

static void GetPaperSize(ZafPrinter *printer, int paperSizeID, int *width, int *height);

ZafPrinter::ZafPrinter() :
	ZafGdiDisplay(), printerType(ZAF_NATIVE_PRINTER), hDevMode(0), hDevNames(0)
{
	preSpace = 2;
	postSpace = 2;
	miniNumeratorX = 1;
	miniDenominatorX = 10;
	miniNumeratorY = 1;
	miniDenominatorY = 10;

	// Load information about the default printer.
	// This does not present a dialog, but only gets information about the printer.
#if defined(ZAF_WIN32)
	PRINTDLGA printDlg;
#else
	PRINTDLG printDlg;
#endif
	memset(&printDlg, 0, sizeof(printDlg));
	printDlg.lStructSize = sizeof(printDlg);
	printDlg.Flags = PD_RETURNDEFAULT | PD_RETURNDC;
#if defined(ZAF_WIN32)
	if (PrintDlgA(&printDlg))
#else
	if (PrintDlg(&printDlg))
#endif
	{
		hDevMode = printDlg.hDevMode;
		hDevNames = printDlg.hDevNames;

		// Initialize margins.
		pixelsPerInchX = GetDeviceCaps(printDlg.hDC, LOGPIXELSX);
		pixelsPerInchY = GetDeviceCaps(printDlg.hDC, LOGPIXELSY);
		marginLeft = marginRight = (int)ConvertXValue(500, ZAF_INCH_1000, ZAF_PIXEL);
		marginTop = marginBottom = (int)ConvertYValue(500, ZAF_INCH_1000, ZAF_PIXEL);

		// Initialize members.
		SetDisplayContext(printDlg.hDC);
	}
	else // No printer is attached to the system.
	{
		pixelsPerInchX = 1;
		pixelsPerInchY = 1;
		marginLeft = marginRight = (int)ConvertXValue(500, ZAF_INCH_1000, ZAF_PIXEL);
		marginTop = marginBottom = (int)ConvertYValue(500, ZAF_INCH_1000, ZAF_PIXEL);
		paperWidth = paperHeight = 1;
	}

	// Initialize tables.
	int index;
	for (index = 0; index < ZAF_MAXCOLORS; index++)
		colorTable[index] = 0xFFFFFFFFL;
	for (index = 0; index < ZAF_MAXFONTS; index++)
		fontTable[index] = ZAF_NULLH(OSFont);

	// Initialize the font table.
	AddFont(ZAF_FNT_SYSTEM, "Helvetica", 12, ZAF_FNT_WEIGHT_NORMAL, ZAF_FNT_SLANT_NORMAL);
	AddFont(ZAF_FNT_DIALOG, "Helvetica", 12, ZAF_FNT_WEIGHT_NORMAL, ZAF_FNT_SLANT_NORMAL);
	AddFont(ZAF_FNT_SMALL, "Helvetica", 8, ZAF_FNT_WEIGHT_NORMAL, ZAF_FNT_SLANT_NORMAL);
	AddFont(ZAF_FNT_APPLICATION, "Helvetica", 12, ZAF_FNT_WEIGHT_BOLD, ZAF_FNT_SLANT_NORMAL);
	AddFont(ZAF_FNT_FIXED, "Courier", 12, ZAF_FNT_WEIGHT_NORMAL, ZAF_FNT_SLANT_NORMAL, ZAF_FNT_PITCH_FIXED);

	// Initialize the color table.
	HPALETTE defaultPalette = (HPALETTE)GetStockObject(DEFAULT_PALETTE);
	for (int i = 0; i < sizeof(zafColors) / sizeof(COLORREF); i++)
	{
		int index = GetNearestPaletteIndex(defaultPalette, zafColors[i]);
		PALETTEENTRY paletteEntry;
		GetPaletteEntries(defaultPalette, index, 1, &paletteEntry);
		colorTable[i] = RGB(paletteEntry.peRed, paletteEntry.peGreen, paletteEntry.peBlue);
	}
	CreateLogicalPalette();

	// Initialize the line style table.
	lineTable[ZAF_LINE_SOLID] = PS_SOLID;
	lineTable[ZAF_LINE_DOTTED] = PS_DOT;

	// Initialize the pattern table.
	patternTable[ZAF_PTN_SOLID_FILL] = CreateBitmap(8, 8, 1, 1, zafSolidData);
	patternTable[ZAF_PTN_INTERLEAVE_FILL] = CreateBitmap(8, 8, 1, 1, zafInterleaveData);

	// Initialize the mix mode table.
	modeTable[ZAF_MODE_COPY].binary = R2_COPYPEN;
	modeTable[ZAF_MODE_COPY].ternary = SRCCOPY;
	modeTable[ZAF_MODE_XOR].binary = R2_XORPEN;
	modeTable[ZAF_MODE_XOR].ternary = SRCINVERT;
	mode = ZAF_MODE_COPY;

	// Initialize the Zinc palette.
	palette.lineStyle = ZAF_LINE_SOLID;
	palette.fillPattern = ZAF_PTN_SOLID_FILL;
	palette.colorForeground = ZAF_CLR_BLACK;
	palette.colorBackground = ZAF_CLR_WHITE;
	palette.monoForeground = ZAF_MONO_BLACK;
	palette.monoBackground = ZAF_MONO_WHITE;
	palette.font = ZAF_FNT_DIALOG;
	palette.osPalette.colorForeground = COLOR_WINDOWTEXT;
	palette.osPalette.colorBackground = COLOR_WINDOW;

}

ZafPrinter::~ZafPrinter(void)
{
	// Clean up.
	DeleteObject(patternTable[ZAF_PTN_SOLID_FILL]);
	DeleteObject(patternTable[ZAF_PTN_INTERLEAVE_FILL]);
	DeleteObject(fontTable[ZAF_FNT_DIALOG]);
	DeleteObject(fontTable[ZAF_FNT_SMALL]);
	DeleteObject(logicalPalette);
	DeleteDC(hDC);
	GlobalFree(hDevMode);
	GlobalFree(hDevNames);
}

OSDisplayContext ZafPrinter::SetDisplayContext(OSDisplayContext context)
{
	HDC oldDC = hDC;
	hDC = context;

	if (hDC)
	{
		// Convert margin values to device independent coordinates (inches)
		// so that precision will not be lost when resolution changes.
		marginLeft = (int)ConvertXValue(marginLeft, ZAF_PIXEL, ZAF_INCH_1000);
		marginTop = (int)ConvertYValue(marginTop, ZAF_PIXEL, ZAF_INCH_1000);
		marginRight = (int)ConvertXValue(marginRight, ZAF_PIXEL, ZAF_INCH_1000);
		marginBottom = (int)ConvertYValue(marginBottom, ZAF_PIXEL, ZAF_INCH_1000);

		// Initialize members.
		columns = GetDeviceCaps(hDC, HORZRES);
		lines = GetDeviceCaps(hDC, VERTRES);
		pixelsPerInchX = GetDeviceCaps(hDC, LOGPIXELSX);
		pixelsPerInchY = GetDeviceCaps(hDC, LOGPIXELSY);
		cellWidth = pixelsPerInchX / 10;
		cellHeight = pixelsPerInchY / 6;
#if defined(ZAF_WIN32)
		nonprintableLeft = GetDeviceCaps(hDC, PHYSICALOFFSETX);
		nonprintableTop = GetDeviceCaps(hDC, PHYSICALOFFSETY);
#else
		POINT point;
		Escape(hDC, GETPRINTINGOFFSET, NULL, NULL, &point);
		nonprintableLeft = point.x;
		nonprintableTop = point.y;
#endif

		// Get paper orientation setting
		if (DriverMode(DM_ORIENTATION) == DMORIENT_LANDSCAPE)
			paperOrientation = ZAF_LANDSCAPE_ORIENTATION;
		else // is really portrait OR the DriverMode call failed...
			paperOrientation = ZAF_PORTRAIT_ORIENTATION;

		// Convert margin values back to device dependent coordinates (pixels).
		marginLeft = (int)ConvertXValue(marginLeft, ZAF_INCH_1000, ZAF_PIXEL);
		marginTop = (int)ConvertYValue(marginTop, ZAF_INCH_1000, ZAF_PIXEL);
		marginRight = (int)ConvertXValue(marginRight, ZAF_INCH_1000, ZAF_PIXEL);
		marginBottom = (int)ConvertYValue(marginBottom, ZAF_INCH_1000, ZAF_PIXEL);

		// Initialize the paper width.
		paperWidth = DriverMode((paperOrientation == ZAF_PORTRAIT_ORIENTATION) ? DM_PAPERWIDTH : DM_PAPERLENGTH);
		if (paperWidth)
			paperWidth = (int)ConvertXValue(paperWidth, ZAF_MILLIMETER_10, ZAF_PIXEL);
		else
		{
			int paperSizeID = DriverMode(DM_PAPERSIZE);
			if (paperSizeID && paperSizeID != DMPAPER_USER)
				GetPaperSize(this, paperSizeID, &paperWidth, 0);
			if (!paperWidth)
				paperWidth = (int)ConvertXValue((paperOrientation == ZAF_PORTRAIT_ORIENTATION) ? 8500 : 11000, ZAF_INCH_1000, ZAF_PIXEL);
		}

		// Initialize the paper height.
		paperHeight = DriverMode((paperOrientation == ZAF_PORTRAIT_ORIENTATION) ? DM_PAPERLENGTH : DM_PAPERWIDTH);
		if (paperHeight)
			paperHeight = (int)ConvertYValue(paperHeight, ZAF_MILLIMETER_10, ZAF_PIXEL);
		else
		{
			int paperSizeID = DriverMode(DM_PAPERSIZE);
			if (paperSizeID && paperSizeID != DMPAPER_USER)
				GetPaperSize(this, paperSizeID, 0, &paperHeight);
			if (!paperHeight)
				paperHeight = (int)ConvertYValue((paperOrientation == ZAF_PORTRAIT_ORIENTATION) ? 11000 : 8500, ZAF_INCH_1000, ZAF_PIXEL);
		}

		// Initialize page size.
		pageWidth = paperWidth - marginLeft - marginRight;
		pageHeight = paperHeight - marginTop - marginBottom;

		// Initialize background mode.
		SetBkMode(hDC, TRANSPARENT);
	}

	return (oldDC);
}

ZafError ZafPrinter::RegionCopy(const ZafRegionStruct &, int, int)
{
	return (ZAF_ERROR_UNKNOWN);
}

ZafError ZafPrinter::RectangleXORDiff(const ZafRegionStruct *,
	const ZafRegionStruct *)
{
	return (ZAF_ERROR_UNKNOWN);
}

ZafCoordinate ZafPrinter::TextBlock(ZafCoordinate left, ZafCoordinate top, ZafCoordinate right, ZafCoordinate bottom,
	int &charactersPrinted, const ZafIChar *text, int length,
	ZafHzJustify hzJustify, ZafVtJustify vtJustify, bool fill)
{
	left = ConvertXValue(left, coordinateType, ZAF_PIXEL);
	top = ConvertYValue(top, coordinateType, ZAF_PIXEL);
	right = ConvertXValue(right, coordinateType, ZAF_PIXEL);
	bottom = ConvertYValue(bottom, coordinateType, ZAF_PIXEL);

	// Set background mode.
	if (fill)
		SetBkMode(hDC, OPAQUE);

	// Set format flags for Windows API.
	UINT wFormat = DT_WORDBREAK | DT_NOCLIP;
	wFormat |= DT_NOPREFIX;

	// Set horizontal justification flags.
	if (hzJustify == ZAF_HZ_CENTER)
		wFormat |= DT_CENTER;
	else if (hzJustify == ZAF_HZ_RIGHT)
		wFormat |= DT_RIGHT;
	else
		wFormat |= DT_LEFT;

	// Set vertical justification flags.
	if (vtJustify == ZAF_VT_TOP)
		wFormat |= DT_TOP;
	else if (vtJustify == ZAF_VT_BOTTOM)
		wFormat |= DT_BOTTOM;
	else
		wFormat |= DT_VCENTER;

	// Draw the text.
	RECT rect = { (int)left, (int)top, (int)right + 1, (int)bottom + 1 };
	if (ZafMSWindowsApp::convertText)
	{
		int tLength = length;
		if (tLength < 0)
			tLength = strlen(text);
		ZafIChar *tDrawText = new ZafIChar[tLength + 1];
		strncpy(tDrawText, text, tLength);
		tDrawText[tLength] = 0;
		char *osText = zafCodeSet->ConvertToOSString(tDrawText);
		delete []tDrawText;
#if defined(ZAF_WIN32) && defined(ZAF_UNICODE)
		length = strlen(osText);
		DrawTextA(hDC, osText, length, &rect, wFormat);
#else
		DrawText(hDC, osText, length, &rect, wFormat);
#endif
		charactersPrinted = strlen(osText);
		delete []osText;
	}
#if defined(ZAF_WIN32) || !defined(ZAF_UNICODE)
	else
	{
		charactersPrinted = length;
		DrawText(hDC, text, length, &rect, wFormat);
	}
#endif

	// Restore the background mode.
	if (fill)
		SetBkMode(hDC, TRANSPARENT);

	return (ConvertYValue(bottom, ZAF_PIXEL, coordinateType));
}

ZafCoordinate ZafPrinter::TextLine(ZafCoordinate left, ZafCoordinate top, ZafCoordinate right, const ZafIChar *text,
	int length, ZafHzJustify hzJustify, bool fill)
{
	left = ConvertXValue(left, coordinateType, ZAF_PIXEL);
	top = ConvertYValue(top, coordinateType, ZAF_PIXEL);
	right = ConvertXValue(right, coordinateType, ZAF_PIXEL);

	ZafCoordinate bottom = 0;

	// Set background mode.
	if (fill)
		SetBkMode(hDC, OPAQUE);

	// Set format flags for Windows API.
	UINT wFormat = DT_SINGLELINE | DT_NOCLIP;
	wFormat |= DT_NOPREFIX;

	// Set horizontal justification flags.
	if (hzJustify == ZAF_HZ_CENTER)
		wFormat |= DT_CENTER;
	else if (hzJustify == ZAF_HZ_RIGHT)
		wFormat |= DT_RIGHT;
	else
		wFormat |= DT_LEFT;

	// Set vertical justification flags.
	wFormat |= DT_TOP | DT_EXTERNALLEADING;

	// Draw the text.
	RECT rect = { (int)left, (int)top, (int)right + 1, (int)bottom + 1 };
	RECT calcRect = rect;
	int height;
	if (ZafMSWindowsApp::convertText)
	{
		int tLength = length;
		if (tLength < 0)
			tLength = strlen(text);
		ZafIChar *tDrawText = new ZafIChar[tLength + 1];
		strncpy(tDrawText, text, tLength);
		tDrawText[tLength] = 0;
		char *osText = zafCodeSet->ConvertToOSString(tDrawText);
		delete []tDrawText;
#if defined(ZAF_WIN32) && defined(ZAF_UNICODE)
		length = strlen(osText);
		height = DrawTextA(hDC, osText, length, &calcRect, wFormat | DT_CALCRECT);
		rect.bottom = top + height + 1;
		DrawTextA(hDC, osText, length, &rect, wFormat);
#else
		height = DrawText(hDC, osText, length, &calcRect, wFormat | DT_CALCRECT);
		rect.bottom = (int)top + height + 1;
		DrawText(hDC, osText, length, &rect, wFormat);
#endif
		delete []osText;
	}
#if defined(ZAF_WIN32) || !defined(ZAF_UNICODE)
	else
	{
		height = DrawText(hDC, text, length, &calcRect, wFormat | DT_CALCRECT);
		rect.bottom = (int)top + height + 1;
		DrawText(hDC, text, length, &rect, wFormat);
	}
#endif

	// Restore the background mode.
	if (fill)
		SetBkMode(hDC, TRANSPARENT);

	return (ConvertYValue(top + height, ZAF_PIXEL, coordinateType));
}

ZafCoordinate ZafPrinter::PageWidth(void) const
{
	return (ConvertXValue(pageWidth, ZAF_PIXEL, coordinateType));
}

ZafCoordinate ZafPrinter::PageHeight(void) const
{
	return (ConvertYValue(pageHeight, ZAF_PIXEL, coordinateType));
}

ZafCoordinate ZafPrinter::PaperWidth(void) const
{
	return (ConvertXValue(paperWidth, ZAF_PIXEL, coordinateType));
}

ZafCoordinate ZafPrinter::PaperHeight(void) const
{
	return (ConvertYValue(paperHeight, ZAF_PIXEL, coordinateType));
}

void ZafPrinter::Margins(ZafCoordinate &leftMargin, ZafCoordinate &topMargin,
	ZafCoordinate &rightMargin, ZafCoordinate &bottomMargin) const
{
	leftMargin = ConvertXValue(marginLeft, ZAF_PIXEL, coordinateType);
	topMargin = ConvertYValue(marginTop, ZAF_PIXEL, coordinateType);
	rightMargin = ConvertXValue(marginRight, ZAF_PIXEL, coordinateType);
	bottomMargin = ConvertYValue(marginBottom, ZAF_PIXEL, coordinateType);
}

ZafPrinterType ZafPrinter::SetPrinterType(ZafPrinterType )
{
	printerType = ZAF_NATIVE_PRINTER;
	return (printerType);
}

ZafPaperOrientation ZafPrinter::SetPaperOrientation(ZafPaperOrientation setPaperOrientation)
{
	if (setPaperOrientation != paperOrientation)
	{
		if (DriverMode(DM_ORIENTATION, (setPaperOrientation == ZAF_PORTRAIT_ORIENTATION) ?
			DMORIENT_PORTRAIT : DMORIENT_LANDSCAPE))
		{
			paperOrientation = setPaperOrientation;

			int temp = paperHeight;
			paperHeight = paperWidth;
			paperWidth = temp;

			pageWidth = paperWidth - marginLeft - marginRight;
			pageHeight = paperHeight - marginTop - marginBottom;
		}
	}

	return (paperOrientation);
}

ZafCoordinate ZafPrinter::SetPaperWidth(ZafCoordinate setPaperWidth)
{
	paperWidth = (int)ConvertXValue(setPaperWidth, coordinateType, ZAF_PIXEL);
	DriverMode(DM_PAPERWIDTH, (int)ConvertXValue(paperWidth, ZAF_PIXEL, ZAF_MILLIMETER_10));
	pageWidth = paperWidth - marginLeft - marginRight;

	return (PaperWidth());
}

ZafCoordinate ZafPrinter::SetPaperHeight(ZafCoordinate setPaperHeight)
{
	paperHeight = (int)ConvertYValue(setPaperHeight, coordinateType, ZAF_PIXEL);
	DriverMode(DM_PAPERLENGTH, (int)ConvertYValue(paperHeight, ZAF_PIXEL, ZAF_MILLIMETER_10));
	pageHeight = paperHeight - marginTop - marginBottom;

	return (PaperHeight());
}

ZafCoordinate ZafPrinter::SetPageWidth(ZafCoordinate setPageWidth)
{
	pageWidth = (int)ConvertXValue(setPageWidth, coordinateType, ZAF_PIXEL);
	marginRight = ZafMax(paperWidth - marginLeft - pageWidth, 0);

	return (PageWidth());
}

ZafCoordinate ZafPrinter::SetPageHeight(ZafCoordinate setPageHeight)
{
	pageHeight = (int)ConvertYValue(setPageHeight, coordinateType, ZAF_PIXEL);
	marginBottom = ZafMax(paperHeight - marginTop - pageHeight, 0);

	return (PageHeight());
}

void ZafPrinter::SetMargins(ZafCoordinate leftMargin, ZafCoordinate topMargin,
	ZafCoordinate rightMargin, ZafCoordinate bottomMargin)
{
	marginLeft = (int)ConvertXValue(leftMargin, coordinateType, ZAF_PIXEL);
	marginTop = (int)ConvertYValue(topMargin, coordinateType, ZAF_PIXEL);
	marginRight = (int)ConvertXValue(rightMargin, coordinateType, ZAF_PIXEL);
	marginBottom = (int)ConvertYValue(bottomMargin, coordinateType, ZAF_PIXEL);

	pageWidth = paperWidth - marginLeft - marginRight;
	pageHeight = paperHeight - marginTop - marginBottom;
}

ZafError ZafPrinter::AbortJob(void)
{
	return (ZAF_ERROR_NONE);
}

ZafError ZafPrinter::BeginJob(ZafIChar *jobName)
{
	if (virtualCount++ == 0)
	{
		if (ZafMSWindowsApp::convertText)
		{
#if defined(ZAF_WIN32) && defined(ZAF_UNICODE)
			DOCINFOA docInfo;
#else
			DOCINFO docInfo;
#endif
			docInfo.cbSize = sizeof(docInfo);
			docInfo.lpszOutput = NULL;

			char *osString;
			if (jobName)
				osString = zafCodeSet->ConvertToOSString(jobName, ZAF_NULLP(char), FALSE);
			else
				osString = zafCodeSet->ConvertToOSString(ZAF_ITEXT("ZafPrinter Document"), ZAF_NULLP(char), FALSE);

#if defined(ZAF_WIN32)
			docInfo.lpszDocName = (LPSTR)osString;
			docInfo.lpszDatatype = NULL;
			docInfo.fwType = 0;
#else
			docInfo.lpszDocName = (LPSTR)osString;
#endif

#if defined(ZAF_WIN32) && defined(ZAF_UNICODE)
			StartDocA(hDC, &docInfo);
#else
			StartDoc(hDC, &docInfo);
#endif
		}
#if defined(ZAF_WIN32) || !defined(ZAF_UNICODE)
		else
		{
			DOCINFO docInfo;
			docInfo.cbSize = sizeof(docInfo);
			docInfo.lpszOutput = NULL;

#	if defined(ZAF_WIN32)
			docInfo.lpszDocName = jobName ? jobName : ZAF_ITEXT("ZafPrinter Document");
			docInfo.lpszDatatype = NULL;
			docInfo.fwType = 0;
#	else
			docInfo.lpszDocName = jobName ? jobName : ZAF_ITEXT("ZafPrinter Document");
#	endif
			StartDoc(hDC, &docInfo);
		}
#endif
	}

	return (ZAF_ERROR_NONE);
}

ZafError ZafPrinter::BeginPage(void)
{
	SetViewportOrgEx(hDC, marginLeft - nonprintableLeft, marginTop - nonprintableTop, NULL);

	HRGN hRegion = CreateRectRgn(marginLeft - nonprintableLeft, marginTop - nonprintableTop,
		marginLeft - nonprintableLeft + pageWidth, marginTop - nonprintableTop + pageHeight);
	SelectClipRgn(hDC, hRegion);
	DeleteObject(hRegion);

	StartPage(hDC);
	return (ZAF_ERROR_NONE);
}

ZafError ZafPrinter::EndJob(void)
{
	if (--virtualCount == 0)
		EndDoc(hDC);
	return (ZAF_ERROR_NONE);
}

ZafError ZafPrinter::EndPage(void)
{
	::EndPage(hDC);
	return (ZAF_ERROR_NONE);
}

ZafRegionStruct ZafPrinter::SetClipRegion(const ZafRegionStruct &region)
{
	ZafRegionStruct pixelRegion;
	pixelRegion.coordinateType = ZAF_PIXEL;
	pixelRegion.left = (int)ConvertXValue(region.left, coordinateType, ZAF_PIXEL) - nonprintableLeft;
	pixelRegion.top = (int)ConvertYValue(region.top, coordinateType, ZAF_PIXEL) - nonprintableTop;
	pixelRegion.right = (int)ConvertXValue(region.right, coordinateType, ZAF_PIXEL) - nonprintableLeft;
	pixelRegion.bottom = (int)ConvertYValue(region.bottom, coordinateType, ZAF_PIXEL) - nonprintableTop;

	ZafCoordinateType oldCoordinateType = SetCoordinateType(ZAF_PIXEL);
	ZafGdiDisplay::SetClipRegion(pixelRegion);
	SetCoordinateType(oldCoordinateType);

	ZafRegionStruct oldClipRegion = clipRegion;
	clipRegion = region;
	return (oldClipRegion);
}

int ZafPrinter::DriverMode(DWORD field, int newValue)
{
	int returnValue = 0;

#if defined(ZAF_WIN32)
	DEVMODEA *devMode = (DEVMODEA *)GlobalLock(hDevMode);
#else
	DEVMODE *devMode = (DEVMODE *)GlobalLock(hDevMode);
#endif
	DEVNAMES *devNames = (DEVNAMES *)GlobalLock(hDevNames);

#if defined(ZAF_WIN32)
	HANDLE hPrinter;
	if (OpenPrinterA((LPSTR)devNames + devNames->wDeviceOffset, &hPrinter, NULL))
	{
		{
#else
	// Load the printer driver.
	HINSTANCE hDriver = LoadLibrary((LPSTR)devNames + devNames->wDriverOffset);
	if (hDriver > HINSTANCE_ERROR)
	{
		// Get a function pointer to the driver's ExtDeviceMode function.
		LPFNDEVMODE ExtDeviceMode = (LPFNDEVMODE)GetProcAddress(hDriver, "EXTDEVICEMODE");
		if (ExtDeviceMode)
		{
#endif
			if (devMode->dmFields & field)
			{
				if (newValue)
				{
					if (field == DM_ORIENTATION)
						devMode->dmOrientation = (short)newValue;
					else if (field == DM_PAPERWIDTH)
						devMode->dmPaperWidth = (short)newValue;
					else if (field == DM_PAPERLENGTH)
						devMode->dmPaperLength = (short)newValue;
					else if (field == DM_PAPERSIZE)
						devMode->dmPaperSize = (short)newValue;

#if defined(ZAF_WIN32)
					DocumentPropertiesA(0, hPrinter,
						(LPSTR)devNames + devNames->wDeviceOffset,
						devMode, devMode, DM_IN_BUFFER | DM_OUT_BUFFER);
#else
					ExtDeviceMode(0, hDriver, devMode,
						(LPSTR)devNames + devNames->wDeviceOffset,
						(LPSTR)devNames + devNames->wOutputOffset,
						devMode, NULL, DM_COPY | DM_MODIFY);
#endif

					DeleteDC(hDC);

#if defined(ZAF_WIN32)
					SetDisplayContext(CreateDCA(
						(LPSTR)devNames + devNames->wDriverOffset,
						(LPSTR)devNames + devNames->wDeviceOffset,
						(LPSTR)devNames + devNames->wOutputOffset,
						devMode));
#else
					SetDisplayContext(CreateDC(
						(LPSTR)devNames + devNames->wDriverOffset,
						(LPSTR)devNames + devNames->wDeviceOffset,
						(LPSTR)devNames + devNames->wOutputOffset,
						devMode));
#endif
				}

				if (field == DM_ORIENTATION)
					returnValue = devMode->dmOrientation;
				else if (field == DM_PAPERWIDTH)
					returnValue = devMode->dmPaperWidth;
				else if (field == DM_PAPERLENGTH)
					returnValue = devMode->dmPaperLength;
				else if (field == DM_PAPERSIZE)
					returnValue = devMode->dmPaperSize;
				else
					returnValue = 0;
			}
		}

#if defined(ZAF_WIN32)
		ClosePrinter(hPrinter);
#else
		FreeLibrary(hDriver);
#endif
	}

	GlobalUnlock(hDevMode);
	GlobalUnlock(hDevNames);

	return (returnValue);
}

bool ZafPrinter::JobSetup(ZafPrintJobStruct &printJob)
{
	ZafPrintDialog printDialog(0, 0, this, &printJob);
	return ((printDialog.Control() == S_DLG_OK) ? true : false);
}

bool ZafPrinter::PrintSetup(void)
{
#if defined(ZAF_WIN32)
	PRINTDLGA printDlg;
#else
	PRINTDLG printDlg;
#endif
	memset(&printDlg, 0, sizeof(printDlg));
	printDlg.lStructSize = sizeof(printDlg);
	printDlg.hwndOwner = zafWindowManager->First() ?
		zafWindowManager->First()->OSScreenID(ZAF_FRAMEID) : NULL;
	printDlg.hDevMode = hDevMode;
	printDlg.hDevNames = hDevNames;
	printDlg.Flags = PD_PRINTSETUP | PD_RETURNDC;
#if defined(ZAF_WIN32)
	if (PrintDlgA(&printDlg))
#else
	if (PrintDlg(&printDlg))
#endif
	{
		hDevMode = printDlg.hDevMode;
		hDevNames = printDlg.hDevNames;
		DeleteDC(hDC);
		SetDisplayContext(printDlg.hDC);
		return (true);
	}

	return (false);
}

ZafPrintDialog::ZafPrintDialog(int left, int top,
	ZafPrinter *setPrinter, ZafPrintJobStruct *setPrintJob) :
	ZafDialogWindow(left, top, 0, 0), printer(setPrinter),
	printJob(setPrintJob), allowModifyCollate(true), allowModifyCopies(true),
	allowModifyRange(true)
{
}

ZafDialogEvent ZafPrintDialog::Control(ZafQFlags)
{
#if defined(ZAF_WIN32)
	PRINTDLGA printDlg;
#else
	PRINTDLG printDlg;
#endif
	memset(&printDlg, 0, sizeof(printDlg));
	printDlg.lStructSize = sizeof(printDlg);
	printDlg.hwndOwner = zafWindowManager->First() ?
		zafWindowManager->First()->OSScreenID(ZAF_FRAMEID) : NULL;
	printDlg.hDevMode = printer->hDevMode;
	printDlg.hDevNames = printer->hDevNames;
	printDlg.Flags = PD_ALLPAGES | PD_NOSELECTION |
		(printJob->collate ? PD_COLLATE : 0) |
		(allowModifyRange ? 0 : PD_NOPAGENUMS) |
		((allowModifyCopies && allowModifyCollate) ? 0 : PD_USEDEVMODECOPIES) |
		PD_RETURNDC;
	printDlg.nFromPage = (WORD)printJob->startPage;
	printDlg.nToPage = (WORD)printJob->endPage;
	printDlg.nMinPage = (WORD)printJob->minPage;
	printDlg.nMaxPage = (WORD)printJob->maxPage;
	printDlg.nCopies = (WORD)printJob->copies;

#if defined(ZAF_WIN32)
	if (PrintDlgA(&printDlg))
#else
	if (PrintDlg(&printDlg))
#endif
	{
		printer->hDevMode = printDlg.hDevMode;
		printer->hDevNames = printDlg.hDevNames;

		DeleteDC(printer->hDC);
		printer->SetDisplayContext(printDlg.hDC);

		printJob->collate = printDlg.Flags & PD_COLLATE ? true : false;
		printJob->copies = printDlg.nCopies;
		if (printDlg.Flags & PD_PAGENUMS)
		{
			printJob->startPage = printDlg.nFromPage;
			printJob->endPage = printDlg.nToPage;
		}
		else
		{
			printJob->startPage = printJob->minPage;
			printJob->endPage = printJob->maxPage;
		}

		return (S_DLG_OK);
	}

	return (S_DLG_CANCEL);
}

ZafEventType ZafPrintDialog::Event(const ZafEventStruct &event)
{
	return (ZafDialogWindow::Event(event));
}

ZafEventType ZafPrintSetupDialog::Event(const ZafEventStruct &event)
{
	return (ZafDialogWindow::Event(event));
}

// **** Paper Size Calculation Unitilities ****

//
// Paper Size --> Width x Height map.  Based on stuff in Windows WINGDI.H file
// The entries may appear in any order to allow for possible gaps in ids.
// A value of zero (0) for height and/or width indicates size is unknown.
//
static struct PaperSizeStruct
{
	int					dmPaperSize;	// Windows DMPAPER_xxx paper size id
	ZafCoordinateType coordinateType;
	long					width;
	long					height;
} ZAF_FARDATA paperSizeLookupTable[] =
{
	{DMPAPER_LETTER, 			ZAF_INCH_1000, 8500, 11000},	/* Letter 8 1/2 x 11 in               */
	{DMPAPER_LETTERSMALL, 		ZAF_INCH_1000, 8500, 11000},	/* Letter Small 8 1/2 x 11 in         */
	{DMPAPER_TABLOID, 			ZAF_INCH_1000,11000, 17000},	/* Tabloid 11 x 17 in                 */
	{DMPAPER_LEDGER, 			ZAF_INCH_1000,17000, 11000},	/* Ledger 17 x 11 in                  */
	{DMPAPER_LEGAL, 			ZAF_INCH_1000, 8500, 14000},	/* Legal 8 1/2 x 14 in                */
	{DMPAPER_STATEMENT, 		ZAF_INCH_1000, 5500,  8500},	/* Statement 5 1/2 x 8 1/2 in         */
	{DMPAPER_EXECUTIVE, 		ZAF_INCH_1000, 7250, 10500},	/* Executive 7 1/4 x 10 1/2 in        */
	{DMPAPER_A3, 				ZAF_MILLIMETER_10,2970,  4200},	/* A3 297 x 420 mm                    */
	{DMPAPER_A4, 				ZAF_MILLIMETER_10,2100,  2970},	/* A4 210 x 297 mm                    */
	{DMPAPER_A4SMALL, 			ZAF_MILLIMETER_10,2100,  2970},	/* A4 Small 210 x 297 mm              */
	{DMPAPER_A5, 				ZAF_MILLIMETER_10,1480,  2100},	/* A5 148 x 210 mm                    */
	{DMPAPER_B4, 				ZAF_MILLIMETER_10,2500,  3540},	/* B4 (JIS) 250 x 354                 */
	{DMPAPER_B5, 				ZAF_MILLIMETER_10,1820,  2570},	/* B5 (JIS) 182 x 257 mm              */
	{DMPAPER_FOLIO, 			ZAF_INCH_1000, 8500, 13000},	/* Folio 8 1/2 x 13 in                */
	{DMPAPER_QUARTO, 			ZAF_MILLIMETER_10,2150,  2750},	/* Quarto 215 x 275 mm                */
	{DMPAPER_10X14, 			ZAF_INCH_1000,10000, 14000},	/* 10x14 in                           */
	{DMPAPER_11X17, 			ZAF_INCH_1000,11000, 17000},	/* 11x17 in                           */
	{DMPAPER_NOTE, 				ZAF_INCH_1000, 8500, 11000},	/* Note 8 1/2 x 11 in                 */
	{DMPAPER_ENV_9, 			ZAF_INCH_1000, 3875,  8875},	/* Envelope #9 3 7/8 x 8 7/8          */
	{DMPAPER_ENV_10, 			ZAF_INCH_1000, 4125,  9500},	/* Envelope #10 4 1/8 x 9 1/2         */
	{DMPAPER_ENV_11, 			ZAF_INCH_1000, 4500, 10375},	/* Envelope #11 4 1/2 x 10 3/8        */
	{DMPAPER_ENV_12, 			ZAF_INCH_1000, 4750, 11000},	/* Envelope #12 4 3/4 x 11            */
	{DMPAPER_ENV_14, 			ZAF_INCH_1000, 5000, 11500},	/* Envelope #14 5 x 11 1/2            */
	{DMPAPER_CSHEET, 			ZAF_INCH_1000,17000, 22000},	/* C size sheet  17 x 22 in           */
	{DMPAPER_DSHEET, 			ZAF_INCH_1000,22000, 34000L},	/* D size sheet  22 x 34              */
	{DMPAPER_ESHEET, 			ZAF_INCH_1000,34000L, 44000L},	/* E size sheet  34 x 44              */
	{DMPAPER_ENV_DL, 			ZAF_MILLIMETER_10,1100,  2200},	/* Envelope DL 110 x 220mm            */
	{DMPAPER_ENV_C5, 			ZAF_MILLIMETER_10,1620,  2290},	/* Envelope C5 162 x 229 mm           */
	{DMPAPER_ENV_C3, 			ZAF_MILLIMETER_10,3240,  4580},	/* Envelope C3  324 x 458 mm          */
	{DMPAPER_ENV_C4, 			ZAF_MILLIMETER_10,2290,  3240},	/* Envelope C4  229 x 324 mm          */
	{DMPAPER_ENV_C6, 			ZAF_MILLIMETER_10,1140,  1620},	/* Envelope C6  114 x 162 mm          */
	{DMPAPER_ENV_C65, 			ZAF_MILLIMETER_10,1140,  2290},	/* Envelope C65 114 x 229 mm          */
	{DMPAPER_ENV_B4, 			ZAF_MILLIMETER_10,2500,  3530},	/* Envelope B4  250 x 353 mm          */
	{DMPAPER_ENV_B5, 			ZAF_MILLIMETER_10,1760,  2500},	/* Envelope B5  176 x 250 mm          */
	{DMPAPER_ENV_B6, 			ZAF_MILLIMETER_10,1760,  1250},	/* Envelope B6  176 x 125 mm          */
	{DMPAPER_ENV_ITALY, 		ZAF_MILLIMETER_10,1100,  2300},	/* Envelope 110 x 230 mm              */
	{DMPAPER_ENV_MONARCH,		ZAF_INCH_1000, 3875,  7500},	/* Envelope Monarch 3.875 x 7.5 in    */
	{DMPAPER_ENV_PERSONAL, 		ZAF_INCH_1000, 3625,  6500},	/* 6 3/4 Envelope 3 5/8 x 6 1/2 in    */
	{DMPAPER_FANFOLD_US, 		ZAF_INCH_1000,14875, 11000},	/* US Std Fanfold 14 7/8 x 11 in      */
	{DMPAPER_FANFOLD_STD_GERMAN,ZAF_INCH_1000,8500,12000},/* German Std Fanfold 8 1/2 x 12 in   */
	{DMPAPER_FANFOLD_LGL_GERMAN,ZAF_INCH_1000,8500,13000},/* German Legal Fanfold 8 1/2 x 13 in */

#if WINVER >= 0x400
	// Windows 95 only ("WINVER >= 0x0400" condition in Win API header files)
	{DMPAPER_ISO_B4, 		ZAF_MILLIMETER_10,2500,  3530},	/* B4 (ISO) 250 x 353 mm              */
	{DMPAPER_JAPANESE_POSTCARD,ZAF_MILLIMETER_10,1000,1480},/* Japanese Postcard 100 x 148 mm     */
	{DMPAPER_9X11, 			ZAF_INCH_1000, 9000, 11000},	/* 9 x 11 in                          */
	{DMPAPER_10X11, 			ZAF_INCH_1000,10000, 11000},	/* 10 x 11 in                         */
	{DMPAPER_15X11, 			ZAF_INCH_1000,15000, 11000},	/* 15 x 11 in                         */
	{DMPAPER_ENV_INVITE, ZAF_MILLIMETER_10,2200,  2200},	/* Envelope Invite 220 x 220 mm       */
	{DMPAPER_RESERVED_48,ZAF_MILLIMETER_10,   0,     0},	/* RESERVED--DO NOT USE               */
	{DMPAPER_RESERVED_49,ZAF_MILLIMETER_10,   0,     0},	/* RESERVED--DO NOT USE               */
	{DMPAPER_LETTER_EXTRA,	ZAF_INCH_1000, 9750, 12000},	/* Letter Extra 9 \275 x 12 in        */
	{DMPAPER_LEGAL_EXTRA, 	ZAF_INCH_1000, 9750, 15000},	/* Legal Extra 9 \275 x 15 in         */
	{DMPAPER_TABLOID_EXTRA, ZAF_INCH_1000,11690, 18000},	/* Tabloid Extra 11.69 x 18 in        */
	{DMPAPER_A4_EXTRA, 		ZAF_INCH_1000, 9270, 12690},	/* A4 Extra 9.27 x 12.69 in           */
	{DMPAPER_LETTER_TRANSVERSE,ZAF_INCH_1000,8750,11000},	/* Letter Transverse 8 \275 x 11 in   */
	{DMPAPER_A4_TRANSVERSE,ZAF_MILLIMETER_10,2100,2970},	/* A4 Transverse 210 x 297 mm         */
	{DMPAPER_LETTER_EXTRA_TRANSVERSE,ZAF_INCH_1000,9750,12000},/* Letter Extra Transverse 9\275 x 12 in */
	{DMPAPER_A_PLUS, 		ZAF_MILLIMETER_10,2270,  3560},	/* SuperA/SuperA/A4 227 x 356 mm      */
	{DMPAPER_B_PLUS, 		ZAF_MILLIMETER_10,3050,  4870},	/* SuperB/SuperB/A3 305 x 487 mm      */
	{DMPAPER_LETTER_PLUS,	ZAF_INCH_1000, 8500, 12690},	/* Letter Plus 8.5 x 12.69 in         */
	{DMPAPER_A4_PLUS, 	ZAF_MILLIMETER_10,2100,  3300},	/* A4 Plus 210 x 330 mm               */
	{DMPAPER_A5_TRANSVERSE,ZAF_MILLIMETER_10,1480,2100},	/* A5 Transverse 148 x 210 mm         */
	{DMPAPER_B5_TRANSVERSE,ZAF_MILLIMETER_10,1820,2570},	/* B5 (JIS) Transverse 182 x 257 mm   */
	{DMPAPER_A3_EXTRA, 	ZAF_MILLIMETER_10, 3220, 4450},	/* A3 Extra 322 x 445 mm              */
	{DMPAPER_A5_EXTRA, 	ZAF_MILLIMETER_10, 1740, 2350},	/* A5 Extra 174 x 235 mm              */
	{DMPAPER_B5_EXTRA, 	ZAF_MILLIMETER_10, 2010, 2760},	/* B5 (ISO) Extra 201 x 276 mm        */
	{DMPAPER_A2, 			ZAF_MILLIMETER_10, 4200, 5940},	/* A2 420 x 594 mm                    */
	{DMPAPER_A3_TRANSVERSE,ZAF_MILLIMETER_10,2970,4200},	/* A3 Transverse 297 x 420 mm         */
	{DMPAPER_A3_EXTRA_TRANSVERSE,ZAF_MILLIMETER_10,3220,4450},/* A3 Extra Transverse 322 x 445 mm   */
#endif
};

#define PAPER_ENTRIES (sizeof paperSizeLookupTable / sizeof(PaperSizeStruct))

void GetPaperSize(ZafPrinter *printer, int paperSizeID, int *width, int *height)
{
	for (int i = 0; i < PAPER_ENTRIES; i++)
	{
		if (paperSizeLookupTable[i].dmPaperSize == paperSizeID)
		{
			long w = paperSizeLookupTable[i].width;
			long h = paperSizeLookupTable[i].height;

			if (printer->PaperOrientation() == ZAF_LANDSCAPE_ORIENTATION)
			{
				long tmp = w;
				w = h;
				h = tmp;
			}

			if (width)
				*width = (int)printer->ConvertXValue(w, paperSizeLookupTable[i].coordinateType, ZAF_PIXEL);
			if (height)
				*height = (int)printer->ConvertYValue(h, paperSizeLookupTable[i].coordinateType, ZAF_PIXEL);

			return;
		}
	}
}
