/*
    ####             #    #     # #
    #   #            #    #       #          The FreeWare C library for 
    #   #  ##   ###  #  # #     # ###             RISC OS machines
    #   # #  # #     # #  #     # #  #   ___________________________________
    #   # ####  ###  ##   #     # #  #                                      
    #   # #        # # #  #     # #  #    Please refer to the accompanying
    ####   ### ####  #  # ##### # ###    documentation for conditions of use
    ________________________________________________________________________

    File:    Print.c
    Author:  Copyright  1995 Julian Smith.
    Version: 1.01 (14 Nov 1995)
    Purpose: Printing.
    History: 1.00
             1.01 (14 Nov 1995) JS Made SDLS compatible.
*/

#include <stdlib.h>
#include <stdio.h>

#include "Desk.Wimp.h"
#include "Desk.WimpSWIs.h"
#include "Desk.PDriver.h"
#include "Desk.Error.h"
#include "Desk.File.h"
#include "Desk.Event.h"
#include "Desk.DeskMem.h"

#include "Desk.Print.h"



typedef enum	{
	Desk_print__progress_2,
	Desk_print__progress_4_5,
	Desk_print__progress_5,
	Desk_print__progress_6,
	Desk_print__progress_7
	}
	Desk_print__progress;
	/* These correspond to the numbered paragraphs in PRMs 3-259.	*/


typedef struct	{

	Desk_print_block	public;
	
	int			Desk_message_ref;	/* id of the last Desk_event_SENDWANTACK we sent.	*/
	Desk_print__progress	progress;
	Desk_print_printfn	printfn;
	Desk_print_savefn	savefn;
	Desk_print_resultfn	resultfn;
	}
	Desk_print__block;


static void	Desk_Print__ClaimMessages( Desk_print__block *print);
static void	Desk_Print__ReleaseMessages( Desk_print__block *print);

static void	Desk_Print__Finish( 
	Desk_print__block	*print, 
	Desk_bool			releasemsgs, 
	Desk_print_result	result
	);



static void	Desk_Print__PrintIt( Desk_print__block *print)
	/* This is called when the Wimp messaging between us	*/
	/* and !Printers has finished.				*/
{
Desk_os_error	*error;

Desk_Print__ReleaseMessages( print);

error =  Desk_PDriver_Info( &print->public.printerinfo);
if (error)	{
	Desk_Print__Finish( print, Desk_bool_FALSE, (Desk_print_result) error);
	return;
	}

print->public.job = Desk_File_Open( "Printer:", Desk_file_WRITE);
if ( !print->public.job)	{
	Desk_Print__Finish( print, Desk_bool_FALSE, Desk_print_result_CANTOPENPRINTER);
	return;
	}

error = Desk_PDriver_SelectJob( print->public.job, print->public.jobtitle, &print->public.oldjob);
if (error)	{
	Desk_Print__Finish( print, Desk_bool_FALSE, (Desk_print_result) error);
	return;
	}

print->printfn( &print->public);

Desk_PDriver_EndJob( print->public.job);
Desk_File_Close( print->public.job);

Desk_Print__Finish( print, Desk_bool_FALSE, Desk_print_result_OK);

return;
}





/*
#ifndef Desk_message_PRINTERROR
#define Desk_message_PRINTERROR 0x80144
#endif

#ifndef Desk_message_PRINTSAVE
#define Desk_message_PRINTSAVE 0x80142
#endif
*/


#define Desk_Message_IsBounce( event, oldref)			\
	( 							\
		(event)->type==Desk_event_USERMESSAGEACK		\
		&& 						\
		(event)->data.message.header.myref==(oldref)	\
	) 							\
	? 							\
	Desk_bool_TRUE : Desk_bool_FALSE;						\
	/* This returns Desk_bool_TRUE if the event is our message being	*/
	/* returned to us by the wimp.				*/

#define Desk_Message_IsReply( event, oldref)						\
	( (event)->data.message.header.yourref == (oldref)) ? Desk_bool_TRUE : Desk_bool_FALSE	\




