-- GCellArrayImpl.mesa
-- Last Edited by: Sturgis, March 8, 1983 12:46 pm
DIRECTORY
   IO USING[char, GetInt, STREAM, int, Put],
   Dependencies USING[Action, DeactivateAction, DefineAction],
   Expressions USING[IdTable, IdTableSet, MakeIdTable],
   GCell USING[CreateGCell, DoColSum, DoRowSum, GCellItemDescriptor, GetGCellContents, LoadGCell, NoteArraySelection, NoteSummers, SelectionDirection, SetAGCellArrayProc, SetAGCellProc,  SetGCellContents, SetGCellIdInfo, StandardGCells, StepSelection],
   NewCalcGlobal USING[Displayer, Document],
   Rope USING[ROPE],
   StructureNodes USING[Action, AddColumnAt, AddRowAt, ColHandle, CreateDisplayArray, DACell, DeleteColumnAt, DeleteRowAt, DisplayArray, GetColNumber, GetColInfoAt, GetContextDA, GetElementAt, GetRowInfoAt, GetRowNumber, PrePaintPass, RowHandle, SetColInfoAt, SetElementAt, SetRowInfoAt, StructureNode, StructureNodeBody, StructureNodeProcs],
   ViewerClasses USING[Viewer];
  

GCellArrayImpl: PROGRAM IMPORTS Dependencies, Expressions, GCell, IO, StructureNodes EXPORTS GCell =

BEGIN OPEN Expressions, GCell, IO, NewCalcGlobal, StructureNodes, ViewerClasses;


GCellArray: TYPE = REF GCellArrayBody;
GCellArrayBody: PUBLIC TYPE = RECORD[
   da: DisplayArray, -- this and next item refer to the associated Display Array
   daSn: StructureNode,
   nRows, nColumns: CARDINAL,
   document: NewCalcGlobal.Document,
   displayer: NewCalcGlobal.Displayer,
   vParent: Viewer];
   
SlotInfo: TYPE = REF SlotInfoBody;
SlotInfoBody: TYPE = RECORD[
	ids: IdTable
	];
   
StructureNodeProcs: REF StructureNodes.StructureNodeProcs ← NEW[StructureNodes.StructureNodeProcs ← [GCellArrayCheckForDirtyData, GCellArrayPreShow, GCellArrayShowLine, GCellArrayPrePrePaint, GCellArrayPrePaint, GCellArrayPaint, GCellArrayUnPaint, GCellArrayNoteEnclosingCell, GCellArrayNoteCoordinates, SaveGCellArray, ActGCellArray, SubstituteInGCellArray, AbandonGCellArray, VerifyGCellArray]];

-- public procedures for GCellArray (matrix) interface

LoadGCellArray: PUBLIC PROCEDURE[document: NewCalcGlobal.Document, displayer: NewCalcGlobal.Displayer, vParent: Viewer, from: IO.STREAM, version: CARDINAL] RETURNS[StructureNode] =
   BEGIN
   gca: GCellArray ← NEW[GCellArrayBody ← [NIL, NIL, 0, 0, document, displayer, vParent]];
   nRows, nColumns: CARDINAL;
   gcaSn: StructureNode ← NEW[StructureNodeBody ← [gca, StructureNodeProcs]];
   [gca.daSn, gca.da] ← CreateDisplayArray[gcaSn];
   
   nRows ← GetInt[from];
   nColumns ← GetInt[from];
   
   FOR I: CARDINAL IN [1..nColumns] DO [] ← BasicInstallColumnAt[gca, I] ENDLOOP;
   FOR J: CARDINAL IN [1..nRows] DO [] ← BasicInstallRowAt[gca, J] ENDLOOP;
   
         
  	
  FOR I: CARDINAL IN [1..gca.nColumns] DO
      colInfo: ColInfo ← NARROW[GetColInfoAt[gca.da, I]];
      FOR J: CARDINAL IN [1..gca.nRows] DO
         rowInfo: RowInfo ← NARROW[GetRowInfoAt[gca.da, J]];
         LoadOneSlot[gcaSn, gca, I, J, rowInfo.rowSummer, colInfo.colSummer, from, version];
         ENDLOOP;
      ENDLOOP;
   
   FOR I: CARDINAL IN [1..gca.nColumns] DO
      FOR J: CARDINAL IN [1..gca.nRows] DO
         ResetSlotIdInfo[gcaSn, gca, I, J];
         ENDLOOP;
      ENDLOOP;
      
   RETURN[gcaSn]
   END;
   
