// MINIT1.BCPL	Second initialization

//This overlay is loaded into the standard overlay zone constructed
//from the space occupied by the display bit buffers

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

external [
// OS
	CallSwat; Endofs; Resets; Wns; Noop; Zero; SetBlock; MoveBlock

// MIDAS
	ElapsedTime; TimeMRGN; TimeMAP; TimeMSYM; TimeMMPRGN

// MINIT2
	DInit0; GetZStorage

// MDISP
	MarkLineInUse

// MASM
	GetStorage; @BlockTable; StrSize

//MRGN
	RegionTable; NRegions; SelectedRegion
	CharInputRoutine; EveryTimeP; EveryTimeA; EveryTimeSlot
	AddToEveryTimeList; ScreenLinesDirty

//MMPRGN
	MPDAs; MPDAVec; MPDVs; MPDVVec; @LongOne
	MPDEveryTime; MPDlist; InitMPDispRegions
	MPDrlx; MPDrcx; MPDdeSelect; SkipVEql; SkipVGr; SkipVLs

//MMENU
	CreateAction; ActionBlock; ActionPtr; LastPermanentAction
	MenuBlock; @ItemV; MenuTVs; ItemStream; @CurrentMDFS
	PaintMenu; MenuMChange; SelectMenu; deSelectMenu; PutMenus
	FormMenu

//MTV
	PutTVs; ResetTVs; CloseTVs; BadTVsCall

//MTXTBUF
	InputTxtRgn; InputTextBuffer; TxtBPaint; TxtBNewChar

//MSYM
	@LastBlockAddr; @HeadBlock; Map
	TVtoString; MakeNewBlock; GetFreeBlock; BlockUpdateRcd; UpdateRcd
	@NextM; @LastM2; @LastM1

// Overlay Package
	InitFmap

//MINIT0
	BlockStoreFP

//Machine dependent
	ScreenHeight; ScreenWidth; InitMPInterface; NHWActions

//MCMD
	InitCmd; CmdMDFS; CmdConfirm; CmdReturn
	CmdCommentStream; CmdCommentDirty; CmdCommentVec; PaintCmdP
	ProgramVec; ProgramStream; PaintPrgP
	ProgramAct; NPrograms; NMActions; MActions; RunProgram
	CmdAddrEq; CmdTimeOut; CmdSkipCmd; CmdSetDisplay
	CmdOpenOutput; CmdCloseOutput; CmdWriteMessage; CmdShowError
	CmdFinish; CmdRunProg; CmdDoRC; CmdLoad; TextCmdOutStream
	ShowActionForm; SavedLoadText; FormCmdmenuText

//MLOAD
	LoadMB; LoadSyms; CompareMB

//STATE
	SaveStatics

//Defined here
	Init1; NewMPDispBlock; DefineRegister; DefineMemory
	HWActions; DefHWAction; DefIAction; MakeTVS
]

manifest[ MaxItemsInCmdMenu = 60; StandardMenu = 1; BadValuePhase = 1 ]

static [ HWActions ]

structure TVS :
[	@ST
	NoteP	word
	NoteArg	word
]

