// GPAGE.SR	Pages and Read-only

get "BRAVO.DF"
get "CHAR.DF"
get "GINN.DF"

// Incoming procedures

external
	[
	updatedisplay
	invalidatewindow
	getint
	binsearcha
	hpfree
	getvch
	putvch
	mapscrcp
	errhlt
	stcopy
	stnum
	stappend
	stsize
	insertstring
	deletea
	hpalloca
	hpalloc
	move
	movec
	enww
	readsel
	stequal
	invalidatedisplay
	receivechange
	backscan
	parsespec
	unparsespec
	min
	max
	cpc
	discard
	bsearch
	growlist
	bubblesegs
	lastparacp
	makelist
	]

// Incoming statics

external
	[
	vww
	mww
	rgdlfirst
	rgdllast
	rgmaxdl
	macww
	rgdoc
	vdoc
	vcp
	vchremain
	rgmaccp
	rgcpfdispl
	rgcplast
	vxleftmarg
	vxrightmarg
	cpscrt
	vdlhint
	vinsertk
	mdoc
	umax
	umin
	vwheel
	vlooktrailer
	rgprogram
	vturning
	]

// Outgoing procedures

external
	[
	turntopage
	pagecp
	cppage
	pagepagenum
	pagenumpage
	pagenumcp
	cppagenum
	setpagecp
	setpagenum
	macpage
	makepage
	wholepages
	discardpages
	pointable
	nextunpointablecp
	prevunpointablecp
	nearestpointablecp
	nextpointablespan
	makeunpointabledoc
	makepointablespan
	makeunpointablespan
	]

// Outgoing statics

external
	[
	rgpage
	rgpagenum
	rgchoppage
	rgreadonly
	]


// Local statics

static
	[
	rgpage
	rgpagenum
	rgchoppage
	rgreadonly
	]

let cppage(doc, cp) = bsearch(rgpage ! doc, cp)

and cppagenum(doc, cp) = pagepagenum(doc, cppage(doc, cp))

and pagepagenum(doc, page) = (rgpagenum ! doc) ! (page + listbase)

and makepage(doc, cp) = valof // $$ only good for appending pages
[
let page = macpage(doc)-2
if cpc(cp, pagecp(doc, page)) le 0 then resultis page
growlist(rgpage+doc, 1, 10, 1, listbase)
growlist(rgpagenum+doc, 1, 10, 1, listbase)
bubblesegs(macpage(doc)-1, 1, page+1,
	rgpage!doc + listbase, rgpagenum!doc + listbase)
setpagecp(doc, page+1, cp)
let hinum = pagepagenum(doc, page)
setpagenum(doc, page+1, hinum+1)
setpagenum(doc, page+2, hinum+2)
resultis page+1
]

and setpagecp(doc, page, cp) be
	(rgpage ! doc) ! (page + listbase) = cp

and setpagenum(doc, page, pagenum) be
	(rgpagenum ! doc) ! (page + listbase) = pagenum

and pagecp(doc, page) = valof
[
// Inverse of cppage
// Given a page, find the cp of the start of it
resultis (rgpage ! doc) ! (page + listbase)
]

and pagenumcp(doc, pagenum) = pagecp(doc, pagenumpage(doc,pagenum))

and pagenumpage(doc, pagenum) = bsearch(rgpagenum ! doc, pagenum)

and macpage(doc) = (rgpage ! doc) >> LIST.siz

and wholepages(doc, cp1, cp2, ppage1, ppage2) = valof
	[
	@ppage1 = cp1 eq 0? 0,cppage(doc, cp1-1)+1
	@ppage2 = cppage(doc, cp2+1)-1
	resultis @ppage1 le @ppage2
	]

and discardpages(doc, page1, page2) be
[
unless page1 do // can't delete page 0 -- sacrifice page 1 instead
	[
	page1 = page1 + 1
	page2 = page2 + 1
	]
page2 = min(page2, macpage(doc)-2)
discard(macpage(doc), page1, page2, rgpage!doc, rgpagenum!doc)
]

