// ---------------------------------------------
// Monitor the print spool and prompt users to confirm print jobs
// ---------------------------------------------
DWORD CGreenPrintMonitorThread::OnSpoolMonitorThread(void)
{
	DWORD cchPrinterName = 0;

	// ---------------------------------------------
	// Get the buffer size needed to hold the printer name
	// ---------------------------------------------
	GetDefaultPrinter( NULL, &cchPrinterName );

	if ( cchPrinterName > 0 )
	{
		WCHAR *PrinterName = (WCHAR*)LocalAlloc( LMEM_ZEROINIT, cchPrinterName * sizeof(WCHAR) );

		if ( NULL != PrinterName )
		{
			// ---------------------------------------------
			// Get the name of the print
			// ---------------------------------------------
			if ( GetDefaultPrinter( PrinterName, &cchPrinterName ) )
			{
				HANDLE hPrinter = NULL;

				if ( OpenPrinter( PrinterName, &hPrinter, NULL ) )
				{
					HANDLE hChangeNotification = NULL;

					// ---------------------------------------------
					// Setup the structures needed to register for print spool notifications
					// ---------------------------------------------

					PRINTER_NOTIFY_INFO_DATA NotifyInfoData[] = {
						JOB_NOTIFY_TYPE,
						JOB_NOTIFY_FIELD_TOTAL_PAGES,
						0, // Reserved
						JOB_NOTIFY_TYPE,
						0
					};

					PRINTER_NOTIFY_OPTIONS_TYPE NotifyOptionsType[] = {
						JOB_NOTIFY_TYPE,
						0, // Reserved 0
						0, // Reserved 1
						0, // Reserved 2
						_countof(NotifyInfoData),
						(PWORD)NotifyInfoData
					};

					PRINTER_NOTIFY_OPTIONS NotifyOptions;
					ZeroMemory( &NotifyOptions, sizeof(NotifyOptions) );
					NotifyOptions.Version = 2;
					NotifyOptions.Count = _countof(NotifyOptionsType);
					NotifyOptions.pTypes = NotifyOptionsType;

					// ---------------------------------------------
					// Request a notification handle that will be signaled when a new print job is queued
					// ---------------------------------------------
					hChangeNotification = 
						FindFirstPrinterChangeNotification( 
						hPrinter, 
						PRINTER_CHANGE_ADD_JOB, 
						0, // Reserved 
						&NotifyOptions
						);

					if ( INVALID_HANDLE_VALUE != hChangeNotification )
					{
						do
						{
							// ---------------------------------------------
							// The order of these handles is important to the code below that checks which event was signaled
							// ---------------------------------------------
							HANDLE HandleList[] = {
								hChangeNotification, 
								m_hExitSpoolMonitorThread
							};

							// ---------------------------------------------
							// Wait for the print job notification handle or the exit handle to be signaled
							// ---------------------------------------------
							DWORD WaitReason = WaitForMultipleObjects( 
								_countof(HandleList), 
								HandleList, 
								FALSE, 
								INFINITE );

							if ( WAIT_OBJECT_0 == WaitReason )
							{
								PRINTER_NOTIFY_INFO *pPrinterNotifyInfo = NULL;

								// ---------------------------------------------
								// The notification handle was signaled so get the info about the print job
								// ---------------------------------------------
								if ( FindNextPrinterChangeNotification( 
										hChangeNotification,
										NULL,
										&NotifyOptions,
										(LPVOID*)&pPrinterNotifyInfo ) )
								{
									if ( NULL != pPrinterNotifyInfo )
									{
										// ---------------------------------------------
										// Required code to make the FindNextPrinterChangeNotification happy (see MSDN documentation)
										// ---------------------------------------------
										if ( PRINTER_NOTIFY_INFO_DISCARDED & pPrinterNotifyInfo->Flags )
										{
											FreePrinterNotifyInfo( pPrinterNotifyInfo );
											pPrinterNotifyInfo = NULL;

											DWORD Flags = NotifyOptions.Flags;

											NotifyOptions.Flags = PRINTER_NOTIFY_OPTIONS_REFRESH;

											FindNextPrinterChangeNotification( 
													hChangeNotification,
													NULL,
													&NotifyOptions,
													(LPVOID*)&pPrinterNotifyInfo );

											NotifyOptions.Flags = Flags;
										}
									}

									// ---------------------------------------------
									// Get the needed information from the job
									// ---------------------------------------------
									DWORD JobId = 0;
									DWORD JobPages = 0;

									if ( NULL != pPrinterNotifyInfo )
									{
										GetJobInfoFromPrinterNotifyInfo( pPrinterNotifyInfo, &JobId, &JobPages );

										FreePrinterNotifyInfo( pPrinterNotifyInfo );
										pPrinterNotifyInfo = NULL;
									}

									// ---------------------------------------------
									// Pause the print job 
									// ---------------------------------------------
									if ( SetJob( hPrinter,
											JobId,
											0,
											NULL,
											JOB_CONTROL_PAUSE ) )
									{
										// ---------------------------------------------
										// If we weren't able to get the number of pages already
										// then get the count from the job itself
										// ---------------------------------------------
										if ( 0 == JobPages )
										{
											JobPages = JobPagesFromJobId( hPrinter, JobId );
										}

										// ---------------------------------------------
										// Interact with the user to determine if they would really like to print
										// ---------------------------------------------
										BOOL ResumeJob = ShouldResumePrintJob( JobPages );
										
										if ( ResumeJob )
										{
											if ( !SetJob( hPrinter,
												JobId,
												0,
												NULL,
												JOB_CONTROL_RESUME ) )
											{
												m_pLogging->Log( L"Failed resuming print job." );
											}
										}
										else
										{
											if ( !SetJob( hPrinter,
												JobId,
												0,
												NULL,
												JOB_CONTROL_DELETE ) )
											{
												m_pLogging->Log( L"Failed deleting print job." );
											}											
										}
									}
								}
								else
								{
									m_pLogging->Log( L"Failed getting information concerning a print job." );
								}
							}
							else if ( ( WAIT_OBJECT_0 + 1 ) == WaitReason ) 
							{
								// ---------------------------------------------
								// The exit handle was signaled. Stop checking for print jobs.
								// ---------------------------------------------
								break;
							}
							else
							{
								m_pLogging->Log( L"Unexpected notification while waiting for print job." );
							}
						}
						while( TRUE );
					}
					else
					{
						m_pLogging->Log( L"Failed trying to get print job notification handle." );
					}

					if ( INVALID_HANDLE_VALUE != hChangeNotification )
					{
						FindClosePrinterChangeNotification( hChangeNotification );
						hChangeNotification = NULL;
					}

					if ( NULL != hPrinter )
					{
						ClosePrinter( hPrinter );
						hPrinter = NULL;
					}
				}
			}

			if ( NULL != PrinterName )
			{
				cchPrinterName = 0;

				LocalFree( PrinterName );
				PrinterName = NULL;
			}
		}
	}

	return NO_ERROR;
}
JNIEXPORT jint JNICALL
Java_sun_print_Win32PrintServiceLookup_notifyPrinterChange(JNIEnv *env,
                                                           jobject peer,
                                                           jlong chgObject) {
    DWORD dwChange;

    DWORD ret = WaitForSingleObject((HANDLE)chgObject, INFINITE);
    if (ret == WAIT_OBJECT_0) {
        return(FindNextPrinterChangeNotification((HANDLE)chgObject,
                                                  &dwChange, NULL, NULL));
    } else {
        return 0;
    }
}
int main (int argc, char* argv[])
{
	
	HANDLE	server, change;
	PRINTER_NOTIFY_INFO	*change_info = NULL;
	PRINTER_NOTIFY_OPTIONS watch, *pWatch = NULL;
	PRINTER_NOTIFY_OPTIONS_TYPE data;
	DWORD option = PRINTER_CHANGE_PRINTER_DRIVER;
	BOOL use_notify_options = TRUE;
	DWORD	condition;
	DWORD flags = PRINTER_NOTIFY_OPTIONS_REFRESH;



	if ((argc < 3) || (strcmp(argv[1], "-l") && strcmp(argv[1], "-t")))
	{
		fprintf (stderr, "usage: -l|-t %s <servername>\n", argv[0]);
		exit (-1);
	}

	if (strcmp(argv[1], "-l") == 0)
		use_notify_options = FALSE;


	if (!OpenPrinter (argv[2], &server, NULL))
	{
		PrintLastError();
		exit (-1);
	}
	else
	{
		printf ("Printer [%s] opened successfully.\n\n", argv[2]);
	}

	printf ("flags = PRINTER_CHANGE_PRINTER\n");
	watch.Version = 2;
	watch.Count = 1;
	watch.pTypes = &data;
	data.Type = PRINTER_NOTIFY_TYPE;
	data.Count = 1;
	data.pFields = &option;

	if (use_notify_options) {
		pWatch = &watch;
		option = PRINTER_NOTIFY_FIELD_DRIVER_NAME;
	}

	if ((change=FindFirstPrinterChangeNotification(server, option, 0, pWatch)) == INVALID_HANDLE_VALUE)
	{
		printf ("FindFirstPrinterChangeNotification failed : ");
		PrintLastError();
		ClosePrinter(server);
		exit (-1);
	}
	else
		printf ("FindFirstPrinterChangeNotification succeeded with flags [PRINTER_CHANGE_PRINTER_DRIVER]\n\n");

	if (pWatch) {
		printf ("Calling FindNextPrinterCangeNotification() with PRINTER_NOTIFY_OPTIONS_REFRESH\n");
		memset(&watch, 0x0, sizeof(watch));
		watch.Flags = PRINTER_NOTIFY_OPTIONS_REFRESH;
		watch.Version = 2;
		if (FindNextPrinterChangeNotification(change, &condition, pWatch, &change_info))
			printf ("Received change notification of [0x%x]\n", condition);
		else
			PrintLastError();

		if (change_info) {
			int i;

			printf("\tVersion\t=0x%x\n", change_info->Version);
			printf("\tFlags\t=0x%x\n", change_info->Flags);
			printf("\tCount\t=%d\n", change_info->Count);

			for (i=0; i<(int)change_info->Count; i++) {
				PrintNotifyInfoData(&change_info->aData[i]);
				printf("\n");
			}
		}

		FreePrinterNotifyInfo(change_info);
		printf ("\n");
	}

	do 
	{

		printf ("Waiting for Printer Change Notification...\n");

		if (WaitForSingleObject(change, INFINITE) != WAIT_OBJECT_0)
			continue;

		if (FindNextPrinterChangeNotification(change, &condition, NULL, &change_info))
			printf ("Received change notification of [0x%x]\n", condition);
		else
			PrintLastError();

		if (change_info) {
			int i;

			printf("\tVersion\t=0x%x\n", change_info->Version);
			printf("\tFlags\t=0x%x\n", change_info->Flags);
			printf("\tCount\t=%d\n", change_info->Count);

			for (i=0; i<(int)change_info->Count; i++) {
				PrintNotifyInfoData(&change_info->aData[i]);
				printf("\n");
			}
		}

		FreePrinterNotifyInfo(change_info);
		printf ("\n");
	} while (1);
	

	if (FindClosePrinterChangeNotification(change))
		printf ("FindClosePrinterChangeNotification call succeeded.\n");
	else
	{
		printf ("FindClosePrinterChangeNotification failed : ");
		PrintLastError();
	}
	printf ("\n");

	if (!ClosePrinter(server))
		PrintLastError();
	else
		printf ("Printer [%s] closed successfully.\n", argv[2]);

	return 0;

}