CreateGCellArray: PUBLIC PROCEDURE[document: NewCalcGlobal.Document, displayer: NewCalcGlobal.Displayer, vParent: Viewer] RETURNS[StructureNode] =
   BEGIN
   gca: GCellArray ← NEW[GCellArrayBody ← [NIL, NIL, 0, 0, document, displayer, vParent]]; 
   col1Summer, col2Summer, col3Summer, row1Summer, row2Summer, row3Summer: Dependencies.Action; 
   gcaSn: StructureNode ← NEW[StructureNodeBody ← [gca, StructureNodeProcs]];
   [gca.daSn, gca.da] ← CreateDisplayArray[gcaSn];
   
   col1Summer ← BasicInstallColumnAt[gca, 1];
   col2Summer ← BasicInstallColumnAt[gca, 2];
	col3Summer ← BasicInstallColumnAt[gca, 3];
	
	row1Summer ← BasicInstallRowAt[gca, 1];
	row2Summer ← BasicInstallRowAt[gca, 2];
	row3Summer ← BasicInstallRowAt[gca, 3];

  

   -- prepare title column
   
      PrepareTitleCellOfColumn[gcaSn, gca, 1, 1, row1Summer, col1Summer, "title"];
      PrepareTitleCellOfRow[gcaSn, gca, 1, 2, row2Summer, col1Summer, "title"];
      PrepareTitleCellOfRow[gcaSn, gca, 1, 3, row3Summer, col1Summer, "total"];
   
   
   -- prepare 1 data column
   
      PrepareTitleCellOfColumn[gcaSn, gca, 2, 1,  row1Summer, col2Summer, "title"];
      PrepareAssignmentCell[gcaSn, gca, 2, 2,  row2Summer, col2Summer];
      PrepareColumnSumCell[gcaSn, gca, 2, 3,  row3Summer, col2Summer];
   
   -- prepare 1 total column
   
      PrepareTitleCellOfColumn[gcaSn, gca, 3, 1, row1Summer, col3Summer, "total"];
      PrepareRowSumCell[gcaSn, gca, 3, 2, row2Summer, col3Summer];
      PrepareColumnSumCell[gcaSn, gca, 3, 3, row3Summer, col3Summer];
   
   
   
   FOR I: CARDINAL IN [1..gca.nColumns] DO
      FOR J: CARDINAL IN [1..gca.nRows] DO
         ResetSlotIdInfo[gcaSn, gca, I, J];
         ENDLOOP;
      ENDLOOP;
   
   RETURN[gcaSn]
   END;

GetGCellArrayShape: PUBLIC PROCEDURE[node: StructureNode] RETURNS[nRows, nColumns: CARDINAL] =
	BEGIN
	gca: GCellArray ← NARROW[node.ref];
	RETURN[gca.nRows, gca.nColumns]
	END;

SetGCellArrayRow: PUBLIC PROCEDURE[gcaSn: StructureNode, nColumns: CARDINAL, J: CARDINAL, GetOneCell: PROCEDURE[SetAGCellProc], entry: BOOLEAN] =
	BEGIN
	gca: GCellArray ← NARROW[gcaSn.ref];
	SGCAR: PROCEDURE =
	BEGIN
	IF nColumns # gca.nColumns THEN FOR I: CARDINAL IN [1..nColumns] DO
		DummySetAGCell: SetAGCellProc = {NULL};
		GetOneCell[DummySetAGCell]
		ENDLOOP
	 ELSE
	  BEGIN
	  FOR I: CARDINAL IN [1..nColumns] DO
		RealSetAGCell: SetAGCellProc = {SetOneArrayGCell[gcaSn, gca, I, J, nItems, getOneItem]};
	  	GetOneCell[RealSetAGCell]
	  	ENDLOOP;
     FOR I: CARDINAL IN [1..nColumns] DO
        IF J > 1 THEN ResetSlotIdInfo[gcaSn, gca, I, J-1];
        ResetSlotIdInfo[gcaSn, gca, I, J];
        IF J < gca.nRows THEN ResetSlotIdInfo[gcaSn, gca, I, J+1];
        ENDLOOP;
	  END;
	END;
	IF entry THEN gca.document.procs.executeInMonitor[gca.document, SGCAR] ELSE SGCAR[];
	END;

SetGCellArrayColumn: PUBLIC PROCEDURE[gcaSn: StructureNode, I: CARDINAL, nRows: CARDINAL, GetOneCell: PROCEDURE[SetAGCellProc], entry: BOOLEAN] =
	BEGIN
	gca: GCellArray ← NARROW[gcaSn.ref];
	SGCAC: PROCEDURE =
	BEGIN
	IF nRows # gca.nRows THEN FOR J: CARDINAL IN [1..nRows] DO
		DummySetAGCell: SetAGCellProc = {NULL};
		GetOneCell[DummySetAGCell]
		ENDLOOP
	 ELSE
	  BEGIN
	  FOR J: CARDINAL IN [1..nRows] DO
		RealSetAGCell: SetAGCellProc = {SetOneArrayGCell[gcaSn, gca, I, J, nItems, getOneItem]};
	  	GetOneCell[RealSetAGCell]
	  	ENDLOOP;
     FOR J: CARDINAL IN [1..nRows] DO
        IF I > 1 THEN ResetSlotIdInfo[gcaSn, gca, I-1, J];
        ResetSlotIdInfo[gcaSn, gca, I, J];
        IF I < gca.nColumns THEN ResetSlotIdInfo[gcaSn, gca, I+1, J];
        ENDLOOP;
	  END;
	END;
	IF entry THEN gca.document.procs.executeInMonitor[gca.document, SGCAC] ELSE SGCAC[];
	END;
   
SetGCellArray: PUBLIC PROCEDURE[gcaSn: StructureNode, nColumns, nRows: CARDINAL, GetOneCell: PROCEDURE[SetAGCellProc], entry: BOOLEAN] =
	BEGIN
	gca: GCellArray ← NARROW[gcaSn.ref];
	SGCA: PROCEDURE =
	BEGIN
	AbandonGCellArray[gcaSn];
	
	
	FOR I: CARDINAL IN [1..nColumns] DO [] ← BasicInstallColumnAt[gca, I] ENDLOOP;
	FOR J: CARDINAL IN [1..nRows] DO [] ← BasicInstallRowAt[gca, J] ENDLOOP;
   
	FOR I: CARDINAL IN [1..gca.nColumns] DO
		FOR J: CARDINAL IN [1..gca.nRows] DO
			SetTheCell: SetAGCellProc = {SetOneArrayGCell[gcaSn, gca, I, J, nItems, getOneItem]};
			GetOneCell[SetTheCell];
			ENDLOOP;
		ENDLOOP;
      
	FOR I: CARDINAL IN [1..gca.nColumns] DO
		FOR J: CARDINAL IN [1..gca.nRows] DO
			ResetSlotIdInfo[gcaSn, gca, I, J];
			ENDLOOP;
		ENDLOOP;
	END;
	IF entry THEN gca.document.procs.executeInMonitor[gca.document, SGCA] ELSE SGCA[];
	END;

