[Runtime] Implemented display of indexes/orders in the debug WorkareasWindow

USING System.Windows.Forms
USING System.Collections.Generic
USING System.Reflection

BEGIN NAMESPACE XSharp.Debugger

INTERNAL ENUM WorkareaDetail
	MEMBER FileName
	MEMBER Rdd
	MEMBER Area
	MEMBER Ansi
	MEMBER Shared
	MEMBER ReadOnly
	MEMBER FieldCount
	MEMBER RecCount
	MEMBER RecSize
	MEMBER RecNo
	MEMBER Eof
	MEMBER Bof
	MEMBER Deleted
	MEMBER Found
	MEMBER Filter
END ENUM

INTERNAL ENUM MovementType
    MEMBER GoTo
    MEMBER GoTop
    MEMBER GoBottom
    MEMBER SkipNext
    MEMBER SkipPrevious
END ENUM

INTERNAL CLASS ListViewItem_workarea INHERIT ListViewItem
	PROPERTY Rdd AS XSharp.RDD.IRdd AUTO
	PROPERTY Workarea AS DWORD AUTO
	CONSTRUCTOR(cText AS STRING)
		SUPER(cText)
	RETURN
END CLASS

CLASS WorkareasWindow INHERIT System.Windows.Forms.Form

    PROTECT oIndexTreeView AS System.Windows.Forms.TreeView
    PROTECT oCloseButton AS System.Windows.Forms.Button
    PROTECT oNavigator AS System.Windows.Forms.ToolStrip
    PROTECT oFieldsListView AS System.Windows.Forms.ListView
    PROTECT oDetailsListView AS System.Windows.Forms.ListView
    PROTECT oWorkareasListView AS System.Windows.Forms.ListView
    // User code starts here (DO NOT remove this line)  ##USER##

	PROTECTED METHOD InitializeForm() AS VOID

        // IDE generated code (please DO NOT modify)

		SELF:oIndexTreeView := System.Windows.Forms.TreeView{}
		SELF:oCloseButton := System.Windows.Forms.Button{}
		SELF:oNavigator := System.Windows.Forms.ToolStrip{}
		SELF:oFieldsListView := System.Windows.Forms.ListView{}
		SELF:oDetailsListView := System.Windows.Forms.ListView{}
		SELF:oWorkareasListView := System.Windows.Forms.ListView{}

		SELF:SuspendLayout()

		SELF:AutoScaleDimensions := System.Drawing.SizeF{ 6 , 13 }
		SELF:AutoScaleMode := System.Windows.Forms.AutoScaleMode.Font
		SELF:ClientSize := System.Drawing.Size{896 , 576}
		SELF:Location := System.Drawing.Point{100 , 100}
		SELF:MaximizeBox := FALSE
		SELF:MinimizeBox := FALSE
		SELF:Name := "WorkareasWindow"
		SELF:ShowIcon := FALSE
		SELF:ShowInTaskbar := FALSE
		SELF:SizeGripStyle := System.Windows.Forms.SizeGripStyle.Hide
		SELF:StartPosition := System.Windows.Forms.FormStartPosition.CenterParent
		SELF:Text := "Active database workareas"

		SELF:CancelButton := SELF:oCloseButton
		SELF:oIndexTreeView:Anchor := System.Windows.Forms.AnchorStyles.Top + System.Windows.Forms.AnchorStyles.Left + System.Windows.Forms.AnchorStyles.Right
		SELF:oIndexTreeView:Location := System.Drawing.Point{600 , 8}
		SELF:oIndexTreeView:Name := "IndexTreeView"
		SELF:oIndexTreeView:Size := System.Drawing.Size{280 , 280}
		SELF:oIndexTreeView:TabIndex := 2
		SELF:Controls:Add(SELF:oIndexTreeView)

		SELF:oCloseButton:Anchor := System.Windows.Forms.AnchorStyles.Right + System.Windows.Forms.AnchorStyles.Bottom
		SELF:oCloseButton:Location := System.Drawing.Point{757 , 544}
		SELF:oCloseButton:Name := "CloseButton"
		SELF:oCloseButton:Size := System.Drawing.Size{123 , 23}
		SELF:oCloseButton:TabIndex := 5
		SELF:oCloseButton:Text := "Close"
		SELF:Controls:Add(SELF:oCloseButton)

		SELF:oNavigator:SuspendLayout()
		SELF:oNavigator:Anchor := System.Windows.Forms.AnchorStyles.Top + System.Windows.Forms.AnchorStyles.Left + System.Windows.Forms.AnchorStyles.Right
		SELF:oNavigator:Dock := System.Windows.Forms.DockStyle.None
		SELF:oNavigator:Location := System.Drawing.Point{8 , 296}
		SELF:oNavigator:Name := "Navigator"
		SELF:oNavigator:Size := System.Drawing.Size{872 , 30}
		SELF:oNavigator:TabIndex := 4
		SELF:Controls:Add(SELF:oNavigator)

		SELF:oFieldsListView:Anchor := System.Windows.Forms.AnchorStyles.Top + System.Windows.Forms.AnchorStyles.Left + System.Windows.Forms.AnchorStyles.Right + System.Windows.Forms.AnchorStyles.Bottom
		SELF:oFieldsListView:FullRowSelect := TRUE
		SELF:oFieldsListView:HideSelection := FALSE
		SELF:oFieldsListView:Location := System.Drawing.Point{8 , 328}
		SELF:oFieldsListView:MultiSelect := FALSE
		SELF:oFieldsListView:Name := "FieldsListView"
		SELF:oFieldsListView:Size := System.Drawing.Size{872 , 208}
		SELF:oFieldsListView:TabIndex := 3
		SELF:oFieldsListView:View := System.Windows.Forms.View.Details
		SELF:Controls:Add(SELF:oFieldsListView)

		SELF:oDetailsListView:FullRowSelect := TRUE
		SELF:oDetailsListView:HideSelection := FALSE
		SELF:oDetailsListView:Location := System.Drawing.Point{288 , 8}
		SELF:oDetailsListView:MultiSelect := FALSE
		SELF:oDetailsListView:Name := "DetailsListView"
		SELF:oDetailsListView:Size := System.Drawing.Size{304 , 280}
		SELF:oDetailsListView:TabIndex := 1
		SELF:oDetailsListView:View := System.Windows.Forms.View.Details
		SELF:Controls:Add(SELF:oDetailsListView)

		SELF:oWorkareasListView:FullRowSelect := TRUE
		SELF:oWorkareasListView:HideSelection := FALSE
		SELF:oWorkareasListView:Location := System.Drawing.Point{8 , 8}
		SELF:oWorkareasListView:MultiSelect := FALSE
		SELF:oWorkareasListView:Name := "WorkareasListView"
		SELF:oWorkareasListView:SelectedIndexChanged += SELF:WorkareasListView_SelectedIndexChanged
		SELF:oWorkareasListView:Size := System.Drawing.Size{272 , 280}
		SELF:oWorkareasListView:TabIndex := 0
		SELF:oWorkareasListView:View := System.Windows.Forms.View.Details
		SELF:Controls:Add(SELF:oWorkareasListView)

		SELF:oNavigator:ResumeLayout()
		SELF:ResumeLayout()

	RETURN

	CONSTRUCTOR()

		SUPER()

		SELF:InitializeForm()

		SELF:oWorkareasListView:Columns:Add("No" , 50)
		SELF:oWorkareasListView:Columns:Add("Alias" , 200)

		SELF:oDetailsListView:Columns:Add("Property" , 90)
		SELF:oDetailsListView:Columns:Add("Value" , 200)

		SELF:CreateDetail("Filename")
		SELF:CreateDetail("RDD name")
		SELF:CreateDetail("Area number")
		SELF:CreateDetail("Ansi")
		SELF:CreateDetail("Shared")
		SELF:CreateDetail("ReadOnly")
		SELF:CreateDetail("Field count")
		SELF:CreateDetail("Record count")
		SELF:CreateDetail("Record size")
		SELF:CreateDetail("Record number")
		SELF:CreateDetail("Eof")
		SELF:CreateDetail("Bof")
		SELF:CreateDetail("Deleted")
		SELF:CreateDetail("Found")
		SELF:CreateDetail("Filter text")

		SELF:oFieldsListView:Columns:Add("Field name" , 80)
		SELF:oFieldsListView:Columns:Add("Type" , 80)
		SELF:oFieldsListView:Columns:Add("Length" , 80)
		SELF:oFieldsListView:Columns:Add("Decimals" , 80)
		SELF:oFieldsListView:Columns:Add("Value" , 400)

		SELF:oNavigator:AutoSize := FALSE

		LOCAL oSource AS BindingNavigator
		oSource := BindingNavigator{TRUE}

		SELF:oNavigator:Items:Add(ToolStripButton{NULL, oSource:MoveFirstItem:Image , {o,e => SELF:DoMove(MovementType.GoTop)} })
		SELF:oNavigator:Items:Add(ToolStripButton{NULL, oSource:MovePreviousItem:Image , {o,e => SELF:DoMove(MovementType.SkipPrevious)} })
		SELF:oNavigator:Items:Add(ToolStripButton{NULL, oSource:MoveNextItem:Image , {o,e => SELF:DoMove(MovementType.SkipNext)} })
		SELF:oNavigator:Items:Add(ToolStripButton{NULL, oSource:MoveLastItem:Image , {o,e => SELF:DoMove(MovementType.GoBottom)} })

		SELF:FillWorkareas()
		IF SELF:oWorkareasListView:Items:Count != 0
			SELF:oWorkareasListView:SelectedIndices:Add(0)
		END IF

	RETURN

	PROTECTED METHOD DoMove(eMove AS MovementType) AS VOID
		LOCAL oRdd AS XSharp.RDD.IRdd
		IF SELF:oWorkareasListView:SelectedIndices:Count == 0
			RETURN
		END IF
		oRdd := ((ListViewItem_workarea)SELF:oWorkareasListView:SelectedItems[0]):Rdd
		SWITCH eMove
		CASE MovementType.GoTop
			oRdd:GoTop()
		CASE MovementType.GoBottom
			oRdd:GoBottom()
		CASE MovementType.SkipNext
			oRdd:Skip(+1)
		CASE MovementType.SkipPrevious
			oRdd:Skip(-1)
		END SWITCH
		SELF:FillAll()
	RETURN

	PROTECTED METHOD CreateDetail(cName AS STRING) AS VOID
		LOCAL oItem AS ListViewItem_workarea
		oItem := ListViewItem_workarea{cName}
		oItem:SubItems:Add("")
		SELF:oDetailsListView:Items:Add(oItem)
	RETURN
	PROTECTED METHOD SetDetail(nIndex AS INT , cValue AS STRING) AS VOID
		LOCAL oItem AS ListViewItem_workarea
		oItem := (ListViewItem_workarea)SELF:oDetailsListView:Items[nIndex]
		oItem:SubItems[1]:Text := cValue
	RETURN
	PROTECTED METHOD ClearDetails() AS VOID
		LOCAL oItem AS ListViewItem_workarea
		LOCAL n AS INT
		FOR n := 0 UPTO SELF:oDetailsListView:Items:Count - 1
			oItem := (ListViewItem_workarea)SELF:oDetailsListView:Items[n]
			oItem:SubItems[1]:Text := ""
		NEXT
	RETURN

	PROTECTED METHOD WorkareasListView_SelectedIndexChanged(sender AS System.Object , e AS System.EventArgs) AS VOID
		SELF:FillAll()
	RETURN

	PROTECTED METHOD FillAll() AS VOID
		LOCAL oRdd AS XSharp.RDD.IRdd
		LOCAL lError := FALSE AS LOGIC
		LOCAL nWorkarea AS DWORD

		IF SELF:oWorkareasListView:SelectedIndices:Count == 0
			SELF:oIndexTreeView:Nodes:Clear()
			SELF:oFieldsListView:Items:Clear()
			SELF:oNavigator:Enabled := FALSE
			SELF:ClearDetails()
			RETURN
		END IF

		oRdd := ((ListViewItem_workarea)SELF:oWorkareasListView:SelectedItems[0]):Rdd
		nWorkarea := ((ListViewItem_workarea)SELF:oWorkareasListView:SelectedItems[0]):Workarea
		Cursor.Current := Cursors.WaitCursor

		SELF:oDetailsListView:BeginUpdate()
		SELF:oIndexTreeView:BeginUpdate()
		SELF:oFieldsListView:BeginUpdate()
		TRY
			SELF:FillDetails(oRdd, nWorkarea)
		CATCH
			SELF:ClearDetails()
			lError := TRUE
		END TRY

		IF lError
			SELF:oIndexTreeView:Nodes:Clear()
			SELF:oFieldsListView:Items:Clear()
		ELSE
			TRY
				SELF:FillIndexes(oRdd)
			CATCH
				SELF:oIndexTreeView:Nodes:Clear()
			END TRY
			TRY
				TRY
					SELF:FillFields(oRdd)
				CATCH /*e*/ AS System.Exception
                //					MessageBox.Show(e:ToString(), "Some error happened:")
				END TRY
				SELF:oNavigator:Enabled := TRUE
			CATCH
				SELF:oFieldsListView:Items:Clear()
				SELF:oNavigator:Enabled := FALSE
			END TRY
		END IF
		SELF:oDetailsListView:EndUpdate()
		SELF:oIndexTreeView:EndUpdate()
		SELF:oFieldsListView:EndUpdate()

		Cursor.Current := Cursors.Default
	RETURN

	PROTECTED METHOD FillWorkareas() AS VOID
		LOCAL oItem AS ListViewItem_workarea
		LOCAL nWorkarea AS DWORD

		LOCAL aItems AS SortedList<DWORD,ListViewItem_workarea>
		aItems := SortedList<DWORD,ListViewItem_workarea>{}
		FOR LOCAL i := 1 AS DWORD UPTO XSharp.RDD.Workareas.MaxWorkareas
			LOCAL oRdd AS XSharp.RDD.IRdd
			oRdd:=  XSharp.RuntimeState.Workareas:GetRDD(i)
			IF oRdd != NULL
            //				? oRdd:Alias
				nWorkarea := i
				oItem := ListViewItem_workarea{nWorkarea:ToString()}
				oItem:SubItems:Add(oRdd:Alias)
				oItem:Rdd := oRdd
				oItem:Workarea := nWorkarea
				aItems:Add(nWorkarea , oItem)
			END IF
		NEXT

		FOREACH oSortedItem AS KeyValuePair<DWORD,ListViewItem_workarea> IN aItems
			SELF:oWorkareasListView:Items:Add(oSortedItem:Value)
		NEXT

	RETURN

	PROTECTED METHOD FillDetails(oRdd AS XSharp.RDD.IRdd, nWorkarea AS DWORD) AS VOID
        /*		FOR LOCAL n := 1 AS INT UPTO 50
        ? n , oRdd:Info(n,NULL)
        NEXT
        LOCAL oDbf AS XSharp.RDD.Workarea
        oDbf := (XSharp.RDD.Workarea)oRdd*/

        //		SELF:SetDetail(WorkareaDetail.FileName , oRdd:Info(24,NULL):ToString())
		SELF:FillFieldDetail(WorkareaDetail.FileName , oRdd, "_FileName")
		SELF:SetDetail(WorkareaDetail.Rdd , oRdd:Driver)
		SELF:SetDetail(WorkareaDetail.Area , nWorkarea:ToString())
		SELF:FillFieldDetail(WorkareaDetail.Ansi , oRdd, "_Ansi")
		SELF:SetDetail(WorkareaDetail.FieldCount , oRdd:FieldCount:ToString())
		SELF:SetDetail(WorkareaDetail.RecCount , oRdd:RecCount:ToString())
		SELF:FillFieldDetail(WorkareaDetail.RecSize , oRdd , "_RecordLength")
		SELF:FillFieldDetail(WorkareaDetail.Shared , oRdd , "Shared")
		SELF:FillFieldDetail(WorkareaDetail.ReadOnly , oRdd , "_ReadOnly")
		SELF:FillFieldDetail(WorkareaDetail.Deleted , oRdd , "Deleted")
		SELF:SetDetail(WorkareaDetail.Eof , oRdd:EoF:ToString())
		SELF:SetDetail(WorkareaDetail.Bof , oRdd:BoF:ToString())
		SELF:FillFieldDetail(WorkareaDetail.Found , oRdd , "Found")
		SELF:SetDetail(WorkareaDetail.Filter , oRdd:FilterText)
		SELF:FillFieldDetail(WorkareaDetail.RecNo , oRdd , "RecNo")
	RETURN
	PROTECTED METHOD FillFieldDetail(eDetail AS WorkareaDetail, oRdd AS XSharp.RDD.IRdd, cField AS STRING) AS VOID
		LOCAL oType AS Type
		LOCAL oFieldInfo AS System.Reflection.FieldInfo
		TRY
			oType := oRdd:GetType()
			oFieldInfo := oType:GetField(cField, System.Reflection.BindingFlags.Public + System.Reflection.BindingFlags.NonPublic + System.Reflection.BindingFlags.Instance)
			IF oFieldInfo != NULL
				SELF:SetDetail((INT)eDetail , oFieldInfo:GetValue(oRdd):ToString())
			ELSE
				LOCAL oPropertyInfo := NULL AS System.Reflection.PropertyInfo
				DO WHILE oPropertyInfo == NULL .AND. oType != NULL
					oPropertyInfo := oType:GetProperty(cField, System.Reflection.BindingFlags.DeclaredOnly + System.Reflection.BindingFlags.Public + System.Reflection.BindingFlags.Instance)
					IF oPropertyInfo == NULL
						oType := oType:BaseType
					END IF
				END DO
				IF oPropertyInfo == NULL
                //					MessageBox.Show("NotFound field " + cField)
					RETURN
				END IF
				SELF:SetDetail((INT)eDetail , oPropertyInfo:GetValue(oRdd):ToString())
			END IF
		CATCH /*e*/ AS System.Exception
            //			MessageBox.Show(e:ToString(), "Some error happened:")
		END TRY

	PROTECTED METHOD FillFields(oRdd AS XSharp.RDD.IRdd) AS VOID
		LOCAL nFieldCount AS INT

		SELF:oFieldsListView:Items:Clear()

		nFieldCount := oRdd:FieldCount
		FOR LOCAL nField := 1 AS INT UPTO nFieldCount
			LOCAL oItem AS ListViewItem
			oItem := ListViewItem{}

			LOCAL oInfo AS XSharp.RDD.Support.RddFieldInfo
			oInfo := oRdd:GetField(nField)
			oItem:Text := oInfo:Name
			oItem:SubItems:Add(oInfo:FieldType:ToString())
			oItem:SubItems:Add(oInfo:Length:ToString())
			oItem:SubItems:Add(oInfo:Decimals:ToString())
			oItem:SubItems:Add(oRdd:GetValue(nField):ToString())
			SELF:oFieldsListView:Items:Add(oItem)
		NEXT

	RETURN

	PROTECTED METHOD FillIndexes(oRdd AS XSharp.RDD.IRdd) AS VOID

		LOCAL oIndexNode AS TreeNode
		LOCAL oOrderNode AS TreeNode
		LOCAL lMultiOrder AS LOGIC
		LOCAL cOldIndex AS STRING
		LOCAL cValue AS STRING
		LOCAL nOrders AS INT

		LOCAL FUNCTION CreateNode(cCaption AS STRING , oValue AS OBJECT) AS TreeNode
			LOCAL cValue AS STRING
			IF oValue == NULL
				cValue := "n/a"
			ELSE
				cValue := oValue:ToString()
			END IF
			RETURN TreeNode{cCaption + " = " + cValue}
		END FUNCTION

		LOCAL oInfo AS XSharp.RDD.Support.DbOrderInfo
		oInfo := XSharp.RDD.Support.DbOrderInfo{}

		cValue := oRdd:OrderInfo(DBOI_NAME,oInfo)
		cValue += " ( " + oRdd:OrderInfo(DBOI_NUMBER,oInfo):ToString() + " )"

		SELF:oIndexTreeView:Nodes:Clear()
		SELF:oIndexTreeView:Nodes:Add("Current Order = " + cValue)

		cValue := oRdd:OrderInfo(DBOI_EXPRESSION,oInfo)
		SELF:oIndexTreeView:Nodes:Add("Current Expression = " + cValue)

		lMultiOrder := oRdd:OrderInfo(DBOI_INDEXEXT, oInfo):ToString():ToUpperInvariant():Contains("CDX")

		IF lMultiOrder

			cOldIndex := ""