let Init1() be
[
//MDISP
	DInit0()	//First part of display init only (need LCB's below)

//MRGN
	RegionTable = GetZStorage(MaxNRegions)
	SelectedRegion = NewRegion(size Rgn/16,0,0,ScreenHeight,ScreenWidth,
		Noop,Noop,Noop,Noop)
	EveryTimeP = GetZHStorage(MaxEveryTime)
	EveryTimeA = GetZHStorage(MaxEveryTime)
	EveryTimeSlot = GetZStorage(MaxEveryTime + 1)
	ElapsedTime(lv TimeMRGN)

//MSYM
	let MapSize = 2*(MaxBlockPages + 1) + 10
	Map = GetStorage(MapSize)
	InitFmap(Map, MapSize, BlockStoreFP)
	ElapsedTime(lv TimeMAP)
	BlockTable = GetZStorage(15)
	BlockTable!0 = 2
	HeadBlock = GetFreeBlock(MakeNewBlock(NPagesPerHeadBlock))
	let CurrentBlock =
		GetFreeBlock(MakeNewBlock(NPagesPerStandardBlock))
	BlockTable!1 = CurrentBlock
	BlockTable!2 = MakeNewBlock(NPagesPerStandardBlock)
//Initialization of other blocks saved till last to make optimal use of
//any unused storage
	LastBlockAddr = CurrentBlock>>BH.BlockAddr
//Enter null & max strings in symtab to avoid end checks
	unless BlockUpdateRcd(HeadBlock,-(size BH/16 - 1), "",
		lv CurrentBlock>>BH.BlockAddr, 1)
	  & BlockUpdateRcd(CurrentBlock,-(size BH/16 - 1), "",
		table [ 0 ] , 1)
	  & BlockUpdateRcd(CurrentBlock,-(size BH/16),
		table [ 1577B; 77577B ] ,table [ 0 ] , 1)
	  do CallSwat("Bug in Init1 for MSYM")
	ElapsedTime(lv TimeMSYM)

//MMENU
	ActionBlock = GetZStorage(MaxActions*(size Action/16))
	MenuBlock = GetZStorage(MaxMenus)
	ItemV = GetZHStorage(ScreenWidth)
	ItemStream = GetStorage(size ST/16)
	SetUpStream(ItemStream,0,0,Noop,Noop,PutMenus,CallSwat,
		Noop,Noop,Noop,Noop,Noop,0)
	MenuTVs = MakeEmptyTVstream()

//MTXTBUF
	let rcx,H,W = 0,1,ScreenWidth-1
	InputTxtRgn = NewRegion(size Rgn/16,ScreenHeight-2,0,1,
		W,TxtBPaint,Noop,Noop,Noop)
	CharInputRoutine = TxtBNewChar
	InputTextBuffer = GetZHStorage(ScreenWidth)

// Following must be last items before call on DriverLoop
//MMPRGN
	InitMPDispRegions()	//Create address and value actions
	MakeTVS(lv MPDAs,lv MPDAVec)
	MakeTVS(lv MPDVs,lv MPDVVec)
	HWActions = GetStorage(NHWActions)
	InitMPInterface()
	DefIAction("SkipVEql",lv SkipVEql)
	DefIAction("SkipVGr",lv SkipVGr)
	DefIAction("SkipVLs",lv SkipVLs)
	AddToEveryTimeList(MPDEveryTime,MPDlist)
	ElapsedTime(lv TimeMMPRGN)

//MCMD
	SavedLoadText = GetZStorage(W+1)
	MakeDisplayLine(lv ProgramStream,lv ProgramVec,
		CmdCommentDirty,PaintPrgP,ScreenHeight-10,H,W,rcx)
	MakeDisplayLine(lv CmdCommentStream,lv CmdCommentVec,
		CmdCommentDirty,PaintCmdP,ScreenHeight-8,H,W,rcx)

	H = 3
	InitCmd()
	MActions = GetStorage(NMActions)
	DefMAction(0,"Exit",lv CmdFinish,0,0,$Q)
	DefMAction(1,"Run-Program",lv CmdRunProg,0)
	DefMAction(2,"Read-Cmds",lv CmdDoRC,0)
	DefMAction(3,"Load",lv CmdLoad,lv LoadMB,0,$L)
	DefMAction(4,"LoadSyms",lv CmdLoad,lv LoadSyms)
	DefMAction(5,"Compare",lv CmdLoad,lv CompareMB,0,$C)
	DefIAction("Addr=",lv CmdAddrEq,0,$=)
	DefIAction("DisplayOff",lv CmdSetDisplay,true,$O-100B)
	DefIAction("DisplayOn",lv CmdSetDisplay,false,$D-100B)
	DefIAction("TimeOut",lv CmdTimeOut)
	DefIAction("Confirm",lv CmdConfirm)
	DefIAction("Skip",lv CmdSkipCmd,false)
	DefIAction("BackSkip",lv CmdSkipCmd,true)
	DefIAction("Return",lv CmdReturn)
	DefIAction("ShowError",lv CmdShowError)
	DefIAction("OpenOutput",lv CmdOpenOutput)
	DefIAction("CloseOutput",lv CmdCloseOutput)
	DefIAction("WriteMessage",lv CmdWriteMessage)
	for I = 0 to NPrograms-1 do
	[ ProgramAct!I = CreateAction(ProgramAct!I,lv RunProgram,
		ProgramAct!I)
	]
	CmdMDFS = MakeMenuRegion($X,-1,ScreenHeight-6,
		0,H,W,H,W,MaxItemsInCmdMenu,0,Noop)
	FormMenu(CmdMDFS,FormCmdmenuText)

	LastPermanentAction = ActionPtr

//Save page zero statics
	SaveStatics(lv BlockTable,lv ItemV,lv CurrentMDFS,lv LastBlockAddr,
		lv HeadBlock,lv NextM,lv LastM2,lv LastM1,lv LongOne)
]