GetGCellArrayRow: PUBLIC  PROCEDURE[gcaSn: StructureNode, J: CARDINAL, send: SetAGCellArrayProc, entry: BOOLEAN] =
	BEGIN
	gca: GCellArray ← NARROW[gcaSn.ref];
	GGCAR: PROCEDURE=
	BEGIN
	I: CARDINAL ← 0;
	SendOneCell: PROCEDURE[sendIt: SetAGCellProc] =
		{GetOneArrayGCell[gca, I←I+1, J, sendIt]};
	IF J > 0 AND J <= gca.nRows THEN send[gca.nColumns, 1, SendOneCell]
		ELSE send[0, 0, SendOneCell];
	END;
	IF entry THEN gca.document.procs.executeInMonitor[gca.document, GGCAR] ELSE GGCAR[];
	END;

GetGCellArrayColumn: PUBLIC  PROCEDURE[gcaSn: StructureNode, I: CARDINAL, send: SetAGCellArrayProc, entry: BOOLEAN] =
	BEGIN
	gca: GCellArray ← NARROW[gcaSn.ref];
	GGCAC: PROCEDURE=
	BEGIN
	J: CARDINAL ← 0;
	SendOneCell: PROCEDURE[sendIt: SetAGCellProc] =
		{GetOneArrayGCell[gca, I, J←J+1, sendIt]};
	IF I > 0 AND I <= gca.nColumns THEN send[1, gca.nRows, SendOneCell]
		ELSE send[0, 0, SendOneCell];
	END;
	IF entry THEN gca.document.procs.executeInMonitor[gca.document, GGCAC] ELSE GGCAC[];
	END;
	
GetIdTableSet: PUBLIC PROCEDURE[gcaSn: StructureNode, I, J: CARDINAL, callBack: PROCEDURE[IdTableSet]] =
	BEGIN
	gca: GCellArray ← NARROW[gcaSn.ref];
	ConstructIdTables[gca, I, J, callBack];
	END;

GetGCellArray: PUBLIC PROCEDURE[gcaSn: StructureNode, send: SetAGCellArrayProc, entry: BOOLEAN] =
	BEGIN
	gca: GCellArray ← NARROW[gcaSn.ref];
	GGCA: PROCEDURE=
	BEGIN
	I: CARDINAL ← 1;
	J: CARDINAL ← 1;
	
	GetOneCell: PROCEDURE[sendIt: SetAGCellProc] =
		BEGIN
		GetOneArrayGCell[gca, I, J, sendIt];
		J ← J + 1;
		IF J > gca.nRows THEN {J ← 1; I ← I + 1};
		END;
		
	send[gca.nColumns, gca.nRows, GetOneCell];
	END;
	IF entry THEN gca.document.procs.executeInMonitor[gca.document, GGCA] ELSE GGCA[];
	END;
	
	
-- procedures for display node interface
 
GCellArrayCheckForDirtyData: PROCEDURE[node: StructureNode] = 
	BEGIN
	gca: GCellArray ← NARROW[node.ref];
	gca.daSn.procs.CheckForDirtyData[gca.daSn];
	END;

GCellArrayPreShow: PROCEDURE[node: StructureNode] RETURNS[lead, height: INTEGER, space, L, A, B, R, W: INTEGER] = 
	BEGIN
	gca: GCellArray ← NARROW[node.ref];
	[lead, height, space, L, A, B, R, W] ← gca.daSn.procs.PreShow[gca.daSn];
	END;
	
GCellArrayShowLine: PROCEDURE[node: StructureNode, L, R, W: INTEGER, lineX: INTEGER, to: STREAM] = 
	BEGIN
	gca: GCellArray ← NARROW[node.ref];
	gca.daSn.procs.ShowLine[gca.daSn, L, R, W, lineX, to];
	END;
   

GCellArrayPrePrePaint: PROCEDURE[node: StructureNode] RETURNS[lead, height: INTEGER, space, L, A, B, R, W: INTEGER] = 
	BEGIN
	gca: GCellArray ← NARROW[node.ref];
	[lead, height, space, L, A, B, R, W] ← gca.daSn.procs.PrePrePaint[gca.daSn];
	END;
   

GCellArrayPrePaint: PROCEDURE[node: StructureNode, y, x, L, R, W: INTEGER, pass: PrePaintPass] = 
	BEGIN
	gca: GCellArray ← NARROW[node.ref];
	gca.daSn.procs.PrePaint[gca.daSn, y, x, L, R, W, pass];
	END;
   

GCellArrayPaint: PROCEDURE[node: StructureNode, dirtyOnly: BOOLEAN] = 
	BEGIN
	gca: GCellArray ← NARROW[node.ref];
	gca.daSn.procs.Paint[gca.daSn, dirtyOnly];
	END;
   

