/*	
    DrvPrinting.c	1.5
    Copyright 1997 Willows Software, Inc. 

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 (at your option) 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
MERCHANTABILITY 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; see the file COPYING.LIB.  If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA.

The maintainer of the Willows TWIN Libraries may be reached (Email) 
at the address twin@willows.com	

*/


#include <Printing.h>
#include <Quickdraw.h>
#include <Dialogs.h>
#include <OSUtils.h>
#include <ToolUtils.h>
#include <Files.h>
#include <MixedMode.h>
#include <string.h>

#include "commdlg.h"
#include "DrvDC.h"
#include "DrvHook.h"
#include "GdiDC.h"
#include "Log.h"
#include "print.h"
#include "TWINPrint.h"

#define PostScriptBegin		190
#define PostScriptEnd		191
#define PostScriptHandle	192
#define PostScriptFile		193

#define	kMacPrinterName		"TWIN Mac Printer"
#define	kMacPrinterVersion	0x0100


/*****************************P R O T O T Y P E S ********************/

	LPDRIVERDC	DrvCreatePrintDC( DWORD dwDCXFlags, LPTWINDEVMODE lpDevMode );
	OSErr		DrvStartDoc( LPDRIVERDC driverDC );
	OSErr		DrvStartPage( LPDRIVERDC driverDC );
	OSErr		DrvEndPage( LPDRIVERDC driverDC );
	OSErr		DrvEndDoc( LPDRIVERDC driverDC );
	Boolean		DrvSetupDlg( TWINDEVMODE* devMode );
	void		DrvGetDefault( TWINDEVMODE* devMode );
	void		DrvFillPrintDlg( LPPRINTDLG lpPrintDlg, LPTWINDEVMODE lpDevMode, Boolean isDevModeSrc );
	
	void		Convert2TPrint( LPTWINDEVMODE lpDevMode );
	void		Convert2DevMode( LPTWINDEVMODE lpDevMode );

	short		SendData( TPPrPort pPrPort, char * buff, long buffLen );
	
//	pascal Boolean	ModalDLOGFilter(DialogPtr theDialog, EventRecord *theEvent,  short *itemHit);

//	pascal TPrDlg *SetUpOffscreenDLOG( THPrint);


/**********************F U N C T I O N S ***************************/

DWORD PrivatePrinterHook(WORD dwCode, LPARAM dwParam1, LPARAM dwParam2, LPVOID lpStruct)
{

    switch(dwCode) {
	/* dwParam1 - compatibility mask */
	/* dwParam2 - init/exit flag */
	case PPH_CREATEDC:
		return((DWORD )DrvCreatePrintDC((DWORD )dwParam1, (LPTWINDEVMODE )lpStruct ));

	case PPH_STARTDOC:
		return((DWORD )DrvStartDoc((LPDRIVERDC )lpStruct ));

	case PPH_STARTPAGE:
		return((DWORD )DrvStartPage((LPDRIVERDC )lpStruct ));

	case PPH_ENDPAGE:
		return((DWORD )DrvEndPage((LPDRIVERDC )lpStruct ));

	case PPH_ENDDOC:
		return((DWORD )DrvEndDoc((LPDRIVERDC )lpStruct ));

	case PPH_SENDDATA:
		return((DWORD )SendData((TPPrPort )lpStruct, (char* )dwParam1, (int )dwParam2 ));

	case PPH_SETUPDLG:
		return((DWORD )DrvSetupDlg((TWINDEVMODE* )lpStruct ));

	case PPH_GETDEVMODESIZE:
		return((DWORD )sizeof( TPrint ));

	case PPH_GETDEFAULT:
		DrvGetDefault((LPTWINDEVMODE )lpStruct );
		return( 0 );

	case PPH_FILLPRINTDLG:
		DrvFillPrintDlg((LPPRINTDLG )lpStruct, (LPTWINDEVMODE )dwParam1, true );
		return( 0 );

	default:
		break;
	}

	return(0L);
}


