-- NodeAddrs.Mesa
-- written by Paxton.  March 1981
-- last written by Paxton.  March 20, 1981  2:42 PM

-- **** Persistent addressing for nodes ****

DIRECTORY
CardAddrs,
NodeProps,
TextNode;

NodeAddrs: DEFINITIONS
	IMPORTS NodeProps, CardAddrs =
BEGIN
OPEN
	nodeI: TextNode,
	addrsI: CardAddrs,
	propsI: NodeProps;

Card: TYPE = LONG CARDINAL;
Ref: TYPE = nodeI.Ref;
RefTextNode: TYPE = nodeI.RefTextNode;

-- **** Text Addr operations 

PutTextAddr: PROC [n: RefTextNode, addr: REF, location: Card] = INLINE { 
	-- assigns addr to location in node
	-- ok if addr was previously assigned elsewhere in the node
	addrs: addrsI.Ref;
	IF (addrs ← propsI.GetTextAddrs[n]) = NIL THEN
		propsI.PutTextAddrs[n, addrs ← addrsI.Create[]];
	addrsI.PutAddr[addrs, addr, location] };

RemTextAddr: PROC [n: RefTextNode, addr: REF] = INLINE
	-- removes the given addr
	{ addrsI.RemAddr[propsI.GetTextAddrs[n], addr] };

GetTextAddr: PROC [n: RefTextNode, addr: REF] RETURNS [location: Card] =
	-- generates ERROR addrsI.AddrNotFound if the addr is not in the mapping
	INLINE { RETURN [addrsI.GetAddr[propsI.GetTextAddrs[n], addr]] };

TryGetTextAddr: PROC [n: RefTextNode, addr: REF]
	RETURNS [found: BOOLEAN, location: Card] = INLINE {
	[found, location] ← addrsI.TryGetAddr[propsI.GetTextAddrs[n], addr] };

MapTextAddrs: PROC [n: RefTextNode, action: TextAddrsAction]
	RETURNS [BOOLEAN] = INLINE
	-- apply the action to each addr&location pair for the node
	-- returns true if&when an action returns true
	{ RETURN [addrsI.MapAddrs[propsI.GetTextAddrs[n], action]] };

	TextAddrsAction: TYPE = addrsI.MapAddrsAction;
		-- = PROC [addr: REF, location: Card] RETURNS [BOOLEAN];

-- **** Editing Operations for text addrs ****

Replace: PROC [n: RefTextNode, start, len, newlen: Card] = INLINE
	-- replace chars in [start..start+len) by newlen chars
	-- addrs that are in the replaced section move to start
	-- add (newlen-len) to addrs that are after the replaced section
	{ addrsI.Replace[propsI.GetTextAddrs[n], start, len, newlen] };

Insert: PROC [n: RefTextNode, start, length: Card] = INLINE {
	-- adds len to addrs at or beyond start
	Replace[n, start, 0, length] };

Delete: PROC [n: RefTextNode, start, length: Card] = INLINE {
	Replace[n, start, length, 0] };

Move: PROC [n: RefTextNode, dest, start, len: Card] = INLINE
	-- dest must not be in [start..start+len)
		-- or get ERROR BadMove
	{ addrsI.Move[propsI.GetTextAddrs[n], dest, start, len] };

Transpose: PROC [n: RefTextNode, astart, alen, bstart, blen: Card] = INLINE
	-- [astart..astart+alen) must not intersect [bstart..bstart+blen)
		-- or get ERROR BadTranspose
	{ addrsI.Transpose[propsI.GetTextAddrs[n], astart, alen, bstart, blen] };


-- **** Child Addr operations 

PutChildAddr: PROC [n: Ref, addr: REF, location: Card] = INLINE { 
	-- assigns addr to location in node
	-- ok if addr was previously assigned elsewhere in the node
	addrs: addrsI.Ref;
	IF (addrs ← propsI.GetChildAddrs[n]) = NIL THEN
		propsI.PutChildAddrs[n, addrs ← addrsI.Create[]];
	addrsI.PutAddr[addrs, addr, location] };

RemChildAddr: PROC [n: Ref, addr: REF] = INLINE
	-- removes the given addr
	{ addrsI.RemAddr[propsI.GetChildAddrs[n], addr] };

GetChildAddr: PROC [n: Ref, addr: REF] RETURNS [location: Card] =
	-- generates ERROR addrsI.AddrNotFound if the addr is not in the mapping
	INLINE { RETURN [addrsI.GetAddr[propsI.GetChildAddrs[n], addr]] };

TryGetChildAddr: PROC [n: Ref, addr: REF]
	RETURNS [found: BOOLEAN, location: Card] = INLINE {
	[found, location] ← addrsI.TryGetAddr[propsI.GetChildAddrs[n], addr] };

FollowChildAddrs: PROC [node: Ref, addr: REF] RETURNS [Ref];

MapChildAddrs: PROC [n: Ref, action: ChildAddrsAction]
	RETURNS [BOOLEAN] = INLINE
	-- apply the action to each addr&location pair for the node
	-- returns true if&when an action returns true
	{ RETURN [addrsI.MapAddrs[propsI.GetChildAddrs[n], action]] };

	ChildAddrsAction: TYPE = addrsI.MapAddrsAction;
		-- = PROC [addr: REF, location: Card] RETURNS [BOOLEAN];

-- **** Editing Operations for child addrs ****

ReplaceNodes: PROC [n: Ref, start, len, newlen: Card] = INLINE
	-- replace chars in [start..start+len) by newlen chars
	-- addrs that are in the replaced section move to start
	-- add (newlen-len) to addrs that are after the replaced section
	{ addrsI.Replace[propsI.GetChildAddrs[n], start, len, newlen] };

MoveNodes: PROC [n: Ref, dest, start, len: Card] = INLINE
	-- dest must not be in [start..start+len)
		-- or get ERROR BadMove
	{ addrsI.Move[propsI.GetChildAddrs[n], dest, start, len] };

InsertNode: PROC [n: Ref, start, length: Card] = INLINE {
	-- adds len to addrs at or beyond start
	ReplaceNodes[n, start, 0, length] };

TransposeNodes: PROC [n: Ref, astart, alen, bstart, blen: Card] = INLINE
	-- [astart..astart+alen) must not intersect [bstart..bstart+blen)
		-- or get ERROR BadTranspose
	{ addrsI.Transpose[propsI.GetChildAddrs[n], astart, alen, bstart, blen] };

END.