and MakeDisplayLine(lvStream,lvVector,Dirty,Paint,Line,H,W,rcx) be
[	rv lvStream = MakeEmptyTVstream()
	rv lvVector = GetStorage(W+1)
	Resets(rv lvStream,rv lvVector,W,Dirty,NewRegion(size Rgn/16,
		Line,rcx,H,W,Paint,Noop,Noop,Noop))
]


and GetZHStorage(Size) = valof
[	let Vector = GetStorage(Size+1)
	Vector!0 = 0; resultis Vector
]


and MakeEmptyTVstream(numargs NA) = valof
[	if NA ne 0 then CallSwat()
	let Stream = GetStorage(size TVS/16)
	SetUpStream(Stream,0,0,CloseTVs,BadTVsCall,PutTVs,ResetTVs,
		BadTVsCall,BadTVsCall,BadTVsCall,BadTVsCall,0,0)
	Stream>>TVS.NoteP = 0
	resultis Stream
]


and MakeTVS(lvStream,lvVector) be
[	rv lvStream = MakeEmptyTVstream()
	rv lvVector = GetStorage(ScreenWidth+1)
	Resets(rv lvStream,rv lvVector,ScreenWidth)
]


and SetUpStream(S,xPar1,xPar2,xClose,xGets,xPuts,xResets,xPutb,
		xError,xEndof,xStateof,xType,xPar3) be
[	S>>ST.par1 = xPar1;	S>>ST.par2 = xPar2
	S>>ST.close = xClose;	S>>ST.gets = xGets
	S>>ST.puts = xPuts;	S>>ST.reset = xResets
	S>>ST.putback = xPutb;	S>>ST.error = xError
	S>>ST.endof = xEndof;	S>>ST.stateof = xStateof
	S>>ST.type = xType;	S>>ST.par3 = xPar3
]

and NewRegion(BlockSize,rlx,rcx,Height,Width,PPaint,PSelect,
		PMChange,PdeSelect) = valof
[	if NRegions ge MaxNRegions then CallSwat()
	if rlx+Height > ScreenHeight then CallSwat()
	if rcx+Width > ScreenWidth then CallSwat()
	let R = GetStorage(BlockSize)
	R>>Rgn.aLineX = rlx
	R>>Rgn.aCharX = rcx
	R>>Rgn.Height = Height
	R>>Rgn.Width = Width
	R>>Rgn.Paint = PPaint
	R>>Rgn.Select = PSelect
	R>>Rgn.MChange = PMChange
	R>>Rgn.deSelect = PdeSelect
	NRegions = NRegions+1
	if NRegions ne 0 do
	[ for I = 0 to Height-1 do MarkLineInUse(rlx+I)
	]
	RegionTable!NRegions = R
	resultis R
]


and MakeMenuRegion(Letter,LineN,rlx,rcx,H,W,MaxH,MaxW,MaxNItems,
		Arg,PdeSelect) = valof
