// C O M M O N   P R I N T   
// errors 1000
//

get "Spruce.d"
get "SpruceFiles.d"
get "Orbit.d"

// outgoing procedures
external
	[
	AddToBin
	Announce
	AwaitPageSync
	IncBinSerial  //increment a bin serial counter
	Print
	PrintNext
	ReadBands
	ReadClock
	ReadFont
	]


// incoming procedures
external
	[
	SpruceError
	IndexedPageIO
	Min
	BankBlt
//SpruceCheck
	CheckPoint
	ReleaseCheckLevel
	RestoreFromCheckPoint
//SpruceUtilsRes
	FSInit
	Overlay
	IsOverlayPresent
//CURSOR
	CursorChar
	CursorToggle
// SprucePrintRes
	DoFunc
//Device dependent module
	DrivePrinter
//OS
	Zero
	GetCode1
	]

// incoming statics
external
	[
	BandFile
	BinCounters
	breakPage
	breakPageCopy
	Capabilities
	Debug
	DebugSystem
	debugTrail
	FA 
	Func
	logBandRecordSize
	maxPrintPassRecs 
	Measure; InitMeasure; CloseMeasure; TickMeasure; measureTable
	nLeadingBands 
	nTrailingBands 
	nVisibleBands 
	NumBins
	OverlayTop
	PermanentBottom
	printerDevice
	printerForward
	stopsPrinting
	xmFonts	// Font data will be read into Bank 1 via Bank 0, if set

//defined here
	bandRecordSize
	FAvalue
	LowAdr
	nBands
	nPagesPrinted
	nRecs
	ros12
	ros13
	]
// internal statics
static
	[
	bandRecordSize
	FAvalue
	LowAdr
	nBands
	nPagesPrinted
	nRecs
	ros12
	ros13
	]

// File-wide structure and manifest declarations.

manifest    RTC=#430

let AddToBin(max, tray; numargs na ) be
[
if na < 2 then tray = 0
let x = BinCounters!tray
x = x+1
BinCounters!tray = x
if (x > max) & (tray eq 0) & ((lv Capabilities)>>Capabilities.cOverflowProtect ne 0) do
		 [  stopsPrinting = binFull ]
]

and IncBinSerial(lvCnt) be
	test printerForward
	  ifso 	[
		@lvCnt=@lvCnt+1
		if @lvCnt ge 100 then @lvCnt=0
		]
	  ifnot 	[
		@lvCnt=@lvCnt-1
		if @lvCnt ls 0 then @lvCnt=99
		]

and Announce(n) be
[
	CursorChar((n ge 16? $K,$P))
	for i=0 to 3 do
		[
		if (n&10b) ne 0 then CursorToggle(i)
		n=n lshift 1
		]
]

and AwaitPageSync(ps) = valof
[
	if Debug then resultis true
    Measure(5, ps)
	let tim=@RTC
	[
	if (@RTC-tim) gr 5*27 then resultis false
	DoFunc(fControl, 0)	//Read ROS special status (1st four bits of status word 0)
	let f=Func!9
	if f<<STATUS.ROSStatusBit0 eq ps break
	] repeat
    Measure(5,ps+2)
    resultis true
]

// ----------------------------------------------------------------------------------
// PrintNext(pDoc, lvCopyNo, nPagesPrinted)
// -----------------------------------------------------------------------------------

// Return pointer to next page to print (given nPagesPrinted)
// Set @lvCopyNo to current copy number, beginning with 1
// nPagesPrinted is the total number of pieces of paper shoved out.
// Routine is complicated by:
//	BreakPage: (always last in array)
//	PrinterForward: printer could be going either way.

and PrintNext(pDoc, lvCopyNo, n; numargs na) = valof
[
	let nPages=pDoc>>DocG.nPages
	nPages=nPages-breakPage
	let nCopies=pDoc>>DocG.nCopies
	let copy = (printerForward? n-breakPage+nPages, n)/breakPage
	@lvCopyNo = printerForward? copy, nCopies-copy
	let totPages=nCopies*nPages+breakPage
	if n ge totPages then resultis 0	//All finished

// Transform to forward sequence:
	unless printerForward then n=totPages-n-1
	n=n-breakPage
	let p=n rem nPages
	if breakPage ne 0 & n ls 0 then
		[  p=nPages+breakPage+n; @lvCopyNo = breakPageCopy ]	//Print break page
	resultis p*(size PageG/16)+pDoc>>DocG.Pages
]

and ReadBands(page, buf, nRecs, nBands; numargs na) be if page do
[
test page ne 1 then
	[
		if nRecs ls page>>PageG.nRecords then SpruceError(1001)
		IndexedPageIO(BandFile>>SPruceFile.map, page>>PageG.bandPos, buf,
			page>>PageG.nRecords, isfRead)
	]
or
	[
	 if na eq 4 do Zero(buf, nBands*2)
	]
]