//			LOCAL nIndex := 1 AS INT
			nOrders := (INT)oRdd:OrderInfo(DBOI_ORDERCOUNT, oInfo)
			LOCAL nCurrentOrder := 1 AS INT
			DO WHILE nCurrentOrder <= nOrders

//			    oInfo:Order := nIndex
				oInfo:Order := nCurrentOrder
				cValue := oRdd:OrderInfo(DBOI_INDEXNAME, oInfo):ToString()
				IF cValue != cOldIndex
					cOldIndex := cValue
//					cValue += "  ( " + oRdd:OrderInfo(DBOI_FULLPATH, oInfo):ToString() + " )"
					oIndexNode := TreeNode{cValue}
					SELF:oIndexTreeView:Nodes:Add(oIndexNode)
				END IF

				/*oInfo := XSharp.RDD.Support.DbOrderInfo{}
				oInfo:BagName := cOldIndex
				nOrders := (INT)oRdd:OrderInfo(DBOI_ORDERCOUNT, oInfo)*/

//				FOR LOCAL nOrder := 1 AS INT UPTO nOrders
//					nCurrentOrder ++
				oInfo := XSharp.RDD.Support.DbOrderInfo{}
				oInfo:Order := nCurrentOrder

				cValue := oRdd:OrderInfo(DBOI_NAME, oInfo):ToString()
				cValue := cValue + "  ( " + oRdd:OrderInfo(DBOI_EXPRESSION, oInfo):ToString() + " )"

				oOrderNode := TreeNode{cValue}
				oOrderNode:Nodes:Add(TreeNode{"Expression = " + oRdd:OrderInfo(DBOI_EXPRESSION, oInfo):ToString()})
				oOrderNode:Nodes:Add(CreateNode( "Rec position" , oRdd:OrderInfo(DBOI_POSITION,oInfo) ) )
				oOrderNode:Nodes:Add(CreateNode( "Descending" , oRdd:OrderInfo(DBOI_ISDESC, oInfo) ) )
				oOrderNode:Nodes:Add(CreateNode( "Conditional" , oRdd:OrderInfo(DBOI_ISCOND, oInfo) ) )
				oOrderNode:Nodes:Add(CreateNode( "Condition" , oRdd:OrderInfo(DBOI_CONDITION, oInfo) ) )

				oIndexNode:Nodes:Add(oOrderNode)
				oIndexNode:Expand()