[	let S = NewRegion(size MDFS/16, rlx, rcx, H, W,
			PaintMenu, SelectMenu, MenuMChange, deSelectMenu)	
	S>>MDFS.Letter = Letter
	S>>MDFS.LineN = LineN & 377B
	S>>MDFS.TextLines = GetZHStorage(MaxH * (MaxW+1)-1)	//~76*21 words
	S>>MDFS.MaxH = MaxH
	S>>MDFS.MaxW = MaxW
	S>>MDFS.ProcV = GetZHStorage(MaxNItems)	//~4*60+60 words
	S>>MDFS.ProcNMax = MaxNItems
	S>>MDFS.SizeV = GetZHStorage(MaxH + MaxNItems-1)	//~4*60+60 words
	S>>MDFS.Arg = Arg
	S>>MDFS.SelectedItem = 0
	S>>MDFS.inLine = 1
	S>>MDFS.deSelect = PdeSelect
	S>>MDFS.mIn = 0

//Menus may be a single letter (A to Z) or a single letter followed
//by a small integer (A0 to E19).  LineN must be -1 if omitted.
//Command menu is "X"
	let LetterV = Letter-$A
	LetterV = (LineN < 0) ? LetterV,(LetterV*MaxLineN)+LineN+($Z-$A+1)
	if LetterV ge MaxMenus then CallSwat("Bad menu name")
	if MenuBlock!LetterV ne 0 then CallSwat("Duplicate menu name?")
	MenuBlock!LetterV = S
	resultis S
]


//Args are Line = line number (0 to n)
// C = left character (0 to ScreenWidth-1)
// Cnm = command file character identifying region
// W = width in characters (C+W < ScreenWidth)
// NoName = true for areas where only the value is printed
and NewMPDispBlock(Line,C,Cnm,W,NoName) be
[	let MPD = GetStorage(size MPD/16)
	MPD>>MPD.Idle = 1
	MPD>>MPD.Phase = BadValuePhase	//DriverLoop will paint
	MPD>>MPD.MenuMode = StandardMenu
	MPD>>MPD.Rabove = MPDlist
	MPD>>MPD.NoName = NoName ? 1,0
	MPD>>MPD.TextSpace = W		//This should be checked, not sure
	MPD>>MPD.MDFS = MakeMenuRegion(Cnm,Line,
		MPDrlx+Line,MPDrcx+C,1,W,1,W,3,MPD,MPDdeSelect)
	MPDlist = MPD
]

and DefineMemory(String,MemNum,BitWidth,Hsize,Size) be
[	let Body = vec (size Symb.M / 16)
	Body>>Symb.M.Type = MemSymb
	Body>>Symb.M.X = MemNum
	Body>>Symb.M.BitWidth = BitWidth
	Body>>Symb.M.Hsize = Hsize
	Body>>Symb.M.Size = Size
	UpdateRcd(String,Body,size Symb.M/16)
]


and DefineRegister(String,RegNum,BitWidth) be
[	let Body = vec (size Symb.R / 16)
	Body>>Symb.R.Type = RegSymb
	Body>>Symb.R.X = RegNum
	Body>>Symb.R.BitWidth = BitWidth
	UpdateRcd(String,Body,size Symb.R/16)
]


and DefHWAction(I,Name,lvProc,Arg,lvMProc,Letter; numargs NA) be
[	if I ge NHWActions then CallSwat()
	let SSize = StrSize(Name)
	let Body = GetStorage(SSize)
	MoveBlock(Body,Name,SSize)
	HWActions!I = CreateAction(Body,lvProc,Arg,
		(NA > 4 ? lvMProc,0),(NA > 5 ? Letter,0))
]


and DefMAction(I,Name,lvProc,Arg,lvMProc,Letter; numargs NA) be
[	if I ge NMActions then CallSwat()
	let SSize = StrSize(Name)
	let Body = GetStorage(SSize)
	MoveBlock(Body,Name,SSize)
	MActions!I = CreateAction(Body,lvProc,Arg,
		(NA > 4 ? lvMProc,0),(NA > 5 ? Letter,0))
]


//Define action which never appears in a menu
//(i.e., command file or keyboard char only)
and DefIAction(Name,lvProc,Arg,Letter; numargs NA) be
[	let SSize = StrSize(Name)
	let Body = GetStorage(SSize)
	MoveBlock(Body,Name,SSize)
	CreateAction(Body,lvProc,Arg,0,(NA > 3 ? Letter,0))
]