// MINIT3.BCPL	Final display and region initialization

//Init3() does final display and region initialization, then parses
//Com.CM in preparation for doing a Read-Cmds.  It returns true if
//Read-Cmds should be done.


get "mdecl.d"
get "streams.d"
get "altofilesys.d"

external [
// OS
	CallSwat; SetBlock; MoveBlock; Zero; lvUserFinishProc
	OpenFile; Gets; Endofs; Closes; fpComCm

// MIDAS
	GetStorage; GetEvenStorage; ZoneErr; Initialized; lvFinishProc
	MidasFinish; Restoring; TimeInit3; ElapsedTime

// MASM
	VertIntCode; Max; Min; @BlockTable

// MDISP
	SaveAdd1; SaveData1; SaveAdd2; SaveData2; SaveAdd3; SaveData3
	SavervDASTART; SavedDASTART; DispSpaceNowAvail
	StandardLineHeight; NwdsPerScanLine
	LineCtrlBlockPtrsVector; FirstDCB; DCBPoolSize; DCBPool
	@BadMouseP; FreeBitBufferChain; AlmostFreeBitBufferChain
	DCBPoolIn; DCBPoolOut; DCBPoolAvail; VertIntFlag; LinesInUse
	GetFreeDCB; PutLineInService; InitBBblock; BBblock

// MRGN
	ScreenTV; ScreenLineDirty; ControlV; RegionTable; NRegions
	BlankS; MouseButtons; MouseButtonunion; PaintDirtyRegions

// MTXTBUF
	InputTextBuffer

// MSYM
	MakeNewBlock

// STATE package
	StorageLeft

// MINIT2
	VecInit; NNonOvBitBuffers; FirstNonOvLine

// Machine dependent
	ScreenHeight		//Number of text lines on screen
	ScreenWidth		//Number of chars/line

//Defined here
	Init3
]

let Init3(fname) = valof
[


// MRGN
	let SSize = (ScreenWidth rshift 1)+1
	for I = 1 to ScreenHeight do
	[ test LinesInUse!I
	  ifso
	  [ ScreenTV!I = GetStorage(SSize)
	    MoveBlock(ScreenTV!I,BlankS,SSize)
	  ]
	  ifnot ScreenTV!I = BlankS
	]
	ScreenLineDirty = VecInit(ScreenHeight,true)
	MouseButtons,MouseButtonunion = 0,0
	for Rn = 0 to NRegions do
	[ let R = RegionTable!Rn
	  if R eq 0 then CallSwat()
	  let alx,acx = R>>Rgn.aLineX,R>>Rgn.aCharX
	  let Llast = alx+R>>Rgn.Height
	  let Clast = acx+R>>Rgn.Width
	  for I = alx+1 to Llast do
	  [ let C1 = acx+1
	    if (C1 & 1) ne 0 do	//Odd byte at beginning
	    [ (ControlV!I)>>CV↑C1 = Rn; C1 = C1+1 ]
	    if (Clast & 1) eq 0 do	//Even byte at end
	    [ (ControlV!I)>>CV↑Clast = Rn ]
	    SetBlock(ControlV!I+(C1 rshift 1),Rn+(Rn lshift 8),
		(Clast-C1+1) rshift 1)
	  ]
	]

// MDISP
	FreeBitBufferChain,AlmostFreeBitBufferChain = 0,0
	VertIntFlag,DispSpaceNowAvail = 0,0
	BadMouseP = true
	CreateDCBs(ScreenHeight+17)	//Extras avoid wait for vert. int.
	CreateLCBs()
	SaveData1 = rv SaveAdd1
	IntVec!(VertIntChan) = VertIntCode
	SaveData2 = rv SaveAdd2
	DASTART!1 = (DASTART!1) logor( 1 lshift (VertIntChan) )
	SaveData3 = rv SaveAdd3
	rv IntActive = (rv IntActive) logor (1 lshift VertIntChan)
	SavervDASTART = rv DASTART	//Saved for exit from Midas
//Midas comes up with the display off until the end of the Com.CM
//command file execution.  The bit buffers remain in OverlayZone
//until after the first command in the command file is executed.
	SavedDASTART = FirstDCB; rv DASTART = 0
	Initialized = true
	InitBBblock(BBblock,NNonOvBitBuffers)
//Have to dirty all the non-overlay regions so that they will get painted
//when the program is resumed after calls to AltIO.
	for Rn = 0 to NRegions do (RegionTable!Rn)>>Rgn.DispDirty = 1
	PaintDirtyRegions()
	for L = FirstNonOvLine to ScreenHeight do PutLineInService(L)
//Finally, allocate extra symbol blocks with any unused storage.  This
//is saved till last to make as many as possible.  Everything procedes ok
//with regard to Midas.SymTab because the extra blocks have been written
//onto the disk before calling AltIO and because the first two blocks
//are preserved in Midas.State.
	while StorageLeft()-2 > NPagesPerStandardBlock*PageSize do
	[ BlockTable!0 = BlockTable!0 + 1
	  BlockTable!(BlockTable!0) = MakeNewBlock(NPagesPerStandardBlock)
	]
	lvFinishProc = @lvUserFinishProc
	@lvUserFinishProc = MidasFinish

	let X,C = 0,nil
	test fname ne 0
	ifso
	[ Restoring!1 = 0
	  X = fname>>lh; if X > 72 then CallSwat(); for I = 0 to X do
	  [ InputTextBuffer!I = fname>>CV↑I ]
	]
	ifnot
//Skip over "Midas.run/n " in Com.CM
	[ let F = OpenFile("Com.CM",ksTypeReadOnly,charItem,0,fpComCm)
	  if F eq 0 then CallSwat()
	  while not Endofs(F) do [ if Gets(F) eq $  then break ]
	  while not Endofs(F) do [ C = Gets(F); if C ne $  then break ]
	  while not Endofs(F) do
	  [ if X < 72 do [ X = X+1; InputTextBuffer!X = C ] ; C = Gets(F) ]
	  Closes(F)
	  InputTextBuffer!0 = X
	]
	ElapsedTime(lv TimeInit3)
	resultis X > 0
]


and CreateLCBs() be
[	let B = GetStorage(ScreenHeight * (size LCB/16))
// create blank space at top of screen
	FirstDCB = GetFreeDCB(NwdsPerScanLine,false,0,SkipScanLines rshift 1)
// now set up NLines
	let PrevLCB = 0
	let LastDCB = FirstDCB
	for L = 1 to ScreenHeight do
	[ let DCB = GetFreeDCB(NwdsPerScanLine, false, 0, 
				StandardLineHeight rshift 1)
	  LastDCB!0 = DCB; LastDCB = DCB
	  let LCB = B
	  B = B + (size LCB/16)
	  LCB>>LCB.DispCtrlBlock = DCB
	  LCB>>LCB.BitBuffer = 0
	  LCB>>LCB.PrevLCB = PrevLCB
	  LCB>>LCB.Hover2 = StandardLineHeight rshift 1
	  LineCtrlBlockPtrsVector!L = LCB
	  PrevLCB = LCB
	]
	LastDCB!0 = 0
]


and CreateDCBs(N) be
[	DCBPoolAvail,DCBPoolIn,DCBPoolOut = 0,0,1
	DCBPool = GetStorage(N+1)
	let DCBSpace = GetEvenStorage(4*N)
	for I = 1 to N do
	[ DCBPool!I = DCBSpace; DCBSpace = DCBSpace + 4 ]
	DCBPool!0 = 0
	DCBPoolSize = N+1
]