//				NEXT

//				SELF:oIndexTreeView:Nodes:Add(oIndexNode)

//				nIndex ++
				nCurrentOrder ++
			END DO

		ELSE

			nOrders := (INT)oRdd:OrderInfo(DBOI_ORDERCOUNT, oInfo)

			FOR LOCAL nOrder := 1 AS INT UPTO nOrders
				oInfo:Order := nOrder
//		    cValue := oRdd:OrderInfo(DBOI_INDEXNAME, oInfo):ToString()
				cValue := oRdd:OrderInfo(DBOI_NAME, oInfo):ToString()
				cValue += " ( " + oRdd:OrderInfo(DBOI_FULLPATH, oInfo):ToString() + " )"

				oOrderNode := TreeNode{cValue}

				oOrderNode:Nodes:Add(TreeNode{"Expression = " + oRdd:OrderInfo(DBOI_EXPRESSION, oInfo):ToString()})
				oOrderNode:Nodes:Add(CreateNode( "Rec position" , oRdd:OrderInfo(DBOI_POSITION,oInfo) ) )
				oOrderNode:Nodes:Add(CreateNode( "Descending" , oRdd:OrderInfo(DBOI_ISDESC, oInfo) ) )
				oOrderNode:Nodes:Add(CreateNode( "Conditional" , oRdd:OrderInfo(DBOI_ISCOND, oInfo) ) )
				oOrderNode:Nodes:Add(CreateNode( "Condition" , oRdd:OrderInfo(DBOI_CONDITION, oInfo) ) )

				SELF:oIndexTreeView:Nodes:Add(oOrderNode)
				oOrderNode:Expand()
			NEXT

		END IF

	RETURN

END CLASS
END NAMESPACE

USING System.Windows.Forms
USING System.Collections.Generic
USING System.Reflection

BEGIN NAMESPACE XSharp.Debugger

ENUM WorkareaDetail
    MEMBER FileName
    MEMBER Rdd
    MEMBER Area
    MEMBER Ansi
    MEMBER Shared
    MEMBER ReadOnly
    MEMBER FieldCount
    MEMBER RecCount
    MEMBER RecSize
    MEMBER RecNo
    MEMBER Eof
    MEMBER Bof
    MEMBER Deleted
    MEMBER Found
    MEMBER Filter
END ENUM

ENUM MovementType
    MEMBER GoTo
    MEMBER GoTop
    MEMBER GoBottom
    MEMBER SkipNext
    MEMBER SkipPrevious
END ENUM

CLASS ListViewItem_workarea INHERIT ListViewItem
PROPERTY Rdd AS XSharp.RDD.IRdd AUTO
PROPERTY Workarea AS DWORD AUTO
CONSTRUCTOR(cText AS STRING)
    SUPER(cText)
RETURN
END CLASS

CLASS WorkareasWindow INHERIT System.Windows.Forms.Form

    PROTECT oIndexTreeView AS System.Windows.Forms.TreeView
    PROTECT oCloseButton AS System.Windows.Forms.Button
    PROTECT oNavigator AS System.Windows.Forms.ToolStrip
    PROTECT oFieldsListView AS System.Windows.Forms.ListView
    PROTECT oDetailsListView AS System.Windows.Forms.ListView
    PROTECT oWorkareasListView AS System.Windows.Forms.ListView
    // User code starts here (DO NOT remove this line)  ##USER##

METHOD InitializeForm() AS VOID

        // IDE generated code (please DO NOT modify)

    SELF:oIndexTreeView := System.Windows.Forms.TreeView{}
    SELF:oCloseButton := System.Windows.Forms.Button{}
    SELF:oNavigator := System.Windows.Forms.ToolStrip{}
    SELF:oFieldsListView := System.Windows.Forms.ListView{}
    SELF:oDetailsListView := System.Windows.Forms.ListView{}
    SELF:oWorkareasListView := System.Windows.Forms.ListView{}

    SELF:SuspendLayout()

    SELF:AutoScaleDimensions := System.Drawing.SizeF{ 6 , 13 }
    SELF:AutoScaleMode := System.Windows.Forms.AutoScaleMode.Font
    SELF:ClientSize := System.Drawing.Size{896 , 576}
    SELF:Location := System.Drawing.Point{100 , 100}
    SELF:MaximizeBox := FALSE
    SELF:MinimizeBox := FALSE
    SELF:Name := "WorkareasWindow"
    SELF:ShowIcon := FALSE
    SELF:ShowInTaskbar := FALSE
    SELF:SizeGripStyle := System.Windows.Forms.SizeGripStyle.Hide
    SELF:StartPosition := System.Windows.Forms.FormStartPosition.CenterParent
    SELF:Text := "Active database workareas"

    SELF:CancelButton := SELF:oCloseButton
    SELF:oIndexTreeView:Anchor := System.Windows.Forms.AnchorStyles.Top + System.Windows.Forms.AnchorStyles.Left + System.Windows.Forms.AnchorStyles.Right
    SELF:oIndexTreeView:Location := System.Drawing.Point{600 , 8}
    SELF:oIndexTreeView:Name := "IndexTreeView"
    SELF:oIndexTreeView:Size := System.Drawing.Size{280 , 280}
    SELF:oIndexTreeView:TabIndex := 2
    SELF:Controls:Add(SELF:oIndexTreeView)

    SELF:oCloseButton:Anchor := System.Windows.Forms.AnchorStyles.Right + System.Windows.Forms.AnchorStyles.Bottom
    SELF:oCloseButton:Location := System.Drawing.Point{757 , 544}
    SELF:oCloseButton:Name := "CloseButton"
    SELF:oCloseButton:Size := System.Drawing.Size{123 , 23}
    SELF:oCloseButton:TabIndex := 5
    SELF:oCloseButton:Text := "Close"
    SELF:Controls:Add(SELF:oCloseButton)

    SELF:oNavigator:SuspendLayout()
    SELF:oNavigator:Anchor := System.Windows.Forms.AnchorStyles.Top + System.Windows.Forms.AnchorStyles.Left + System.Windows.Forms.AnchorStyles.Right
    SELF:oNavigator:Dock := System.Windows.Forms.DockStyle.None
    SELF:oNavigator:Location := System.Drawing.Point{8 , 296}
    SELF:oNavigator:Name := "Navigator"
    SELF:oNavigator:Size := System.Drawing.Size{872 , 30}
    SELF:oNavigator:TabIndex := 4
    SELF:Controls:Add(SELF:oNavigator)

    SELF:oFieldsListView:Anchor := System.Windows.Forms.AnchorStyles.Top + System.Windows.Forms.AnchorStyles.Left + System.Windows.Forms.AnchorStyles.Right + System.Windows.Forms.AnchorStyles.Bottom
    SELF:oFieldsListView:FullRowSelect := TRUE
    SELF:oFieldsListView:HideSelection := FALSE
    SELF:oFieldsListView:Location := System.Drawing.Point{8 , 328}
    SELF:oFieldsListView:MultiSelect := FALSE
    SELF:oFieldsListView:Name := "FieldsListView"
    SELF:oFieldsListView:Size := System.Drawing.Size{872 , 208}
    SELF:oFieldsListView:TabIndex := 3
    SELF:oFieldsListView:View := System.Windows.Forms.View.Details
    SELF:Controls:Add(SELF:oFieldsListView)

    SELF:oDetailsListView:FullRowSelect := TRUE
    SELF:oDetailsListView:HideSelection := FALSE
    SELF:oDetailsListView:Location := System.Drawing.Point{288 , 8}
    SELF:oDetailsListView:MultiSelect := FALSE
    SELF:oDetailsListView:Name := "DetailsListView"
    SELF:oDetailsListView:Size := System.Drawing.Size{304 , 280}
    SELF:oDetailsListView:TabIndex := 1
    SELF:oDetailsListView:View := System.Windows.Forms.View.Details
    SELF:Controls:Add(SELF:oDetailsListView)

    SELF:oWorkareasListView:FullRowSelect := TRUE
    SELF:oWorkareasListView:HideSelection := FALSE
    SELF:oWorkareasListView:Location := System.Drawing.Point{8 , 8}
    SELF:oWorkareasListView:MultiSelect := FALSE
    SELF:oWorkareasListView:Name := "WorkareasListView"
    SELF:oWorkareasListView:SelectedIndexChanged += SELF:WorkareasListView_SelectedIndexChanged
    SELF:oWorkareasListView:Size := System.Drawing.Size{272 , 280}
    SELF:oWorkareasListView:TabIndex := 0
    SELF:oWorkareasListView:View := System.Windows.Forms.View.Details
    SELF:Controls:Add(SELF:oWorkareasListView)

    SELF:oNavigator:ResumeLayout()
    SELF:ResumeLayout()

RETURN

CONSTRUCTOR()

    SUPER()

    SELF:InitializeForm()

    SELF:oWorkareasListView:Columns:Add("No" , 50)
    SELF:oWorkareasListView:Columns:Add("Alias" , 200)

    SELF:oDetailsListView:Columns:Add("Property" , 90)
    SELF:oDetailsListView:Columns:Add("Value" , 200)

    SELF:CreateDetail("Filename")
    SELF:CreateDetail("RDD name")
    SELF:CreateDetail("Area number")
    SELF:CreateDetail("Ansi")
    SELF:CreateDetail("Shared")
    SELF:CreateDetail("ReadOnly")
    SELF:CreateDetail("Field count")
    SELF:CreateDetail("Record count")
    SELF:CreateDetail("Record size")
    SELF:CreateDetail("Record number")
    SELF:CreateDetail("Eof")
    SELF:CreateDetail("Bof")
    SELF:CreateDetail("Deleted")
    SELF:CreateDetail("Found")
    SELF:CreateDetail("Filter text")

    SELF:oFieldsListView:Columns:Add("Field name" , 80)
    SELF:oFieldsListView:Columns:Add("Type" , 80)
    SELF:oFieldsListView:Columns:Add("Length" , 80)
    SELF:oFieldsListView:Columns:Add("Decimals" , 80)
    SELF:oFieldsListView:Columns:Add("Value" , 400)

    SELF:oNavigator:AutoSize := FALSE

    LOCAL oSource AS BindingNavigator
    oSource := BindingNavigator{TRUE}

    SELF:oNavigator:Items:Add(ToolStripButton{NULL, oSource:MoveFirstItem:Image , {o,e => SELF:DoMove(MovementType.GoTop)} })
    SELF:oNavigator:Items:Add(ToolStripButton{NULL, oSource:MovePreviousItem:Image , {o,e => SELF:DoMove(MovementType.SkipPrevious)} })
    SELF:oNavigator:Items:Add(ToolStripButton{NULL, oSource:MoveNextItem:Image , {o,e => SELF:DoMove(MovementType.SkipNext)} })
    SELF:oNavigator:Items:Add(ToolStripButton{NULL, oSource:MoveLastItem:Image , {o,e => SELF:DoMove(MovementType.GoBottom)} })

    SELF:FillWorkareas()
    IF SELF:oWorkareasListView:Items:Count != 0
        SELF:oWorkareasListView:SelectedIndices:Add(0)
    END IF