GCellArrayUnPaint: PROCEDURE[node: StructureNode] = 
	BEGIN
	gca: GCellArray ← NARROW[node.ref];
	gca.daSn.procs.UnPaint[gca.daSn];
	END;
   

GCellArrayNoteEnclosingCell: PROCEDURE[node: StructureNode, dac: DACell] = 
	BEGIN
	gca: GCellArray ← NARROW[node.ref];
	gca.daSn.procs.NoteEnclosingCell[gca.daSn, dac];
	END;
   

GCellArrayNoteCoordinates: PROCEDURE[node: StructureNode, da: DisplayArray, I, J: CARDINAL] = 
	BEGIN
	gca: GCellArray ← NARROW[node.ref];
	gca.daSn.procs.NoteCoordinates[gca.daSn, da, I, J];
	END;
   
 
   
   
-- procedures for logical node interface

SaveGCellArray: PROCEDURE[info: StructureNode, to: IO.STREAM] =
   BEGIN
   gca: GCellArray ← NARROW[info.ref];
   
   Put[to, char[' ], int[gca.nRows], char[' ]];
   Put[to, int[gca.nColumns]];
   
   FOR I: CARDINAL IN [1..gca.nColumns] DO
      FOR J: CARDINAL IN [1..gca.nRows] DO
      	SaveOneSlot[gca, I, J, to];
      	ENDLOOP;
   	  ENDLOOP;
   
   
   END;
   
SubstituteInGCellArray: PROCEDURE[info: StructureNode, newText, oldText: Rope.ROPE] =
   BEGIN
   gca: GCellArray ← NARROW[info.ref];
   SubstituteInWholeArray[gca, newText, oldText];
   END;

   
AbandonGCellArray: PROCEDURE[info: StructureNode] =
   BEGIN
   gca: GCellArray ← NARROW[info.ref];
   WHILE gca.nColumns # 0 DO RemoveColumnAt[info, gca, gca.nColumns] ENDLOOP;
   WHILE gca.nRows # 0 DO RemoveRowAt[info, gca, gca.nRows] ENDLOOP;
   END;  
    
ActGCellArray: PROCEDURE[info: StructureNode, I, J: CARDINAL, action: StructureNodes.Action, p1, p2: REF ANY] RETURNS[StructureNode, CARDINAL, CARDINAL] = 
   BEGIN
   gca: GCellArray ← NARROW[info.ref];  
   SELECT action FROM
      InsertColumn => {InstallColumnAt[info, gca, I, I+1]; [] ← MoveSelectionTo[gca, I, J, first]};
      AppendColumn => {InstallColumnAt[info, gca, I+1, I]; [] ← MoveSelectionTo[gca, I, J, first]};
      DeleteColumn => {RemoveColumnAt[info, gca, I]; IF I <= gca.nColumns THEN [] ← MoveSelectionTo[gca, I, J, first]};
      InsertRow => {InstallRowAt[info, gca, J, J+1]; [] ← MoveSelectionTo[gca, I, J, first]};
      AppendRow => {InstallRowAt[info, gca, J+1, J]; [] ← MoveSelectionTo[gca, I, J, first]};
      DeleteRow => {RemoveRowAt[info, gca, J]; IF J <= gca.nRows THEN [] ← MoveSelectionTo[gca, I, J, first]};
      MoveSelectionToNext => MoveSelectionToNext[gca, I, J];
      MoveSelectionToPrevious => MoveSelectionToPrevious[gca, I, J];
      SubstituteInArray => SubstituteInWholeArray[gca, p1, p2];
      SubstituteInRow => SubstituteInRow[gca, J, p1, p2];
      SubstituteInColumn => SubstituteInColumn[gca, I, p1, p2];
      NoteArraySelection => NoteArraySelection[gca.displayer, info, I, J];
      ENDCASE => 
      	BEGIN
      	cSn: StructureNode; cI, cJ: CARDINAL;
      	[cSn, cI, cJ] ← GetContextDA[gca.da];
      	RETURN[cSn, cI, cJ];
      	END;
   RETURN[NIL, 0, 0];
   END;

VerifyGCellArray: PROCEDURE[info: StructureNode] =
   BEGIN
   gca: GCellArray ← NARROW[info.ref];
   
         
       
   FOR I: CARDINAL IN [1..gca.nColumns] DO
      FOR J: CARDINAL IN [1..gca.nRows] DO
      	 sn: StructureNode;
      	 [sn: sn] ← StructureNodes.GetElementAt[gca.da, I, J];
        	 sn.procs.Verify[sn];
      	 ENDLOOP;
      ENDLOOP;
      
   END;

   
-- column and row activity

InstallColumnAt: PROCEDURE[gcaSn: StructureNode, gca: GCellArray, I: CARDINAL, copyFrom: CARDINAL] =
   BEGIN
   colSummer: Dependencies.Action ← BasicInstallColumnAt[gca, I];
   FOR J: CARDINAL IN [1..gca.nRows] DO
      rowInfo: RowInfo ← NARROW[GetRowInfoAt[gca.da, J]];
      PrepareGCellFromNeighbor[gcaSn, gca, I, J, rowInfo.rowSummer, colSummer, copyFrom, J];
      ENDLOOP;
   FOR J: CARDINAL IN [1..gca.nRows] DO
      IF I > 1 THEN ResetSlotIdInfo[gcaSn, gca, I-1, J];
      ResetSlotIdInfo[gcaSn, gca, I, J];
      IF I < gca.nColumns THEN ResetSlotIdInfo[gcaSn, gca, I+1, J];
      ENDLOOP;
   END;
   
   
