// PDInstall.bcpl -- PDPrint installation routines
// derived from PressInstall.bcpl 2/7/83

//  errors 250

//last InstallPrompt index used: 19

get "PDInternals.d"
get "AltoFileSys.d"
get "Disks.d"
get "Streams.d"
get "SysDefs.d"
get "BcplFiles.D"

// outgoing procedures
external
	[
	PDInstall
	]

// incoming procedures
external
	[
//PDINSTALLUTILS
	IndexFile
	GetFileStatic
	SetupDrive1
	CloseDrive1

//PDPRINT
	PDError

//PDML
	DoubleAdd
	Ugt
	MulDiv

//Used for initialization of files, etc. -- removed by Junta
	OpenFile
	DeleteFile
	Closes
	Gets
	Puts
	Endofs
	ReadBlock
	WriteBlock
	FileLength
	Resets
	PositionPage
	SetFilePos

//WINDOW
	WindowInit
	WindowClose
	WindowWriteBlock

//SCANSTRINGS
	TypeForm
	ReadNumber

//FLOAT
	FLDI; FDV; FML; FTR; FAD; FSB;

//ALLOC
	InitializeZone
	Allocate

//OS
	MoveBlock
	Zero

//TFS
	TFSInit
	TFSClose
	TFSCreateDDMgr
	TFSDiskModel
	]

// incoming statics
external
	[
	MeterFile
	BitsFile
	tridentUsed
	tridentVec

	printerDevice
	rosDevice
	nPrinterColors
	useStandardQueue
	ResolutionS	
	ResolutionB	
	PaperDimensionS
	PaperDimensionB
	PaperSpeedInches
	BitMarginAdjust
	ScanMarginAdjust

	VersatecFF

	SLOTScanLength
	SLOTDouble
	SLOTTimeOut

	DPzero
	BESizes
	DoFileMeter
	DoMeter
	Debug
	UseXM

	OverlayTable
	OverlayReloc

	sysDisk
	PDZone
	]

// internal statics
static
	[
	defaultVec
	]

// File-wide structure and manifest declarations.

manifest nDefaults=40		//Only need change in this file!!

structure STR[
	length byte
	char↑1,255 byte
	]

// Procedures

