// November 3, 1978  5:50 PM				*** overlay C ***

//Edited by Lyle Ramshaw, September 5, 1980  9:28 AM:
//  played with positioning of text strings in press file;  added
//  "isArrows" flag code.


get "zpDefs.bcpl"

get "zpPressDf.bcpl"

get "time.d"


// outgoing procedures:

external [
	writePressFile
	]

// outgoing statics:

external [
	// for debugging
	@showValues
	@showObjects
	@previousColor
	// for EL data
	@ELtable
	@ELtableLength
	@objectCount
	@rectangleCount
	// color maps
	@hueTable
	@saturationTable
	@brightnessTable
	// page size
	@pageLeft
	@pageRight
	@pageBottom
	@pageTop
	]


static [
	@showValues=0
	@showObjects=0
	@previousColor
	@ELtable
	@ELtableLength
	@objectCount
	@rectangleCount
	@hueTable
	@saturationTable
	@brightnessTable
	@pageLeft
	@pageRight
	@pageBottom
	@pageTop
	]


// incoming procedures:

external [
	Puts			// SYSTEM
	Gets
	Closes
	WriteBlock
	ReadBlock
	MoveBlock
	Zero
	ReadCalendar
	DoubleAdd

	confirm			// ZPUTIL
	openWrite
	typeForm

	WriteDLspline		// ZPOBJECT

	WriteDLdot		// ZPPIECE
	WriteDLline

	UNPACKDT		// TIME package
	CONVUDT

	PutObjectInELtable		// ZPPUTS
	PutRectangleInELtable
	PutColorInELtable
	PutNewColorInELtable
	DPadd
	OutsideThePage
	RectangleSpline
	PrintFpValues

	ArrowsMicaAdjust	// ZPARROWS
	]


// incoming statics:

external [
	keys			// SYSTEM
	UserName

	@splineTable		// ZPINIT
	@textTable
	@maxSplineID
	@maxTextID
	@fontDefTable
	@lineThicknessTable
	@fontFile
	@font
	@dspFont
	@bitmap
	@height
	@width
	@scanlineWidth
	@bitmapSize
	@Xmax
	@Ymax

	@dashOn			// ZPDRAW
	@dashOff
	]

// local static:

static [
	@useAlternative=-1
	]



//****************************************************************
// Output PRESS file
//****************************************************************


