{************************************************************************
 ***                                                                  ***
 ***                PRINTER DEVICES & FILTERS                         ***
 ***                                                                  ***
 ************************************************************************}
{$I compdirs}

unit printers;

INTERFACE

uses devices, kamsetup, setup,
			tuimsgs, tuiedit,
			files,
			forms,{}
			objects;

const
	PrinterDeviceExt = 'PRD';
	PrinterFilterExt = 'PRF';

type
	PPrinterStream = ^TPrinterStream;
	TPrinterStream = object(TDeviceStream)

		DoCheckPort : boolean;    {marks whether to check the bios port}
		DoCheckBusy : boolean; 		{some printers return busy a lot - ignore if not checked}

		DefFilter : string[8];	{default filter name}
		DefPaper  : string[8];	{default paper name}
		DefLabels : string[8];	{default labels name}

		{--- Stream Admin methods ---}
		constructor Init;
		procedure CheckStatus(Msg : TMessageStr); virtual;
		procedure UpdateStatus; virtual;
		procedure SetNulFilter; virtual;

		{for getting info about printer}
		procedure CheckPort(Byte1, Byte2 : byte); {Internal method for checking hardware printer status}
		function  CheckDos : byte;              {Internal method for checking printer via DOS interrupt}

		{Overriders}
		procedure EndPrint; virtual; {End ordinary print - closes file}

		{editable...}
		procedure AddEditFields(EditBox : PEditBox); virtual;
		constructor Load(var S : TDataStream);
		procedure Store(var S : TDataStream);
	end;


const
	ESCStrLen = 90;

type
	TESCStr = string[ESCStrLen];

	PPrinterFilter = ^TPrinterFilter;
	TPrinterFilter = object(TDeviceFilter)

			Portrait : TESCStr;
			LandScape : TESCStr;

			BoldOn : TESCStr;
			BoldOff : TESCStr;
			UnderOn : TESCStr;
			UnderOff : TESCStr;
			ItalicsOn : TESCStr;
			ItalicsOff : TESCStr;
			LargeOn : TESCStr;
			LargeOff : TESCStr;
			NLQ : TESCStr;
			Draft : TESCStr;

			LPI4 : TESCStr;
			LPI6 : TESCStr;
			LPI8 : TESCStr;

			CPI10: TESCStr;
			CPI12 : TESCStr;
			CPI15 : TESCStr;

			ibmChars : string; {IBM character set ie box drawing - extra long in case of defining chars - see epson driver!}

			Currency : char;

			User : array[1..4] of	record	{set up user-definable codes, eg colours}
				FormCode 	: string[4];
				ESCCode 	: TESCStr;
			end;

		function Edit : word; virtual;
		constructor Load(var S : TDataStream);
		procedure Store(var S : TDataStream);
		procedure SetFormCodes(const FormCodes : PFormCodeCollection); virtual;
	end;

function EditPrinterFilter(var FullFileName : FNameStr; const Ext : string) : word;
function EditPrinterDEvice(var FullFileName : FNameStr; const Ext : string) : word;

const
	{Standard nul/screen filter}
	NulPrinterFilter : TPrinterFilter = (Name : 'NUL'; InitSeq : '';
																FormFeed : #12;
																PagePause : False;
																Portrait : ''; Landscape : '';
																BoldOn : ''; BoldOff : ''; UnderOn : ''; UnderOff : '';
																ItalicsOn : ''; ItalicsOff : '';
																LargeOn : ''; LargeOff : ''; NLQ : ''; Draft : '';
																lpi4 : ''; lpi6 : ''; lpi8 : '';
																cpi10 : ''; cpi12 : ''; cpi15 : '';
																IBMChars : '';
																Currency : Global.PoundSign
																);


var
	Printer : PPrinterStream;                        {Global channel}
	PrinterName : string[8];			{name of current printer driver}

IMPLEMENTATION

uses 	global,
			tui,views,dialogs, {text}
			tuiboxes, tuiapp,
			dosUtils, {filename processing}
			drivers, minilib, dos, app,
			help,
			inpfname,
			tasks;