BasicInstallColumnAt: PROCEDURE[gca: GCellArray, I: CARDINAL] RETURNS[colSummer: Dependencies.Action] =
   BEGIN
   colInfo: ColInfo ← NEW[ColInfoBody ← [gca]];
   gca.nColumns ← gca.nColumns+1;
   StructureNodes.AddColumnAt[gca.da, I]; 
   colInfo.colHandle ← SetColInfoAt[gca.da, I, colInfo];
   colSummer ← colInfo.colSummer ← Dependencies.DefineAction[gca.document.dSet, ColumnSummer, colInfo];
    
   FOR J: CARDINAL IN [1..gca.nRows] DO
   		BasicInstallSlot[gca, I, J];
   		ENDLOOP;
   		 
   END;
   
RemoveColumnAt: PROCEDURE[gcaSn: StructureNode, gca: GCellArray, I: CARDINAL] =
   BEGIN
   colInfo: ColInfo ← NARROW[GetColInfoAt[gca.da, I]];
   Dependencies.DeactivateAction[colInfo.colSummer];
   StructureNodes.DeleteColumnAt[gca.da, I];
   gca.nColumns ← gca.nColumns-1;
   
     
   FOR J: CARDINAL IN [1..gca.nRows] DO
   	  IF I > 1 THEN ResetSlotIdInfo[gcaSn, gca, I-1, J];
      IF I <= gca.nColumns THEN ResetSlotIdInfo[gcaSn, gca, I, J];
      ENDLOOP;
   END;
   
InstallRowAt: PROCEDURE[gcaSn: StructureNode, gca: GCellArray, J: CARDINAL, copyFrom: CARDINAL] =
   BEGIN
   rowSummer: Dependencies.Action ← BasicInstallRowAt[gca, J];
   FOR I: CARDINAL IN [1..gca.nColumns] DO
      colInfo: ColInfo ← NARROW[GetColInfoAt[gca.da, I]];
      PrepareGCellFromNeighbor[gcaSn, gca, I, J, rowSummer, colInfo.colSummer, I, copyFrom];
      ENDLOOP;
   FOR I: CARDINAL IN [1..gca.nColumns] DO
   	  IF J > 1 THEN ResetSlotIdInfo[gcaSn, gca, I, J-1];
      ResetSlotIdInfo[gcaSn, gca, I, J];
      IF J < gca.nRows THEN ResetSlotIdInfo[gcaSn, gca, I, J+1];
      ENDLOOP;
   END;

   
BasicInstallRowAt: PROCEDURE[gca: GCellArray, J: CARDINAL] RETURNS[rowSummer: Dependencies.Action] =
   BEGIN
   rowInfo: RowInfo ← NEW[RowInfoBody ← [gca]];
   gca.nRows ← gca.nRows+1;
   StructureNodes.AddRowAt[gca.da, J];
   rowInfo.rowHandle ← SetRowInfoAt[gca.da, J, rowInfo];
   rowSummer ←rowInfo.rowSummer ← Dependencies.DefineAction[gca.document.dSet, RowSummer, rowInfo];
   
       
   FOR I: CARDINAL IN [1..gca.nColumns] DO
    	BasicInstallSlot[gca, I, J];
    	ENDLOOP;
      
   END;
   
RemoveRowAt: PROCEDURE[gcaSn: StructureNode, gca: GCellArray, J: CARDINAL] =
   BEGIN
   rowInfo: RowInfo ← NARROW[GetRowInfoAt[gca.da, J]];
   Dependencies.DeactivateAction[rowInfo.rowSummer];
   StructureNodes.DeleteRowAt[gca.da, J];
   gca.nRows ← gca.nRows-1;
   
      
   FOR I: CARDINAL IN [1..gca.nColumns] DO
   	  IF J > 1 THEN ResetSlotIdInfo[gcaSn, gca, I, J-1];
      IF J <= gca.nRows THEN ResetSlotIdInfo[gcaSn, gca, I, J];
      ENDLOOP
   END;

   
   
   

-- slot operations

BasicInstallSlot: PROCEDURE[gca: GCellArray, I, J: CARDINAL] =
	BEGIN
	si: SlotInfo ← NEW[SlotInfoBody ← [MakeIdTable[]]];
	StructureNodes.SetElementAt[gca.da, I, J, NIL, si];
	END;  
   