Desk_SDLS_PtrFn(
	static,
	Desk_bool,
	Desk_Print__MessageHandler( Desk_event_pollblock *event, void *reference)
	)
/* cc warns about extern ... not declared in header in SDLS compiles	*/
{
Desk_print__block	*print = (Desk_print__block *) reference;
Desk_bool			reply;
Desk_bool			bounced;

reply	= Desk_Message_IsReply( event, print->Desk_message_ref);
bounced	= Desk_Message_IsBounce( event, print->Desk_message_ref);


if ( print->progress == Desk_print__progress_2)	{

	if ( bounced)		{
		/* PrintSave message bounced...	*/
		if ( print->printfn)	Desk_Print__PrintIt( print);
		else	Desk_Print__Finish( print, Desk_bool_TRUE, Desk_print_result_NEEDPRINTERMANAGER);
			
		return Desk_bool_TRUE;
		}
	
	else if ( reply && event->data.message.header.action == Desk_message_PRINTERROR)	{
		Desk_Print__Finish( print, Desk_bool_TRUE, Desk_print_result_PRINTERROR);
		return Desk_bool_TRUE;
		}
	
	else if ( reply && event->data.message.header.action == Desk_message_PRINTFILE)	{
		print->progress = Desk_print__progress_4_5;
		return Desk_bool_TRUE;
		}
	
	else if ( reply && event->data.message.header.action == Desk_message_DATASAVEACK)	{
		print->progress = Desk_print__progress_4_5;
		}
	}


if ( print->progress == Desk_print__progress_4_5)	{

	if ( /*reply &&*/ event->data.message.header.action == Desk_message_PRINTTYPEODD)	{
		Desk_message_block	message = event->data.message;
		
		if ( print->printfn)	{
			/* We can print the file ourselves...	*/
			message.header.action	= Desk_message_PRINTTYPEKNOWN;
			message.header.yourref	= event->data.message.header.myref;
			message.header.size	= 256;
			Desk_Wimp_eSendMessage( 
				Desk_event_SEND, 
				&message, event->data.message.header.sender, 
				0
				);
				/* This is the last message of the protool, so we don't	*/
				/* want it returned if not replied to.			*/
			Desk_Print__PrintIt( print);
			return Desk_bool_TRUE;
			}
		
		else	{
			/* We can't print directly, so we ignore Desk_message_PRINTTYPEODD	*/
			/*  - printers will send DATASAVEACK next	*/
			}
			
		return Desk_bool_TRUE;
		}
	
	else if ( reply && event->data.message.header.action == Desk_message_DATASAVEACK)	{
		/* Save the file, for queing etc., to the filename specified. Then send	*/
		/* Desk_message_DATALOAD.							*/
		/* wait for file to reach top of thr printer queue, 			*/
		/* whereapon printers will send us a Desk_message_PRINTTYPEODD.		*/
		/* Note that Desk_Print_ doesn't deal with a broadcast PRINTTYPEODD.		*/

		print->progress = Desk_print__progress_6;
		if ( print->savefn)	{
			Desk_message_block	reply;
			Desk_bool		error;
			
			error = print->savefn( 
				&print->public, &event->data.message.data.datasaveack
				);
			if (error)	{
				/* Couldn't save file.	*/
				/*Desk_Error_Report( 0, "Couldn't save the data to be printed");*/
				/* Leave savefn to report the error.	*/
				Desk_Print__Finish( print, Desk_bool_TRUE, Desk_print_result_SAVEFAILED);
				return Desk_bool_TRUE;
				}
			
			reply = event->data.message;
			reply.header.action	= Desk_message_DATALOAD;
			reply.header.yourref	= event->data.message.header.myref;
			Desk_Wimp_eSendMessage( 
				Desk_event_SENDWANTACK, 
				&reply, 
				event->data.message.header.sender,
				0
				);
			print->Desk_message_ref = reply.header.myref;
			
			print->progress = Desk_print__progress_7;
			return Desk_bool_TRUE;
			}
		
		else	{
			Desk_Error_Report( 0, 
				"Printer busy, and we are unable to save "
				"data to be printed to printer queue"
				);
			Desk_Print__Finish( print, Desk_bool_TRUE, Desk_print_result_CANTSAVE);
			}
			
		return Desk_bool_TRUE;
		}
	}

if ( print->progress == Desk_print__progress_7)	{
	if ( bounced)	{
		Desk_Error_Report( 0, "Print bounced, Desk_progress_7");
		Desk_Print__Finish( print, Desk_bool_TRUE, Desk_print_result_FAILED);
		return Desk_bool_TRUE;
		}	
		
	if ( reply && event->data.message.header.action == Desk_message_DATALOADACK)	{
		Desk_Print__Finish( print, Desk_bool_TRUE, Desk_print_result_QUEUED);
		return Desk_bool_TRUE;
		}
	}


if (reply)	{
	Desk_Error_ReportInternal( 0, 
		"Unrecognised print reply %i, progress %i", 
		event->data.message.header.action,
		print->progress
		);
	Desk_Print__Finish( print, Desk_bool_TRUE, Desk_print_result_FAILED);
	return Desk_bool_TRUE;
	}

return Desk_bool_FALSE;
}