const
	peError      = $01;

	peTimeOut    = $02;
	peOutOfPaper = $04;
	peBusy       = $08;
	peIOError    = $10;
	peNotSelected = $20;

	msPrintErr : array[0..7] of string = ('OK','Error','Timeout','Out of Paper',
																				'Busy','I/O Error','Off Line','');

{*********************************
 ***   SPECIALISED ERROR BOX   ***
 *********************************}

type
	PPrinterStatusBox = ^TPrinterStatusBox;
	TPrinterStatusBox = object(TMessageBox)
		OldErrorInfo : byte;
		Printer : PPrinterStream;
		constructor Init(NPrinter : PPrinterStream);
		{$IFDEF MSDOS} procedure HAndleEvent(var Event : TEVent); virtual; {$ENDIF}
		procedure Idle; virtual;
	end;

constructor TPrinterStatusBox.Init;
begin
	{--- Create & Insert Error Box ------}
	inherited Init('PRINTER PROBLEM',space(22),mfWarning + mfCancelButton, hcPrinterStatusBox);
	IdleOff := False; {TMessageBox turns it off, we want it on for continuously
											checking the printer status}
	OldErrorInfo := 0;
	Printer := NPrinter;
	if Printer^.ErrorInfo<>0 then WarningBleep;
	Options := Options or ofIdle; {so idle is done}
	Idle;
end;