SaveOneSlot: PROCEDURE[gca: GCellArray, I, J: CARDINAL, to: IO.STREAM] =
   BEGIN
   sn: StructureNodes.StructureNode;
   [sn: sn] ← StructureNodes.GetElementAt[gca.da, I, J];
   Put[to, char[' ]];
   sn.procs.Save[sn, to];
   END; 
   
   
 -- MUST ALLOW FOR POSSIBILITY OF GCellArray HERE  
 
LoadOneSlot: PROCEDURE[gcaSn: StructureNode, gca: GCellArray, I, J: CARDINAL, rowSummer, colSummer: Dependencies.Action, from: IO.STREAM, version: CARDINAL] =
   BEGIN
   info: REF ANY;
   si: SlotInfo;
   gcSn: StructureNodes.StructureNode;
   [info: info] ← StructureNodes.GetElementAt[gca.da, I, J];
   si ← NARROW[info];
   gcSn ← LoadGCell[gca.document, gca.displayer, gcaSn, gca.vParent, from, version];
   StructureNodes.SetElementAt[gca.da, I, J, gcSn, si];
   NoteSummers[gcSn, rowSummer, colSummer];
   END;
   
   
PrepareNullCell: PROCEDURE[gcaSn: StructureNode, gca: GCellArray, I, J: CARDINAL, rowSummer, colSummer: Dependencies.Action] =
   {PrepareGCell[gcaSn, gca, I, J, rowSummer, colSummer, null]};
   
SetOneArrayGCell: PROCEDURE[gcaSn: StructureNode, gca: GCellArray, I, J: CARDINAL, nItems: CARDINAL, getOneItem: PROCEDURE RETURNS[GCellItemDescriptor]] =
	BEGIN
	info: REF ANY;
	si: SlotInfo;
	gcSn: StructureNode;
	colInfo: ColInfo ← NARROW[GetColInfoAt[gca.da, I]];
	rowInfo: RowInfo ← NARROW[GetRowInfoAt[gca.da, J]];
         	
	[info: info] ← StructureNodes.GetElementAt[gca.da, I, J];
	si ← NARROW[info];
	gcSn ← CreateGCell[gca.document, gca.displayer, gcaSn, gca.vParent, null];
	StructureNodes.SetElementAt[gca.da, I, J, gcSn, si];
	SetGCellContents[gcSn, nItems, getOneItem];
	NoteSummers[gcSn, rowInfo.rowSummer, colInfo.colSummer];
	END;

GetOneArrayGCell: PROCEDURE[gca: GCellArray, I, J: CARDINAL, sendIt: SetAGCellProc] =
	BEGIN
	info: REF ANY;
	si: SlotInfo;
	gcSn: StructureNode;
	[sn: gcSn, info: info] ← StructureNodes.GetElementAt[gca.da, I, J];
	si ← NARROW[info];
	GetGCellContents[gcSn, sendIt];
	--J ← J + 1;
	--IF J > gca.nRows THEN {J ← 1; I ← I + 1};
	END;
 
PrepareGCellFromNeighbor: PROCEDURE[gcaSn: StructureNode, gca: GCellArray, I, J: CARDINAL, rowSummer, colSummer: Dependencies.Action, fromI: CARDINAL, fromJ: CARDINAL] =
 	BEGIN
   info: REF ANY;
   si: SlotInfo;
   gcSn: StructureNode;
   neighborRA: REF ANY;
   neighbor: SlotInfo;
   neighborGcSn: StructureNode;
    
    ShipInfo: SetAGCellProc =
    	{SetGCellContents[gcSn, nItems, getOneItem]};
   
   [sn: gcSn, info: info] ← StructureNodes.GetElementAt[gca.da, I, J];
   si ← NARROW[info];

   [sn: neighborGcSn, info: neighborRA] ← StructureNodes.GetElementAt[gca.da, fromI, fromJ];
    neighbor ← NARROW[neighborRA];
    	
    gcSn ← CreateGCell[gca.document, gca.displayer, gcaSn, gca.vParent, null];
    StructureNodes.SetElementAt[gca.da, I, J, gcSn, si];
    GetGCellContents[neighborGcSn, ShipInfo];
    NoteSummers[gcSn, rowSummer, colSummer];
	END;
 
 ResetSlotIdInfo: PROCEDURE[gcaSn: StructureNode, gca: GCellArray, I, J: CARDINAL] =
   BEGIN
   idTables: IdTableSet;
   ReceiveIdTables: PROCEDURE[ids: IdTableSet] = {idTables ← ids};
   ConstructIdTables[gca, I, J, ReceiveIdTables];
   SetGCellIdInfo[StructureNodes.GetElementAt[gca.da, I, J].sn, idTables];
   END;

	 
ConstructIdTables: PROCEDURE[gca: GCellArray, I, J: CARDINAL, callBack: PROCEDURE[IdTableSet]] =
   BEGIN
   siRa: REF ANY;
   si: SlotInfo;
   
   nRA: REF ANY;
   nSI: SlotInfo;
   n: IdTable;
   
   eRA: REF ANY;
   eSI: SlotInfo;
   e: IdTable;
   
   sRA: REF ANY;
   sSI: SlotInfo;
   s: IdTable;
   
   wRA: REF ANY;
   wSI: SlotInfo;
   w: IdTable;
   
   IF J > 1 THEN
   	BEGIN
   	[info: nRA] ← StructureNodes.GetElementAt[gca.da, I, J-1];
   	nSI ← NARROW[nRA];
   	n ← nSI.ids;
   	END
   ELSE n ← NIL;
   
   IF I < gca.nColumns THEN
   	BEGIN
   	[info: eRA] ← StructureNodes.GetElementAt[gca.da, I+1, J];
   	eSI ← NARROW[eRA];
   	e ← eSI.ids;
   	END
   ELSE e ← NIL;
   
   IF J < gca.nRows THEN
   	BEGIN
   	[info: sRA] ← StructureNodes.GetElementAt[gca.da, I, J+1];
   	sSI ← NARROW[sRA];
   	s ← sSI.ids;
   	END
   ELSE s ← NIL;
   
   IF I > 1 THEN
   	BEGIN
   	[info: wRA] ← StructureNodes.GetElementAt[gca.da, I-1, J];
   	wSI ← NARROW[wRA];
   	w ← wSI.ids;
   	END
   ELSE w ← NIL;
   
   [sn: , info: siRa] ← GetElementAt[gca.da, I, J];
   si ← NARROW[siRa];
   
   callBack[[si.ids, n, e, s, w, NIL, gca.document.ids]];
   END;

  
 
PrepareTitleCellOfRow: PROCEDURE[gcaSn: StructureNode, gca: GCellArray, I, J: CARDINAL,  rowSummer, colSummer: Dependencies.Action, title: Rope.ROPE] =
   {PrepareGCell[gcaSn, gca, I, J, rowSummer, colSummer, rowTitle]};
 
PrepareTitleCellOfColumn: PROCEDURE[gcaSn: StructureNode, gca: GCellArray, I, J: CARDINAL, rowSummer, colSummer: Dependencies.Action, title: Rope.ROPE] =
   {PrepareGCell[gcaSn, gca, I, J, rowSummer, colSummer, colTitle]};
 
PrepareColumnSumCell: PROCEDURE[gcaSn: StructureNode, gca: GCellArray, I, J: CARDINAL, rowSummer, colSummer: Dependencies.Action] =
   {PrepareGCell[gcaSn, gca, I, J, rowSummer, colSummer, colSum]};
 
PrepareRowSumCell: PROCEDURE[gcaSn: StructureNode, gca: GCellArray, I, J: CARDINAL, rowSummer, colSummer: Dependencies.Action] =
   {PrepareGCell[gcaSn, gca, I, J, rowSummer, colSummer, rowSum]};
   
PrepareAssignmentCell: PROCEDURE[gcaSn: StructureNode, gca: GCellArray, I, J: CARDINAL, rowSummer, colSummer: Dependencies.Action] =
   {PrepareGCell[gcaSn, gca, I, J, rowSummer, colSummer, assignment]};


PrepareGCell: PROCEDURE[gcaSn: StructureNode, gca: GCellArray, I, J: CARDINAL, rowSummer: Dependencies.Action, colSummer: Dependencies.Action, type: StandardGCells] =
   BEGIN
   info: REF ANY;
   si: SlotInfo;
   gcSn: StructureNode;
   [sn: gcSn, info: info] ← StructureNodes.GetElementAt[gca.da, I, J];
   si ← NARROW[info];
   IF gcSn # NIL THEN ERROR; -- February 27, 1983 3:07 pm: expect NIL here, else have to abandon the cell???
   gcSn ← CreateGCell[gca.document, gca.displayer, gcaSn, gca.vParent, type];
   NoteSummers[gcSn, rowSummer, colSummer];
   StructureNodes.SetElementAt[gca.da, I, J, gcSn, si];
   END;	

MoveSelectionToNext: PROCEDURE[gca: GCellArray, I, J: CARDINAL] =
	BEGIN
   WHILE TRUE DO
   	IF I # gca.nColumns THEN I ← I+1
   	 ELSE IF J # gca.nRows THEN {I ← 1; J ← J + 1}
   	 ELSE RETURN;
   	IF MoveSelectionTo[gca, I, J, first] THEN RETURN;
   	ENDLOOP;
	END;	

MoveSelectionToPrevious: PROCEDURE[gca: GCellArray, I, J: CARDINAL] =
	BEGIN
   WHILE TRUE DO
   	IF I # 1 THEN I ← I - 1
   	 ELSE IF J # 1 THEN {I ← gca.nColumns; J ← J - 1}
   	 ELSE RETURN;
   	IF MoveSelectionTo[gca, I, J, last] THEN RETURN;
   	ENDLOOP;
	END;

MoveSelectionTo: PROCEDURE[gca: GCellArray, I, J: CARDINAL, position: SelectionDirection] RETURNS[BOOLEAN] =
	BEGIN
   gcSn: StructureNode;
   [sn: gcSn] ← StructureNodes.GetElementAt[gca.da, I, J];
   RETURN[StepSelection[gcSn, 0,  position]];
	END;

SubstituteInWholeArray: PROCEDURE[gca: GCellArray, p1, p2: REF ANY] =
	BEGIN
	FOR I: CARDINAL IN [1..gca.nColumns] DO
		SubstituteInColumn[gca, I, p1, p2];
		ENDLOOP;
	END;

SubstituteInRow: PROCEDURE[gca: GCellArray, J: CARDINAL, p1, p2: REF ANY] =
	BEGIN
	newText: Rope.ROPE ← NARROW[p1];
	oldText: Rope.ROPE ← NARROW[p2];
	FOR I: CARDINAL IN [1..gca.nColumns] DO
   	gcSn: StructureNode;
   	[sn: gcSn] ← StructureNodes.GetElementAt[gca.da, I, J];
   	gcSn.procs.Substitute[gcSn, newText, oldText];
		ENDLOOP;
	END;

SubstituteInColumn: PROCEDURE[gca: GCellArray, I: CARDINAL, p1, p2: REF ANY] =
	BEGIN
	newText: Rope.ROPE ← NARROW[p1];
	oldText: Rope.ROPE ← NARROW[p2];
	FOR J: CARDINAL IN [1..gca.nRows] DO
   	gcSn: StructureNode;
   	[sn: gcSn] ← StructureNodes.GetElementAt[gca.da, I, J];
   	gcSn.procs.Substitute[gcSn, newText, oldText];
		ENDLOOP;
	END;

-- row and column summers

RowInfo: TYPE = REF RowInfoBody;
RowInfoBody: TYPE = RECORD[
		gca: GCellArray,
		rowHandle: RowHandle ← NIL,
		rowSummer: Dependencies.Action ← NIL
		];

ColInfo: TYPE = REF ColInfoBody;
ColInfoBody: TYPE = RECORD[
		gca: GCellArray,
		colHandle: ColHandle ← NIL,
		colSummer: Dependencies.Action ← NIL
		];

RowSummer: PROCEDURE[action: Dependencies.Action, info: REF ANY] =
	BEGIN
	rowInfo: RowInfo ← NARROW[info];
	sum: REAL ← 0;
	J: CARDINAL ← GetRowNumber[rowInfo.rowHandle];
	
	FOR I: CARDINAL IN [1..rowInfo.gca.nColumns] DO
		gcSn: StructureNode;
		[sn: gcSn] ← StructureNodes.GetElementAt[rowInfo.gca.da, I,  J];
		sum ← DoRowSum[gcSn, sum];
		ENDLOOP;
	END;

ColumnSummer: PROCEDURE[action: Dependencies.Action, info: REF ANY] =
	BEGIN
	colInfo: ColInfo ← NARROW[info];
	sum: REAL ← 0;
	I: CARDINAL ← GetColNumber[colInfo.colHandle];
	
	FOR J: CARDINAL IN [1..colInfo.gca.nRows] DO
		gcSn: StructureNode;
		[sn: gcSn] ← StructureNodes.GetElementAt[colInfo.gca.da, I,  J];
		sum ← DoColSum[gcSn, sum];
		ENDLOOP;
	END;
   
-- debugging routines



END..


--  September 21, 1982 6:58 pm: Sturgis, started GCMatrixImpl.mesa, edit from AdditiveMatrixImpl

-- RTE: October 1, 1982 2:49 pm: BasicInstallRow  installed nRows slots, rather than nColumns slots.
-- RTE: October 1, 1982 2:57 pm: REsetSlotIdInfo subracted 1 in a case where it should have added 1.
-- RTE: October 1, 1982 3:05 pm: CreateGCellArray prepared column 2 twice, rather than also column 3.
--BTE: October 2, 1982 3:09 pm: change verify loop to use ln.procs.Verify, rather than a VerifyGCell procedure that does not exist.
-- change: October 3, 1982 1:00 pm: modify selection mechanism so that when an action fales, Act returns enclosing context, after obtaining it from the associated DisplayArray.
-- RTE: October 3, 1982 1:38 pm: old AdditiveMatrixCode (from which this was edited) would not allow appending to early rows or columns, as they were special.  Now no row or column is special, so remove the tests.
-- RTE: October 3, 1982 1:49 pm: PrepareGCellFromNeighbor did not use the neighbor as the source, but rather the cell that was being prepared.
-- RTE: October 3, 1982 2:34 pm: load failed because gca.nRows was non zero, when in fact there were no rows yet.  So an inapropriate attempt was made to install a slot.
RTE: October 3, 1982 3:22 pm: imperfect fix, the loop callin basic install used counts from gca.nRows for example.  but these are 0.
-- RTE: October 10, 1982 12:56 pm: ResetSlotIdInfo was not including global ids from global.
-- change: October 11, 1982 2:47 pm: export to GCell, also export SetGCellArray and GetGCellArray.
-- change: October 14, 1982 5:05 pm: displayer now arrives at laod and creation time, and additional params passed to gcells.
RTE: October 14, 1982 6:18 pm: GetGCellArray was running row and column indices from 0 rather than 1. 
RTE: October 14, 1982 6:30 pm: forgot to construct a new GCell before trying to set its contents.
October 16, 1982 3:39 pm: conditional entry into global monitor in GetGCellArray and SetGCellArray.
-- October 22, 1982 2:34 pm: add row and column summers.
-- RTE: October 23, 1982 1:55 pm: col and row sums not appearing in appended columns and rows.  DUe to current coding of GCellImpl, must call NoteSummers AFTER creating the cell and setting its contents.
-- change: October 26, 1982 2:31 pm: put a title cell in upper left hand cell of an array.
-- change: October 26, 1982 5:16 pm: install move selection machinary.
-- change: October 26, 1982 6:21 pm: add code to retain selection in appropriate column and row after deletio or insertion.
-- change: November 2, 1982 4:28 pm: add 2 ref any params to ActGCellArray.
-- change: November 2, 1982 5:09 pm: add SubstituteInRow and Column actions.
-- chnage: November 3, 1982 3:43 pm: add SubstituteInArray action, and as a logical node proc.
-- change: November 14, 1982 1:15 pm: add Get/Set Row/Column
-- change: November 14, 1982 3:03 pm: add NoteArraySelection, so as to handle new selection logic.
-- BTE: November 14, 1982 3:49 pm: add GetGCellArrayShape.
-- February 27, 1983 1:56 pm: convert from logical and display nodes to a single node, structure node.  idea is to reduce to one the pointers to an entity, also remove the back poitners to the node.  February 27, 1983 3:16 pm: Took about 1.2 hours. Discovered that I have to store info as well as gcSn at each crosspoint, so as to hold the id table.  This forced a change to StructureNode displayArray calls.  This requires work on ColumnOfRows.
-- February 28, 1983 2:20 pm: add dummy NoteCoordinates procedure.
-- March 4, 1983 11:38 am: add provision to compute IdTableSets on the fly.
-- March 4, 1983 1:14 pm: owing to unsafe large return record, convert COnstructeIdTableSet to using a call back procedure to deliver the result.  ALso convert to passing gcaSn through more procedures.
-- RTE: March 4, 1983 1:39 pm: ResetSlotIdInfo passed gcaSn rather than gcSn to the GCell routine.
-- March 8, 1983 11:40 am: add UnPaint.
-- RTE: March 8, 1983 12:44 pm: did not propogate NoteCoordinates to associated da cell.