void	Desk_Print_StartPrint( 
		Desk_print_printfn	printfn,
		Desk_print_savefn	savefn,
		Desk_print_resultfn	resultfn,
		void			*reference, 
		int			filetype,
		int			estsize,
		char			*leafname,
		char			*jobtitle
		)
{
Desk_message_block	message;
Desk_print__block	*print = (Desk_print__block *) Desk_DeskMem_Malloc( sizeof( Desk_print__block));

print->printfn	= printfn;
print->savefn	= savefn;
print->resultfn	= resultfn;
print->public.reference	= reference;
print->public.jobtitle	= jobtitle;

message.header.action		= Desk_message_PRINTSAVE;
message.header.size		= 256;
message.data.print.filler[4]	= estsize;
message.data.print.filetype	= filetype;
message.header.yourref		= 0;		/* not a reply*/
sprintf( message.data.print.filename, leafname);
Desk_Wimp_eSendMessage( Desk_event_SENDWANTACK, &message, 0, 0);
print->Desk_message_ref = message.header.myref;

Desk_Print__ClaimMessages( print);

print->progress = Desk_print__progress_2;

return;
}






static void	Desk_Print__ClaimMessages( Desk_print__block *print)
{
Desk_Event_Claim( Desk_event_USERMESSAGE, 		Desk_event_ANY, Desk_event_ANY, Desk_SDLS_dllEntry( Desk_Print__MessageHandler), print);
Desk_Event_Claim( Desk_event_USERMESSAGERECORDED, 	Desk_event_ANY, Desk_event_ANY, Desk_SDLS_dllEntry( Desk_Print__MessageHandler), print);
Desk_Event_Claim( Desk_event_ACK, 			Desk_event_ANY, Desk_event_ANY, Desk_SDLS_dllEntry( Desk_Print__MessageHandler), print);
}

static void	Desk_Print__ReleaseMessages( Desk_print__block *print)
{
Desk_Event_Release( Desk_event_USERMESSAGE, 		Desk_event_ANY, Desk_event_ANY, Desk_SDLS_dllEntry( Desk_Print__MessageHandler), print);
Desk_Event_Release( Desk_event_USERMESSAGERECORDED, 	Desk_event_ANY, Desk_event_ANY, Desk_SDLS_dllEntry( Desk_Print__MessageHandler), print);
Desk_Event_Release( Desk_event_ACK, 			Desk_event_ANY, Desk_event_ANY, Desk_SDLS_dllEntry( Desk_Print__MessageHandler), print);
}



static void	Desk_Print__Finish( 
	Desk_print__block	*print, 
	Desk_bool			releasemsgs, 
	Desk_print_result	result
	)
{
if ( print->resultfn)	print->resultfn( &print->public, result);
if ( releasemsgs)	Desk_Print__ReleaseMessages( print);
Desk_DeskMem_Free( print);
}