//Wait for page sync to equal given value.
// Returns true if there was nothing unexpected
// low order 10 bits of RTC, left justified; works on AltoII only
and ReadClock() = (   GetCode1( (table [ #61003; #1401 ] )() )  &  #7774   ) lshift 4

and ReadFont(font, buf, maxRecords) = valof
// reads font rasters into buf (which is maxRecords long) or (XM, using buf, into bank 1)
// reads ICC table for font load into area following font rasters, or (XM, into area beginning at buf)
// returns ICC table address
[
	Measure(#22,true)
	let bandPos, totalRecords = font>>FontG.bandPos, font>>FontG.nRecords
	let fontLength = font>>FontG.fontLength
	let map = BandFile>>SPruceFile.map
	test xmFonts
	    ifnot [ IndexedPageIO(map, bandPos, buf, totalRecords, isfRead)
		  resultis buf+fontLength
		  ]
	    ifso [
		let fontRecords = (fontLength+bandRecordSize-1) rshift logBandRecordSize
		let fontLoc = 0
		let endRec = bandPos+fontRecords
		// for rec = bandPos by maxRecords to endRec-1 do . . . 
		let rec = bandPos
			[
			if rec ge endRec break
			let pieceRecs = Min(maxRecords, endRec-rec)
			IndexedPageIO(map, rec, buf, pieceRecs, isfRead)
			let bufSrc = buf
			for i = 1 to pieceRecs do
			    [
			    BankBlt(bufSrc, fontLoc, bandRecordSize) // do in segments for interrupts
			    bufSrc = bufSrc+bandRecordSize
			    fontLoc = fontLoc + bandRecordSize  // and to avoid signed compare problems
			    ]
			rec = rec + maxRecords
			] repeat
		IndexedPageIO(map, bandPos+fontRecords, buf, totalRecords-fontRecords, isfRead)
		resultis buf
		]
	Measure(#22,false)
]
and Print(pDoc, nPagesAlreadyPrinted,lvFailureCode) = valof
[
	Overlay(OVBase, IsOverlayPresent(OVPrint)+1)
	Overlay(OVInit, IsOverlayPresent(OVPrint)+2)
    ReleaseCheckLevel(LEVReport) // Release if there is any
    RestoreFromCheckPoint(LEVReport, LEVReport)
	let ovdev = selecton printerDevice into
		[
		case printerDover: OVDover
		case printerPenguin: OVPenguin
		case printerSequoia: OVSequoia
		case printerPimlico: OVPimlico
		case printerPuffin: OVPuffin
		]
	Overlay(ovdev, IsOverlayPresent(OVPrint)+1)
	//||(OVT80),OVPrint, OV[printer]
	CursorChar($P)
	bandRecordSize = 1 lshift logBandRecordSize
	@lvFailureCode = 0
	nPagesPrinted=nPagesAlreadyPrinted

	LowAdr = OverlayTop
	measureTable = LowAdr
	if (DebugSystem&#20000) ne 0 then LowAdr = LowAdr+2000 // Imaging measurements table
	LowAdr = (LowAdr+1)&(-2)
	nRecs=(PermanentBottom-LowAdr-(loSize+4+10)) rshift logBandRecordSize
	if nRecs ls maxPrintPassRecs then SpruceError(1000)

	nBands=nLeadingBands+nVisibleBands+nTrailingBands

	let funcTab=table [ 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0 ]   
	Func=(funcTab+1)&(-2)
	Func!9 = 0
	FAvalue=FA lshift 8
	stopsPrinting = false		//guaranteed because binFull stops printing until cleared
	let result = DrivePrinter(pDoc, nPagesAlreadyPrinted,lvFailureCode)
	if (result eq -1) & ((Capabilities & mSpruceClear) ne 0) then Zero(BinCounters, NumBins)
	Overlay(OVBase, IsOverlayPresent(OVPrint)+1)
	Overlay(OVInit, IsOverlayPresent(OVPrint)+2)
	FSInit()
    CheckPoint(LEVReport, LEVReport)
	resultis result
]


//BWB November 13, 1978 12:45 PM derived from spruceprint
// December 7, 1978  4:04 PM cleanup
// March 20, 1979  1:47 PM four-color Puffin
// April 27, 1979  1:48 PM, add Dover Engine Control Monitoring code, see SpruceMeasure, by Swinehart
// 	 add ability to place fonts in bank 1 -- see all uses of xmFonts
// 	 repair bug in BankBlt interface for xmFonts stuff
// July 30, 1979  4:35 PM, AddToBin
// August 2, 1979  4:56 PM, SetupPrint
// August 16, 1979  10:54 AM, reset stopsPrinting in SetupPrint 
// August 29, 1979  12:50 PM, BinCounter clearing moved to SpruceUser.bcpl
// September 27, 1979  3:54 PM, except for SpruceClear (JobProtection)
// March 3, 1980 11:55 AM, use breakPageCopy at appropriate time
// July 16, 1980, 4:27 PM, breakPage now contains # of images for  break page (PrintNext)
// February 5, 1981  3:31 PM,  add IncBinSerial