//
//	DrvCreatePrintDC():
//
//	Creates a driver specific device context that is used in subsequent QuickDraw and
//	and PrintManager calls.  If lpPrintDlg is NULL then the Macintosh standard print
//	dialogs are to be used.  Otherwise, the Windows standard print dialogs were used to
//	provide the needed information.
//
LPDRIVERDC
DrvCreatePrintDC( DWORD dwDCXFlags, LPTWINDEVMODE lpDevMode )
{
	GrafPtr		savePort;
	LPDRIVERDC	lpDriverDC;
	THPrint		hPrint;
	Rect		rect;
	
	GetPort( &savePort );							/* Get current port to restore */

	if ( dwDCXFlags & DCX_COMPATIBLE_DC )
	{
		lpDriverDC = (LPDRIVERDC )DrvCreateDC( dwDCXFlags, NULL );
		SetPort( savePort );
		return( lpDriverDC );
	}

	/* Allocate memory for the driver dc structure */
	lpDriverDC = (LPDRIVERDC) DrvMalloc(sizeof(DRIVERDC));
	if ( lpDriverDC == NULL )
		return( NULL );
	
	memset(lpDriverDC, '\0', sizeof(DRIVERDC));			/* Slick way to clear memory */
	lpDriverDC->dwDCFlags = dwDCXFlags;					/* Store the flags */
	
	PrOpen();
	if ( PrError() != noErr )
	{
		DrvFree( lpDriverDC );
		return( NULL );
	}

//
//	Allocate a TPrint handle and set it to the default values
//
	lpDriverDC->hPrint = NewHandle( sizeof( TPrint ));
	if ( lpDriverDC->hPrint == NULL )
	{
		PrClose();
		DrvFree( lpDriverDC );
		SetPort( savePort );
		return( NULL );
	}
	hPrint = lpDriverDC->hPrint;
	PrintDefault( hPrint );
	if ( PrError() != noErr )
	{
		DisposeHandle((Handle )hPrint );
		PrClose();
		DrvFree( lpDriverDC );
		SetPort( savePort );
		return( NULL );
	}

//
//	Copy things from the extended DEVMODE record into our TPrint handle
//
	if ( lpDevMode )
	{
		HLock((Handle )hPrint );
		BlockMove( &lpDevMode->tPrint, (char* )*hPrint, sizeof ( TPrint ));
		HUnlock((Handle )hPrint );
		Convert2TPrint( lpDevMode );
	}
	
	if ( PrJobDialog( hPrint ) == false )
	{
		DisposeHandle((Handle )hPrint );
		PrClose();
		DrvFree( lpDriverDC );
		SetPort( savePort );
		return( NULL );
	}

	lpDriverDC->grafPort = PrOpenDoc( hPrint, NULL, NULL );
	if ( PrError() != noErr )
	{
		DisposeHandle((Handle )hPrint );
		PrClose();
		DrvFree( lpDriverDC );
		SetPort( savePort );
		return( NULL );
	}
//
//	Create the image STRUCTURE and place the screen contents into it
//	A screen DC is our domain, and we must manage the image contents
//
	rect = (*hPrint)->prInfo.rPage;
	lpDriverDC->lpDrvImage = (DRVIMAGEDATA* )DrvMalloc(sizeof(DRVIMAGEDATA));
	lpDriverDC->lpDrvImage->nWidth 		= rect.right - rect.left;
	lpDriverDC->lpDrvImage->nHeight 	= rect.bottom - rect.top;
	lpDriverDC->lpDrvImage->nLinePad	= 0;
	lpDriverDC->lpDrvImage->nBitsPixel 	= 1;
//	lpDriverDC->lpDrvImage->nBitsPixel 	= (*newPixMap)->pixelSize;
//	lpDriverDC->lpDrvImage->nWidthBytes = (*newPixMap)->rowBytes | !(PMROWBYTESMSB);
	lpDriverDC->lpDrvImage->fMono 		= false;
	lpDriverDC->lpDrvImage->fInvalid 	= false;
	
	lpDriverDC->updateRegion			= NULL;
	lpDriverDC->brushFlag				= BFP_PIXEL;	/* Default to a solid color */
	lpDriverDC->brushFillPat			= NULL;

	LOGSTR((LF_OBJECTS,"PDCH: Create DC returns lpddc = %x grafPort = %x (%s)\n", lpDriverDC, lpDriverDC->grafPort, (lpDriverDC->dwDCFlags & DCX_COMPATIBLE_DC)? "MEMORY":"SCREEN"));
	
	SetPort( savePort );
	return( lpDriverDC );
}


//
//	DrvStartDoc():
//
//	Simulates Windows StartDoc().  Doesn't do much since most of the initialization
//	is done by the DrvCreatePrintDC() function.
//
OSErr
DrvStartDoc( LPDRIVERDC /*lpDriverDC*/ )
{
	return( PrError());
}


//
//	DrvStartPage():
//
//	Simulates Windows StartPage() by calling the PrintManager PrOpenPage() function.
//
OSErr
DrvStartPage( LPDRIVERDC lpDriverDC )
{
	PrOpenPage((TPPrPort )lpDriverDC->grafPort, nil );
	return( PrError());
}