RETURN

METHOD DoMove(eMove AS MovementType) AS VOID
    LOCAL oRdd AS XSharp.RDD.IRdd
    IF SELF:oWorkareasListView:SelectedIndices:Count == 0
        RETURN
    END IF
    oRdd := ((ListViewItem_workarea)SELF:oWorkareasListView:SelectedItems[0]):Rdd
    SWITCH eMove
    CASE MovementType.GoTop
        oRdd:GoTop()
    CASE MovementType.GoBottom
        oRdd:GoBottom()
    CASE MovementType.SkipNext
        oRdd:Skip(+1)
    CASE MovementType.SkipPrevious
        oRdd:Skip(-1)
    END SWITCH
    SELF:FillAll()
RETURN

PROTECTED METHOD CreateDetail(cName AS STRING) AS VOID
    LOCAL oItem AS ListViewItem_workarea
    oItem := ListViewItem_workarea{cName}
    oItem:SubItems:Add("")
    SELF:oDetailsListView:Items:Add(oItem)
RETURN
PROTECTED METHOD SetDetail(nIndex AS INT , cValue AS STRING) AS VOID
    LOCAL oItem AS ListViewItem_workarea
    oItem := (ListViewItem_workarea)SELF:oDetailsListView:Items[nIndex]
    oItem:SubItems[1]:Text := cValue
RETURN
PROTECTED METHOD ClearDetails() AS VOID
    LOCAL oItem AS ListViewItem_workarea
    LOCAL n AS INT
    FOR n := 0 UPTO SELF:oDetailsListView:Items:Count - 1
        oItem := (ListViewItem_workarea)SELF:oDetailsListView:Items[n]
        oItem:SubItems[1]:Text := ""
    NEXT
RETURN

METHOD WorkareasListView_SelectedIndexChanged(sender AS System.Object , e AS System.EventArgs) AS VOID
    SELF:FillAll()
RETURN

METHOD FillAll() AS VOID
    LOCAL oRdd AS XSharp.RDD.IRdd
    LOCAL lError := FALSE AS LOGIC
    LOCAL nWorkarea AS DWORD

    IF SELF:oWorkareasListView:SelectedIndices:Count == 0
        SELF:oIndexTreeView:Nodes:Clear()
        SELF:oFieldsListView:Items:Clear()
        SELF:oNavigator:Enabled := FALSE
        SELF:ClearDetails()
        RETURN
    END IF

    oRdd := ((ListViewItem_workarea)SELF:oWorkareasListView:SelectedItems[0]):Rdd
    nWorkarea := ((ListViewItem_workarea)SELF:oWorkareasListView:SelectedItems[0]):Workarea
    Cursor.Current := Cursors.WaitCursor

    SELF:oDetailsListView:BeginUpdate()
    SELF:oIndexTreeView:BeginUpdate()
    SELF:oFieldsListView:BeginUpdate()
    TRY
        FillDetails(oRdd, nWorkarea)
    CATCH
        SELF:ClearDetails()
        lError := TRUE
    END TRY

    IF lError
        SELF:oIndexTreeView:Nodes:Clear()
        SELF:oFieldsListView:Items:Clear()
    ELSE
        TRY
            FillIndexes(oRdd)
        CATCH
            SELF:oIndexTreeView:Nodes:Clear()
        END TRY
        TRY
            TRY
                FillFields(oRdd)
            CATCH /*e*/ AS System.Exception
                //					MessageBox.Show(e:ToString(), "Some error happened:")
            END TRY
            SELF:oNavigator:Enabled := TRUE
        CATCH
            SELF:oFieldsListView:Items:Clear()
            SELF:oNavigator:Enabled := FALSE
        END TRY
    END IF
    SELF:oDetailsListView:EndUpdate()
    SELF:oIndexTreeView:EndUpdate()
    SELF:oFieldsListView:EndUpdate()

    Cursor.Current := Cursors.Default
RETURN

METHOD FillWorkareas() AS VOID
    LOCAL oItem AS ListViewItem_workarea
    LOCAL nWorkarea AS DWORD

    LOCAL aItems AS SortedList<DWORD,ListViewItem_workarea>
    aItems := SortedList<DWORD,ListViewItem_workarea>{}
    FOR LOCAL i := 1 AS DWORD UPTO XSharp.RDD.Workareas.MaxWorkareas
        LOCAL oRdd AS XSharp.RDD.IRdd
        oRdd:=  XSharp.RuntimeState.Workareas:GetRDD(i)
        IF oRdd != NULL
            //				? oRdd:Alias
            nWorkarea := i
            oItem := ListViewItem_workarea{nWorkarea:ToString()}
            oItem:SubItems:Add(oRdd:Alias)
            oItem:Rdd := oRdd
            oItem:Workarea := nWorkarea
            aItems:Add(nWorkarea , oItem)
        END IF
    NEXT

    FOREACH oSortedItem AS KeyValuePair<DWORD,ListViewItem_workarea> IN aItems
        SELF:oWorkareasListView:Items:Add(oSortedItem:Value)
    NEXT

RETURN

METHOD FillDetails(oRdd AS XSharp.RDD.IRdd, nWorkarea AS DWORD) AS VOID
        /*		FOR LOCAL n := 1 AS INT UPTO 50
        ? n , oRdd:Info(n,NULL)
        NEXT
        LOCAL oDbf AS XSharp.RDD.Workarea
        oDbf := (XSharp.RDD.Workarea)oRdd*/

        //		SELF:SetDetail(WorkareaDetail.FileName , oRdd:Info(24,NULL):ToString())
    SELF:FillFieldDetail(WorkareaDetail.FileName , oRdd, "_FileName")
    SELF:SetDetail(WorkareaDetail.Rdd , oRdd:Driver)
    SELF:SetDetail(WorkareaDetail.Area , nWorkarea:ToString())
    SELF:FillFieldDetail(WorkareaDetail.Ansi , oRdd, "_Ansi")
    SELF:SetDetail(WorkareaDetail.FieldCount , oRdd:FieldCount:ToString())
    SELF:SetDetail(WorkareaDetail.RecCount , oRdd:RecCount:ToString())
    SELF:FillFieldDetail(WorkareaDetail.RecSize , oRdd , "_RecordLength")
    SELF:FillFieldDetail(WorkareaDetail.Shared , oRdd , "Shared")
    SELF:FillFieldDetail(WorkareaDetail.ReadOnly , oRdd , "_ReadOnly")
    SELF:FillFieldDetail(WorkareaDetail.Deleted , oRdd , "Deleted")
    SELF:SetDetail(WorkareaDetail.Eof , oRdd:EoF:ToString())
    SELF:SetDetail(WorkareaDetail.Bof , oRdd:BoF:ToString())
    SELF:FillFieldDetail(WorkareaDetail.Found , oRdd , "Found")
    SELF:SetDetail(WorkareaDetail.Filter , oRdd:FilterText)
    SELF:FillFieldDetail(WorkareaDetail.RecNo , oRdd , "RecNo")
RETURN
VIRTUAL METHOD FillFieldDetail(eDetail AS WorkareaDetail, oRdd AS XSharp.RDD.IRdd, cField AS STRING) AS VOID
    LOCAL oType AS Type
    LOCAL oFieldInfo AS System.Reflection.FieldInfo
    TRY
        oType := oRdd:GetType()
        oFieldInfo := oType:GetField(cField, System.Reflection.BindingFlags.Public + System.Reflection.BindingFlags.NonPublic + System.Reflection.BindingFlags.Instance)
        IF oFieldInfo != NULL
            SELF:SetDetail((INT)eDetail , oFieldInfo:GetValue(oRdd):ToString())
        ELSE
            LOCAL oPropertyInfo := NULL AS System.Reflection.PropertyInfo
            DO WHILE oPropertyInfo == NULL .AND. oType != NULL
                oPropertyInfo := oType:GetProperty(cField, System.Reflection.BindingFlags.DeclaredOnly + System.Reflection.BindingFlags.Public + System.Reflection.BindingFlags.Instance)
                IF oPropertyInfo == NULL
                    oType := oType:BaseType
                END IF
            END DO
            IF oPropertyInfo == NULL
                //					MessageBox.Show("NotFound field " + cField)
                RETURN
            END IF
            SELF:SetDetail((INT)eDetail , oPropertyInfo:GetValue(oRdd):ToString())
        END IF
    CATCH /*e*/ AS System.Exception
            //			MessageBox.Show(e:ToString(), "Some error happened:")
    END TRY

METHOD FillFields(oRdd AS XSharp.RDD.IRdd) AS VOID
    LOCAL nFieldCount AS INT

    SELF:oFieldsListView:Items:Clear()

    nFieldCount := oRdd:FieldCount
    FOR LOCAL nField := 1 AS INT UPTO nFieldCount
        LOCAL oItem AS ListViewItem
        oItem := ListViewItem{}

        LOCAL oInfo AS XSharp.RDD.Support.RddFieldInfo
        oInfo := oRdd:GetField(nField)
        oItem:Text := oInfo:Name
        oItem:SubItems:Add(oInfo:FieldType:ToString())
        oItem:SubItems:Add(oInfo:Length:ToString())
        oItem:SubItems:Add(oInfo:Decimals:ToString())
        oItem:SubItems:Add(oRdd:GetValue(nField):ToString())
        SELF:oFieldsListView:Items:Add(oItem)
    NEXT

RETURN