let writePressFile() be [writePressFile

	// -------------------- PRESS file tables:

	let DLdotsCommands=table [
		#400+0; 0; 0;	// zero for size of bitmap
		1; 0; 0; 0; 0;	// same for setwindow
		#1000+3		// bit-dir to right; line-dir down
		2; 0; 0;	// size left zero
		3 ]		// dots follow

	let dotsEntityTrailer=table [ 0;0;0;0;0;0;0;0;0;0;0;0 ]

	let objectEntityTrailer=table [ 0;0;0;0;0;0;0;0;0;0;0;0 ]

	let textEntityTrailer=table [ 0;0;0;0;0;0;0;0;0;0;0;0 ]

	let FDIRentry=table [
		FDIRlen;
		0; 127;
		0; 0; 0; 0; 0; 0; 0; 0; 0; 0;
		0; 0; 0
		]

	let documentDirectory=table [ 27183; 0; 0; 0; 1; 0; -1; -1; 1; 1; $S ]
	manifest [ lDocDir=11 ]

	let defLineThicknessTable=table [
		defThickness0; defThickness1; defThickness2; defThickness3 ]
	test lineThicknessTable eq 0
	ifso lineThicknessTable=defLineThicknessTable
	ifnot for t=0 to 3 do if lineThicknessTable!t eq 0 then
		lineThicknessTable!t=defLineThicknessTable!t

	// color tables are indexed by color (0 to 7):
	//	white, cyan, magenta, blue (violet), yellow, green, red, black
	hueTable= table [
		EsetHue; EsetHue+120; EsetHue+200; EsetHue+160;
		EsetHue+40; EsetHue+80; EsetHue; EsetHue ] 
	saturationTable= table [
		EsetSaturation; EsetSaturation+255; EsetSaturation+255; EsetSaturation+255;
		EsetSaturation+255; EsetSaturation+255; EsetSaturation+255; EsetSaturation ] 
	brightnessTable= table [
		EsetBrightness+255; EsetBrightness+255; EsetBrightness+255; EsetBrightness+255;
		EsetBrightness+255; EsetBrightness+255; EsetBrightness+255; EsetBrightness ] 

	unless textTable!0 % splineTable!0 then [
		typeForm(0, "Sorry, no picture to print!*N")
		return
		]

	// -------------------- Go ahead:

	let pressFileName=nil
	let pressFile=openWrite("*NWrite PRESS file: ", wordItem, lv pressFileName)
	unless pressFile return

	let record=vec 256
	Zero(record, 256)
	let partDirectory=vec (5*PDIRlen)
	Zero(partDirectory, 5*PDIRlen)
	let partEntry=partDirectory
	let Rbegin=0

	// page coordinates of low left corner of screen
	let screenX0=(1270*17-Xmax*scaleFactor)/2
	let screenY0=(1270*22-Ymax*scaleFactor)/2
	// screen coordinates of page border, plus some margin
	pageLeft=-screenX0/scaleFactor
	pageRight=(1270*17-screenX0)/scaleFactor
	pageBottom=-screenY0/scaleFactor
	pageTop=(1270*22-screenY0)/scaleFactor

	let fontUsed=vec maxFont
	Zero(fontUsed, maxFont)

	// find the minimum text window
	let twLeft, twRight, twTop, twBottom = Xmax, 0, 0, Ymax
	if textTable!0 then for t=1 to maxTextID do [
		let textPointer=textTable!t
		unless textPointer loop
		let f=textPointer>>TEXT.font
		if fontFile>>FONTFILE.length↑f eq 0 then f=dspFont
		fontUsed!f=true
		let tLeft=textPointer>>TEXT.left
		let tRight=textPointer>>TEXT.right
		let tTop=textPointer>>TEXT.top
		let tBottom=textPointer>>TEXT.bottom
		let outside=OutsideThePage(tLeft, tRight, tTop, tBottom)
		if outside then [
			typeForm(0, "WARNING: caption #", 10, t,
				0, " lies outside the printed page, on the ", 0, outside, 0,
				".*NIt should be deleted before printing.  Type any character to continue.*N")
			Gets(keys)
			loop
			]
		if twLeft gr tLeft then twLeft=tLeft
		if twRight ls tRight then twRight=tRight
		if twTop ls tTop then twTop=tTop
		if twBottom gr tBottom then twBottom=tBottom
		]
	let tXe=screenX0 + twLeft*scaleFactor
	let tYe=screenY0 + twBottom*scaleFactor

	// find the minimum spline window (for objects & rectangles)
	let swLeft, swRight, swTop, swBottom = Xmax, 0, 0, Ymax
	if splineTable!0 then for id=1 to maxSplineID do [
		let splinePointer=splineTable!id
		unless splinePointer loop
		let sLeft=splinePointer>>SPLINE.left
		let sRight=splinePointer>>SPLINE.right
		let sTop=splinePointer>>SPLINE.top
		let sBottom=splinePointer>>SPLINE.bottom
		let outside=OutsideThePage(sLeft, sRight, sTop, sBottom)
		if outside then [
			typeForm(0, "WARNING: line  or curve #", 10, id,
				0, " lies outside the printed page, on the ", 0, outside, 0,
				".*NIt should be deleted before printing.  Type any character to continue.*N")
			Gets(keys)
			loop
			]
		if swLeft gr sLeft then swLeft=sLeft
		if swRight ls sRight then swRight=sRight
		if swTop ls sTop then swTop=sTop
		if swBottom gr sBottom then swBottom=sBottom
		]
	let sXe=screenX0 + swLeft*scaleFactor
	let sYe=screenY0 + swBottom*scaleFactor

	// find the minimum bitmap window (for dots)
	let bwLeft, bwRight, bwTop, bwBottom=Xmax, 0, 0, Ymax
	if splineTable!0 then for id=1 to maxSplineID do [
		let splinePointer=splineTable!id
		unless splinePointer loop
		if RectangleSpline(splinePointer) loop
		let bLeft=splinePointer>>SPLINE.left - 16
		let bRight=splinePointer>>SPLINE.right + 16
		let bTop=splinePointer>>SPLINE.top + 16
		let bBottom=splinePointer>>SPLINE.bottom - 16
		if bwLeft gr bLeft then bwLeft=bLeft
		if bwRight ls bRight then bwRight=bRight
		if bwTop ls bTop then bwTop=bTop
		if bwBottom gr bBottom then bwBottom=bBottom
		]
	if bwRight gr Xmax then bwRight=Xmax
	if bwLeft ls 0 then bwLeft=0
	if bwTop gr Ymax then bwTop=Ymax
	if bwBottom ls 0 then bwBottom=0
	let someDots=(bwLeft ls Xmax) & (bwRight gr 0) &
			(bwBottom ls Ymax) & (bwTop gr 0)
	let bwWordLeft=bwLeft/16
	bwLeft=bwWordLeft*16
	let bwWordRight=bwRight/16
	bwRight=bwWordRight*16
	let bwWordWidth=bwWordRight-bwWordLeft+1
	let bwWidth=bwWordWidth*16
	let bwHeight=bwTop-bwBottom+1
	let bXe=screenX0 + bwLeft*scaleFactor
	let bYe=screenY0 + bwBottom*scaleFactor

	// WARNING: bitmap is used as temporary storage for Entity List Table !!!!
	ELtable=bitmap

	let wordCount=vec 2
	wordCount!0=0; wordCount!1=0

	// information about objects (number of objects, word count for each object)
	ELtableLength=0
	objectCount=0
	rectangleCount=0


	//------------------------------------------------------ DATA LIST

	//............................................. DL dots

	manifest [ DLdummyWordCount=3 ]
	let DLdotWordCount=0
	if someDots then [
		//................. dummy object alternative
		if useAlternative then [
			let dummyObject= table [ Dmove; 0; 0 ]
			WriteBlock(pressFile, dummyObject, DLdummyWordCount)
			DLdotWordCount=DLdotWordCount + DLdummyWordCount
			]
		//................. dots commands
		DLdotsCommands>>DLDC.dots=bwWidth
		DLdotsCommands>>DLDC.lines=bwHeight
		DLdotsCommands>>DLDC.pl=0
		DLdotsCommands>>DLDC.dl=bwHeight
		DLdotsCommands>>DLDC.pb=0
		DLdotsCommands>>DLDC.db=bwWidth
		DLdotsCommands>>DLDC.width=scaleFactor*bwWidth
		DLdotsCommands>>DLDC.height=scaleFactor*bwHeight
		WriteBlock(pressFile, DLdotsCommands, DLDClen)
		//................. bitmap
		let dbm=bitmap+margin+(Ymax-bwTop)*scanlineWidth+bwWordLeft
		for sl=1 to bwHeight do [
			WriteBlock(pressFile, dbm, bwWordWidth)
			dbm=dbm+scanlineWidth
			]
		DLdotWordCount=DLdotWordCount + DLDClen + bwWordWidth*bwHeight
		]
	DPadd(wordCount, DLdotWordCount)

	//............................................. DL object

	let DLobjectWordCount=0
	if splineTable!0 then for id=1 to maxSplineID do [
		let splinePointer=splineTable!id
		unless splinePointer loop
		if OutsideThePage(
			splinePointer>>SPLINE.left, splinePointer>>SPLINE.right,
			splinePointer>>SPLINE.top, splinePointer>>SPLINE.bottom) loop
		PutColorInELtable(splinePointer>>SPLINE.color)
		DLobjectWordCount=DLobjectWordCount +
			selecton splinePointer>>SPLINE.nKnots into [
			case 1:
				WriteDLdot(pressFile, splinePointer, swLeft, swBottom);
			case 2:
				WriteDLline(pressFile, splinePointer, swLeft, swBottom);
			default:
				WriteDLspline(pressFile, splinePointer, swLeft, swBottom)
				]
		typeForm(1, $|)
		]
	DPadd(wordCount, DLobjectWordCount)

	//............................................. DL text

	let DLtextWordCount=0
	if textTable!0 then for id=1 to maxTextID do [
		let textPointer=textTable!id
		unless textPointer loop
		if OutsideThePage(
			textPointer>>TEXT.left, textPointer>>TEXT.right,
			textPointer>>TEXT.top, textPointer>>TEXT.bottom) loop
		let textString=textPointer+TEXTblockSize
		let wCount=(textString>>STRING.length)/2+1
		WriteBlock(pressFile, textString, wCount)
		DLtextWordCount=DLtextWordCount+wCount
		]
	DPadd(wordCount, DLtextWordCount)

	//............................................. DL spline

	let DLsplineWordCount=0
	if splineTable!0 then [
		Puts(pressFile, splineTable!0)
		DLsplineWordCount=1
		for id=1 to maxSplineID do [
			let splinePointer=splineTable!id
			unless splinePointer loop
			let nKnots=splinePointer>>SPLINE.nKnots
			test splinePointer>>SPLINE.cyclic
			ifso Puts(pressFile, (-nKnots))
			ifnot Puts(pressFile, nKnots)
			Puts(pressFile, ((splinePointer>>SPLINE.shape) lshift 8)
						% (splinePointer>>SPLINE.thickness))
			test splinePointer>>SPLINE.dashed
			ifso Puts(pressFile, (dashOn lshift 8) % dashOff)
			ifnot Puts(pressFile, 0)
			let knotCount= 4 * nKnots
			WriteBlock(pressFile, splinePointer+SPLINEknotBase, knotCount)
			DLsplineWordCount=DLsplineWordCount + knotCount + 3
			]
		]
	DPadd(wordCount, DLsplineWordCount)

	//------------------------------------------------------ ENTITY LIST

	Puts(pressFile, 0)
	DPadd(wordCount, 1)
	Zero(dotsEntityTrailer, ETlen)
	Zero(objectEntityTrailer, ETlen)
	Zero(textEntityTrailer, ETlen)

	//............................................. EL dots

	if someDots then [
		let ELdotWordCount=0
		//........................................ dummy (object) alternative
		if useAlternative then [
			let dummyAlternative= table [
				EnopLeft+Ealternative; EobjectAlternative; 0; 4; 0;
				2*DLdummyWordCount; EnopLeft+EshowObject; DLdummyWordCount ]
			WriteBlock(pressFile, dummyAlternative, 8)
			ELdotWordCount=ELdotWordCount + 8
			]
		//........................................ dots alternative
		let dotsAlternative= table [
			EnopLeft+Ealternative; EdotsAlternative; 0; 14; 0; 0;
			EnopLeft+EsetX; 0; EnopLeft+EsetY; 0; EnopLeft+EshowDots; 0; 0 ]
		dotsAlternative!5=2*DLdotWordCount
		dotsAlternative!12=DLdotWordCount
		test useAlternative
		ifso [
			WriteBlock(pressFile, dotsAlternative, 13)
			ELdotWordCount=ELdotWordCount + 13
			]
		ifnot [
			WriteBlock(pressFile, dotsAlternative+6, 7)
			ELdotWordCount=ELdotWordCount + 7
			]
		//........................................ end alternative
		if useAlternative then [
			let endAlternative= table [
				EnopLeft+Ealternative; 0; 0; 0; 0; 0 ]
			WriteBlock(pressFile, endAlternative, 6)
			ELdotWordCount=ELdotWordCount + 6
			]

		//........................................ trailer
		ELdotWordCount=ELdotWordCount + ETlen
		DPadd(lv dotsEntityTrailer>>ET.Blength, DLdotWordCount)
		DPadd(lv dotsEntityTrailer>>ET.Blength, DLdotWordCount)
		dotsEntityTrailer>>ET.Elength=ELdotWordCount
		dotsEntityTrailer>>ET.Xe=bXe
		dotsEntityTrailer>>ET.Ye=bYe
		dotsEntityTrailer>>ET.left=bwLeft*scaleFactor
		dotsEntityTrailer>>ET.bottom=bwBottom*scaleFactor
		dotsEntityTrailer>>ET.width=bwWidth*scaleFactor
		dotsEntityTrailer>>ET.height=bwHeight*scaleFactor
		WriteBlock(pressFile, dotsEntityTrailer, ETlen)

		DPadd(wordCount, ELdotWordCount)
		]

	//............................................. EL objects & rectangles

	if splineTable!0 then [
		//........................................ commands
		WriteBlock(pressFile, ELtable, ELtableLength)
		let ELobjectWordCount=ELtableLength

		//........................................ skip splines
		if DLsplineWordCount ne 0 then [
			Puts(pressFile, EnopLeft+EskipControl)
			Puts(pressFile, DLsplineWordCount)
			Puts(pressFile, EskipTypeLeft+Enop)
			ELobjectWordCount=ELobjectWordCount+3
			]

		//........................................ trailer
		ELobjectWordCount=ELobjectWordCount + ETlen
		objectEntityTrailer>>ET.Bbegin=dotsEntityTrailer>>ET.Bbegin
		objectEntityTrailer>>ET.BbeginLSB=dotsEntityTrailer>>ET.BbeginLSB
		DoubleAdd(lv objectEntityTrailer>>ET.Bbegin, lv dotsEntityTrailer>>ET.Blength)
		objectEntityTrailer>>ET.BlengthLSB=2*DLobjectWordCount
		objectEntityTrailer>>ET.Elength=ELobjectWordCount
		objectEntityTrailer>>ET.Xe=sXe
		objectEntityTrailer>>ET.Ye=sYe
		objectEntityTrailer>>ET.left=swLeft*scaleFactor
		objectEntityTrailer>>ET.bottom=swBottom*scaleFactor
		objectEntityTrailer>>ET.width=(swRight-swLeft+1)*scaleFactor
		objectEntityTrailer>>ET.height=(swTop-swBottom+1)*scaleFactor
		WriteBlock(pressFile, objectEntityTrailer, ETlen)

		DPadd(wordCount, ELobjectWordCount)
		]


	//............................................. EL text

	if textTable!0 then [
		//........................................ commands
		let ELtextWordCount=0
		for id=1 to maxTextID do [
			let textPointer=textTable!id
			unless textPointer loop
			if OutsideThePage(
				textPointer>>TEXT.left, textPointer>>TEXT.right,
				textPointer>>TEXT.top, textPointer>>TEXT.bottom) loop
			let textString=textPointer+TEXTblockSize
			let count=textString>>STRING.length
			let f=textPointer>>TEXT.font
			if fontFile>>FONTFILE.length↑f eq 0 then f=dspFont
			let color=textPointer>>TEXT.color
			Puts(pressFile, hueTable!color) 		
			Puts(pressFile, saturationTable!color)
			Puts(pressFile, brightnessTable!color)
			Puts(pressFile, (Efont+f) lshift 8 + EsetX)
			let xMicas=scaleFactor*(textPointer>>TEXT.left - twLeft)
			let yMicas=scaleFactor*(textPointer>>TEXT.top - fontFile>>FONTFILE.baseline↑f - twBottom)
			if (textString>>STRING.length eq 1) &
			  (fontDefTable!f>>FONTDEF.isArrows eq 1)
			  then ArrowsMicaAdjust(textString>>STRING.char↑1, lv xMicas, lv yMicas)
			Puts(pressFile, xMicas)
			Puts(pressFile, EskipOneCharLeft+EsetY)
			Puts(pressFile, yMicas)
			Puts(pressFile, EshowCharLeft+count)
			ELtextWordCount=ELtextWordCount+8
			unless count rem 2 then [
				Puts(pressFile, EnopLeft+EskipOneChar)
				ELtextWordCount=ELtextWordCount+1
				]
			]

		//........................................ trailer
		ELtextWordCount=ELtextWordCount + ETlen
		textEntityTrailer>>ET.Bbegin=objectEntityTrailer>>ET.Bbegin
		textEntityTrailer>>ET.BbeginLSB=objectEntityTrailer>>ET.BbeginLSB
		DoubleAdd(lv textEntityTrailer>>ET.Bbegin, lv objectEntityTrailer>>ET.Blength)
		textEntityTrailer>>ET.BlengthLSB=2*DLtextWordCount
		textEntityTrailer>>ET.Elength=ELtextWordCount
		textEntityTrailer>>ET.Xe=tXe
		textEntityTrailer>>ET.Ye=tYe
		textEntityTrailer>>ET.left=twLeft*scaleFactor
		textEntityTrailer>>ET.bottom=twBottom*scaleFactor
		textEntityTrailer>>ET.width=(twRight-twLeft+1)*scaleFactor
		textEntityTrailer>>ET.height=(twTop-twBottom+1)*scaleFactor
		WriteBlock(pressFile, textEntityTrailer, ETlen)

		DPadd(wordCount, ELtextWordCount)
		]

	//............................................. DL/EL padding

	let padWords=256-((wordCount!1) & #377)
	if padWords eq 256 then padWords=0
	Zero(record, 256)
	WriteBlock(pressFile, record, padWords)


	//............................................. Part Directory Entry

	let Rlength=(wordCount!1 rshift 8) % (wordCount!0 lshift 8)
	if padWords ne 0 then Rlength=Rlength+1
	partEntry>>PDIR.type=0
	partEntry>>PDIR.Rbegin=Rbegin
	partEntry>>PDIR.Rlength=Rlength
	partEntry>>PDIR.Plength=padWords
	Rbegin=Rbegin+Rlength
	partEntry=partEntry+PDIRlen

	typeForm(10, objectCount, 0, " objects & ", 10, rectangleCount, 0, " rectangles.*N")

	//------------------------------------------------------ FONT DIRECTORY

	let nf=0
	// assume it fits in one record
	if textTable!0 then for f=0 to maxFont-1 do [
		if fontFile>>FONTFILE.length↑f eq 0 & f ne dspFont loop
		unless fontUsed!f loop
		let fontEntry=fontDefTable!f
		FDIRentry>>FDIR.font=f
		MoveBlock(FDIRentry+3, fontEntry, FONTDEFnameLength/2+1)
		FDIRentry>>FDIR.face=fontEntry>>FONTDEF.face
		FDIRentry>>FDIR.ptSize=fontEntry>>FONTDEF.ptSize
		MoveBlock(record+nf*FDIRlen, FDIRentry, FDIRlen)
		nf=nf+1
		]
	WriteBlock(pressFile, record, 256)
	partEntry>>PDIR.type=1
	partEntry>>PDIR.Rbegin=Rbegin
	partEntry>>PDIR.Rlength=1
	partEntry>>PDIR.Plength=0
	Rbegin=Rbegin+1

	//------------------------------------------------------ PART DIRECTORY

	Zero(record, 256)
	MoveBlock(record, partDirectory, 2*PDIRlen)
	WriteBlock(pressFile, record, 256)

	//------------------------------------------------------ DOCUMENT DIRECTORY

	documentDirectory!1=Rbegin+2
	documentDirectory!2=2
	documentDirectory!3=Rbegin
	// date for Press width
	ReadCalendar(documentDirectory+6)
	Zero(record, 256)
	MoveBlock(record, documentDirectory, lDocDir)

	MoveBlock(record + #200, pressFileName, 20)

	// creator's name
	let creatorsName=record + #232
	MoveBlock(creatorsName, UserName, 16)
	if creatorsName>>STRING.length gr 31 then creatorsName>>STRING.length=31

	// creation date
	let creationDate= record + #252
	let utv=vec lenUTV
	CONVUDT(creationDate, UNPACKDT(0, utv))
	
	WriteBlock(pressFile, record, 256)

	Closes(pressFile)
	typeForm(0, "Done!*N")

	]writePressFile