//----------------------------------------------------------------------------
let PDInstall(cfa, hintState) be
//----------------------------------------------------------------------------
[
	Zero(hintState, lFP)
	let st=OpenFile("PDPrint.State",0,0,0,hintState)
	hintState!lFP=@#430			//Get real time clock bits

//First thing in the file is the "time stamp":
	Puts(st, hintState!lFP)

//Second thing in the state file is a list of default values of various things,
// up to nDefaults of them.  Read into defaults vector:
	let defaults=vec nDefaults+1
	Zero(defaults, nDefaults+1)
	defaultVec=defaults+1		//defaultVec!-1=true if defaults valid
	test Endofs(st) then
	   [ Puts(st, nDefaults); WriteBlock(st, defaults, nDefaults) ] or
	   [ Gets(st); ReadBlock(st, defaultVec, nDefaults); defaultVec!-1=true ]

//Various statics
	DoMeter=InstallPrompt("General installation parameters:*n   Record metering information",0)
	DoFileMeter=InstallPrompt("   Meter each page transfer",1)
	UseXM=InstallPrompt("   Normally use extended memory",2)
	SaveStatic(st, lv DoMeter)
	SaveStatic(st, lv DoFileMeter)
	SaveStatic(st, lv UseXM)

// Set output device stuff.  Printer codes are defined in PDInternals.df
	printerDevice=InstallPrompt("Printer parameters:*n   Output device (Dover,Sequoia,Pimlico,Puffin,Slot,Versatec,Hg)",3,3)
	ResolutionB = InstallPrompt("   Resolution in bits/inch", 4, 1);
	ResolutionS = InstallPrompt("   Resolution in scans/inch", 5, 1);
	nPrinterColors=1
	rosDevice=printerDevice
	if printerDevice le printerOrbitLast then
		PaperSpeedInches=InstallPrompt("   Paper speed (inches/second)",6,2)
	if (printerDevice eq printerPimlico)%
		(printerDevice eq printerPuffin)%
		(printerDevice eq printerSlot) do 
		nPrinterColors=InstallPrompt("   Number of printer colors",7,1)
	if (printerDevice eq printerPimlico)%
		(printerDevice eq printerPuffin) then
		[
		useStandardQueue=InstallPrompt("   Use standard n-color printing queue",8)
		if printerDevice eq printerPuffin &
			InstallPrompt("   Does the machine use a Pimlico ROS",9)
				then rosDevice=printerPimlico
		]

	if printerDevice eq printerSlot % printerDevice le printerOrbitLast then
		[
		SLOTScanLength=InstallPrompt("   Scan line length in bits (for bit clock)",10,1)
		ScanMarginAdjust=InstallPrompt("   Scan margin adjustment",11,1)
		BitMarginAdjust=InstallPrompt("   Bit margin adjustment",12,1)
		SLOTTimeOut=InstallPrompt("   How many seconds before timing out printer",13,1)

		if printerDevice eq printerSlot then
			SLOTDouble=InstallPrompt("   Do you want scan-lines doubled",14)
		]

	if printerDevice eq printerVersatec then
		[
		let ffBefore=InstallPrompt("   Number of form-feeds prior to printing",15,1)
		let ffAfter=InstallPrompt("   Number of form-feeds after printing",16,1)
		VersatecFF=256*ffBefore+ffAfter
		]
	SaveStatic(st, lv printerDevice)
	SaveStatic(st, lv rosDevice)
	SaveStatic(st, lv nPrinterColors)
	SaveStatic(st, lv useStandardQueue)
	SaveStatic(st, lv PaperSpeedInches)
	SaveStatic(st, lv ResolutionB)
	SaveStatic(st, lv ResolutionS)
	SaveStatic(st, lv ScanMarginAdjust)
	SaveStatic(st, lv BitMarginAdjust)
	SaveStatic(st, lv SLOTScanLength)
	SaveStatic(st, lv SLOTDouble)
	SaveStatic(st, lv SLOTTimeOut)
	SaveStatic(st, lv VersatecFF)

//Paper sizes.
	PaperDimensionB=InstallPrompt("Paper parameters:*n   Scan dimension",17,2)
	PaperDimensionS=InstallPrompt("   Transport dimension",18,2)
	SaveStatic(st, lv PaperDimensionB)
	SaveStatic(st, lv PaperDimensionS)

//See what disks he wants:
	let z=vec 3000
	PDZone=InitializeZone(z, 3000)
	let tv=vec NTridentDrives*NPartitions;tridentVec=tv
	Zero(tridentVec,NTridentDrives*NPartitions)

	tridentUsed=InstallPrompt("Disk information:*n   Do you want to use Trident disk(s)",19)
	if tridentUsed then
		[
		//there are Trident drive nos 0-7, each with up to 3 file systems
		//allow user to grab any or all
		let ddmgr=TFSCreateDDMgr(PDZone)
		let noTrident=true
		for t=0 to NTridentDrives*NPartitions-1 do
		 [ tridentVec!t=
				TFSInit(PDZone,true,(NPartitions-1-(t rem NPartitions))*#400 + (NTridentDrives-1-(t/NPartitions)),ddmgr)
			if tridentVec!t ne 0 then noTrident=false
		 ]
		if noTrident then TypeForm("Cannot operate any Trident disk!*n")
		]
	if InstallPrompt("   Do you want to use drive 1 of the Model 31",20) then
		if SetupDrive1() eq 0 then TypeForm("Cannot operate the second drive!*n")

//Now initialize all the known files:
	let p=vec 3000
	for f=0 to FILEInitMax do
	   [
	   let len=IndexFile(p, f)
	   if len eq 0 then PDError(250)
	   let a=GetFileStatic(f)
		if a eq lv BitsFile then //test for T80 or T300
		 [ let disk=p>>F.Device
			if disk ge DISKT80 then tridentUsed =
				(TFSDiskModel(tridentVec!(disk-2)) eq 80)?5,19	//nHeads
		 ]
	   @a=p
	   SaveStatic(st, a, len)
	   if f eq FILEMeter then
		[
		//Meter file needs initializing
		let a=WindowInit(MeterFile)
		WindowWriteBlock(a, (table [ 0;2 ] ),2)	//Current length
		WindowClose(a)
		]
	   ]

	SaveStatic(st, lv tridentUsed)
	CloseDrive1()
	if tridentUsed then 
		for t=0 to NTridentDrives*NPartitions-1 do 
			if tridentVec!t ne 0 then TFSClose(tridentVec!t,true)

//Now go down the PDPrint.Run file and find all the overlays (page numbers)

	let ovTab=vec 20
	let ovNum=0
	let s=OpenFile("PDPrint.Run", ksTypeReadWrite)
	let pn=cfa>>CFA.fa.pageNumber
	   [
		PositionPage(s, pn)
		if Endofs(s) then break
		let v=vec 15
		ReadBlock(s, v, 16)
		if v!2 ne 1 % v!5 ne pn-1 then PDError(251)
		ovTab!ovNum=pn
		ovNum=ovNum+1
		pn=pn+(v!4 + 255)/256
	   ] repeat
	OverlayTable=ovTab
	SaveStatic(st, lv OverlayTable, ovNum)

//Now ramble down PDPrint.Run and plug in the hintState
	Resets(s)
	let v=vec (size BLV/16)+(size SV.H/16)
	ReadBlock(s, v, (size BLV/16)+(size SV.H/16))
	let ns=(size BLV/16)+(size SV.H/16)+#300
	ns=ns+v>>SV.BLV.endOfStatics-v>>SV.BLV.startOfStatics+1
	ns=ns+hintState-v>>SV.BLV.startOfCode
	SetFilePos(s, 0, ns*2)
	WriteBlock(s, hintState, lFP+1)	//Write in the magic fp.
	Closes(s)

	OverlayReloc=v>>SV.BLV.relPairTable
	SaveStatic(st, lv OverlayReloc)

//Save sysDisk, because it will be Junta'ed away
	SaveStatic(st, lv sysDisk, (size DSK/16)+lKDHeader)

//Any other state to be saved goes here.....
	Puts(st, 0)		//Termination
	SetFilePos(st, 0, 1*2)
	Puts(st, nDefaults)
	WriteBlock(st, defaultVec, nDefaults)
	Closes(st)

	finish
]

//InstallPrompt(string, defaultIndex, type)
//	type=0 (default) Yes/No
//	type=1 simple cardinal (up to 65,000)
//	type=2 number*10
//	type=3 lookup a string and return its index

//----------------------------------------------------------------------------
and InstallPrompt(str, defaultIndex, type; numargs n) = valof
//----------------------------------------------------------------------------
[	let GetInstallString(i) = selecton i into
	 [	case printerDover: "Dover"
		case printerSequoia: "Sequoia"
		case printerPimlico: "Pimlico"
		case printerPenguin: "Penguin"
		case printerPuffin: "Puffin"
		case printerSlot: "Slot"
		case printerVersatec: "Versatec"
		case printerHg: "Hg" 
	]

	if n eq 2 then type=0
	if defaultIndex ge nDefaults then PDError(253)
	let defVal=defaultVec!defaultIndex
	TypeForm(str);
	if defaultVec!-1 then	//Defaults valid
	[
	TypeForm($();
	switchon type into
		[
		case 0: TypeForm((defVal? "Yes","No"))
			endcase
		case 1: TypeForm(10, defVal)
			endcase
		case 2: FLDI(1, defVal)
			FLDI(2,10); FDV(1,2)
			TypeForm(2,1)
			endcase
		case 3: TypeForm(GetInstallString(defVal))
		]
	TypeForm($))
	]
	let ans=vec 20
	TypeForm((type eq 0? $?, $:),1,ans)
	if ans>>STR.length eq 0 then resultis defVal
	let res=nil
	switchon type into [
	case 0: [
		let c=ans>>STR.char↑1
		res=( c eq $y % c eq $Y)
		endcase
		]
	case 3: [
		let match=nil
		[
		for i=0 to 9 do
			[
			let s=GetInstallString(i)
			match=true
			for j=1 to ans>>STR.length do
			   [
			   if ((ans>>STR.char↑j xor s>>STR.char↑j)&(not #40)) ne 0 then
				match=false
			   ]
			if match then [ res=i; break ]
			]
		if match then break
		TypeForm("Invalid response, try again: ",1,ans)
		] repeat
		endcase
		]
	default: [
		res=ReadNumber(ans)
		if type eq 2 then
			[
			FLDI(2,20); FML(1,2);
			FLDI(2,1); FAD(1,2); FLDI(2,2); FDV(1,2) //Round
			res=FTR(1)
			]
		endcase
		]	
	]
	defaultVec!defaultIndex=res
	resultis res
]

// State saving and restoring for static values (and vectors)

//----------------------------------------------------------------------------
and SaveStatic(stream, staticAdr, len; numargs n) be
//----------------------------------------------------------------------------
[
	if n ne 3 then len=0
	Puts(stream, staticAdr)
	Puts(stream, len)
	test len eq 0 then Puts(stream, staticAdr!0)
	       or WriteBlock(stream, staticAdr!0, len)
]