//
//	DrvEndPage():
//
//	Simulates Windows EndPage() by calling the PrintManager PrClosePage() function.
//
OSErr
DrvEndPage( LPDRIVERDC lpDriverDC )
{
	PrClosePage((TPPrPort )lpDriverDC->grafPort );
	return( PrError());
}


//
//	DrvEndDoc():
//
//	Simulates Windows EndDoc() by calling the PrintManager PrCloseDoc() and other
//	functions to terminate the use of the print driver.
//
OSErr
DrvEndDoc( LPDRIVERDC lpDriverDC )
{
	OSErr		result;
	THPrint		hPrint = lpDriverDC->hPrint;
	TPrStatus	thePrStatus;

	PrCloseDoc((TPPrPort )lpDriverDC->grafPort );
	result = PrError();
//	if (( result == noErr ) &&
//		((*hPrint)->prJob.bJDocLoop == bSpoolLoop ))
	if ( result == noErr )
	{
		PrPicFile( lpDriverDC->hPrint, nil, nil, nil, &thePrStatus );
		result = PrError();
	}
	PrClose();

//
//	Release the printing handle
//
	DisposeHandle((Handle )hPrint );
	lpDriverDC->hPrint = nil;
	
	return( result );
}


//
//	SendData():
//
//	I don't think this is necessary anymore
//
short
SendData( TPPrPort pPrPort, char *buff, long buffLen){
	
	Handle	buffHandle;

	if(buffLen<1)		/*return if no data in buffer*/
		return -1;
		
		buffHandle = NewHandleClear(buffLen);

		PtrToHand((char *)buff, &buffHandle, buffLen);
		PicComment(PostScriptHandle,buffLen, buffHandle);

	DisposeHandle(buffHandle);
	
	return 0;
 
} /* SendData*/


//
//	DrvSetupDlg():
//
//	Displays the Macintosh printer setup dialog for the default printer.  Creates
//	an extended DEVMODE record and fills it in with what is defined by the printers
//	style dialog.  Returns true if all was successful.
//
Boolean
DrvSetupDlg( TWINDEVMODE* lpDevMode )
{
	THPrint			hPrint;

	PrOpen();
	if ( PrError() != noErr )
		return( false );

//
//	Allocate a TPrint handle
//
	hPrint = (THPrint )NewHandle( sizeof( TPrint ));
	if ( hPrint == NULL )
	{
		PrClose();
		return( false );
	}
//
//	Copy what was provided by the caller and verify the result
//
	if ( lpDevMode )
	{
		HLock((Handle )hPrint );
		BlockMove( &lpDevMode->tPrint, (char* )*hPrint, sizeof( TPrint ));
		HUnlock((Handle )hPrint );
		Convert2TPrint( lpDevMode );
	}
	PrValidate( hPrint );
	if ( PrError() != noErr )
	{
		DisposeHandle((Handle )hPrint );
		PrClose();
		return( false );
	}

//
//	Do the style dialog and return the result
//
	if ( PrStlDialog( hPrint ) == false )
	{
		DisposeHandle((Handle )hPrint );
		PrClose();
		return( false );
	}
	
//	TODO:	Convert the fields that are set by the PrStlDialog() call into the associated
//	fields that are part of the device-independent DEVMODE record.	
	HLock((Handle )hPrint );
	BlockMove((char* )*hPrint, &lpDevMode->tPrint, sizeof( TPrint ));
	HUnlock((Handle )hPrint );
	DisposeHandle((Handle )hPrint );
	Convert2DevMode( lpDevMode );
	return( true );
}


//
//	DrvGetDefault():
//
//	Fill in an extended DEVMODE record with default values that are provided by the
//	current printer driver
//
void
DrvGetDefault( LPTWINDEVMODE lpDevMode )
{
	THPrint			hPrint;

	PrOpen();
	if ( PrError() != noErr )
		return;

//
//	Allocate a TPrint handle and set it to the default values
//
	hPrint = (THPrint )NewHandle( sizeof( TPrint ));
	if ( hPrint == NULL )
	{
		PrClose();
		return;
	}
	PrintDefault( hPrint );
	if ( PrError() != noErr )
	{
		DisposeHandle((Handle )hPrint );
		PrClose();
		return;
	}

//
//	Copy the values into the provided record
//
	HLock((Handle )hPrint );
	BlockMove((char* )*hPrint, &lpDevMode->tPrint, sizeof( TPrint ));
	HUnlock((Handle )hPrint );
	PrClose();

//
//	Fill in any device-independent elements that we are supposed to
//
	strcpy((char* )lpDevMode->devMode.dmDeviceName, kMacPrinterName );
	lpDevMode->devMode.dmDriverVersion		= kMacPrinterVersion;
	Convert2DevMode( lpDevMode );
}