and pointingsection(doc, cp) = valof
	[ // even sections are read only, odds are pointable
	// This considers the first cp in a r-o section unpointable
	let rr = rgreadonly ! doc
	unless rr do resultis -1
	let r = bsearch(rr, cp)
	resultis r << odd & rr ! (listbase+r) eq cp? r-1, r
	]

and pointable(doc, cp1, cp2) = valof
	[
	// This considers the first cp in a r-o section unpointable
		// except when cp1 > cp2
	unless rgreadonly!doc do resultis true
	if cpc(umax(cp1,cp2),
			lastparacp(doc)-(rgprogram!doc?2,0)) ge 0
		then resultis false
	if vwheel & doc ne mdoc then resultis true
	let r1 = pointingsection(doc, cp1)
	if r1 eq -1 then resultis true
	let r2 = cp2 eq -1? 0, bsearch(rgreadonly!doc, cp2)
	resultis r2 << odd & (cpc(cp1, cp2) gr 0 % r1 eq r2)
	]

and nextunpointablecp(doc, cp) = valof
	[ // cp assumed in pointable section
	// This considers the first cp in a r-o section unpointable
	let rr = rgreadonly ! doc
	if (vwheel & doc ne mdoc) % not rr then
		resultis lastparacp(doc)-(rgprogram!doc?2,0)
	resultis (rr + listbase) !
		((pointingsection(doc, cp)+1) & #177776)
	]

and prevunpointablecp(doc, cp) = valof
	[ // cp assumed in pointable section
	let rr = rgreadonly ! doc
	if (vwheel & doc ne mdoc) % not rr then resultis -1
	resultis (rr + listbase) !
		(((pointingsection(doc, cp)-1) & #177776) % 1)
	]

and nearestpointablecp(doc, cp, cp1, cp2) = valof
	[ // rgreadonly better exist and cp assumed in read only section
	// cp1 and cp2 are limits to result
	// This considers the first cp in a r-o section pointable
	let rr = rgreadonly ! doc
	let r = pointingsection(doc, cp)
	let cpl = r eq 0? -1, rr ! (listbase + r)
	let cpr = r ge rr >> LIST.siz-2? -1, rr ! (listbase+r+1) + 1
	if cpc(cpl, cp1) ls 0 then cpl = -1
	if cpc(cpr, cp2) gr 0 then cpr = -1
	resultis cpl eq -1? cpr, cpr eq -1? cpl,
		cpc(cp-cpl, cpr-cp) ls 0? cpl, cpr
	]

and nextpointablespan(doc, cp, pcp1, pcp2) = valof
	[ // rgreadonly better exist and cp assumed in read only section
	// This considers the first cp in a r-o section unpointable
	let rr = rgreadonly ! doc
	let r = pointingsection(doc, cp)
	if r ge rr >> LIST.siz-2 then resultis false
	@pcp1 = rr ! (listbase + r + 1) + 1
	@pcp2 = rr ! (listbase + r + 2) - 1
	resultis true
	]

and makeunpointabledoc(doc, nrosections) = valof
	[
	if rgreadonly ! doc then hpfree(rgreadonly ! doc)
	let rr = makelist(2*nrosections, 1, listbase, false)
	rr ! (listbase+2*nrosections-1) = rgmaccp ! doc
	// caller should fill in the rest if nrosections > 1
	rgreadonly ! doc = rr
	resultis rr + 2
	]

and turntopage(doc, pnum) be // $$
	[
	if vww le mww then return
	pnum = max(pnum, 0)
	pnum = min(pnum, (rgpagenum!doc)!(listbase+macpage(doc)-2))
	updatedisplay()
	invalidatewindow(vww)
	vturning = true
	rgcpfdispl ! vww = pagenumcp(doc, pnum)
	]

and makepointablespan(doc, cp1, cp2) be
	[ // later for ddoc
	]

and makeunpointablespan(doc, cp1, cp2) be
	[ // later for ddoc
	]