METHOD FillIndexes(oRdd AS XSharp.RDD.IRdd) AS VOID

        //		LOCAL oOrderInfoMethod AS MethodInfo
        //		LOCAL oItmResultField AS FieldInfo
    LOCAL oIndexNode AS TreeNode
    LOCAL oOrderNode AS TreeNode
        //		LOCAL oDBOrderInfo AS Value
        //		LOCAL oStringValue AS Value
    LOCAL nCurrentOrder := 0 AS INT
    LOCAL lMultiOrder AS LOGIC
        //		LOCAL oType AS DebugType
        //		LOCAL aParams AS Value[]
    LOCAL cOldIndex AS STRING
        //		LOCAL oValue AS Value
    LOCAL cValue AS STRING
    LOCAL nOrders AS INT
    LOCAL n,m AS INT

        //		aParams := Value[]{2}
        //		oType := DebugType.Create(SELF:oDebugProcess , Nullable<DWORD>{} , "Vulcan.RDD.DBORDERINFO")

    SELF:oIndexTreeView:Nodes:Clear()
    LOCAL oInfo AS XSharp.RDD.Support.DbOrderInfo
    oInfo := XSharp.RDD.Support.DbOrderInfo{}
        //		oInfo:Order := 2
        /*		? 3,oRdd:OrderInfo(3,oInfo)
        ? 4,oRdd:OrderInfo(4,oInfo)
        ? 5,oRdd:OrderInfo(5,oInfo)
        ? 6,oRdd:OrderInfo(6,oInfo)
        ? 7,oRdd:OrderInfo(7,oInfo)
        ? 8,oRdd:OrderInfo(8,oInfo)
        ? 44,oRdd:OrderInfo(44,oInfo)
        ? "aaa",oInfo:BagName*/

    lMultiOrder := FALSE

    //		lMultiOrder := oExpression:Evaluate(SELF:oDebugProcess):AsString:Contains("CDX")

    //		oOrderInfoMethod := SELF:oRDDBaseType:GetMethod("OrderInfo")
    //		oItmResultField := oType:GetField("itmResult")

    //		oDBOrderInfo := Eval.NewObjectNoConstructor(oType)
    //		aParams[1] := PrimitiveExpression{DBOI_NAME}:Evaluate(SELF:oDebugProcess)
    //		aParams[2] := oDBOrderInfo
    //		oExpression:Evaluate(SELF:oDebugProcess):InvokeMethod(oOrderInfoMethod , aParams)
    //		cValue := oDBOrderInfo:GetFieldValue(oItmResultField):AsString

    //		aParams[1] := PrimitiveExpression{DBOI_NUMBER}:Evaluate(SELF:oDebugProcess)
    //		oExpression:Evaluate(SELF:oDebugProcess):InvokeMethod(oOrderInfoMethod , aParams)
    //		cValue += " (" + oDBOrderInfo:GetFieldValue(oItmResultField):PrimitiveValue:ToString() + ")"

    cValue := "AAA"

    //		SELF:oIndexTreeView:Nodes:Add("Current Order = " + cValue)

    /*		aParams[1] := PrimitiveExpression{DBOI_EXPRESSION}:Evaluate(SELF:oDebugProcess)
    oExpression:Evaluate(SELF:oDebugProcess):InvokeMethod(oOrderInfoMethod , aParams)
    cValue := oDBOrderInfo:GetFieldValue(oItmResultField):AsString*/
    cValue := "BBB"
    //		SELF:oIndexTreeView:Nodes:Add("Current Expression = " + cValue)

    IF lMultiOrder

        cOldIndex := ""
        n := 1
        DO WHILE TRUE .AND. n < 10

    /*				oDBOrderInfo := Eval.NewObjectNoConstructor(oType)
    oDBOrderInfo:GetFieldValue(oType:GetField("itmOrder")):SetValue(PrimitiveExpression{n}:Evaluate(SELF:oDebugProcess))
    //		oDBOrderInfo:GetFiebldValue(oType:GetField("itmCobExpr")):SetValue(PrimitiveExpression{n}:Evaluate(SELF:oDebugProcess))
    aParams[1] := PrimitiveExpression{DBOI_INDEXNAME}:Evaluate(SELF:oDebugProcess)
    aParams[2] := oDBOrderInfo
    oExpression:Evaluate(SELF:oDebugProcess):InvokeMethod(oOrderInfoMethod , aParams)
    oValue := oDBOrderInfo:GetFieldValue(oItmResultField)
    IF oValue:IsNull
    EXIT
    END IF
    cValue := oValue:AsString*/
            cValue := oRdd:OrderInfo(5,oInfo):ToString()

            IF cValue == cOldIndex
                EXIT
            END IF
            cOldIndex := cValue

    /*				aParams[1] := PrimitiveExpression{DBOI_FULLPATH}:Evaluate(SELF:oDebugProcess)
    oExpression:Evaluate(SELF:oDebugProcess):InvokeMethod(oOrderInfoMethod , aParams)
    cValue += "  (" + oDBOrderInfo:GetFieldValue(oItmResultField):AsString + ")"*/

            cValue += "  (" + oRdd:OrderInfo(7,oInfo):ToString() + ")"

            oIndexNode := TreeNode{cValue}

    /*				oStringValue := Eval.NewString(SELF:oDebugProcess , cOldIndex)
    oDBOrderInfo := Eval.NewObjectNoConstructor(oType)
    oDBOrderInfo:GetFieldValue(oType:GetField("sBagName")):SetValue(oStringValue)
    aParams[1] := PrimitiveExpression{DBOI_ORDERCOUNT}:Evaluate(SELF:oDebugProcess)
    aParams[2] := oDBOrderInfo
    oExpression:Evaluate(SELF:oDebugProcess):InvokeMethod(oOrderInfoMethod , aParams)
    nOrders := (INT)oDBOrderInfo:GetFieldValue(oItmResultField):PrimitiveValue*/
            nOrders := (INT)oRdd:OrderInfo(DBOI_ORDERCOUNT,oInfo)

            FOR m := 1 UPTO nOrders
                nCurrentOrder ++
        /*					oDBOrderInfo := Eval.NewObjectNoConstructor(oType)
        oDBOrderInfo:GetFieldValue(oType:GetField("itmOrder")):SetValue(PrimitiveExpression{nCurrentOrder}:Evaluate(SELF:oDebugProcess))
        aParams[1] := PrimitiveExpression{DBOI_NAME}:Evaluate(SELF:oDebugProcess)
        aParams[2] := oDBOrderInfo
        oExpression:Evaluate(SELF:oDebugProcess):InvokeMethod(oOrderInfoMethod , aParams)
        cValue := oDBOrderInfo:GetFieldValue(oItmResultField):AsString

        aParams[1] := PrimitiveExpression{DBOI_EXPRESSION}:Evaluate(SELF:oDebugProcess)
        oExpression:Evaluate(SELF:oDebugProcess):InvokeMethod(oOrderInfoMethod , aParams)
        cValue := cValue + "  (" + oDBOrderInfo:GetFieldValue(oItmResultField):AsString + ")"*/

                oInfo:Order := m
                cValue := oRdd:OrderInfo(DBOI_NAME,oInfo):ToString()

                oOrderNode := TreeNode{cValue}

        /*					aParams[1] := PrimitiveExpression{DBOI_ISCOND}:Evaluate(SELF:oDebugProcess)
        oExpression:Evaluate(SELF:oDebugProcess):InvokeMethod(oOrderInfoMethod , aParams)
        oOrderNode:Nodes:Add(SELF:CreateNode("Descending" , oDBOrderInfo , oItmResultField))

        aParams[1] := PrimitiveExpression{DBOI_ISDESC}:Evaluate(SELF:oDebugProcess)
        oExpression:Evaluate(SELF:oDebugProcess):InvokeMethod(oOrderInfoMethod , aParams)
        oOrderNode:Nodes:Add(SELF:CreateNode("Conditional" , oDBOrderInfo , oItmResultField))

        aParams[1] := PrimitiveExpression{DBOI_CONDITION}:Evaluate(SELF:oDebugProcess)
        oExpression:Evaluate(SELF:oDebugProcess):InvokeMethod(oOrderInfoMethod , aParams)
        oOrderNode:Nodes:Add(SELF:CreateNode("Condition" , oDBOrderInfo , oItmResultField))

        aParams[1] := PrimitiveExpression{DBOI_RECNO}:Evaluate(SELF:oDebugProcess)
        oExpression:Evaluate(SELF:oDebugProcess):InvokeMethod(oOrderInfoMethod , aParams)
        oOrderNode:Nodes:Add(SELF:CreateNode("RecNo" , oDBOrderInfo , oItmResultField))*/

                oIndexNode:Nodes:Add(oOrderNode)
                oIndexNode:Expand()

            NEXT

            SELF:oIndexTreeView:Nodes:Add(oIndexNode)

            n ++
        END DO

    ELSE

        nOrders := (INT)oRdd:OrderInfo(DBOI_ORDERCOUNT,oInfo)
    /*			oDBOrderInfo := Eval.NewObjectNoConstructor(oType)
    aParams[1] := PrimitiveExpression{DBOI_ORDERCOUNT}:Evaluate(SELF:oDebugProcess)
    aParams[2] := oDBOrderInfo
    oExpression:Evaluate(SELF:oDebugProcess):InvokeMethod(oOrderInfoMethod , aParams)
    nOrders := (INT)oDBOrderInfo:GetFieldValue(oItmResultField):PrimitiveValue*/

        FOR n := 1 UPTO nOrders
    /*				oDBOrderInfo := Eval.NewObjectNoConstructor(oType)
    oDBOrderInfo:GetFieldValue(oType:GetField("itmOrder")):SetValue(PrimitiveExpression{n}:Evaluate(SELF:oDebugProcess))
    aParams[1] := PrimitiveExpression{DBOI_INDEXNAME}:Evaluate(SELF:oDebugProcess)
    aParams[2] := oDBOrderInfo
    oExpression:Evaluate(SELF:oDebugProcess):InvokeMethod(oOrderInfoMethod , aParams)
    cValue := oDBOrderInfo:GetFieldValue(oItmResultField):AsString

    aParams[1] := PrimitiveExpression{DBOI_FULLPATH}:Evaluate(SELF:oDebugProcess)
    oExpression:Evaluate(SELF:oDebugProcess):InvokeMethod(oOrderInfoMethod , aParams)
    cValue += " (" + oDBOrderInfo:GetFieldValue(oItmResultField):AsString + ")"

    oOrderNode := TreeNode{cValue}

    aParams[1] := PrimitiveExpression{DBOI_EXPRESSION}:Evaluate(SELF:oDebugProcess)
    oExpression:Evaluate(SELF:oDebugProcess):InvokeMethod(oOrderInfoMethod , aParams)
    oOrderNode:Nodes:Add(TreeNode{"Expression = " + oDBOrderInfo:GetFieldValue(oItmResultField):AsString})

    aParams[1] := PrimitiveExpression{DBOI_ISCOND}:Evaluate(SELF:oDebugProcess)
    oExpression:Evaluate(SELF:oDebugProcess):InvokeMethod(oOrderInfoMethod , aParams)
    oOrderNode:Nodes:Add(SELF:CreateNode("Descending" , oDBOrderInfo , oItmResultField))

    aParams[1] := PrimitiveExpression{DBOI_ISDESC}:Evaluate(SELF:oDebugProcess)
    oExpression:Evaluate(SELF:oDebugProcess):InvokeMethod(oOrderInfoMethod , aParams)
    oOrderNode:Nodes:Add(SELF:CreateNode("Conditional" , oDBOrderInfo , oItmResultField))

    aParams[1] := PrimitiveExpression{DBOI_CONDITION}:Evaluate(SELF:oDebugProcess)
    oExpression:Evaluate(SELF:oDebugProcess):InvokeMethod(oOrderInfoMethod , aParams)
    oOrderNode:Nodes:Add(SELF:CreateNode("Condition" , oDBOrderInfo , oItmResultField))*/

            oInfo:Order := n
            cValue := oRdd:OrderInfo(5,oInfo):ToString()
            cValue += "  (" + oRdd:OrderInfo(7,oInfo):ToString() + ")"

            oOrderNode := TreeNode{cValue}

            SELF:oIndexTreeView:Nodes:Add(oOrderNode)
            oOrderNode:Expand()
        NEXT

    END IF