{$IFDEF MSDOS}
procedure TPrinterStatusBox.HandleEvent;
begin
{	if Event.What = evNothing then Idle;{}

	inherited HandleEvent(Event);
end;
{$ENDIF}

procedure TPrinterStatusBox.Idle;
var S : TMessageStr;
begin
	with Printer^ do begin
		{see if status has changed}
		UpdateStatus;

		if Status = stOK then
			{error has gone}
			EndModal(cmOK) 				{end box}
		else
			{error still there}
			if OldErrorInfo <> ErrorInfo then begin
				{error has changed, so update screen message}

				OldErrorInfo := ErrorInfo;

				{$IFDEF Fixit}
					S := '     DOS AH: $'+Hex(Printer^.ErrorInfo)+'     '#13;
				{$ELSE}
					S := 'Check Printer & Cables'+#13;
				{$ENDIF}

				{work out message from errorinfo}
				if (ErrorInfo and peTimeOut)   <>0  then S := S + msPrintErr[2]+' ';
				if (ErrorInfo and peOutOfPaper )<>0 then S := S + msPrintErr[3]+' ';
				if (ErrorInfo and peNotSelected)<>0 then S := S + msPrintErr[6]+' ';

				{If not a specific error, then check for general ones. (O/w the general
				ones appear as well - ie NotSelected alse results in Busy & IO Error)}
				if (ErrorInfo and (peOutOfPaper or peNotSelected))=0 then begin
					if (ErrorInfo and peError)     <>0  then S := S + msPrintErr[1]+' ';
					if (ErrorInfo and peBusy       )<>0 then S := S + msPrintErr[4]+' ';
					if (ErrorInfo and peIOError    )<>0 then S := S + msPRintErr[5]+' ';
				end;

				SetMessage(S);
			end;
	end;
end;


{*******************************************************
 ***                   PRINTER STREAM                ***
 *******************************************************}
constructor TPrinterStream.init;
begin
	inherited Init('Printer Device','LPT1');

	DoCheckPort := True;
	DoCheckBusy := False;
end;


{==== CHECK STATUS ================}
{Rather than check ioresult, looks first at port details}
procedure TPrinterStream.UpdateStatus;
var B : byte;
begin
	Status := stOK; ErrorInfo := 0;

	inherited UpdateStatus; {checks IOResult}
	if ErrorInfo = 16 then begin Status := stOK; ErrorInfo := 0; end; {don't know what this is, but ignore it}

	if DoCHeckPort and (Status=stOK) then begin
		B := CheckDos;
		ErrorInfo := 0;

		{translate error info}
		if (B and $01)>0 then ErrorInfo := ErrorInfo OR peTimeOut;
		if (B and $02)>0 then ErrorInfo := ErrorInfo OR peError;
		if (B and $04)>0 then ErrorInfo := ErrorInfo OR peError;
		if (B and $08)>0 then ErrorInfo := ErrorInfo OR peIOError;
		if (B and $10)=0 then ErrorInfo := ErrorInfo OR peNotSelected;
		if (B and $20)>0 then ErrorInfo := ErrorInfo OR peOutOfPaper;
		if (B and $40)>0 then ErrorInfo := ErrorInfo OR peError;
		if DoCheckBusy then if (B and $80)=0 then ErrorInfo := ErrorInfo OR peBusy;{ignore}
	end;
end;


{=== CHECK PORT ===================}
procedure TPrinterStream.CheckPort;
var
	P : ^Byte;

begin
	P := ptr($3BE, $0); Byte1 := P^;
	P := ptr($3BD, $0); Byte2 := P^;
end;

{=== CHECK DOS STATUS =============}
function TPrinterStream.CheckDos;
var
	Reg : Registers;

begin
	Reg.AH := $02;  {Request Status}
	Reg.DX := $00;  {LPT1}

	Intr($17,Reg);
	CheckDos := Reg.AH;
end;


procedure TPrinterStream.CheckStatus;
var	ErrorBox : PPrinterStatusBox;
		Control : word;
begin
	UpdateStatus;

	if (Status <> stOK) and (ErrorInfo <> peBusy) then begin {if only busy, it's OK}
		{--- Create & Insert Error Box ------}
		New(ErrorBox, Init(@Self));
		Control := Desktop^.ExecView(ErrorBox);
		Dispose(ErrorBox,Done);
		if Control = cmCancel then Status:= stAbandoned else Reset;
	end;
end;


{==== END PRINT =====================}
procedure TPrinterStream.EndPrint;
begin
	inherited EndPrint;

	{switch back to defaults}
	with PPrinterFilter(Filter)^ do begin
		LoadCodes(LandScape);
		LoadCodes(cpi10);
		LoadCodes(lpi6);
	end;
	SetPaper(GetPaper(PrintersPath+DefPaper+'.'+PaperExt));{Do on .init and at endprint, so that it can
															be overriden before startprint}

	Close; {close printer channel to release for other apps}
end;


procedure TPrinterStream.SetNulFilter;
begin
	Filter := New(PPrinterFilter, init('Nul')); Filter^ := NulPrinterFilter;
end;

{**************************************
 ***       SPECIAL PRINTER STATUS   ***
 **************************************}
procedure TPrinterStream.AddEditFields(EditBox : PEditBox);
var R : TRect;
begin
	with EditBox^ do begin
		GrowTo(Size.X, Size.Y+2);
		HelpCtx := hcEditPrinter;

		{skip fields to end of devicestream}
		InsTitledField(12,  2, 8, 1, '~P~ort', New(PInputELine, init(R,8)));

		Insert(New(PSkipBytes, init(sizeof(TDeviceStream)-DataSize)));

		InsTitledField(12,  3, 1, 1, 'C~h~eck Port', New(PInputBoolean, init(R)));
		InsTitledField(12,  4, 1, 1, 'Check ~B~usy', New(PInputBoolean, init(R)));

		InsTitledField(12,  6, 8, 1, '~F~ilter',
															New(PinputFName, Init(R, 8, PrinterFilterExt, PrintersPath, True, EditPrinterFilter)));
		Current^.HelpCtx := hcEditFilter;
		InsTitledField(12,  7, 8, 1, '~P~aper', 	New(PinputFName, Init(R, 8, PaperExt, PrintersPath, True, EditPaper)));
		Current^.HelpCtx := hcEditPaper;
		InsTitledField(12,  8, 8, 1, '~L~abels', 	New(PinputFName, Init(R, 8, LabelPaperExt, PrintersPath, True, EditPaper)));
		Current^.HelpCtx := hcEditLabels;
	end;
end;

constructor TPrinterStream.Load(var S : TDataStream);
var Ver : byte;
begin
	S.Read(Ver, 1);
	case Ver of
		1 : begin
			inherited Load(S);
			S.Read(DoCheckPort,1);
			DoCheckBusy := False;
			DefFilter := S.ReadStr;
			DefPaper := S.ReadStr;
			DefLabels := S.ReadStr;
		end;
		2 : begin
			inherited Load(S);
			S.Read(DocheckPort,1);
			S.Read(DocheckBusy,1);
			DefFilter := S.ReadStr;
			DefPaper := S.ReadStr;
			DefLabels := S.ReadStr;
		end;
	end;

	SetFilter(GetFilter(PrintersPath+DefFilter+'.'+PrinterFilterExt));
	SetPaper(GetPaper(PrintersPath+DefPaper+'.'+PaperExt));
end;

procedure TPrinterStream.Store(var S : TDataStream);
var Ver : byte;
begin
	Ver := 2; S.Write(Ver, 1);
	inherited Store(S);
	S.Write(DoCheckPort,1);
	S.Write(DoCheckBusy,1);
	S.WriteStr(@DefFilter);
	S.WriteStr(@DefPaper);
	S.WriteStr(@DefLabels);
end;


{*********************************************
 ***         PRINTER FILTER                ***
 *********************************************}

function TPrinterFIlter.Edit : word;
var EditBox : PObjectEditBox;
		R : TREct;
		I : word;
begin
	R.Assign(0,0,58,23);
	New(EditBox, init(R, 'PRINTER FILTER',nil));

	with EditBox^ do begin
		 Options := Options or ofCenterX or ofCenterY;
		 HelpCtx := hcEditFilter;

		 {--- Set up box interior ---}
		 { X, Y, Boxlen,  depth, FieldLen,     Title}
		 InsTitledBox(  12, 1,  30, 1, '~N~ame', 30);
		 InsTitledBox(  12, 3,  15, 1, '~I~nit', 50);
		 InsTitledField(12, 4,   4, 1, '~F~orm Feed', New(PInputByte, Init(R, 4)));
		 InsTitledField(12, 5,   1, 1, '~P~age Pause', New(PInputBoolean, init(R)));

		 InsTitledBox(38, 3,  15, 1, 'Portrait', ESCStrLen);
		 InsTitledBox(38, 4,  15, 1, 'Landscape', ESCStrLen);

		 InsTitledBox(  12, 7,  15, 1, '~B~old On', ESCStrLen);
		 InsTitledBox(  12, 8,  15, 1, 'Off', ESCStrLen);
		 InsTitledBox(  12, 9,  15, 1, '~U~/line On', ESCStrLen);
		 InsTitledBox(  12,10,  15, 1, 'Off', ESCStrLen);
		 InsTitledBox(  12,11,  15, 1, 'I~t~alics On', ESCStrLen);
		 InsTitledBox(  12,12,  15, 1, 'Off', ESCStrLen);
		 InsTitledBox(  12,13,  15, 1, '~L~arge On', ESCStrLen);
		 InsTitledBox(  12,14,  15, 1, 'Off', ESCStrLen);
		 InsTitledBox(  12,15,  15, 1, 'NL~Q~', ESCStrLen);
		 InsTitledBox(  12,16,  15, 1, 'Draft', ESCStrLen);

		 InsTitledBox(  12,18,  15, 1, 'lpi 4', ESCStrLen);
		 InsTitledBox(  12,19,  15, 1, '6', ESCStrLen);
		 InsTitledBox(  12,20,  15, 1, '8', ESCStrLen);

		 InsTitledBox(  38, 7,  15, 1, 'cpi 10', ESCStrLen);
		 InsTitledBox(  38, 8,  15, 1, '12', ESCStrLen);
		 InsTitledBox(  38, 9,  15, 1, '15', ESCStrLen);

		 InsTitledBox(  38,11,  15, 1, 'IB~M~', 255);

		 InsTitledField(38,13,   4, 1, 'C~u~rrency', New(PInputByte, Init(R,4)));

		 for I := 1 to 4 do begin
			 InsTitledBox(31,14+I, 4, 1, '', 4);
			 PInputELine(Current)^.UpperCase := True;
			 InsTitledBox(38,14+I,15, 1, '', ESCStrLen);
		 end;

		 {-- Buttons --}
		 InsOKButton(    37,Size.Y-3, @Self);
		 InsCancelButton(47,Size.Y-3);

		 SelectNext(False);

		 SetData(Self);
	 end;

	 Edit := Desktop^.ExecView(EditBox);

	 dispose(EditBox, done);
end;

constructor TPrinterFilter.Load;
var Ver : byte;
		T : string;
		I : word;
begin
	S.Read(Ver, 1);

	case Ver of
		4 : begin
			{added user codes}
			inherited Load(S);
			BoldOn 		:= S.ReadStr;
			BoldOff 	:= S.ReadStr;
			UnderOn 	:= S.ReadStr;
			UnderOff 	:= S.ReadStr;
			ItalicsOn := S.ReadStr;
			ItalicsOff := S.ReadStr;
			LargeOn := S.ReadStr;
			LargeOff := S.ReadStr;
			NLQ := S.REadStr;
			Draft := S.ReadStr;
			lpi4 := S.REadStr;
			lpi6 := S.REadStr;
			lpi8 := S.REadStr;
			cpi10 := S.ReadStr;
			cpi12 := S.ReadStr;
			cpi15 := S.ReadStr;
			S.Read(Currency,1);
			Portrait := S.ReadStr;
			Landscape := S.ReadStr;
			IBMChars := S.ReadStr;
			for I := 1 to 4 do begin
				User[I].FormCode := S.REadStr;
				User[I].ESCCode := S.ReadStr;
			end;
		end;
		3 : begin
			{added ibm char set, orientation}
			inherited Load(S);
			BoldOn 		:= S.ReadStr;
			BoldOff 	:= S.ReadStr;
			UnderOn 	:= S.ReadStr;
			UnderOff 	:= S.ReadStr;
			ItalicsOn := S.ReadStr;
			ItalicsOff := S.ReadStr;
			LargeOn := S.ReadStr;
			LargeOff := S.ReadStr;
			NLQ := S.REadStr;
			Draft := S.ReadStr;
			lpi4 := S.REadStr;
			lpi6 := S.REadStr;
			lpi8 := S.REadStr;
			cpi10 := S.ReadStr;
			cpi12 := S.ReadStr;
			cpi15 := S.ReadStr;
			S.Read(Currency,1);
			Portrait := S.ReadStr;
			Landscape := S.ReadStr;
			IBMChars := S.ReadStr;
			for I := 1 to 4 do begin
				User[I].FormCode := '';
				User[I].ESCCode := ''
			end;
		end;
		2 : begin
			inherited Load(S);
			BoldOn 		:= S.ReadStr;
			BoldOff 	:= S.ReadStr;
			UnderOn 	:= S.ReadStr;
			UnderOff 	:= S.ReadStr;
			ItalicsOn := S.ReadStr;
			ItalicsOff := S.ReadStr;
			LargeOn := S.ReadStr;
			LargeOff := S.ReadStr;
			NLQ := S.REadStr;
			Draft := S.ReadStr;
			lpi4 := S.REadStr;
			lpi6 := S.REadStr;
			lpi8 := S.REadStr;
			cpi10 := S.ReadStr;
			cpi12 := S.ReadStr;
			cpi15 := S.ReadStr;
			S.Read(Currency,1);
			Portrait := '';
			Landscape := '';
			IBMChars := '';
			for I := 1 to 4 do begin
				User[I].FormCode := '';
				User[I].ESCCode := ''
			end;
		end;
		1 : begin
			inherited Load(S);
			BoldOn 		:= S.ReadStr;
			BoldOff 	:= S.ReadStr;
			UnderOn 	:= S.ReadStr;
			UnderOff 	:= S.ReadStr;
			ItalicsOn := S.ReadStr;
			ItalicsOff := S.ReadStr;
			LargeOn := S.ReadStr;
			cpi10 := S.ReadStr;
			cpi12 := S.ReadStr;
			cpi15 := S.ReadStr;
			S.Read(Currency,1);
			LargeOff := '';
			NLQ := '';
			Draft := '';
			lpi4 := '';
			lpi6 := '';
			lpi8 := '';
			Portrait := '';
			Landscape := '';
			IBMChars := '';
			for I := 1 to 4 do begin
				User[I].FormCode := '';
				User[I].ESCCode := ''
			end;
		end;
	end;
end;

procedure TPrinterFilter.Store;
var Ver : byte;
		I : integer;
begin
	Ver := 4;	S.Write(Ver,1);
	inherited Store(S);
	S.WriteStr(@BoldOn);
	S.WriteStr(@BoldOff);
	S.WriteStr(@UnderOn);
	S.WriteStr(@UnderOff);
	S.WriteStr(@ItalicsOn);
	S.WriteStr(@ItalicsOff);
	S.WriteStr(@LargeOn);
	S.WriteStr(@LargeOff);
	S.WriteStr(@NLQ);
	S.WriteStr(@Draft);
	S.WriteStr(@lpi4);
	S.WriteStr(@lpi6);
	S.WriteStr(@lpi8);
	S.WriteStr(@cpi10);
	S.WriteStr(@cpi12);
	S.WriteStr(@cpi15);
	S.Write(Currency,1);
	S.WriteStr(@Portrait);
	S.WriteStr(@Landscape);
	S.WriteStr(@IBMChars);
	for I := 1 to 4 do begin
		S.WriteStr(@User[I].FormCode);
		S.WriteStr(@User[I].ESCCode);
	end;

end;

procedure TPrinterFilter.SetFormCodes(const FormCodes : PFormCodeCollection);
var I : integer;
begin
	inherited SetFormCodes(FormCodes);

	with FormCodes^ do begin
		SetStr('B+',DecodeESC(BoldOn));
		SetStr('B-',DecodeESC(BoldOff));
		SetStr('U+',DecodeESC(UnderOn));
		SetStr('U-',DecodeESC(UnderOff));
		SetStr('I+',DecodeESC(ItalicsOn));
		SetStr('I-',DecodeESC(ItalicsOff));
		SetStr('L+', DecodeESC(LargeOn));
		SetStr('L-', DecodeESC(LargeOff));
		SetStr('NLQ', DecodeESC(NLQ));
		SetStr('DRAFT', DecodeESC(Draft));

		SetStr('4LPI', DecodeESC(lpi4));
		SetStr('6LPI', DecodeESC(lpi6));
		SetStr('8LPI', DecodeESC(lpi8));
		SetStr('10CPI', DecodeESC(cpi10));
		SetStr('12CPI', DecodeESC(cpi12));
		SetStr('15CPI', DecodeESC(cpi15));

		SetStr('PORTRAIT', DecodeESC(Portrait));
		SetStr('LANDSCAPE', DecodeESC(LAndscape));
		SetStr('PO', DecodeESC(Portrait));
		SetStr('LA', DecodeESC(Landscape));
		SetStr('IBM', DecodeESC(IBMCHars));
		SetStr(#35, Currency);
		SetStr('$', Currency);

		for I := 1 to 4 do
			SetStr(User[I].FormCode, DecodeESC(User[I].ESCCode));

		{etc}
	end;
end;

{*********************************************
 ***       INputFName compatible editors   ***
 *********************************************}
{These procedures are suitable as editors for
the InpFname inputline, when selecting paper, etc
for printers, or label types for printing labels, etc}

{===== PRINTER FILTER =============}
function EditPrinterFilter(var FullFileName : FNameStr; const Ext : string) : word;
var	Control : word;
		Filter : PPrinterFilter;
		Name : string;

begin
	EditPrinterFilter := cmCancel;

	{Open file, retrieve details, warn if new, edit and save}
	Name := GetFileName(FullFileName);

	if (Name = '') or (Name[1] = '.') then
		New(Filter, init(''))
	else begin
		Filter := PPrinterFilter(GetFilter(Name));

		if Filter = nil then begin
			ProgramWarning('Could not find filter '+Name,hcFileNotFoundMsg);
			exit;
		end;
	end;

	Control := Filter^.Edit;  {Edit}

	{get name if new}
	if (Control = cmOK) and ((Name = '') or (Name[1]='.')) then
		Control := SaveAsBox(FullFileName,PrinterFilterExt);

	{store}
	if COntrol = cmOK then PutObjToFile(FullFileName, Filter);

	dispose(Filter, done);

	EditPrinterFilter := Control;
end;

{===== PRINTER DEVICE =============}
function CreatePrinter(P : pointer) : pointer; far;
begin CreatePrinter := New(PPrinterStream, init); end;

function EditPrinterDEvice(var FullFileName : FNameStr; const Ext : string) : word;
var	Control : word;
		P : Boolean;

begin
	Control := EditDevice(FullFileName, Ext, CreatePrinter);

	if Control = cmOK then begin
		{check if we're editing the actual current driver, and re-set if so}
		if GetFileName(FullFileName) = PrinterName+'.PRD' then begin
			P := Printer^.Permanant; {store...}
			Printer^.Permanant := False;
			dispose(Printer, done);
			Printer := PPrinterstream(GetObjFromFile(FullFIleName)); {so it reloads filters, etc}
			Printer^.Permanant := P; {restore, eg in setprinter the permanancy is removed so it can be changed}
		end;
	end;

	EditPrinterDevice := Control;
end;


{*********************************************
 ***         PRINTER STREAM MAINTENANCE   ***
 *********************************************}


procedure StartUpPrinter; far;
var Device : PDeviceStream;
begin
	ProgramSetup.SetGroup('');
	PrinterName := ProgramSetup.Get(siDefaultPrinter,'');
	New(Printer, init);
	if PrinterName<>'' then begin
		Device := GetDevice(PrintersPath+PrinterName+'.'+PrinterDeviceExt);
		if Device<>nil then begin
			dispose(Printer, done);
			Printer := PPrinterStream(Device);
		end else begin
			ProgramWarning('Could not load Printer Driver'#13
											+PrintersPath+PrinterName+'.'+PrinterDeviceExt+#13
											+'Check Printer Setup in Maintenance',
										hcFIleNotFoundMsg);
		end;
	end;
	Printer^.Permanant := True;
end;

procedure ShutDownPrinter; far;
begin
	if Printer<>nil then begin
		Printer^.Permanant := False;
		dispose(Printer, done); {logs off user form codes, etc}
	end;
	Printer := nil;
end;

procedure SetPrinter; far;
begin
	Printer^.Permanant := False;

	SetDevice(PDeviceStream(Printer), 'SELECT PRINTER', PrinterDeviceExt, siDefaultPrinter, EditPrinterDevice);

	PrinterName := ProgramSetup.Get(siDefaultPrinter,'');
	if Printer = nil then New(Printer, init);{always make sure there's some kind of device}
	Printer^.Permanant := True;
end;


{***************************************
 ***        INITIALISE UNIT          ***
 ***************************************}
const
	{--- Required for Stream ----}
	RPrinterFilter : TStreamRec = (
		ObjType : srPrinterFilter;
		VmtLink : Ofs(TypeOf(TPrinterFilter)^);
		Load : @TPrinterFilter.Load;
		Store : @TPrinterFilter.Store
	);

	RPrinterStream : TStreamRec = (
		ObjType : srPrinterDevice;
		VmtLink : Ofs(TypeOf(TPrinterStream)^);
		Load : @TPrinterStream.Load;
		Store : @TPrinterStream.Store
	);

begin
	RegisterType(RPrinterStream);
	RegisterType(RPrinterFilter);

	Printer := nil;
	PrinterName := '';

	RegisterTask(DesktopTasks, cmSetPrinter, @SetPrinter);

	{don't do if install program as it might get upset if .cfg exists}
	{$IFNDEF Install}
		RegisterTask(StartUpTAsks, cmNone, @STartupPrinter);
		RegisterTask(ShutDownTAsks, 10, @ShutDownPrinter);
	{$ENDIF}
end.