//
//	DrvFillPrintDlg():
//
//	Given an extended DEVMODE record that has been filled in by either DrvSetupDlg()
//	or DrvCreateDC(), this routine propagates the internal record into the device
//	independent external record that is the standard DEVMODE record.  This allows
//	a client program to examine the DEVMODE record for things like number of copies
//	in order to print what the user has asked for when using the driver supplied dialogs.
//
void
DrvFillPrintDlg( LPPRINTDLG lpPrintDlg, LPTWINDEVMODE lpDevMode, Boolean isDevModeSrc )
{
	lpPrintDlg->nCopies = 1;
#ifdef	COMMENT
	if ( isDevModeSrc )
	{
		lpPrintDlg->nFromPage	= lpDevMode->tPrint.prJob.iFstPage;
		lpPrintDlg->nToPage		= lpDevMode->tPrint.prJob.iLstPage;
		lpPrintDlg->nMinPage	= lpDevMode->tPrint.prJob.iFstPage;
		lpPrintDlg->nMaxPage	= lpDevMode->tPrint.prJob.iLstPage;
		lpPrintDlg->nCopies		= lpDevMode->tPrint.prJob.iCopies;
	}
	else
	{
		lpDevMode->tPrint.prJob.iFstPage	= lpPrintDlg->nFromPage;
		lpDevMode->tPrint.prJob.iLstPage	= lpPrintDlg->nToPage;
		lpDevMode->tPrint.prJob.iCopies		= lpPrintDlg->nCopies;
	}
#endif	//	COMMENT
}


//
//	Convert2TPrint():
//
//	This routine uses the device-independent portion of the extended DEVMODE record
//	to fill in certain elements of the Macintosh TPrint record.
//
void
Convert2TPrint( LPTWINDEVMODE lpDevMode )
{
}


//
//	Convert2DevMode():
//
//	This routine uses the Macintosh portion of the extended DEVMODE record to fill in
//	certain elements of the device-independent record.
//
void
Convert2DevMode( LPTWINDEVMODE lpDevMode )
{
	TPPrint		pPrint = &lpDevMode->tPrint;
	Rect*		rPage = &pPrint->prInfo.rPage;

	if ( rPage->bottom > rPage->right )
		lpDevMode->devMode.dmOrientation = DMORIENT_PORTRAIT;
	else
		lpDevMode->devMode.dmOrientation = DMORIENT_LANDSCAPE;
	lpDevMode->devMode.dmPaperSize		= 0;	//	Use length and width that follow
	lpDevMode->devMode.dmPaperLength	= rPage->bottom - rPage->top;
	lpDevMode->devMode.dmPaperWidth		= rPage->right - rPage->left;
	lpDevMode->devMode.dmCopies			= pPrint->prJob.iCopies;
	lpDevMode->devMode.dmPrintQuality	= pPrint->prInfo.iHRes;
	lpDevMode->devMode.dmYResolution	= pPrint->prInfo.iVRes;
}


#ifdef	COMMENT
/****************SetUpOffscreenDLOG ************************/
/*
*				„Sets up the standard print job dialog
*				„ moves it offscreen
*				„ "displays" it (unseen to user)
*				„ Simulates "OK" click
*				„ Cleans up dialog
*				„ returns ptr to print job Dialog
*/
/********************** ************************/
pascal TPrDlg *SetUpOffscreenDLOG( hPrint )
{

		ModalFilterUPP   theModalFilterProc;
		TPrDlg	*pPrDlog;

  				pPrDlog =(TPrDlg *) NewPtrClear(sizeof(TPrDlg));
  			
  				pPrDlog = PrJobInit((THPrint )hPrint);
				MoveWindow((GrafPort *)&( pPrDlog->Dlg.window), 3000, 3000, 1);
	
				theModalFilterProc = NewModalFilterProc( ModalDLOGFilter);
	
				pPrDlog->pFltrProc = theModalFilterProc;
		
		
	return(pPrDlog);
 } /*SetUpOffscreenDLOG */

/****************ModalDLOGFilter ************************/
/*
*				„FilterProc for PrintJobDLOG
*/
/********************** ************************/
pascal Boolean	ModalDLOGFilter(DialogPtr theDialog, EventRecord *theEvent,  short *itemHit){

		*itemHit = 1;		/* simulate OK Click */
		return TRUE;			/* Click Was Handled */

}

#endif	//	COMMENT