RETURN

END CLASS
END NAMESPACE


[Runtime] Fixes #642. This is weird but it works like this in VFP 9.

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//
USING System.Collections
USING System.Collections.Generic
USING System.Linq
USING System.Diagnostics
USING System.Reflection
USING System.Text
USING XSharp
BEGIN NAMESPACE XSharp
    /// Internal type that implements the FoxPro Compatible ARRAY type.

    /// This type has methods and properties that normally are never directly called from user code.
    ///
    /// <remarks>FoxPro arrays can be one dimensional or two dimensional.
	/// Two dimensional arrays are implemented as a projection
    /// on top of a one dimensional array.

    /// So a two dimensional array of 4 x 3 elements will be implemented as an array of 12 elements.
    /// The elements 1-3 represent row 1, 4-6 row 2 etc. </remarks>
    /// <seealso cref='IIndexer' />
    /// <include file="RTComments.xml" path="Comments/ZeroBasedIndex/*" />
    //[DebuggerTypeProxy(TYPEOF(ArrayDebugView))];
    [DebuggerDisplay("{DebuggerString(),nq}")] ;
    PUBLIC SEALED CLASS __FoxArray INHERIT __Array IMPLEMENTS IIndexer
        [DebuggerBrowsable(DebuggerBrowsableState.Never)];
        PRIVATE _nCols := 1 AS DWORD
        [DebuggerBrowsable(DebuggerBrowsableState.Never)];
        PROPERTY MultiDimensional AS LOGIC GET _nCols > 1
        PROPERTY Columns AS LONG GET (LONG) _nCols
        PROPERTY Rows    AS LONG GET _internalList:Count / (LONG) _nCols
         /// <inheritdoc />
        CONSTRUCTOR()
            SUPER()

            /// <inheritdoc />
        CONSTRUCTOR(capacity AS DWORD)
            SUPER(capacity, TRUE)

        CONSTRUCTOR(nRows AS DWORD, nCols AS DWORD)
            SUPER( nRows * nCols, TRUE)
            SELF:_nCols := nCols

            /// <inheritdoc />
        CONSTRUCTOR( elements AS OBJECT[] )
            SUPER(elements)

        PRIVATE CONSTRUCTOR( elements AS USUAL[])
            SUPER(elements)

        INTERNAL METHOD __Fill(uValue AS USUAL) AS VOID
            FOR VAR nElement := 0 TO SELF:Length-1
               SELF:_internalList[nElement] := uValue
            NEXT
            RETURN

        INTERNAL METHOD __GetDimensionError(nDimensionsAsked AS LONG) AS Error
            VAR err         := Error.BoundError(ProcName(2),"indices", 1)
            IF SELF:MultiDimensional
               err:Description := i"Bound error: You cannot access a 2 dimensional array with {nDimensionsAsked} indices"
            ELSE
               err:Description := i"Bound error: You cannot access a single dimensional array with {nDimensionsAsked} indices"
            ENDIF
            err:Stack   := ErrorStack(1)
            RETURN err

        INTERNAL STATIC METHOD __NestedArrayError() AS Error
            VAR err     := Error.ArgumentError(ProcName(2),"value", "You cannot assign an array to an element inside a Fox Array")
            err:Stack   := ErrorStack(1)
            RETURN err

        PUBLIC OVERRIDE METHOD __GetElement(index AS INT, index2 AS INT) AS USUAL
             VAR item := SELF:__GetIndex(index, index2)
             SUPER:__CheckArrayElement(SELF, item, nameof(index),1)
             RETURN SUPER:__GetElement(item)

        PUBLIC OVERRIDE METHOD __GetElement(indices PARAMS INT[] ) AS USUAL
            IF  indices:Length == 1
                RETURN SUPER:__GetElement(indices[1])
            ELSEIF indices:Length == 2 .and. SELF:_nCols > 1
                RETURN SELF:__GetElement(indices[1], indices[2])
            ELSE
                VAR err     := Error.BoundError(ProcName(1),nameof(indices), 1, indices)
                err:Stack   := ErrorStack(1)
                err:Description := i"Bound error: Too many dimensions)"
                THROW err
            ENDIF

       PUBLIC OVERRIDE METHOD __SetElement(u AS USUAL, index AS INT) AS USUAL
             IF IsArray(u)
                  THROW __NestedArrayError()
             ENDIF
             SUPER:__CheckArrayElement(SELF, index, nameof(index),1)
             RETURN SUPER:__SetElement(u, index)

        PUBLIC OVERRIDE METHOD __SetElement(u AS USUAL, index AS INT, index2 AS INT) AS USUAL
             IF IsArray(u)
                  THROW __NestedArrayError()
             ENDIF
             VAR item := SELF:__GetIndex(index, index2)
             SUPER:__CheckArrayElement(SELF, item, nameof(index),1)
             RETURN SUPER:__SetElement(u, item)

        PUBLIC OVERRIDE METHOD __SetElement(u AS USUAL, indices PARAMS INT[] ) AS USUAL
            IF indices:Length == 1
                RETURN SUPER:__SetElement(u, indices[1])
            ELSEIF indices:Length == 2 .and. _nCols > 1
                RETURN SELF:__SetElement(u, indices[1], indices[2])
            ELSE
                VAR err     := Error.BoundError(ProcName(1),"indices", 2, indices)
                err:Stack   := ErrorStack(1)
                err:Description := i"Bound error: Too many dimensions"
                THROW err
            ENDIF

        PRIVATE METHOD __GetIndex(nRow AS INT, nColumn AS INT) AS INT
            // Note that nRow and nColumn are already Zero based !
            // And also that FoxPro does not complain when you indicate a row number even
            // when the array is single dimensional. FoxPro then simply returns the element indicated with nColumn
            IF SELF:_nCols > 1
                RETURN (nRow * _nCols) + nColumn
            ELSE
                RETURN nColumn
            ENDIF

        /// <include file="RTComments.xml" path="Comments/ZeroBasedIndexProperty/*" />
        /// <param name="index"><include file="RTComments.xml" path="Comments/ZeroBasedIndexParam/*" /></param>
        /// <returns>The value of the property of the element stored at the indicated location in the array.</returns>
        OVERRIDE PUBLIC PROPERTY SELF[index AS INT] AS USUAL
            GET
                 SUPER:__CheckArrayElement(SELF, index, nameof(index),1)
                 RETURN SUPER:__GetElement(index)
            END GET
            SET
                IF IsArray(value)
                    THROW __NestedArrayError()
                ENDIF
                SUPER:__CheckArrayElement(SELF, index, nameof(index),1)
                SUPER:__SetElement(value,index)
            END SET
        END PROPERTY

        /// <include file="RTComments.xml" path="Comments/ZeroBasedIndexProperty/*" />
        /// <param name="index"><include file="RTComments.xml" path="Comments/ZeroBasedIndexParam/*" /></param>
        /// <param name="index2"><include file="RTComments.xml" path="Comments/ZeroBasedIndexParam/*" /></param>
        /// <returns>The value of the property of the element stored at the indicated location in the array.</returns>
        OVERRIDE PUBLIC PROPERTY SELF[index AS INT, index2 AS INT] AS USUAL
            GET
                IF ! SELF:MultiDimensional
                    THROW SELF:__GetDimensionError(2)
                ELSE
                    RETURN SELF:__GetElement(index, index2)
                ENDIF
            END GET
            SET
                IF IsArray(value)
                    THROW __NestedArrayError()
                ENDIF
                IF ! SELF:MultiDimensional
                    THROW SELF:__GetDimensionError(2)
                ELSE
                    SELF:__SetElement(value,SELF:__GetIndex(index, index2))
                ENDIF
            END SET
        END PROPERTY

        /// <include file="RTComments.xml" path="Comments/ZeroBasedIndexProperty/*" />
        /// <param name="indices"><include file="RTComments.xml" path="Comments/ZeroBasedIndexParam/*" /></param>
        /// <returns>The value of the property of the element stored at the indicated location in the array.</returns>
        OVERRIDE PUBLIC PROPERTY SELF[indices PARAMS INT[]] AS USUAL
            GET
                IF indices:Length == 1
                    SUPER:__CheckArrayElement(SELF, indices[1], nameof(indices),1)
                    RETURN SELF:__GetElement(indices[1])
                ELSEIF indices:Length == 2 .and. SELF:MultiDimensional
                    VAR index := SELF:__GetIndex(indices[1], indices[2])
                    SUPER:__CheckArrayElement(SELF, index, nameof(indices),1)
                    RETURN SELF:__GetElement(index)
                ELSE
                    THROW SELF:__GetDimensionError(indices:Length)
                ENDIF
            END GET
            SET
                IF IsArray(value)
                    THROW __NestedArrayError()
                ENDIF
                IF indices:Length == 1
                    SELF:__CheckArrayElement(SELF, indices[1], nameof(indices),1)
                    SELF:__SetElement(indices[1], value)
                ELSEIF indices:Length == 2 .and. SELF:MultiDimensional
                    VAR index := SELF:__GetIndex(indices[1], indices[2])
                    SELF:__CheckArrayElement(SELF, index, nameof(indices),1)
                    SELF:__SetElement(index, value)
                ELSE
                    THROW SELF:__GetDimensionError(indices:Length)
                ENDIF
            END SET
        END PROPERTY

        /// Redimension the array. Existing data will be saved if the # of cells in the new array <= the # of cells in the old array.
        METHOD ReDim(nRows AS DWORD, nCols := 1 AS DWORD) AS __FoxArray
            _nCols := nCols
            SELF:Resize( (INT) (nRows * nCols))
            RETURN SELF

       /// Delete a row from a multi dimensional array.
        /// <param name="nRow">1 based row number to delete</param>
        /// <remarks>Deleting rows will shift other rows up and will add a blank row at the bottom of the array</remarks>
        METHOD DeleteRow(nRow AS INT) AS __FoxArray
            // __GetIndex expects 0 based indices. DeleteRow works with 1 based rows
            VAR nStart := SELF:__GetIndex(nRow-1, 0)              // first element on the row
            VAR nEnd   := _internalList:Count - _nCols-1
            FOR VAR nIndex := nStart UPTO nEnd
                _internalList[nIndex] := _internalList[nIndex+_nCols]
            NEXT
            nStart := _internalList:Count - _nCols
            nEnd   := _internalList:Count-1
            FOR VAR nIndex :=  nStart UPTO nEnd
                _internalList[nIndex] := NIL
            NEXT
            RETURN SELF

       /// Delete a column from a multi dimensional array.
        /// <param name="nColumn">1 based column number to delete</param>
       /// <remarks>When no columns are defined then nothing happens.

        /// When an array has columns then the elements are deleted and shifted.

        /// Assume a 4 x 4 array. When DeleteColumn() is called with column 2 then the elements 2,6,10 and 14 are deleted
        /// and the elements 3 & 4, 7 & 8, 11 & 12 and 15 & 16 are shifted to the left.
        /// New empty elements are inserted on locations 4,8,12 and 16.</remarks>
       METHOD DeleteColumn(nColumn AS INT) AS __FoxArray
            IF SELF:_nCols > 1 .and. nColumn > 0 .and. nColumn <= _nCols
                LOCAL nRowStart := 0 AS INT
                LOCAL nColumns  := SELF:Columns AS LONG
                DO WHILE nRowStart < SELF:_internalList:Count
                    FOR VAR nElement := nColumn UPTO nColumns-1
                        SELF:_internalList[nRowStart+nElement -1] := SELF:_internalList[nRowStart+nElement ]
                    NEXT
                    SELF:_internalList[nRowStart + nColumns-1 ] := NIL
                    nRowStart += nColumns
                ENDDO
            ENDIF
            RETURN SELF

        /// Insert a row into a multi dimensional array.
        /// <param name="nRow">1 based row number to insert</param>
        /// <remarks>Inserting rows shifts rows up and deletes a row at the end of the array: FoxPro arrays do not grow automatically</remarks>
        METHOD InsertRow(nRow AS INT) AS __FoxArray
            VAR nStart := SELF:__GetIndex(nRow-1, 0)              // first element on the row
            FOR VAR nIndex := _internalList:Count-1 DOWNTO nStart+_nCols
                SELF:_internalList[nIndex] := SELF:_internalList[nIndex-_nCols]
            NEXT
            FOR VAR nIndex := nStart UPTO nStart + _nCols-1
                SELF:_internalList[nIndex] := NIL
            NEXT
            RETURN SELF

        /// Insert a column into a multi dimensional array.
        /// <param name="nColumn">1 based column number to insert</param>
        /// <remarks>Inserting columns deletes columns at the end of each row.</remarks>
        METHOD InsertColumn(nColumn AS INT) AS __FoxArray
            IF nColumn <= SELF:Columns .and. nColumn > 0
                // this is more difficult to do
                // we cannot simply insert because that would shift elements to new rows
                // so we loop through the rows and shift the elements forward
                // assume we have a [3,5] element array and we insert column 3
                // then for each row
                //    element 5 has to be replaced by element 4,
                //    element 4 has to be replaced by element 3
                //    element 3 will be cleared
                // note that _GetIndex is ZERO based
                VAR nToMove  := SELF:Columns - nColumn
                FOR VAR nRow := 0 UPTO SELF:Rows-1
                    VAR nLastInRow := SELF:__GetIndex(nRow,  SELF:Columns-1)
                    FOR VAR nCell := 0 UPTO nToMove-1
                        _internalList[nLastInRow - nCell] := _internalList[nLastInRow - nCell-1]
                    NEXT
                    _internalList[nLastInRow - nToMove] := NIL
                NEXT
            ENDIF
            RETURN SELF

        /// <exclude />
        PUBLIC OVERRIDE METHOD Resize(newSize AS INT) AS VOID
            // Make sure we have a multiple of the # of columns
            // Assume we have a 3 column array and we resize to 10
            // then we must make the size a multiple of 3, so it will become 12
            IF SELF:_nCols != 1
                VAR nDiff := newSize % SELF:Columns
                IF nDiff != 0
                    newSize += (SELF:Columns - nDiff)
                ENDIF
            ENDIF
            SUPER:Resize(newSize)

        INTERNAL METHOD GetRow(nElement AS LONG) AS LONG
            // calculate the row
            VAR nZeroBased := nElement -1
            RETURN (nZeroBased / (INT) SELF:Columns) +1

        INTERNAL METHOD GetColumn(nElement AS LONG) AS LONG
            VAR nZeroBased := nElement -1
            RETURN (nZeroBased % (INT) SELF:Columns) +1

        INTERNAL METHOD GetSubScript(nElement AS LONG) AS STRING
            IF !SELF:MultiDimensional
                RETURN "["+nElement:ToString()+"]"
            ELSE
                RETURN "["+SELF:GetRow(nElement):ToString()+","+SELF:GetColumn(nElement):ToString()+"]"
            ENDIF

        PROTECTED OVERRIDE METHOD DebuggerString() AS STRING
            LOCAL sb AS StringBuilder
            sb := StringBuilder{}
            sb:Append("FoxArray[")
            VAR nRows := SELF:Rows
            IF _nCols == 1
                sb:Append(_internalList:Count)
            ELSE
                sb:Append(nRows)
                sb:Append(",")
                sb:Append(_nCols)
            ENDIF
            sb:Append("] (")
            FOR VAR i := 1 TO Math.Min(SELF:Length,10)
                IF i > 1
                    sb:Append(",")
                ENDIF
                sb:Append(AsString(_internalList[i-1]))
            NEXT
            IF SELF:Length > 10
                sb:Append(",..")
            ENDIF
            sb:Append(")")
            RETURN sb:ToString()

        [DebuggerBrowsable(DebuggerBrowsableState.Never)];
        INTERNAL PROPERTY Values AS STRING[]
            GET
                VAR result := List<STRING>{}
                FOR VAR nElement := 1 TO SELF:Count
                    result:Add(SELF:GetSubScript(nElement)+" "+AsString(_internalList[nElement-1]))
                NEXT
                RETURN result:ToArray()
            END GET
        END PROPERTY

        /// <exclude />
        PUBLIC OVERRIDE METHOD Add(u AS USUAL) AS VOID
            VAR err     := Error{NotSupportedException{"The FoxPro array type does not support the Add functionality because it cannot dynamically grow. " + ;
                            "You will have to use the DIMENSION statement to change its size"}}
            THROW err

    END CLASS
END NAMESPACE

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//
USING System.Collections
USING System.Collections.Generic
USING System.Linq
USING System.Diagnostics
USING System.Reflection
USING System.Text
USING XSharp
BEGIN NAMESPACE XSharp
    /// Internal type that implements the FoxPro Compatible ARRAY type.

    /// This type has methods and properties that normally are never directly called from user code.
    ///
    /// <remarks>FoxPro arrays can be one dimensional or two dimensional.
	/// Two dimensional arrays are implemented as a projection
    /// on top of a one dimensional array.

    /// So a two dimensional array of 4 x 3 elements will be implemented as an array of 12 elements.
    /// The elements 1-3 represent row 1, 4-6 row 2 etc. </remarks>
    /// <seealso cref='IIndexer' />
    /// <include file="RTComments.xml" path="Comments/ZeroBasedIndex/*" />
    //[DebuggerTypeProxy(TYPEOF(ArrayDebugView))];
    [DebuggerDisplay("{DebuggerString(),nq}")] ;
    PUBLIC SEALED CLASS __FoxArray INHERIT __Array IMPLEMENTS IIndexer
        [DebuggerBrowsable(DebuggerBrowsableState.Never)];
        PRIVATE _nCols := 1 AS DWORD
        [DebuggerBrowsable(DebuggerBrowsableState.Never)];
        PROPERTY MultiDimensional AS LOGIC GET _nCols > 1
        PROPERTY Columns AS LONG GET (LONG) _nCols
        PROPERTY Rows    AS LONG GET _internalList:Count / (LONG) _nCols
         /// <inheritdoc />
        CONSTRUCTOR()
            SUPER()

            /// <inheritdoc />
        CONSTRUCTOR(capacity AS DWORD)
            SUPER(capacity, TRUE)

        CONSTRUCTOR(nRows AS DWORD, nCols AS DWORD)
            SUPER( nRows * nCols, TRUE)
            SELF:_nCols := nCols

            /// <inheritdoc />
        CONSTRUCTOR( elements AS OBJECT[] )
            SUPER(elements)

        PRIVATE CONSTRUCTOR( elements AS USUAL[])
            SUPER(elements)

        INTERNAL METHOD __Fill(uValue AS USUAL) AS VOID
            FOR VAR nElement := 0 TO SELF:Length-1
               SELF:_internalList[nElement] := uValue
            NEXT
            RETURN

        INTERNAL METHOD __GetDimensionError(nDimensionsAsked AS LONG) AS Error
            VAR err         := Error.BoundError(ProcName(2),"indices", 1)
            IF SELF:MultiDimensional
               err:Description := i"Bound error: You cannot access a 2 dimensional array with {nDimensionsAsked} indices"
            ELSE
               err:Description := i"Bound error: You cannot access a single dimensional array with {nDimensionsAsked} indices"
            ENDIF
            err:Stack   := ErrorStack(1)
            RETURN err

        INTERNAL STATIC METHOD __NestedArrayError() AS Error
            VAR err     := Error.ArgumentError(ProcName(2),"value", "You cannot assign an array to an element inside a Fox Array")
            err:Stack   := ErrorStack(1)
            RETURN err

        PUBLIC OVERRIDE METHOD __GetElement(index AS INT, index2 AS INT) AS USUAL
             VAR item := SELF:__GetIndex(index, index2)
             SUPER:__CheckArrayElement(SELF, item, nameof(index),1)
             RETURN SUPER:__GetElement(item)

        PUBLIC OVERRIDE METHOD __GetElement(indices PARAMS INT[] ) AS USUAL
            IF  indices:Length == 1
                RETURN SUPER:__GetElement(indices[1])
            ELSEIF indices:Length == 2 .and. SELF:_nCols > 1
                RETURN SELF:__GetElement(indices[1], indices[2])
            ELSE
                VAR err     := Error.BoundError(ProcName(1),nameof(indices), 1, indices)
                err:Stack   := ErrorStack(1)
                err:Description := i"Bound error: Too many dimensions)"
                THROW err
            ENDIF

       PUBLIC OVERRIDE METHOD __SetElement(u AS USUAL, index AS INT) AS USUAL
             IF IsArray(u)
                  THROW __NestedArrayError()
             ENDIF
             SUPER:__CheckArrayElement(SELF, index, nameof(index),1)
             RETURN SUPER:__SetElement(u, index)

        PUBLIC OVERRIDE METHOD __SetElement(u AS USUAL, index AS INT, index2 AS INT) AS USUAL
             IF IsArray(u)
                  THROW __NestedArrayError()
             ENDIF
             VAR item := SELF:__GetIndex(index, index2)
             SUPER:__CheckArrayElement(SELF, item, nameof(index),1)
             RETURN SUPER:__SetElement(u, item)

        PUBLIC OVERRIDE METHOD __SetElement(u AS USUAL, indices PARAMS INT[] ) AS USUAL
            IF  indices:Length == 1
                RETURN SUPER:__SetElement(u, indices[1])
            ELSEIF indices:Length == 2 .and. _nCols > 1
                RETURN SELF:__SetElement(u, indices[1], indices[2])
            ELSE
                VAR err     := Error.BoundError(ProcName(1),"indices", 2, indices)
                err:Stack   := ErrorStack(1)
                err:Description := i"Bound error: Too many dimensions"
                THROW err
            ENDIF

        PRIVATE METHOD __GetIndex(nRow AS INT, nColumn AS INT) AS INT
            // Note that nRow and nColumn are already Zero based !
            IF SELF:_nCols > 1
                RETURN (nRow * _nCols) + nColumn
            ELSE
                THROW SELF:__GetDimensionError(2)
            ENDIF

        /// <include file="RTComments.xml" path="Comments/ZeroBasedIndexProperty/*" />
        /// <param name="index"><include file="RTComments.xml" path="Comments/ZeroBasedIndexParam/*" /></param>
        /// <returns>The value of the property of the element stored at the indicated location in the array.</returns>
        OVERRIDE PUBLIC PROPERTY SELF[index AS INT] AS USUAL
            GET
                 SUPER:__CheckArrayElement(SELF, index, nameof(index),1)
                 RETURN SUPER:__GetElement(index)
            END GET
            SET
                IF IsArray(value)
                    THROW __NestedArrayError()
                ENDIF
                SUPER:__CheckArrayElement(SELF, index, nameof(index),1)
                SUPER:__SetElement(value,index)
            END SET
        END PROPERTY

        /// <include file="RTComments.xml" path="Comments/ZeroBasedIndexProperty/*" />
        /// <param name="index"><include file="RTComments.xml" path="Comments/ZeroBasedIndexParam/*" /></param>
        /// <param name="index2"><include file="RTComments.xml" path="Comments/ZeroBasedIndexParam/*" /></param>
        /// <returns>The value of the property of the element stored at the indicated location in the array.</returns>
        OVERRIDE PUBLIC PROPERTY SELF[index AS INT, index2 AS INT] AS USUAL
            GET
                IF ! SELF:MultiDimensional
                    THROW SELF:__GetDimensionError(2)
                ELSE
                    RETURN SELF:__GetElement(index, index2)
                ENDIF
            END GET
            SET
                IF IsArray(value)
                    THROW __NestedArrayError()
                ENDIF
                IF ! SELF:MultiDimensional
                    THROW SELF:__GetDimensionError(2)
                ELSE
                    SELF:__SetElement(value,SELF:__GetIndex(index, index2))
                ENDIF
            END SET
        END PROPERTY

        /// <include file="RTComments.xml" path="Comments/ZeroBasedIndexProperty/*" />
        /// <param name="indices"><include file="RTComments.xml" path="Comments/ZeroBasedIndexParam/*" /></param>
        /// <returns>The value of the property of the element stored at the indicated location in the array.</returns>
        OVERRIDE PUBLIC PROPERTY SELF[indices PARAMS INT[]] AS USUAL
            GET
                IF indices:Length == 1
                    SUPER:__CheckArrayElement(SELF, indices[1], nameof(indices),1)
                    RETURN SELF:__GetElement(indices[1])
                ELSEIF indices:Length == 2 .and. SELF:MultiDimensional
                    VAR index := SELF:__GetIndex(indices[1], indices[2])
                    SUPER:__CheckArrayElement(SELF, index, nameof(indices),1)
                    RETURN SELF:__GetElement(index)
                ELSE
                    THROW SELF:__GetDimensionError(indices:Length)
                ENDIF
            END GET
            SET
                IF IsArray(value)
                    THROW __NestedArrayError()
                ENDIF
                IF indices:Length == 1
                    SELF:__CheckArrayElement(SELF, indices[1], nameof(indices),1)
                    SELF:__SetElement(indices[1], value)
                ELSEIF indices:Length == 2 .and. SELF:MultiDimensional
                    VAR index := SELF:__GetIndex(indices[1], indices[2])
                    SELF:__CheckArrayElement(SELF, index, nameof(indices),1)
                    SELF:__SetElement(index, value)
                ELSE
                    THROW SELF:__GetDimensionError(indices:Length)
                ENDIF
            END SET
        END PROPERTY

        /// Redimension the array. Existing data will be saved if the # of cells in the new array <= the # of cells in the old array.
        METHOD ReDim(nRows AS DWORD, nCols := 1 AS DWORD) AS __FoxArray
            _nCols := nCols
            SELF:Resize( (INT) (nRows * nCols))
            RETURN SELF

       /// Delete a row from a multi dimensional array.
        /// <param name="nRow">1 based row number to delete</param>
        /// <remarks>Deleting rows will shift other rows up and will add a blank row at the bottom of the array</remarks>
        METHOD DeleteRow(nRow AS INT) AS __FoxArray
            // __GetIndex expects 0 based indices. DeleteRow works with 1 based rows
            VAR nStart := SELF:__GetIndex(nRow-1, 0)              // first element on the row
            VAR nEnd   := _internalList:Count - _nCols-1
            FOR VAR nIndex := nStart UPTO nEnd
                _internalList[nIndex] := _internalList[nIndex+_nCols]
            NEXT
            nStart := _internalList:Count - _nCols
            nEnd   := _internalList:Count-1
            FOR VAR nIndex :=  nStart UPTO nEnd
                _internalList[nIndex] := NIL
            NEXT
            RETURN SELF

       /// Delete a column from a multi dimensional array.
        /// <param name="nColumn">1 based column number to delete</param>
       /// <remarks>When no columns are defined then nothing happens.

        /// When an array has columns then the elements are deleted and shifted.

        /// Assume a 4 x 4 array. When DeleteColumn() is called with column 2 then the elements 2,6,10 and 14 are deleted
        /// and the elements 3 & 4, 7 & 8, 11 & 12 and 15 & 16 are shifted to the left.
        /// New empty elements are inserted on locations 4,8,12 and 16.</remarks>
       METHOD DeleteColumn(nColumn AS INT) AS __FoxArray
            IF SELF:_nCols > 1 .and. nColumn > 0 .and. nColumn <= _nCols
                LOCAL nRowStart := 0 AS INT
                LOCAL nColumns  := SELF:Columns AS LONG
                DO WHILE nRowStart < SELF:_internalList:Count
                    FOR VAR nElement := nColumn UPTO nColumns-1
                        SELF:_internalList[nRowStart+nElement -1] := SELF:_internalList[nRowStart+nElement ]
                    NEXT
                    SELF:_internalList[nRowStart + nColumns-1 ] := NIL
                    nRowStart += nColumns
                ENDDO
            ENDIF
            RETURN SELF

        /// Insert a row into a multi dimensional array.
        /// <param name="nRow">1 based row number to insert</param>
        /// <remarks>Inserting rows shifts rows up and deletes a row at the end of the array: FoxPro arrays do not grow automatically</remarks>
        METHOD InsertRow(nRow AS INT) AS __FoxArray
            VAR nStart := SELF:__GetIndex(nRow-1, 0)              // first element on the row
            FOR VAR nIndex := _internalList:Count-1 DOWNTO nStart+_nCols
                SELF:_internalList[nIndex] := SELF:_internalList[nIndex-_nCols]
            NEXT
            FOR VAR nIndex := nStart UPTO nStart + _nCols-1
                SELF:_internalList[nIndex] := NIL
            NEXT
            RETURN SELF

        /// Insert a column into a multi dimensional array.
        /// <param name="nColumn">1 based column number to insert</param>
        /// <remarks>Inserting columns deletes columns at the end of each row.</remarks>
        METHOD InsertColumn(nColumn AS INT) AS __FoxArray
            IF nColumn <= SELF:Columns .and. nColumn > 0
                // this is more difficult to do
                // we cannot simply insert because that would shift elements to new rows
                // so we loop through the rows and shift the elements forward
                // assume we have a [3,5] element array and we insert column 3
                // then for each row
                //    element 5 has to be replaced by element 4,
                //    element 4 has to be replaced by element 3
                //    element 3 will be cleared
                // note that _GetIndex is ZERO based
                VAR nToMove  := SELF:Columns - nColumn
                FOR VAR nRow := 0 UPTO SELF:Rows-1
                    VAR nLastInRow := SELF:__GetIndex(nRow,  SELF:Columns-1)
                    FOR VAR nCell := 0 UPTO nToMove-1
                        _internalList[nLastInRow - nCell] := _internalList[nLastInRow - nCell-1]
                    NEXT
                    _internalList[nLastInRow - nToMove] := NIL
                NEXT
            ENDIF
            RETURN SELF

        /// <exclude />
        PUBLIC OVERRIDE METHOD Resize(newSize AS INT) AS VOID
            // Make sure we have a multiple of the # of columns
            // Assume we have a 3 column array and we resize to 10
            // then we must make the size a multiple of 3, so it will become 12
            IF SELF:_nCols != 1
                VAR nDiff := newSize % SELF:Columns
                IF nDiff != 0
                    newSize += (SELF:Columns - nDiff)
                ENDIF
            ENDIF
            SUPER:Resize(newSize)

        INTERNAL METHOD GetRow(nElement AS LONG) AS LONG
            // calculate the row
            VAR nZeroBased := nElement -1
            RETURN (nZeroBased / (INT) SELF:Columns) +1

        INTERNAL METHOD GetColumn(nElement AS LONG) AS LONG
            VAR nZeroBased := nElement -1
            RETURN (nZeroBased % (INT) SELF:Columns) +1

        INTERNAL METHOD GetSubScript(nElement AS LONG) AS STRING
            IF !SELF:MultiDimensional
                RETURN "["+nElement:ToString()+"]"
            ELSE
                RETURN "["+SELF:GetRow(nElement):ToString()+","+SELF:GetColumn(nElement):ToString()+"]"
            ENDIF

        PROTECTED OVERRIDE METHOD DebuggerString() AS STRING
            LOCAL sb AS StringBuilder
            sb := StringBuilder{}
            sb:Append("FoxArray[")
            VAR nRows := SELF:Rows
            IF _nCols == 1
                sb:Append(_internalList:Count)
            ELSE
                sb:Append(nRows)
                sb:Append(",")
                sb:Append(_nCols)
            ENDIF
            sb:Append("] (")
            FOR VAR i := 1 TO Math.Min(SELF:Length,10)
                IF i > 1
                    sb:Append(",")
                ENDIF
                sb:Append(AsString(_internalList[i-1]))
            NEXT
            IF SELF:Length > 10
                sb:Append(",..")
            ENDIF
            sb:Append(")")
            RETURN sb:ToString()

        [DebuggerBrowsable(DebuggerBrowsableState.Never)];
        INTERNAL PROPERTY Values AS STRING[]
            GET
                VAR result := List<STRING>{}
                FOR VAR nElement := 1 TO SELF:Count
                    result:Add(SELF:GetSubScript(nElement)+" "+AsString(_internalList[nElement-1]))
                NEXT
                RETURN result:ToArray()
            END GET
        END PROPERTY

        /// <exclude />
        PUBLIC OVERRIDE METHOD Add(u AS USUAL) AS VOID
            VAR err     := Error{NotSupportedException{"The FoxPro array type does not support the Add functionality because it cannot dynamically grow. " + ;
                            "You will have to use the DIMENSION statement to change its size"}}
            THROW err

    END CLASS
END NAMESPACE