[DBFCDX] Added missing change

[DBFCDX] Added missing change

//
// 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 XSharp.RDD.Support
USING XSharp.RDD.CDX
USING XSharp.RDD.Enums
USING System.IO
BEGIN NAMESPACE XSharp.RDD
    // Inherits all standard DBF and Memo behavior
    // Only adds Order Handling
    /// <summary>DBFCDX RDD. For DBF/FPT/CDX.</summary>
    CLASS DBFCDX INHERIT DBFFPT
        INTERNAL _indexList  AS CdxOrderBagList
        INTERNAL PROPERTY CurrentOrder AS CdxTag GET _indexList:CurrentOrder

            CONSTRUCTOR()
                SUPER()
                _indexList := CdxOrderBagList{SELF}
                RETURN

            PROPERTY SysName AS STRING GET typeof(DBFCDX):ToString()
            #REGION Order Support

            VIRTUAL METHOD OrderCreate(orderInfo AS DbOrderCreateInfo ) AS LOGIC
                RETURN SELF:_indexList:Create(orderInfo)

            VIRTUAL METHOD OrderDestroy(orderInfo AS DbOrderInfo ) AS LOGIC
                RETURN SUPER:OrderDestroy(orderInfo)

		METHOD OrderCondition(info AS DbOrderCondInfo) AS LOGIC
            		RETURN SUPER:OrderCondition(info)

            VIRTUAL METHOD OrderListAdd( orderInfo AS DbOrderInfo) AS LOGIC
                BEGIN LOCK SELF
                    SELF:GoCold()
                    LOCAL fullPath AS STRING
                    fullPath := orderInfo:BagName
                    IF File(fullPath)
                        fullPath := FPathName()
                    ELSEIF ! String.IsNullOrEmpty(Path.GetExtension(fullPath))
                        fullPath := Path.ChangeExtension(fullPath, CdxOrderbag.CDX_EXTENSION)
                        IF File(fullPath)
                            fullPath := FPathName()
                        ENDIF
                    ENDIF
                    IF String.IsNullOrEmpty(System.IO.Path.GetDirectoryName(fullPath))
                        fullPath := System.IO.Path.Combine(SYstem.IO.Path.GetDirectoryName(SELF:_FileName), fullPath)
                        orderinfo:BagName := fullPath
                    ENDIF
                    LOCAL lOk := FALSE AS LOGIC
                    IF SELF:_indexList:FindOrderBag(orderInfo:BagName) == NULL
                        lOk := SELF:_indexList:Add(orderInfo)
                        IF lOk .AND. SELF:_indexList:Count == 1
                            // After opening the first index file the first order in the file becomes active
                            orderInfo := DbOrderInfo{}
                            orderInfo:Order := 1
                            lOk := SELF:OrderListFocus(orderInfo)
                        ENDIF
                    ELSE
                        // Already open, do nothing
                        lOk := TRUE
                    ENDIF
                    RETURN lOk
                END LOCK

            VIRTUAL METHOD OrderListDelete(orderInfo AS DbOrderInfo) AS LOGIC

                BEGIN LOCK SELF
                    SELF:GoCold()
                    RETURN SELF:_indexList:CloseAll(orderInfo)
                END LOCK

            VIRTUAL METHOD OrderListFocus(orderInfo AS DbOrderInfo) AS LOGIC

                BEGIN LOCK SELF
                    SELF:GoCold()
                    RETURN SELF:_indexList:SetFocus(orderInfo)
                END LOCK

            VIRTUAL METHOD OrderListRebuild() AS LOGIC
                BEGIN LOCK SELF
                    SELF:GoCold()
                    RETURN SELF:_indexList:Rebuild()
                END LOCK

            OVERRIDE METHOD OrderInfo(nOrdinal AS DWORD , info AS DbOrderInfo ) AS OBJECT
                LOCAL result AS LONG
                LOCAL workOrder AS CdxTag
                LOCAL isOk := FALSE AS LOGIC

                result := 0
                workOrder := SELF:_indexList:FindOrder(info)
                IF workOrder == NULL
                    workOrder := SELF:CurrentOrder
                ENDIF

                BEGIN SWITCH nOrdinal
            CASE DBOI_CONDITION
                IF workOrder != NULL
                    info:Result := workOrder:Condition
                ENDIF
            CASE DBOI_EXPRESSION
                IF workOrder != NULL
			        info:Result := workOrder:Expression
        	    ENDIF
            CASE DBOI_ORDERCOUNT
                info:Result := SELF:_indexList:Count
            CASE DBOI_POSITION
                IF workOrder == NULL
                    info:Result := SELF:RecNo
                ELSE
                    isOk := workOrder:_getRecPos( REF result)
                    IF isOk
                        info:Result := result
                    ENDIF
                ENDIF
            CASE DBOI_KEYCOUNT
                result := 0
                IF workOrder != NULL
                    info:Result := 0
                    isOk := workOrder:_CountRecords(REF result)
                ENDIF
                IF isOk
                    info:Result := result
                ENDIF
            CASE DBOI_NUMBER
                info:Result := SELF:_indexList:OrderPos(workOrder)
            CASE DBOI_BAGEXT
                // according to the docs this should always return the default extension and not the actual extension
                info:Result := CdxOrderBag.CDX_EXTENSION
            CASE DBOI_FULLPATH
                IF workOrder != NULL
                    info:Result := workOrder:OrderBag:FullPath
                ELSE
                    info:Result := ""
                ENDIF
            CASE DBOI_BAGNAME
                IF workOrder != NULL
                    info:Result := workOrder:FileName
                ELSE
                    info:Result := ""
                ENDIF
            CASE DBOI_NAME
                IF workOrder != NULL
                    info:Result := workOrder:_orderName
                ELSE
                    info:Result := ""
                ENDIF
            CASE DBOI_FILEHANDLE
                IF workOrder != NULL
                    info:Result := workOrder:OrderBag:Handle
                ELSE
                    info:Result := IntPtr.Zero
                ENDIF
            CASE DBOI_ISDESC
                IF workOrder != NULL
                    info:Result := workOrder:Descending
                ELSE
                    info:Result := FALSE
                ENDIF
            CASE DBOI_ISCOND
                IF workOrder != NULL
				    info:Result := workOrder:Conditional
                ELSE
                    info:Result := FALSE
                ENDIF
            CASE DBOI_KEYTYPE
                IF workOrder != NULL
                    info:Result := workOrder:KeyType
                ELSE
                    info:Result := 0
                ENDIF
            CASE DBOI_KEYSIZE
                IF workOrder != NULL
                    info:Result := workOrder:KeyLength
                ELSE
                    info:Result := 0
                ENDIF
            CASE DBOI_KEYDEC
			    info:Result := 0
            CASE DBOI_UNIQUE
                IF workOrder != NULL
                    info:Result := workOrder:Unique
                ELSE
                    info:Result := FALSE
                ENDIF
            CASE DBOI_LOCKOFFSET
                IF workOrder != NULL
                    info:Result := workOrder:OrderBag:_lockOffset
                ELSE
                    info:Result := 0
                ENDIF
            CASE DBOI_SETCODEBLOCK
                IF workOrder != NULL
					info:Result := workOrder:KeyCodeBlock
				ENDIF
            CASE DBOI_KEYVAL
                IF workOrder != NULL
                    isOk := TRUE
                    TRY
					info:Result := SELF:EvalBlock(workOrder:KeyCodeBlock)
                    CATCH
                        isOk := FALSE
                    END TRY
                    IF !isOk
                        info:Result := NULL
                    ENDIF
                ELSE
                    info:Result := NULL
                ENDIF
            CASE DBOI_SCOPETOP
            CASE DBOI_SCOPEBOTTOM
            CASE DBOI_SCOPETOPCLEAR
            CASE DBOI_SCOPEBOTTOMCLEAR
                IF workOrder != NULL
                    IF info:Result != NULL
                        workOrder:SetOrderScope(info:Result, (DbOrder_Info) nOrdinal)
                    ENDIF
                    IF nOrdinal == DBOI_SCOPETOP
                        info:Result := workOrder:TopScope
                    ELSEIF nOrdinal == DBOI_SCOPEBOTTOM
                        info:Result := workOrder:BottomScope
                    ELSE
                        info:Result := NULL
                    ENDIF
                ELSE
                    info:Result := NULL
                ENDIF
            CASE DBOI_USER + 42
                // Dump Cdx to Txt file
                IF workOrder != NULL
                    workOrder:_dump()
                ENDIF

            OTHERWISE
                SUPER:OrderInfo(nOrdinal, info)
            END SWITCH
            RETURN info:Result

            #endregion

        #region Pack, Zap
        METHOD Pack() AS LOGIC
            LOCAL isOk AS LOGIC
            isOk := SUPER:Pack()
            IF isOk
                isOk := SELF:OrderListRebuild()
            ENDIF
            RETURN isOk

        PUBLIC METHOD Zap() AS LOGIC
            LOCAL isOk AS LOGIC
            isOk := SUPER:Zap()
            IF isOk
                isOk := SELF:OrderListRebuild()
            ENDIF
            RETURN isOk

            #endregion
        #REGION Open, Close, Create
        PUBLIC OVERRIDE METHOD Close() AS LOGIC
            LOCAL orderInfo AS DbOrderInfo

            orderInfo := DbOrderInfo{}
            orderInfo:AllTags := TRUE
            SELF:OrderListDelete(orderInfo)
            RETURN SUPER:Close()

        PUBLIC OVERRIDE METHOD Create( openInfo AS DbOpenInfo ) AS LOGIC
            LOCAL isOk AS LOGIC

            isOk := SUPER:Create(openInfo)
            IF  XSharp.RuntimeState.Ansi .AND. isOk
                VAR sig := SELF:_Header:Version
                //SET bit TO Force ANSI Signature
                sig := sig |4
                //Should we also SET the CodePage ??
                //SELF:_Header:DbfCodePage := DbfCodePage.CP_DBF_WIN_ANSI
                SELF:_Header:Version := sig
            ENDIF
            RETURN isOk

        METHOD Open(info AS DbOpenInfo) AS LOGIC
            LOCAL lOk AS LOGIC
            lOk := SUPER:Open(info)
            IF lOk

                IF RuntimeState.AutoOpen
                    VAR cCdxFileName := System.IO.Path.ChangeExtension(info:FileName, ".CDX")
                    IF System.IO.File.Exists(cCdxFileName)
                        LOCAL orderinfo := DbOrderInfo{} AS DbOrderInfo
                        orderInfo:BagName := cCdxFileName
                        SELF:_indexList:Add(orderInfo, TRUE)
                    ENDIF
                ENDIF
            ENDIF
            RETURN lOk
            #ENDREGION

        #REGION Move

        INTERNAL METHOD ReadRecord() AS LOGIC
            RETURN SELF:_ReadRecord()

        PUBLIC METHOD Seek(seekInfo AS DBSEEKINFO ) AS LOGIC
            LOCAL isOk AS LOGIC
            LOCAL ntxIndex AS CdxTag

            isOk := FALSE
            BEGIN LOCK SELF
                ntxIndex := SELF:CurrentOrder
                IF ntxIndex != NULL
                    isOk := ntxIndex:Seek(seekInfo)
                ENDIF
                IF  !isOk
                    SELF:_DbfError(SubCodes.ERDD_DATATYPE, GenCode.EG_NOORDER )
                ENDIF
            END LOCK
            RETURN isOk

        PUBLIC METHOD GoBottom() AS LOGIC
            BEGIN LOCK SELF
                IF SELF:CurrentOrder != NULL
                    RETURN SELF:CurrentOrder:GoBottom()
                ELSE
                    RETURN SUPER:GoBottom()
                ENDIF
            END LOCK

        PUBLIC METHOD GoTop() AS LOGIC
            BEGIN LOCK SELF
                IF SELF:CurrentOrder != NULL
                    RETURN SELF:CurrentOrder:GoTop()
                ELSE
                    RETURN SUPER:GoTop()
                ENDIF
            END LOCK

        METHOD __Goto(nRec AS LONG) AS LOGIC
            // Skip without reset of topstack
            RETURN SUPER:Goto(nRec)

        METHOD GoTo(nRec AS LONG) AS LOGIC
            SELF:GoCold()
            IF SELF:CurrentOrder != NULL
                SELF:CurrentOrder:ClearStack()
            ENDIF
            RETURN SUPER:Goto(nRec)

        PUBLIC METHOD SkipRaw( move AS LONG ) AS LOGIC
            BEGIN LOCK SELF
                IF SELF:CurrentOrder != NULL
                    RETURN SELF:CurrentOrder:SkipRaw(move)
                ELSE
                    RETURN SUPER:SkipRaw(move)
                ENDIF
            END LOCK

            #ENDREGION

        #REGION GoCold, GoHot, Flush
        PUBLIC OVERRIDE METHOD GoCold() AS LOGIC
            LOCAL isOk AS LOGIC

            isOk := TRUE
            BEGIN LOCK SELF
                IF !SELF:IsHot
                    RETURN isOk
                ENDIF
                isOk := SELF:_indexList:GoCold()
                IF !isOk
                    RETURN isOk
                ENDIF
                RETURN SUPER:GoCold()
            END LOCK

        PUBLIC OVERRIDE METHOD GoHot() AS LOGIC
            LOCAL isOk AS LOGIC

            isOk := TRUE
            BEGIN LOCK SELF
                isOk := SUPER:GoHot()
                IF !isOk
                    RETURN isOk
                ENDIF
                RETURN SELF:_indexList:GoHot()
            END LOCK

        PUBLIC OVERRIDE METHOD Flush() AS LOGIC
            LOCAL isOk AS LOGIC

            isOk := TRUE
            BEGIN LOCK SELF
                isOk := SUPER:Flush()
                RETURN SELF:_indexList:Flush()
            END LOCK

        #ENDREGION
    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 XSharp.RDD.Support
USING XSharp.RDD.CDX
USING XSharp.RDD.Enums
USING System.IO
BEGIN NAMESPACE XSharp.RDD
    // Inherits all standard DBF and Memo behavior
    // Only adds Order Handling
    /// <summary>DBFCDX RDD. For DBF/FPT/CDX.</summary>
    CLASS DBFCDX INHERIT DBFFPT
        INTERNAL _indexList  AS CdxOrderBagList
        INTERNAL PROPERTY CurrentOrder AS CdxTag GET _indexList:CurrentOrder

            CONSTRUCTOR()
                SUPER()
                _indexList := CdxOrderBagList{SELF}
                RETURN

            PROPERTY SysName AS STRING GET typeof(DBFCDX):ToString()
            #REGION Order Support

            VIRTUAL METHOD OrderCreate(orderInfo AS DbOrderCreateInfo ) AS LOGIC
                RETURN SELF:_indexList:Create(orderInfo)

            VIRTUAL METHOD OrderDestroy(orderInfo AS DbOrderInfo ) AS LOGIC
                RETURN SUPER:OrderDestroy(orderInfo)

		METHOD OrderCondition(info AS DbOrderCondInfo) AS LOGIC
            		RETURN SUPER:OrderCondition(info)

            VIRTUAL METHOD OrderListAdd( orderInfo AS DbOrderInfo) AS LOGIC
                BEGIN LOCK SELF
                    SELF:GoCold()
                    LOCAL fullPath AS STRING
                    fullPath := orderInfo:BagName
                    IF File(fullPath)
                        fullPath := FPathName()
                    ELSEIF ! String.IsNullOrEmpty(Path.GetExtension(fullPath))
                        fullPath := Path.ChangeExtension(fullPath, CdxOrderbag.CDX_EXTENSION)
                        IF File(fullPath)
                            fullPath := FPathName()
                        ENDIF
                    ENDIF
                    IF String.IsNullOrEmpty(System.IO.Path.GetDirectoryName(fullPath))
                        fullPath := System.IO.Path.Combine(SYstem.IO.Path.GetDirectoryName(SELF:_FileName), fullPath)
                        orderinfo:BagName := fullPath
                    ENDIF
                    LOCAL lOk := FALSE AS LOGIC
                    IF SELF:_indexList:FindOrderBag(orderInfo:BagName) == NULL
                        lOk := SELF:_indexList:Add(orderInfo)
                        IF lOk .AND. SELF:_indexList:Count == 1
                            // After opening the first index file the first order in the file becomes active
                            orderInfo := DbOrderInfo{}
                            orderInfo:Order := 1
                            lOk := SELF:OrderListFocus(orderInfo)
                        ENDIF
                    ELSE
                        // Already open, do nothing
                        lOk := TRUE
                    ENDIF
                    RETURN lOk
                END LOCK

            VIRTUAL METHOD OrderListDelete(orderInfo AS DbOrderInfo) AS LOGIC

                BEGIN LOCK SELF
                    SELF:GoCold()
                    RETURN SELF:_indexList:CloseAll()
                END LOCK

            VIRTUAL METHOD OrderListFocus(orderInfo AS DbOrderInfo) AS LOGIC

                BEGIN LOCK SELF
                    SELF:GoCold()
                    RETURN SELF:_indexList:SetFocus(orderInfo)
                END LOCK

            VIRTUAL METHOD OrderListRebuild() AS LOGIC
                BEGIN LOCK SELF
                    SELF:GoCold()
                    RETURN SELF:_indexList:Rebuild()
                END LOCK

            OVERRIDE METHOD OrderInfo(nOrdinal AS DWORD , info AS DbOrderInfo ) AS OBJECT
                LOCAL result AS LONG
                LOCAL workOrder AS CdxTag
                LOCAL isOk := FALSE AS LOGIC

                result := 0
                workOrder := SELF:_indexList:FindOrder(info)
                IF workOrder == NULL
                    workOrder := SELF:CurrentOrder
                ENDIF

                BEGIN SWITCH nOrdinal
            CASE DBOI_CONDITION
                IF workOrder != NULL
                    info:Result := workOrder:Condition
                ENDIF
            CASE DBOI_EXPRESSION
                IF workOrder != NULL
			        info:Result := workOrder:Expression
        	    ENDIF
            CASE DBOI_ORDERCOUNT
                info:Result := SELF:_indexList:Count
            CASE DBOI_POSITION
                IF workOrder == NULL
                    info:Result := SELF:RecNo
                ELSE
                    isOk := workOrder:_getRecPos( REF result)
                    IF isOk
                        info:Result := result
                    ENDIF
                ENDIF
            CASE DBOI_KEYCOUNT
                result := 0
                IF workOrder != NULL
                    info:Result := 0
                    isOk := workOrder:_CountRecords(REF result)
                ENDIF
                IF isOk
                    info:Result := result
                ENDIF
            CASE DBOI_NUMBER
                info:Result := SELF:_indexList:OrderPos(workOrder)
            CASE DBOI_BAGEXT
                // according to the docs this should always return the default extension and not the actual extension
                info:Result := CdxOrderBag.CDX_EXTENSION
            CASE DBOI_FULLPATH
                IF workOrder != NULL
                    info:Result := workOrder:OrderBag:FullPath
                ELSE
                    info:Result := ""
                ENDIF
            CASE DBOI_BAGNAME
                IF workOrder != NULL
                    info:Result := workOrder:FileName
                ELSE
                    info:Result := ""
                ENDIF
            CASE DBOI_NAME
                IF workOrder != NULL
                    info:Result := workOrder:_orderName
                ELSE
                    info:Result := ""
                ENDIF
            CASE DBOI_FILEHANDLE
                IF workOrder != NULL
                    info:Result := workOrder:OrderBag:Handle
                ELSE
                    info:Result := IntPtr.Zero
                ENDIF
            CASE DBOI_ISDESC
                IF workOrder != NULL
                    info:Result := workOrder:Descending
                ELSE
                    info:Result := FALSE
                ENDIF
            CASE DBOI_ISCOND
                IF workOrder != NULL
				    info:Result := workOrder:Conditional
                ELSE
                    info:Result := FALSE
                ENDIF
            CASE DBOI_KEYTYPE
                IF workOrder != NULL
                    info:Result := workOrder:KeyType
                ELSE
                    info:Result := 0
                ENDIF
            CASE DBOI_KEYSIZE
                IF workOrder != NULL
                    info:Result := workOrder:KeyLength
                ELSE
                    info:Result := 0
                ENDIF
            CASE DBOI_KEYDEC
			    info:Result := 0
            CASE DBOI_UNIQUE
                IF workOrder != NULL
                    info:Result := workOrder:Unique
                ELSE
                    info:Result := FALSE
                ENDIF
            CASE DBOI_LOCKOFFSET
                IF workOrder != NULL
                    info:Result := workOrder:OrderBag:_lockOffset
                ELSE
                    info:Result := 0
                ENDIF
            CASE DBOI_SETCODEBLOCK
                IF workOrder != NULL
					info:Result := workOrder:KeyCodeBlock
				ENDIF
            CASE DBOI_KEYVAL
                IF workOrder != NULL
                    isOk := TRUE
                    TRY
					info:Result := SELF:EvalBlock(workOrder:KeyCodeBlock)
                    CATCH
                        isOk := FALSE
                    END TRY
                    IF !isOk
                        info:Result := NULL
                    ENDIF
                ELSE
                    info:Result := NULL
                ENDIF
            CASE DBOI_SCOPETOP
            CASE DBOI_SCOPEBOTTOM
            CASE DBOI_SCOPETOPCLEAR
            CASE DBOI_SCOPEBOTTOMCLEAR
                IF workOrder != NULL
                    IF info:Result != NULL
                        workOrder:SetOrderScope(info:Result, (DbOrder_Info) nOrdinal)
                    ENDIF
                    IF nOrdinal == DBOI_SCOPETOP
                        info:Result := workOrder:TopScope
                    ELSEIF nOrdinal == DBOI_SCOPEBOTTOM
                        info:Result := workOrder:BottomScope
                    ELSE
                        info:Result := NULL
                    ENDIF
                ELSE
                    info:Result := NULL
                ENDIF
            CASE DBOI_USER + 42
                // Dump Cdx to Txt file
                IF workOrder != NULL
                    workOrder:_dump()
                ENDIF

            OTHERWISE
                SUPER:OrderInfo(nOrdinal, info)
            END SWITCH
            RETURN info:Result

            #endregion

        #region Pack, Zap
        METHOD Pack() AS LOGIC
            LOCAL isOk AS LOGIC
            isOk := SUPER:Pack()
            IF isOk
                isOk := SELF:OrderListRebuild()
            ENDIF
            RETURN isOk

        PUBLIC METHOD Zap() AS LOGIC
            LOCAL isOk AS LOGIC
            isOk := SUPER:Zap()
            IF isOk
                isOk := SELF:OrderListRebuild()
            ENDIF
            RETURN isOk

            #endregion
        #REGION Open, Close, Create
        PUBLIC OVERRIDE METHOD Close() AS LOGIC
            LOCAL orderInfo AS DbOrderInfo

            orderInfo := DbOrderInfo{}
            orderInfo:AllTags := TRUE
            SELF:OrderListDelete(orderInfo)
            RETURN SUPER:Close()

        PUBLIC OVERRIDE METHOD Create( openInfo AS DbOpenInfo ) AS LOGIC
            LOCAL isOk AS LOGIC

            isOk := SUPER:Create(openInfo)
            IF  XSharp.RuntimeState.Ansi .AND. isOk
                VAR sig := SELF:_Header:Version
                //SET bit TO Force ANSI Signature
                sig := sig |4
                //Should we also SET the CodePage ??
                //SELF:_Header:DbfCodePage := DbfCodePage.CP_DBF_WIN_ANSI
                SELF:_Header:Version := sig
            ENDIF
            RETURN isOk

        METHOD Open(info AS DbOpenInfo) AS LOGIC
            LOCAL lOk AS LOGIC
            lOk := SUPER:Open(info)
            IF lOk

                IF RuntimeState.AutoOpen
                    VAR cCdxFileName := System.IO.Path.ChangeExtension(info:FileName, ".CDX")
                    IF System.IO.File.Exists(cCdxFileName)
                        LOCAL orderinfo := DbOrderInfo{} AS DbOrderInfo
                        orderInfo:BagName := cCdxFileName
                        SELF:_indexList:Add(orderInfo, TRUE)
                    ENDIF
                ENDIF
            ENDIF
            RETURN lOk
            #ENDREGION

        #REGION Move

        INTERNAL METHOD ReadRecord() AS LOGIC
            RETURN SELF:_ReadRecord()

        PUBLIC METHOD Seek(seekInfo AS DBSEEKINFO ) AS LOGIC
            LOCAL isOk AS LOGIC
            LOCAL ntxIndex AS CdxTag

            isOk := FALSE
            BEGIN LOCK SELF
                ntxIndex := SELF:CurrentOrder
                IF ntxIndex != NULL
                    isOk := ntxIndex:Seek(seekInfo)
                ENDIF
                IF  !isOk
                    SELF:_DbfError(SubCodes.ERDD_DATATYPE, GenCode.EG_NOORDER )
                ENDIF
            END LOCK
            RETURN isOk

        PUBLIC METHOD GoBottom() AS LOGIC
            BEGIN LOCK SELF
                IF SELF:CurrentOrder != NULL
                    RETURN SELF:CurrentOrder:GoBottom()
                ELSE
                    RETURN SUPER:GoBottom()
                ENDIF
            END LOCK

        PUBLIC METHOD GoTop() AS LOGIC
            BEGIN LOCK SELF
                IF SELF:CurrentOrder != NULL
                    RETURN SELF:CurrentOrder:GoTop()
                ELSE
                    RETURN SUPER:GoTop()
                ENDIF
            END LOCK

        METHOD __Goto(nRec AS LONG) AS LOGIC
            // Skip without reset of topstack
            RETURN SUPER:Goto(nRec)

        METHOD GoTo(nRec AS LONG) AS LOGIC
            SELF:GoCold()
            IF SELF:CurrentOrder != NULL
                SELF:CurrentOrder:ClearStack()
            ENDIF
            RETURN SUPER:Goto(nRec)

        PUBLIC METHOD SkipRaw( move AS LONG ) AS LOGIC
            BEGIN LOCK SELF
                IF SELF:CurrentOrder != NULL
                    RETURN SELF:CurrentOrder:SkipRaw(move)
                ELSE
                    RETURN SUPER:SkipRaw(move)
                ENDIF
            END LOCK

            #ENDREGION

        #REGION GoCold, GoHot, Flush
        PUBLIC OVERRIDE METHOD GoCold() AS LOGIC
            LOCAL isOk AS LOGIC

            isOk := TRUE
            BEGIN LOCK SELF
                IF !SELF:IsHot
                    RETURN isOk
                ENDIF
                isOk := SELF:_indexList:GoCold()
                IF !isOk
                    RETURN isOk
                ENDIF
                RETURN SUPER:GoCold()
            END LOCK

        PUBLIC OVERRIDE METHOD GoHot() AS LOGIC
            LOCAL isOk AS LOGIC

            isOk := TRUE
            BEGIN LOCK SELF
                isOk := SUPER:GoHot()
                IF !isOk
                    RETURN isOk
                ENDIF
                RETURN SELF:_indexList:GoHot()
            END LOCK

        PUBLIC OVERRIDE METHOD Flush() AS LOGIC
            LOCAL isOk AS LOGIC

            isOk := TRUE
            BEGIN LOCK SELF
                isOk := SUPER:Flush()
                RETURN SELF:_indexList:Flush()
            END LOCK

        #ENDREGION
    END CLASS

END NAMESPACE


[Runtime] Split ASort() error in 2 messages

//
// 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.
//

INTERNAL STATIC CLASS ArrayHelpers

	STATIC METHOD AScan<T>(aTarget AS __ArrayBase<T>, element  AS T , nStart AS LONG, nCount AS LONG) AS DWORD WHERE T IS NEW()
		LOCAL nItem AS LONG
		LOCAL nLen  AS LONG
		nLen := (INT) aTarget:Length
		FOR nItem := nStart TO nLen
			IF object.Equals(aTarget[ nItem], element)
				RETURN (DWORD) nItem
			ENDIF
			nCount -= 1
			IF nCount == 0
				EXIT
			ENDIF
		NEXT
		RETURN 0

	STATIC METHOD AScan<T>(aTarget AS __ArrayBase<T>, bAction AS @@Func<T, LOGIC> , nStart AS LONG, nCount AS LONG) AS DWORD WHERE T IS NEW()
		LOCAL nItem AS LONG
		LOCAL nLen  AS LONG
		nLen := (INT) aTarget:Length
		FOR nItem := nStart TO nLen
			LOCAL oElement := aTarget[ nItem] AS T
			IF bAction(oElement)
				RETURN  (DWORD) nItem
			ENDIF
			nCount -= 1
			IF nCount == 0
				EXIT
			ENDIF
		NEXT
		RETURN 0

	STATIC METHOD AScan( aTarget AS USUAL, x AS USUAL, uStart AS USUAL, uCount AS USUAL, lExact AS LOGIC ) AS DWORD
		LOCAL nSize		AS DWORD
		IF ! ArrayHelpers.ValidateArrayParams(REF aTarget, REF uStart, REF uCount, OUT nSize)
			RETURN 0
		ENDIF
		LOCAL a := aTarget AS ARRAY
		LOCAL nStart := uStart	AS DWORD
		LOCAL nCount := uCount	AS DWORD
		LOCAL nRet := 0			AS DWORD
		LOCAL i					AS DWORD
		LOCAL cb				AS CODEBLOCK
		IF IsCodeBlock( x )
			cb := x
		ELSE
			IF lExact
				cb   := {|element| element == x }
			ELSE
				cb   := {|element| element = x }
			ENDIF
		ENDIF
		IF nStart < nSize
			FOR i := nStart UPTO nSize
				IF nCount > 0
					IF Eval( cb, a[i] )
						nRet := i
						EXIT
					ENDIF
					nCount--
				ELSE
					EXIT
				ENDIF
			NEXT
		ELSE
			FOR i := nStart DOWNTO nSize
				IF nCount > 0
					IF Eval( cb, a[i] )
						nRet := i
						EXIT
					ENDIF
					nCount--
				ELSE
					EXIT
				ENDIF
			NEXT
		ENDIF

		RETURN nRet

	STATIC METHOD AScanBin(cFuncName AS STRING, a AS ARRAY, seekVal AS USUAL, lExact AS LOGIC ) AS DWORD
		LOCAL dwLow        AS DWORD
		LOCAL dwHigh       AS DWORD
		LOCAL x            AS DWORD
		LOCAL dwRet        AS DWORD
		LOCAL iSave        AS DWORD
		LOCAL lIsCodeBlock AS LOGIC
		LOCAL iCBRet       AS USUAL
		LOCAL iComp        AS INT
		LOCAL cb			  AS CODEBLOCK

		dwLow  := 1
		dwHigh := (DWORD) ALen(a)
		iSave := dwRet := 0
		iComp := 0
		lIsCodeblock := IsCodeBlock( seekVal )
		IF lIsCodeBlock
			cb := seekVal
		ELSEIF lExact
			cb := {|element| IIF( element == seekVal , 0, IIF( seekVal < element, -1, 1 ) ) }
		ELSE
			cb := {|element| IIF( element = seekVal , 0, IIF( seekVal < element, -1, 1 ) ) }
		ENDIF

		DO WHILE dwLow <= dwHigh
			x := dwLow + ( ( dwHigh - dwLow ) / 2 )

			IF iSave == x
				IF dwHigh - dwLow == 1
					x++
					dwLow++
				ELSE
					EXIT
				ENDIF
			ENDIF

			iSave := x
			IF lIsCodeBlock
				iCBRet := Eval( cb, a[x] )
				IF ! iCBRet:IsNumeric
					THROW Error.DataTypeError(cFuncName, "Return value of Codeblock", 0)
				ELSE
					iComp := iCBRet
				ENDIF
			ELSE
				iComp := Eval( cb, a[x] )
			ENDIF
			IF iComp < 0
				dwHigh := x
			ELSEIF iComp > 0
				dwLow := x
			ELSE
				dwRet := x
				x--

				DO WHILE dwLow <= x

					IF lIsCodeBlock
						iCBRet := Eval( cb, a[x] )
						IF ! iCBRet:IsNumeric
							THROW Error.DataTypeError(cFuncName, "Return value of Codeblock", 0)
						ELSE
							iComp := iCBRet
						ENDIF
					ELSE
						iComp := Eval( cb, a[x] )
					ENDIF

					IF iComp != 0
						EXIT
					ENDIF

					dwRet := x
					x--
				ENDDO
				dwLow := dwHigh + 1
			ENDIF
		ENDDO

		RETURN dwRet

	STATIC METHOD AEval(aArray AS ARRAY, cbBlock AS ICodeblock, nStart AS DWORD, nCount AS DWORD, bUpdateArray AS CONST LOGIC )  AS ARRAY
		LOCAL elements := ALen(aArray) AS DWORD
		LOCAL last   AS DWORD
		LOCAL result AS USUAL
		LOCAL x      AS DWORD
		IF elements == 0
            RETURN aArray
        ENDIF
		IF nStart == 0
			THROW  Error.ArgumentError( __ENTITY__, nameof(nStart), 3, __CavoStr( VOErrors.ArgCannotBeZero ), { nStart } )
		ENDIF

		IF nCount != 0

			IF nStart < 0
				nStart := elements + 1 + nStart
			ENDIF

			IF nCount > 0

				last := Math.Min( nStart + ( nCount - 1 ), elements )

				FOR x := nStart UPTO last
    				result := Eval( cbBlock, aArray[x], x )

					IF ( bUpdateArray )
						aArray[x] := result
					ENDIF
				NEXT
			ELSE

				last := Math.Max( 1, nStart + nCount + 1 )

				FOR x := nStart DOWNTO last
					result := Eval( cbBlock, aArray[x], x )

					IF ( bUpdateArray )
						aArray[x] := result
					ENDIF
				NEXT
			ENDIF
		ENDIF

		RETURN aArray

	STATIC METHOD AEvalCheckArgs(aArray AS ARRAY, cb AS ICodeblock, iStart REF USUAL, iCount REF USUAL,cFuncName AS STRING) AS VOID
		IF aArray == NULL_ARRAY
            RETURN
		ENDIF
		IF cb == NULL
			THROW Error.NullArgumentError( cFuncName, NAMEOF(cb),2)
		ENDIF
		Default( REF iStart, 1)
		Default( REF iCount, ALen(aArray))
		IF ! iStart:IsNumeric
			THROW Error.ArgumentError( cFuncName, NAMEOF(iStart), 3 , <OBJECT>{iStart})
		ENDIF
		IF ! iCount:IsNumeric
			THROW Error.ArgumentError( cFuncName, NAMEOF(iCount), 4 , <OBJECT>{iCount})
		ENDIF
		RETURN

	STATIC METHOD ValidateArrayParams(aTarget REF USUAL, nStart REF USUAL,nCount REF USUAL, nSize OUT DWORD) AS LOGIC
		nSize := 0
		IF aTarget:IsArray
			nSize := ALen( (ARRAY) aTarget )
			IF nSize == 0
				RETURN FALSE
			ENDIF
		ELSE
			RETURN FALSE
		ENDIF

		IF ! nCount:IsNumeric
			IF ! nStart:IsNumeric
				nStart := 1
			END IF
			nCount := ALen(aTarget) - nStart + 1
		ELSE
			IF nCount >= 0
				IF ! nStart:IsNumeric
					nStart := 1
				ENDIF
				IF nStart > nSize
					RETURN FALSE
				END IF
			ELSE
				IF ! nStart:IsNumeric
					nStart := ALen(aTarget)
				ENDIF
				nSize := 1
				nCount := - nCount
				IF nStart < nSize
					RETURN FALSE
				END IF
			END IF
		END IF
		RETURN TRUE

	END CLASS

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraycreate/*" />
FUNCTION ArrayCreate(dwElements AS DWORD) AS ARRAY
	RETURN __Array{dwElements, TRUE}

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraycreate/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayCreate<T>(dwElements AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN __ArrayBase<T>{dwElements}

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayinit/*" />
FUNCTION ArrayInit(wElements AS DWORD, avalues REF USUAL[]) AS ARRAY
	LOCAL aTemp AS ARRAY
	LOCAL x AS DWORD

	IF wElements > (DWORD) aValues:Length
		THROW Error.ArgumentError( __ENTITY__, NAMEOF(wElements), "Element too big")
	ENDIF

	aTemp := ArrayNew(aValues:Length)
	FOR x := 1 UPTO aValues:Length
		aTemp [x] := aValues[x]
	NEXT
	RETURN aTemp

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aadd/*" />
FUNCTION AAdd(aTarget AS ARRAY,uNewElement AS USUAL) AS USUAL
	RETURN AAdd<USUAL>(aTarget, uNewElement)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aadd/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AAdd<T>(aTarget AS __ArrayBase<T>,uNewElement AS T) AS T WHERE T IS NEW()
	aTarget:Add(uNewElement)
	RETURN uNewElement

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aclone/*" />
FUNCTION AClone(aSource AS ARRAY) AS ARRAY
	IF aSource == NULL_ARRAY
		RETURN aSource
	END IF
	RETURN (ARRAY) aSource:Clone()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aclone/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AClone<T>(aSource AS __ArrayBase<T>) AS __ArrayBase<T> WHERE T IS NEW()
	IF aSource == NULL
		RETURN aSource
	END IF
	RETURN  aSource:Clone()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/acloneshallow/*" />
FUNCTION ACloneShallow(aSource AS ARRAY) AS ARRAY
	IF aSource == NULL_ARRAY
		RETURN aSource
	END IF
	RETURN (ARRAY) aSource:CloneShallow()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/acloneshallow/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ACloneShallow<T>(aSource AS __ArrayBase<T>) AS __ArrayBase<T> WHERE T IS NEW()
	IF aSource == NULL
		RETURN aSource
	END IF
	RETURN aSource:Clone()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/adel/*" />
FUNCTION ADel(aTarget AS ARRAY,dwPosition AS DWORD) AS ARRAY
	aTarget:Delete((INT) dwPosition)
	RETURN aTarget

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/adel/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ADel<T>(aTarget AS __ArrayBase<T>,dwPosition AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	aTarget:Delete((INT) dwPosition)
	RETURN aTarget

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/adel/*" />
FUNCTION ATrueDel(aTarget AS ARRAY,dwPosition AS DWORD) AS ARRAY
	aTarget:RemoveAt((INT) dwPosition)
	RETURN aTarget

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/adel/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ATrueDel<T>(aTarget AS __ArrayBase<T>,dwPosition AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	aTarget:RemoveAt((INT) dwPosition)
	RETURN aTarget

/// Calculate the # of dimensions in an array
/// <param name="a"></param>
/// <returns>Number of dimensions in an array</returns>
FUNCTION ADim(a AS ARRAY) AS DWORD
	LOCAL dwDims AS DWORD
	dwDims := 1
	DO WHILE a != NULL_ARRAY
		IF ALen(a) > 0
			IF IsArray(a[1])
				dwDims += 1
				a := a[1]
			ELSE
				EXIT
			ENDIF
		ELSE
			EXIT
		ENDIF
	ENDDO
	RETURN dwDims

/// Calculate a string that represents the dimensions in an array
/// <param name="a"></param>
/// <returns>String that displays the dimensions in an array</returns>
FUNCTION ADimPic(a AS ARRAY) AS STRING
	RETURN repl("[]", aDim(a))

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ains/*" />
FUNCTION AIns(aTarget AS ARRAY,dwPosition AS DWORD) AS ARRAY
	aTarget:Insert((INT) dwPosition)
	RETURN aTarget

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ains/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AIns<T>(aTarget AS __ArrayBase<T>,dwPosition AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	aTarget:Insert((INT) dwPosition)
	RETURN aTarget

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/alen/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ALen<T>(aTarget AS __ArrayBase<T>) AS DWORD WHERE T IS NEW()
	IF aTarget != NULL
		RETURN aTarget:Length
	ELSE
		RETURN 0
	ENDIF

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/alen/*" />
FUNCTION ALen(aTarget AS ARRAY) AS DWORD
	IF aTarget != NULL
		RETURN aTarget:Length
	ELSE
		RETURN 0
	ENDIF

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraydeprotect/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayDeProtect<T>(aTarget AS __ArrayBase<T>) AS LOGIC WHERE T IS NEW()
	RETURN aTarget:Lock(FALSE)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraydeprotect/*" />
FUNCTION ArrayDeProtect(aTarget AS ARRAY) AS LOGIC
	RETURN aTarget:Lock(FALSE)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayget/*" />
FUNCTION ArrayGet(aTarget AS ARRAY,dwElement AS DWORD) AS USUAL
	RETURN aTarget:__GetElement( (INT) dwElement-1)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayget/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayGet<T>(aTarget AS __ArrayBase<T>,dwElement AS DWORD) AS T WHERE T IS NEW()
	RETURN aTarget:__GetElement( (INT) dwElement-1)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayprotect/*" />
FUNCTION ArrayProtect(aTarget AS ARRAY) AS LOGIC
	RETURN aTarget:Lock(TRUE)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayprotect/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayProtect<T>(aTarget AS __ArrayBase<T>) AS LOGIC WHERE T IS NEW()
	RETURN aTarget:Lock(TRUE)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayput/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayPut<T>(aTarget AS __ArrayBase<T>,dwElement AS DWORD,uValue AS T) AS T WHERE T IS NEW()
	aTarget:__SetElement(uValue, (INT)dwElement -1)
	RETURN uValue

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayput/*" />
FUNCTION ArrayPut(aTarget AS ARRAY,dwElement AS DWORD,uValue AS USUAL) AS USUAL
	aTarget:__SetElement(uValue, (INT)dwElement -1)
	RETURN uValue

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraystore/*" />
FUNCTION ArrayStore(aSource AS ARRAY,Buff AS USUAL PTR,dwLen AS DWORD) AS DWORD
	LOCAL i AS DWORD
	LOCAL nLen AS DWORD
	nLen := ALen(aSource)
	dwLen := Math.Min(dwLen, nLen)
	FOR i := 1 TO dwLen
		buff[i] := aSource[i]
	NEXT
	RETURN dwLen

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraystore/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayStore<T>(aSource AS __ArrayBase<T>,Buff AS T PTR,dwLen AS DWORD) AS DWORD WHERE T IS NEW()
	LOCAL i AS DWORD
	LOCAL nLen AS DWORD
	nLen := aSource:Length
	dwLen := Math.Min(dwLen, nLen)
	FOR i := 1 TO (LONG) dwLen
		buff[i] := aSource[(INT) i]
	NEXT
	RETURN dwLen

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayswap/*" />
FUNCTION ArraySwap(aTarget AS ARRAY,dwElement AS DWORD,uNewValue AS USUAL) AS USUAL
	RETURN aTarget:Swap((INT) dwElement, uNewValue)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayswap/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArraySwap<T>(aTarget AS __ArrayBase<T>,dwElement AS DWORD,uNewValue AS T) AS T  WHERE T IS NEW()
	RETURN aTarget:Swap((INT) dwElement, uNewValue)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
FUNCTION AScan(aTarget AS ARRAY, uSearch AS USUAL,nStart := NIL AS USUAL,nCount := NIL AS USUAL) AS DWORD
	RETURN ArrayHelpers.AScan( aTarget, uSearch, nStart, nCount, SetExact())

/// <inheritdoc cref='M:XSharp.RT.Functions.AScan(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScan(aTarget AS ARRAY, uSearch AS USUAL,nStart AS USUAL) AS DWORD
	RETURN ArrayHelpers.AScan( aTarget, uSearch, nStart, NIL, SetExact())

/// <inheritdoc cref='M:XSharp.RT.Functions.AScan(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScan(aTarget AS ARRAY, uSearch AS USUAL) AS DWORD
	RETURN ArrayHelpers.Ascan( aTarget, uSearch, 1, NIL, SetExact())

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascanexact/*" />
FUNCTION AScanExact( aTarget AS ARRAY, uSearch AS USUAL, nStart := NIL AS USUAL, nCount := NIL AS USUAL) AS DWORD
	RETURN ArrayHelpers.Ascan( aTarget, uSearch, nStart, nCount, TRUE )

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascanexact/*" />
FUNCTION AScanExact( aTarget AS ARRAY, uSearch AS USUAL, nStart AS USUAL) AS DWORD
	RETURN ArrayHelpers.Ascan( aTarget, uSearch, nStart, NIL, TRUE )

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascanexact/*" />
FUNCTION AScanExact( aTarget AS ARRAY, uSearch AS USUAL) AS DWORD
	RETURN ArrayHelpers.Ascan( aTarget, uSearch, 1, NIL, TRUE )

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascanbin/*" />
FUNCTION AScanBin(aTarget AS ARRAY,uSearch AS USUAL) AS DWORD
	RETURN ArrayHelpers.AScanBin( "AscanBin" , aTarget, uSearch, FALSE )

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascanbinexact/*" />
FUNCTION AScanBinExact(aTarget AS ARRAY,uSearch AS USUAL) AS DWORD
	RETURN ArrayHelpers.AScanBin( "AscanBin" , aTarget, uSearch, TRUE )

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, uSearch AS T) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, uSearch,1, (INT) aTarget:Length)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
/// <param name="act">A lambda expression that will be evaluated for every element in the array.</param>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, act AS @@Func<T,LOGIC>) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, act,1, (INT) aTarget:Length)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, uSearch AS T, nStart AS LONG) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, uSearch, nStart, (INT) aTarget:Length- nStart +1)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
/// <param name="act">A lambda expression that will be evaluated for every element in the array.</param>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, act AS @@Func<T,LOGIC>, nStart AS LONG) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, act, nStart, (INT) aTarget:Length - nStart +1)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, uSearch AS T, nStart AS LONG, nCount AS LONG) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, uSearch, nStart, nCount)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, act AS @@Func<T,LOGIC>, nStart AS LONG, nCount  AS LONG) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, act, nStart, nCount)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/asize/*" />
FUNCTION ASize(aTarget AS ARRAY,dwLength AS DWORD) AS ARRAY
	aTarget:Resize((INT) dwLength)
	RETURN aTarget

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/asize/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ASize<T>(aTarget AS __ArrayBase<T>,dwLength AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	aTarget:Resize((INT) dwLength)
	RETURN aTarget

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/atail/*" />
FUNCTION ATail(aTarget AS ARRAY) AS USUAL
	RETURN aTarget:Tail()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/atail/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ATail<T>(aTarget AS __ArrayBase<T>) AS T WHERE T IS NEW()
	RETURN aTarget:Tail()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/acopy/*" />
FUNCTION ACopy(aSource ,aTarget ,nStart ,nCount ,nTargetPos ) AS ARRAY CLIPPER
	LOCAL sourceLen  AS DWORD
	LOCAL start AS DWORD
	LOCAL count AS DWORD
	IF !aSource:IsArray
      THROW Error.ArgumentError( __ENTITY__, NAMEOF(aSource), 1, <OBJECT>{ aSource } )
    ENDIF

     IF !aTarget:IsArray
        THROW Error.ArgumentError( __ENTITY__, NAMEOF(aTarget), 2, <OBJECT>{ aTarget } )
     ENDIF
	 start := 1
	 sourceLen  := ALen(aSource)
	 IF pCount() > 2
		IF nStart:IsNumeric
			start := nStart
		ELSE
			THROW Error.ArgumentError( __ENTITY__, NAMEOF(nStart), 3, <OBJECT>{ nStart } )
		ENDIF
		IF start < 0
			start := sourceLen
		ELSE
			start := Math.Min(start, sourceLen)
		ENDIF
	 ENDIF
	 IF pCount() > 3
		IF nCount:IsNumeric
			count := nCount
		ELSE
			THROW Error.ArgumentError( __ENTITY__, NAMEOF(nCount), 4, <OBJECT>{ nCount } )
		ENDIF
		IF count > 0
			sourceLen := Math.Min(sourceLen, start+count-1)
		ELSE
			sourceLen := Math.Max(1, start+count-1)
		ENDIF
	 ENDIF
	 LOCAL offSet		:= 1 AS DWORD
	 LOCAL targetLen	:= ALen(aTarget) AS DWORD
	 IF pCount() > 4
		IF nTargetPos:IsNumeric
			offSet := nTargetPos
			offSet := Math.Min( offSet, targetLen )
            offSet := Math.Max( 1, offSet )
		ELSE
			THROW Error.ArgumentError( __ENTITY__, NAMEOF(nTargetPos), 5, <OBJECT>{ nTargetPos } )
		ENDIF
	 ENDIF
	 XSharp.__Array.Copy(aSource, aTarget, start, sourceLen, offSet, targetLen)

	 RETURN aTarget

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/afill/*" />
FUNCTION AFill(aTarget AS ARRAY,uValue := NIL AS USUAL, nStart := NIL AS USUAL, nCount := NIL AS USUAL) AS ARRAY
	// The behavior of AFill() in VO is different than what is descibed in the help file
	// - if start <= 0 throws an error
	// - if start == NIL, then start becomes 1
	// - if count < 0 then it does nothing, unless start == nil, in which case start becomes 1 and count becomes 1, too (yeah, crap!)
	// - if count == nil, then it fills from start to lenght of array

	// warning, with the current definition of the function, it is not possible for the user to omit the start param
	LOCAL nLen := ALen( aTarget ) AS DWORD
	IF nLen > 0

		LOCAL lStartWasNil := FALSE AS LOGIC
		IF nStart == NIL
			nStart := 1
			lStartWasNil := TRUE
		ENDIF

		IF nStart > nLen .OR. nStart <= 0
			THROW Error.BoundError( "AFill", nameof(nStart), 3, <OBJECT>{ nStart } )
		ENDIF
		IF nCount == NIL
			nCount := (INT)nLen - nStart + 1
		ELSEIF nCount > 0
			// VO does not throw an error if count is longer than the array
			IF nStart + nCount - 1 > nLen
				nCount := (INT)nLen - nStart + 1
			END IF
		ELSE
			IF lStartWasNil
				nCount := 1
			ELSE
				RETURN aTarget
			END IF
		END IF

		FOR LOCAL x := nStart AS INT UPTO nStart + nCount - 1
			aTarget[(DWORD) x] := uValue
		NEXT
	ENDIF
	RETURN aTarget

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraybuild/*" />
FUNCTION ArrayBuild() AS ARRAY
	RETURN ARRAY{}

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraynew/*" />
FUNCTION ArrayNew() AS ARRAY
	RETURN ArrayNew(0)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraynew/*" />
FUNCTION ArrayNew(wElementList PARAMS USUAL[]) AS ARRAY
	LOCAL aDimInt AS INT[]
	LOCAL i AS INT
	aDimInt := INT[]{wElementList:Length}
	FOR i := 1 TO wElementList:Length
		aDimInt[i] := (INT) wElementList[i]
	NEXT
	RETURN __Array.ArrayCreate(aDimInt)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraynew/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayNew<T>(wElementList AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN __ArrayBase<T>{wElementList}

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraynew/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayNew<T>(wElementList AS INT) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN __ArrayBase<T>{(DWORD) wElementList}

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/areplicate/*" />
FUNCTION AReplicate(xFill AS USUAL,nElements AS DWORD) AS ARRAY
	VAR a:= __Array{nElements, TRUE}
	LOCAL i AS DWORD
	FOR i := 1 UPTO nElements
		a[i] := xFill
	NEXT
	RETURN a

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/asort/*" />
FUNCTION ASort(aTarget AS ARRAY, nStart := NIL AS USUAL,nCount := NIL AS USUAL,cbOrder := NIL AS USUAL) AS ARRAY
	LOCAL nLen AS DWORD
	Default( REF nStart, 1 )

	nLen := ALen(aTarget)
	IF nLen == 0 // Let it execute if nLen == 1, maybe the codeblock is important to be executed in this case for some (user) reason
		RETURN aTarget
	END IF

	EnforceNumeric( nStart )
	Default( REF nCount, nLen - nStart + 1 )
	EnforceNumeric( nCount )

	// Note: ASort() in VO accepts arguments out of bounds and translates them this way:
	IF nStart <= 0
		nStart := 1
	ELSEIF nStart > nLen
		RETURN aTarget
	END IF

	IF nCount <= 0 .OR. nStart + nCount - 1 > nLen
		nCount := nLen - nStart + 1
	ENDIF

/*	IF startIndex < 1 .or. nStart > nLen
		THROW Error.ArgumentError( __ENTITY__, NAMEOF(nStart), 2, <OBJECT>{ nStart } )
	ENDIF
	IF nCount + nStart > ALen((ARRAY)aArray)+1
		THROW Error.ArgumentError( __ENTITY__, NAMEOF(nCount), 3, <OBJECT>{ nCount } )
	ENDIF */

	IF cbOrder != NIL
        var ok := cbOrder:IsCodeBlock
        IF ok
            var cb := (CodeBlock) cbOrder
            ok := cb:PCount() >= 2
            IF ! Ok
                THROW Error.ArgumentError( __ENTITY__, nameof(cbOrder), "ASort Codeblock must have at least 2 arguments" )
            ENDIF
        ELSE
		    THROW Error.ArgumentError( __ENTITY__, nameof(cbOrder), 4, <OBJECT>{ cbOrder } )
        ENDIF

	ENDIF

	IF cbOrder == NIL
		aTarget:Sort( nStart, nCount, NULL ) // this uses __Usual.ICompareTo()
	ELSE
		aTarget:Sort( nStart, nCount, ArraySortComparer{ cbOrder } )
	ENDIF

	RETURN aTarget

	// This wraps a codeblock and provides an IComparer implementation so
	// we can use ArrayList:Sort() with a codeblock.

INTERNAL STRUCTURE ArraySortComparer  IMPLEMENTS System.Collections.Generic.IComparer<USUAL>

	PRIVATE _cb AS ICodeblock

	CONSTRUCTOR( cb AS ICodeblock)
		_cb := cb
		RETURN

	METHOD Compare( x AS USUAL, y AS USUAL ) AS INT
		IF x == y
			RETURN 0
		ENDIF
		LOCAL u AS USUAL
		u := _cb:EvalBlock( x, y )
		RETURN IIF (  (LOGIC) u , -1, 1 )

END STRUCTURE

INTERNAL STRUCTURE ArraySortComparer<T, U>  IMPLEMENTS System.Collections.Generic.IComparer<T> WHERE T IS NEW()

	PRIVATE _cb AS @@Func<T,T,LOGIC>

	CONSTRUCTOR( cb AS @@Func<T,T,LOGIC> )
		_cb := cb
		RETURN

	METHOD Compare( x AS T, y AS T ) AS INT
		IF Object.ReferenceEquals(x, y )
			RETURN 0
		ENDIF
		LOCAL u AS LOGIC
		u := _cb( x, y )
		RETURN IIF (  u , -1, 1 )

END STRUCTURE

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/asort/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ASort<T>(aTarget AS __ArrayBase<T> ,nStart AS INT,nCount AS INT,cbOrder AS @@Func<T,T,LOGIC>) AS __ArrayBase<T> WHERE T IS NEW()
	aTarget:Sort( nStart, nCount, ArraySortComparer<T, LOGIC> { cbOrder } )
	RETURN aTarget

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/asort/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ASort<T>(aTarget AS __ArrayBase<T> ,cbOrder AS @@Func<T,T,LOGIC>) AS __ArrayBase<T> WHERE T IS NEW()

	aTarget:Sort( ArraySortComparer<T, LOGIC> { cbOrder } )

	RETURN aTarget

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
FUNCTION AEval<T>(aArray AS __ArrayBase<T>, cbBlock AS Action<T>) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN AEval(aArray, cbBlock, 1, ALen(aArray) )

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
FUNCTION AEval<T>(aArray AS __ArrayBase<T>, cbBlock AS Action<T>,nStart AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN AEval(aArray, cbBlock, nStart, ALen(aArray) - nStart +1)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AEval<T>(aArray AS __ArrayBase<T>, cbBlock AS Action<T>,nStart AS DWORD,nCount  AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	LOCAL nEnd AS DWORD
	nEnd := nStart + nCount -1
	FOR VAR nX := nStart TO nEnd
		cbBlock(aArray[ (INT) nX])
	NEXT
	RETURN aArray

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
FUNCTION AEval(aArray AS ARRAY,cbBlock AS ICodeblock ) AS ARRAY
	LOCAL uCount    := NIL AS USUAL
	LOCAL uStart	:= NIL AS USUAL
	ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF uStart, REF uCount, "AEval")
	RETURN ArrayHelpers.AEval( aArray, cbBlock, uStart, uCount, FALSE)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
FUNCTION AEval(aArray AS ARRAY,cbBlock AS ICodeblock ,nStart AS USUAL ) AS ARRAY
	LOCAL uCount    := NIL AS USUAL
	ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF uCount, "AEval")
	RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart, uCount, FALSE)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
FUNCTION AEval(aArray AS ARRAY,cbBlock AS ICodeblock ,nStart AS USUAL ,nCount AS USUAL) AS ARRAY
	ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF nCount, "AEval")
	RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart, nCount , FALSE )

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
FUNCTION AEvalA(aArray AS ARRAY ,cbBlock AS ICodeblock) AS ARRAY
	LOCAL uCount    := NIL AS USUAL
	LOCAL uStart	:= NIL AS USUAL
	ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF uStart, REF uCount, "AEvalA")
	RETURN ArrayHelpers.AEval( aArray, cbBlock, uStart,uCount , TRUE)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
FUNCTION AEvalA(aArray AS ARRAY ,cbBlock AS ICodeblock, nStart AS USUAL ) AS ARRAY
	LOCAL uCount    := NIL AS USUAL
	ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF uCount, "AEvalA")
	RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart,uCount , TRUE)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
FUNCTION AEvalA(aArray AS ARRAY ,cbBlock AS ICodeblock, nStart  AS USUAL ,nCount AS USUAL) AS ARRAY
	ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF nCount, "AEvalA")
	RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart,nCount , TRUE)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AEvalA<T>(aArray AS __ArrayBase<T>, cbBlock AS @@Func<T,T>) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN AEvalA(aArray, cbBlock, 1, ALen(aArray))

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AEvalA<T>(aArray AS __ArrayBase<T>, cbBlock AS @@Func<T,T>,nStart AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN AEvalA(aArray, cbBlock, nStart, ALen(aArray) - nStart +1)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AEvalA<T>(aArray AS __ArrayBase<T>, cbBlock AS @@Func<T,T>,nStart AS DWORD, nCount AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	LOCAL nEnd  AS DWORD
	nEnd := nStart + nCount -1
	FOR VAR nX := nStart TO nEnd
		aArray[ (INT) nX] := cbBlock( aArray[(INT)  nX])
	NEXT
	RETURN aArray

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevalold/*" />
FUNCTION AEvalOld(aArray AS ARRAY ,cbBlock AS ICodeblock,nStart  AS USUAL ,nCount AS USUAL) AS ARRAY
	ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF nCount, "AEvalOld")
	RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart,nCount , FALSE)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevalold/*" />
FUNCTION AEvalOld(aArray AS ARRAY ,cbBlock AS ICodeblock,nStart  AS USUAL ) AS ARRAY
	LOCAL uCount	 := NIL AS USUAL
    ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF uCount, "AEvalOld")
	RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart,uCount , FALSE)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevalold/*" />
FUNCTION AEvalOld(aArray AS ARRAY ,cbBlock AS ICodeblock) AS ARRAY
	LOCAL uStart	 := NIL AS USUAL
	LOCAL uCount	 := NIL AS USUAL
	ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF uStart, REF uCount, "AEvalOld")
	RETURN ArrayHelpers.AEval( aArray, cbBlock, uStart,uCount , FALSE)

//
// 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.
//

INTERNAL STATIC CLASS ArrayHelpers

	STATIC METHOD AScan<T>(aTarget AS __ArrayBase<T>, element  AS T , nStart AS LONG, nCount AS LONG) AS DWORD WHERE T IS NEW()
		LOCAL nItem AS LONG
		LOCAL nLen  AS LONG
		nLen := (INT) aTarget:Length
		FOR nItem := nStart TO nLen
			IF object.Equals(aTarget[ nItem], element)
				RETURN (DWORD) nItem
			ENDIF
			nCount -= 1
			IF nCount == 0
				EXIT
			ENDIF
		NEXT
		RETURN 0

	STATIC METHOD AScan<T>(aTarget AS __ArrayBase<T>, bAction AS @@Func<T, LOGIC> , nStart AS LONG, nCount AS LONG) AS DWORD WHERE T IS NEW()
		LOCAL nItem AS LONG
		LOCAL nLen  AS LONG
		nLen := (INT) aTarget:Length
		FOR nItem := nStart TO nLen
			LOCAL oElement := aTarget[ nItem] AS T
			IF bAction(oElement)
				RETURN  (DWORD) nItem
			ENDIF
			nCount -= 1
			IF nCount == 0
				EXIT
			ENDIF
		NEXT
		RETURN 0

	STATIC METHOD AScan( aTarget AS USUAL, x AS USUAL, uStart AS USUAL, uCount AS USUAL, lExact AS LOGIC ) AS DWORD
		LOCAL nSize		AS DWORD
		IF ! ArrayHelpers.ValidateArrayParams(REF aTarget, REF uStart, REF uCount, OUT nSize)
			RETURN 0
		ENDIF
		LOCAL a := aTarget AS ARRAY
		LOCAL nStart := uStart	AS DWORD
		LOCAL nCount := uCount	AS DWORD
		LOCAL nRet := 0			AS DWORD
		LOCAL i					AS DWORD
		LOCAL cb				AS CODEBLOCK
		IF IsCodeBlock( x )
			cb := x
		ELSE
			IF lExact
				cb   := {|element| element == x }
			ELSE
				cb   := {|element| element = x }
			ENDIF
		ENDIF
		IF nStart < nSize
			FOR i := nStart UPTO nSize
				IF nCount > 0
					IF Eval( cb, a[i] )
						nRet := i
						EXIT
					ENDIF
					nCount--
				ELSE
					EXIT
				ENDIF
			NEXT
		ELSE
			FOR i := nStart DOWNTO nSize
				IF nCount > 0
					IF Eval( cb, a[i] )
						nRet := i
						EXIT
					ENDIF
					nCount--
				ELSE
					EXIT
				ENDIF
			NEXT
		ENDIF

		RETURN nRet

	STATIC METHOD AScanBin(cFuncName AS STRING, a AS ARRAY, seekVal AS USUAL, lExact AS LOGIC ) AS DWORD
		LOCAL dwLow        AS DWORD
		LOCAL dwHigh       AS DWORD
		LOCAL x            AS DWORD
		LOCAL dwRet        AS DWORD
		LOCAL iSave        AS DWORD
		LOCAL lIsCodeBlock AS LOGIC
		LOCAL iCBRet       AS USUAL
		LOCAL iComp        AS INT
		LOCAL cb			  AS CODEBLOCK

		dwLow  := 1
		dwHigh := (DWORD) ALen(a)
		iSave := dwRet := 0
		iComp := 0
		lIsCodeblock := IsCodeBlock( seekVal )
		IF lIsCodeBlock
			cb := seekVal
		ELSEIF lExact
			cb := {|element| IIF( element == seekVal , 0, IIF( seekVal < element, -1, 1 ) ) }
		ELSE
			cb := {|element| IIF( element = seekVal , 0, IIF( seekVal < element, -1, 1 ) ) }
		ENDIF

		DO WHILE dwLow <= dwHigh
			x := dwLow + ( ( dwHigh - dwLow ) / 2 )

			IF iSave == x
				IF dwHigh - dwLow == 1
					x++
					dwLow++
				ELSE
					EXIT
				ENDIF
			ENDIF

			iSave := x
			IF lIsCodeBlock
				iCBRet := Eval( cb, a[x] )
				IF ! iCBRet:IsNumeric
					THROW Error.DataTypeError(cFuncName, "Return value of Codeblock", 0)
				ELSE
					iComp := iCBRet
				ENDIF
			ELSE
				iComp := Eval( cb, a[x] )
			ENDIF
			IF iComp < 0
				dwHigh := x
			ELSEIF iComp > 0
				dwLow := x
			ELSE
				dwRet := x
				x--

				DO WHILE dwLow <= x

					IF lIsCodeBlock
						iCBRet := Eval( cb, a[x] )
						IF ! iCBRet:IsNumeric
							THROW Error.DataTypeError(cFuncName, "Return value of Codeblock", 0)
						ELSE
							iComp := iCBRet
						ENDIF
					ELSE
						iComp := Eval( cb, a[x] )
					ENDIF

					IF iComp != 0
						EXIT
					ENDIF

					dwRet := x
					x--
				ENDDO
				dwLow := dwHigh + 1
			ENDIF
		ENDDO

		RETURN dwRet

	STATIC METHOD AEval(aArray AS ARRAY, cbBlock AS ICodeblock, nStart AS DWORD, nCount AS DWORD, bUpdateArray AS CONST LOGIC )  AS ARRAY
		LOCAL elements := ALen(aArray) AS DWORD
		LOCAL last   AS DWORD
		LOCAL result AS USUAL
		LOCAL x      AS DWORD
		IF elements == 0
            RETURN aArray
        ENDIF
		IF nStart == 0
			THROW  Error.ArgumentError( __ENTITY__, nameof(nStart), 3, __CavoStr( VOErrors.ArgCannotBeZero ), { nStart } )
		ENDIF

		IF nCount != 0

			IF nStart < 0
				nStart := elements + 1 + nStart
			ENDIF

			IF nCount > 0

				last := Math.Min( nStart + ( nCount - 1 ), elements )

				FOR x := nStart UPTO last
    				result := Eval( cbBlock, aArray[x], x )

					IF ( bUpdateArray )
						aArray[x] := result
					ENDIF
				NEXT
			ELSE

				last := Math.Max( 1, nStart + nCount + 1 )

				FOR x := nStart DOWNTO last
					result := Eval( cbBlock, aArray[x], x )

					IF ( bUpdateArray )
						aArray[x] := result
					ENDIF
				NEXT
			ENDIF
		ENDIF

		RETURN aArray

	STATIC METHOD AEvalCheckArgs(aArray AS ARRAY, cb AS ICodeblock, iStart REF USUAL, iCount REF USUAL,cFuncName AS STRING) AS VOID
		IF aArray == NULL_ARRAY
            RETURN
		ENDIF
		IF cb == NULL
			THROW Error.NullArgumentError( cFuncName, NAMEOF(cb),2)
		ENDIF
		Default( REF iStart, 1)
		Default( REF iCount, ALen(aArray))
		IF ! iStart:IsNumeric
			THROW Error.ArgumentError( cFuncName, NAMEOF(iStart), 3 , <OBJECT>{iStart})
		ENDIF
		IF ! iCount:IsNumeric
			THROW Error.ArgumentError( cFuncName, NAMEOF(iCount), 4 , <OBJECT>{iCount})
		ENDIF
		RETURN

	STATIC METHOD ValidateArrayParams(aTarget REF USUAL, nStart REF USUAL,nCount REF USUAL, nSize OUT DWORD) AS LOGIC
		nSize := 0
		IF aTarget:IsArray
			nSize := ALen( (ARRAY) aTarget )
			IF nSize == 0
				RETURN FALSE
			ENDIF
		ELSE
			RETURN FALSE
		ENDIF

		IF ! nCount:IsNumeric
			IF ! nStart:IsNumeric
				nStart := 1
			END IF
			nCount := ALen(aTarget) - nStart + 1
		ELSE
			IF nCount >= 0
				IF ! nStart:IsNumeric
					nStart := 1
				ENDIF
				IF nStart > nSize
					RETURN FALSE
				END IF
			ELSE
				IF ! nStart:IsNumeric
					nStart := ALen(aTarget)
				ENDIF
				nSize := 1
				nCount := - nCount
				IF nStart < nSize
					RETURN FALSE
				END IF
			END IF
		END IF
		RETURN TRUE

	END CLASS

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraycreate/*" />
FUNCTION ArrayCreate(dwElements AS DWORD) AS ARRAY
	RETURN __Array{dwElements, TRUE}

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraycreate/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayCreate<T>(dwElements AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN __ArrayBase<T>{dwElements}

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayinit/*" />
FUNCTION ArrayInit(wElements AS DWORD, avalues REF USUAL[]) AS ARRAY
	LOCAL aTemp AS ARRAY
	LOCAL x AS DWORD

	IF wElements > (DWORD) aValues:Length
		THROW Error.ArgumentError( __ENTITY__, NAMEOF(wElements), "Element too big")
	ENDIF

	aTemp := ArrayNew(aValues:Length)
	FOR x := 1 UPTO aValues:Length
		aTemp [x] := aValues[x]
	NEXT
	RETURN aTemp

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aadd/*" />
FUNCTION AAdd(aTarget AS ARRAY,uNewElement AS USUAL) AS USUAL
	RETURN AAdd<USUAL>(aTarget, uNewElement)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aadd/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AAdd<T>(aTarget AS __ArrayBase<T>,uNewElement AS T) AS T WHERE T IS NEW()
	aTarget:Add(uNewElement)
	RETURN uNewElement

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aclone/*" />
FUNCTION AClone(aSource AS ARRAY) AS ARRAY
	IF aSource == NULL_ARRAY
		RETURN aSource
	END IF
	RETURN (ARRAY) aSource:Clone()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aclone/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AClone<T>(aSource AS __ArrayBase<T>) AS __ArrayBase<T> WHERE T IS NEW()
	IF aSource == NULL
		RETURN aSource
	END IF
	RETURN  aSource:Clone()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/acloneshallow/*" />
FUNCTION ACloneShallow(aSource AS ARRAY) AS ARRAY
	IF aSource == NULL_ARRAY
		RETURN aSource
	END IF
	RETURN (ARRAY) aSource:CloneShallow()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/acloneshallow/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ACloneShallow<T>(aSource AS __ArrayBase<T>) AS __ArrayBase<T> WHERE T IS NEW()
	IF aSource == NULL
		RETURN aSource
	END IF
	RETURN aSource:Clone()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/adel/*" />
FUNCTION ADel(aTarget AS ARRAY,dwPosition AS DWORD) AS ARRAY
	aTarget:Delete((INT) dwPosition)
	RETURN aTarget

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/adel/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ADel<T>(aTarget AS __ArrayBase<T>,dwPosition AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	aTarget:Delete((INT) dwPosition)
	RETURN aTarget

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/adel/*" />
FUNCTION ATrueDel(aTarget AS ARRAY,dwPosition AS DWORD) AS ARRAY
	aTarget:RemoveAt((INT) dwPosition)
	RETURN aTarget

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/adel/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ATrueDel<T>(aTarget AS __ArrayBase<T>,dwPosition AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	aTarget:RemoveAt((INT) dwPosition)
	RETURN aTarget

/// Calculate the # of dimensions in an array
/// <param name="a"></param>
/// <returns>Number of dimensions in an array</returns>
FUNCTION ADim(a AS ARRAY) AS DWORD
	LOCAL dwDims AS DWORD
	dwDims := 1
	DO WHILE a != NULL_ARRAY
		IF ALen(a) > 0
			IF IsArray(a[1])
				dwDims += 1
				a := a[1]
			ELSE
				EXIT
			ENDIF
		ELSE
			EXIT
		ENDIF
	ENDDO
	RETURN dwDims

/// Calculate a string that represents the dimensions in an array
/// <param name="a"></param>
/// <returns>String that displays the dimensions in an array</returns>
FUNCTION ADimPic(a AS ARRAY) AS STRING
	RETURN repl("[]", aDim(a))

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ains/*" />
FUNCTION AIns(aTarget AS ARRAY,dwPosition AS DWORD) AS ARRAY
	aTarget:Insert((INT) dwPosition)
	RETURN aTarget

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ains/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AIns<T>(aTarget AS __ArrayBase<T>,dwPosition AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	aTarget:Insert((INT) dwPosition)
	RETURN aTarget

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/alen/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ALen<T>(aTarget AS __ArrayBase<T>) AS DWORD WHERE T IS NEW()
	IF aTarget != NULL
		RETURN aTarget:Length
	ELSE
		RETURN 0
	ENDIF

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/alen/*" />
FUNCTION ALen(aTarget AS ARRAY) AS DWORD
	IF aTarget != NULL
		RETURN aTarget:Length
	ELSE
		RETURN 0
	ENDIF

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraydeprotect/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayDeProtect<T>(aTarget AS __ArrayBase<T>) AS LOGIC WHERE T IS NEW()
	RETURN aTarget:Lock(FALSE)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraydeprotect/*" />
FUNCTION ArrayDeProtect(aTarget AS ARRAY) AS LOGIC
	RETURN aTarget:Lock(FALSE)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayget/*" />
FUNCTION ArrayGet(aTarget AS ARRAY,dwElement AS DWORD) AS USUAL
	RETURN aTarget:__GetElement( (INT) dwElement-1)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayget/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayGet<T>(aTarget AS __ArrayBase<T>,dwElement AS DWORD) AS T WHERE T IS NEW()
	RETURN aTarget:__GetElement( (INT) dwElement-1)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayprotect/*" />
FUNCTION ArrayProtect(aTarget AS ARRAY) AS LOGIC
	RETURN aTarget:Lock(TRUE)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayprotect/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayProtect<T>(aTarget AS __ArrayBase<T>) AS LOGIC WHERE T IS NEW()
	RETURN aTarget:Lock(TRUE)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayput/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayPut<T>(aTarget AS __ArrayBase<T>,dwElement AS DWORD,uValue AS T) AS T WHERE T IS NEW()
	aTarget:__SetElement(uValue, (INT)dwElement -1)
	RETURN uValue

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayput/*" />
FUNCTION ArrayPut(aTarget AS ARRAY,dwElement AS DWORD,uValue AS USUAL) AS USUAL
	aTarget:__SetElement(uValue, (INT)dwElement -1)
	RETURN uValue

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraystore/*" />
FUNCTION ArrayStore(aSource AS ARRAY,Buff AS USUAL PTR,dwLen AS DWORD) AS DWORD
	LOCAL i AS DWORD
	LOCAL nLen AS DWORD
	nLen := ALen(aSource)
	dwLen := Math.Min(dwLen, nLen)
	FOR i := 1 TO dwLen
		buff[i] := aSource[i]
	NEXT
	RETURN dwLen

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraystore/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayStore<T>(aSource AS __ArrayBase<T>,Buff AS T PTR,dwLen AS DWORD) AS DWORD WHERE T IS NEW()
	LOCAL i AS DWORD
	LOCAL nLen AS DWORD
	nLen := aSource:Length
	dwLen := Math.Min(dwLen, nLen)
	FOR i := 1 TO (LONG) dwLen
		buff[i] := aSource[(INT) i]
	NEXT
	RETURN dwLen

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayswap/*" />
FUNCTION ArraySwap(aTarget AS ARRAY,dwElement AS DWORD,uNewValue AS USUAL) AS USUAL
	RETURN aTarget:Swap((INT) dwElement, uNewValue)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arrayswap/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArraySwap<T>(aTarget AS __ArrayBase<T>,dwElement AS DWORD,uNewValue AS T) AS T  WHERE T IS NEW()
	RETURN aTarget:Swap((INT) dwElement, uNewValue)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
FUNCTION AScan(aTarget AS ARRAY, uSearch AS USUAL,nStart := NIL AS USUAL,nCount := NIL AS USUAL) AS DWORD
	RETURN ArrayHelpers.AScan( aTarget, uSearch, nStart, nCount, SetExact())

/// <inheritdoc cref='M:XSharp.RT.Functions.AScan(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScan(aTarget AS ARRAY, uSearch AS USUAL,nStart AS USUAL) AS DWORD
	RETURN ArrayHelpers.AScan( aTarget, uSearch, nStart, NIL, SetExact())

/// <inheritdoc cref='M:XSharp.RT.Functions.AScan(XSharp.__Array,XSharp.__Usual,XSharp.__Usual,XSharp.__Usual)'/>
FUNCTION AScan(aTarget AS ARRAY, uSearch AS USUAL) AS DWORD
	RETURN ArrayHelpers.Ascan( aTarget, uSearch, 1, NIL, SetExact())

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascanexact/*" />
FUNCTION AScanExact( aTarget AS ARRAY, uSearch AS USUAL, nStart := NIL AS USUAL, nCount := NIL AS USUAL) AS DWORD
	RETURN ArrayHelpers.Ascan( aTarget, uSearch, nStart, nCount, TRUE )

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascanexact/*" />
FUNCTION AScanExact( aTarget AS ARRAY, uSearch AS USUAL, nStart AS USUAL) AS DWORD
	RETURN ArrayHelpers.Ascan( aTarget, uSearch, nStart, NIL, TRUE )

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascanexact/*" />
FUNCTION AScanExact( aTarget AS ARRAY, uSearch AS USUAL) AS DWORD
	RETURN ArrayHelpers.Ascan( aTarget, uSearch, 1, NIL, TRUE )

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascanbin/*" />
FUNCTION AScanBin(aTarget AS ARRAY,uSearch AS USUAL) AS DWORD
	RETURN ArrayHelpers.AScanBin( "AscanBin" , aTarget, uSearch, FALSE )

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascanbinexact/*" />
FUNCTION AScanBinExact(aTarget AS ARRAY,uSearch AS USUAL) AS DWORD
	RETURN ArrayHelpers.AScanBin( "AscanBin" , aTarget, uSearch, TRUE )

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, uSearch AS T) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, uSearch,1, (INT) aTarget:Length)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
/// <param name="act">A lambda expression that will be evaluated for every element in the array.</param>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, act AS @@Func<T,LOGIC>) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, act,1, (INT) aTarget:Length)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, uSearch AS T, nStart AS LONG) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, uSearch, nStart, (INT) aTarget:Length- nStart +1)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
/// <param name="act">A lambda expression that will be evaluated for every element in the array.</param>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, act AS @@Func<T,LOGIC>, nStart AS LONG) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, act, nStart, (INT) aTarget:Length - nStart +1)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, uSearch AS T, nStart AS LONG, nCount AS LONG) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, uSearch, nStart, nCount)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ascan/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AScan<T>(aTarget AS __ArrayBase<T>, act AS @@Func<T,LOGIC>, nStart AS LONG, nCount  AS LONG) AS DWORD WHERE T IS NEW()
	RETURN ArrayHelpers.Ascan( aTarget, act, nStart, nCount)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/asize/*" />
FUNCTION ASize(aTarget AS ARRAY,dwLength AS DWORD) AS ARRAY
	aTarget:Resize((INT) dwLength)
	RETURN aTarget

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/asize/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ASize<T>(aTarget AS __ArrayBase<T>,dwLength AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	aTarget:Resize((INT) dwLength)
	RETURN aTarget

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/atail/*" />
FUNCTION ATail(aTarget AS ARRAY) AS USUAL
	RETURN aTarget:Tail()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/atail/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ATail<T>(aTarget AS __ArrayBase<T>) AS T WHERE T IS NEW()
	RETURN aTarget:Tail()

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/acopy/*" />
FUNCTION ACopy(aSource ,aTarget ,nStart ,nCount ,nTargetPos ) AS ARRAY CLIPPER
	LOCAL sourceLen  AS DWORD
	LOCAL start AS DWORD
	LOCAL count AS DWORD
	IF !aSource:IsArray
      THROW Error.ArgumentError( __ENTITY__, NAMEOF(aSource), 1, <OBJECT>{ aSource } )
    ENDIF

     IF !aTarget:IsArray
        THROW Error.ArgumentError( __ENTITY__, NAMEOF(aTarget), 2, <OBJECT>{ aTarget } )
     ENDIF
	 start := 1
	 sourceLen  := ALen(aSource)
	 IF pCount() > 2
		IF nStart:IsNumeric
			start := nStart
		ELSE
			THROW Error.ArgumentError( __ENTITY__, NAMEOF(nStart), 3, <OBJECT>{ nStart } )
		ENDIF
		IF start < 0
			start := sourceLen
		ELSE
			start := Math.Min(start, sourceLen)
		ENDIF
	 ENDIF
	 IF pCount() > 3
		IF nCount:IsNumeric
			count := nCount
		ELSE
			THROW Error.ArgumentError( __ENTITY__, NAMEOF(nCount), 4, <OBJECT>{ nCount } )
		ENDIF
		IF count > 0
			sourceLen := Math.Min(sourceLen, start+count-1)
		ELSE
			sourceLen := Math.Max(1, start+count-1)
		ENDIF
	 ENDIF
	 LOCAL offSet		:= 1 AS DWORD
	 LOCAL targetLen	:= ALen(aTarget) AS DWORD
	 IF pCount() > 4
		IF nTargetPos:IsNumeric
			offSet := nTargetPos
			offSet := Math.Min( offSet, targetLen )
            offSet := Math.Max( 1, offSet )
		ELSE
			THROW Error.ArgumentError( __ENTITY__, NAMEOF(nTargetPos), 5, <OBJECT>{ nTargetPos } )
		ENDIF
	 ENDIF
	 XSharp.__Array.Copy(aSource, aTarget, start, sourceLen, offSet, targetLen)

	 RETURN aTarget

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/afill/*" />
FUNCTION AFill(aTarget AS ARRAY,uValue := NIL AS USUAL, nStart := NIL AS USUAL, nCount := NIL AS USUAL) AS ARRAY
	// The behavior of AFill() in VO is different than what is descibed in the help file
	// - if start <= 0 throws an error
	// - if start == NIL, then start becomes 1
	// - if count < 0 then it does nothing, unless start == nil, in which case start becomes 1 and count becomes 1, too (yeah, crap!)
	// - if count == nil, then it fills from start to lenght of array

	// warning, with the current definition of the function, it is not possible for the user to omit the start param
	LOCAL nLen := ALen( aTarget ) AS DWORD
	IF nLen > 0

		LOCAL lStartWasNil := FALSE AS LOGIC
		IF nStart == NIL
			nStart := 1
			lStartWasNil := TRUE
		ENDIF

		IF nStart > nLen .OR. nStart <= 0
			THROW Error.BoundError( "AFill", nameof(nStart), 3, <OBJECT>{ nStart } )
		ENDIF
		IF nCount == NIL
			nCount := (INT)nLen - nStart + 1
		ELSEIF nCount > 0
			// VO does not throw an error if count is longer than the array
			IF nStart + nCount - 1 > nLen
				nCount := (INT)nLen - nStart + 1
			END IF
		ELSE
			IF lStartWasNil
				nCount := 1
			ELSE
				RETURN aTarget
			END IF
		END IF

		FOR LOCAL x := nStart AS INT UPTO nStart + nCount - 1
			aTarget[(DWORD) x] := uValue
		NEXT
	ENDIF
	RETURN aTarget

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraybuild/*" />
FUNCTION ArrayBuild() AS ARRAY
	RETURN ARRAY{}

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraynew/*" />
FUNCTION ArrayNew() AS ARRAY
	RETURN ArrayNew(0)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraynew/*" />
FUNCTION ArrayNew(wElementList PARAMS USUAL[]) AS ARRAY
	LOCAL aDimInt AS INT[]
	LOCAL i AS INT
	aDimInt := INT[]{wElementList:Length}
	FOR i := 1 TO wElementList:Length
		aDimInt[i] := (INT) wElementList[i]
	NEXT
	RETURN __Array.ArrayCreate(aDimInt)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraynew/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayNew<T>(wElementList AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN __ArrayBase<T>{wElementList}

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/arraynew/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ArrayNew<T>(wElementList AS INT) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN __ArrayBase<T>{(DWORD) wElementList}

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/areplicate/*" />
FUNCTION AReplicate(xFill AS USUAL,nElements AS DWORD) AS ARRAY
	VAR a:= __Array{nElements, TRUE}
	LOCAL i AS DWORD
	FOR i := 1 UPTO nElements
		a[i] := xFill
	NEXT
	RETURN a

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/asort/*" />
FUNCTION ASort(aTarget AS ARRAY, nStart := NIL AS USUAL,nCount := NIL AS USUAL,cbOrder := NIL AS USUAL) AS ARRAY
	LOCAL nLen AS DWORD
	Default( REF nStart, 1 )

	nLen := ALen(aTarget)
	IF nLen == 0 // Let it execute if nLen == 1, maybe the codeblock is important to be executed in this case for some (user) reason
		RETURN aTarget
	END IF

	EnforceNumeric( nStart )
	Default( REF nCount, nLen - nStart + 1 )
	EnforceNumeric( nCount )

	// Note: ASort() in VO accepts arguments out of bounds and translates them this way:
	IF nStart <= 0
		nStart := 1
	ELSEIF nStart > nLen
		RETURN aTarget
	END IF

	IF nCount <= 0 .OR. nStart + nCount - 1 > nLen
		nCount := nLen - nStart + 1
	ENDIF

/*	IF startIndex < 1 .or. nStart > nLen
		THROW Error.ArgumentError( __ENTITY__, NAMEOF(nStart), 2, <OBJECT>{ nStart } )
	ENDIF
	IF nCount + nStart > ALen((ARRAY)aArray)+1
		THROW Error.ArgumentError( __ENTITY__, NAMEOF(nCount), 3, <OBJECT>{ nCount } )
	ENDIF */

	IF cbOrder != NIL .AND. ( ( ! cbOrder:IsCodeBlock ) || ((CODEBLOCK)cbOrder):PCount() != 2 )
		THROW Error.ArgumentError( __ENTITY__, nameof(cbOrder), 4, <OBJECT>{ cbOrder } )
	ENDIF

	IF cbOrder == NIL
		aTarget:Sort( nStart, nCount, NULL ) // this uses __Usual.ICompareTo()
	ELSE
		aTarget:Sort( nStart, nCount, ArraySortComparer{ cbOrder } )
	ENDIF

	RETURN aTarget

	// This wraps a codeblock and provides an IComparer implementation so
	// we can use ArrayList:Sort() with a codeblock.

INTERNAL STRUCTURE ArraySortComparer  IMPLEMENTS System.Collections.Generic.IComparer<USUAL>

	PRIVATE _cb AS ICodeblock

	CONSTRUCTOR( cb AS ICodeblock)
		_cb := cb
		RETURN

	METHOD Compare( x AS USUAL, y AS USUAL ) AS INT
		IF x == y
			RETURN 0
		ENDIF
		LOCAL u AS USUAL
		u := _cb:EvalBlock( x, y )
		RETURN IIF (  (LOGIC) u , -1, 1 )

END STRUCTURE

INTERNAL STRUCTURE ArraySortComparer<T, U>  IMPLEMENTS System.Collections.Generic.IComparer<T> WHERE T IS NEW()

	PRIVATE _cb AS @@Func<T,T,LOGIC>

	CONSTRUCTOR( cb AS @@Func<T,T,LOGIC> )
		_cb := cb
		RETURN

	METHOD Compare( x AS T, y AS T ) AS INT
		IF Object.ReferenceEquals(x, y )
			RETURN 0
		ENDIF
		LOCAL u AS LOGIC
		u := _cb( x, y )
		RETURN IIF (  u , -1, 1 )

END STRUCTURE

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/asort/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ASort<T>(aTarget AS __ArrayBase<T> ,nStart AS INT,nCount AS INT,cbOrder AS @@Func<T,T,LOGIC>) AS __ArrayBase<T> WHERE T IS NEW()
	aTarget:Sort( nStart, nCount, ArraySortComparer<T, LOGIC> { cbOrder } )
	RETURN aTarget

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/asort/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION ASort<T>(aTarget AS __ArrayBase<T> ,cbOrder AS @@Func<T,T,LOGIC>) AS __ArrayBase<T> WHERE T IS NEW()

	aTarget:Sort( ArraySortComparer<T, LOGIC> { cbOrder } )

	RETURN aTarget

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
FUNCTION AEval<T>(aArray AS __ArrayBase<T>, cbBlock AS Action<T>) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN AEval(aArray, cbBlock, 1, ALen(aArray) )

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
FUNCTION AEval<T>(aArray AS __ArrayBase<T>, cbBlock AS Action<T>,nStart AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN AEval(aArray, cbBlock, nStart, ALen(aArray) - nStart +1)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AEval<T>(aArray AS __ArrayBase<T>, cbBlock AS Action<T>,nStart AS DWORD,nCount  AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	LOCAL nEnd AS DWORD
	nEnd := nStart + nCount -1
	FOR VAR nX := nStart TO nEnd
		cbBlock(aArray[ (INT) nX])
	NEXT
	RETURN aArray

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
FUNCTION AEval(aArray AS ARRAY,cbBlock AS ICodeblock ) AS ARRAY
	LOCAL uCount    := NIL AS USUAL
	LOCAL uStart	:= NIL AS USUAL
	ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF uStart, REF uCount, "AEval")
	RETURN ArrayHelpers.AEval( aArray, cbBlock, uStart, uCount, FALSE)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
FUNCTION AEval(aArray AS ARRAY,cbBlock AS ICodeblock ,nStart AS USUAL ) AS ARRAY
	LOCAL uCount    := NIL AS USUAL
	ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF uCount, "AEval")
	RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart, uCount, FALSE)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aeval/*" />
FUNCTION AEval(aArray AS ARRAY,cbBlock AS ICodeblock ,nStart AS USUAL ,nCount AS USUAL) AS ARRAY
	ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF nCount, "AEval")
	RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart, nCount , FALSE )

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
FUNCTION AEvalA(aArray AS ARRAY ,cbBlock AS ICodeblock) AS ARRAY
	LOCAL uCount    := NIL AS USUAL
	LOCAL uStart	:= NIL AS USUAL
	ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF uStart, REF uCount, "AEvalA")
	RETURN ArrayHelpers.AEval( aArray, cbBlock, uStart,uCount , TRUE)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
FUNCTION AEvalA(aArray AS ARRAY ,cbBlock AS ICodeblock, nStart AS USUAL ) AS ARRAY
	LOCAL uCount    := NIL AS USUAL
	ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF uCount, "AEvalA")
	RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart,uCount , TRUE)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
FUNCTION AEvalA(aArray AS ARRAY ,cbBlock AS ICodeblock, nStart  AS USUAL ,nCount AS USUAL) AS ARRAY
	ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF nCount, "AEvalA")
	RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart,nCount , TRUE)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AEvalA<T>(aArray AS __ArrayBase<T>, cbBlock AS @@Func<T,T>) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN AEvalA(aArray, cbBlock, 1, ALen(aArray))

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AEvalA<T>(aArray AS __ArrayBase<T>, cbBlock AS @@Func<T,T>,nStart AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	RETURN AEvalA(aArray, cbBlock, nStart, ALen(aArray) - nStart +1)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevala/*" />
/// <typeparam name="T">The type of the array elements</typeparam>
FUNCTION AEvalA<T>(aArray AS __ArrayBase<T>, cbBlock AS @@Func<T,T>,nStart AS DWORD, nCount AS DWORD) AS __ArrayBase<T> WHERE T IS NEW()
	LOCAL nEnd  AS DWORD
	nEnd := nStart + nCount -1
	FOR VAR nX := nStart TO nEnd
		aArray[ (INT) nX] := cbBlock( aArray[(INT)  nX])
	NEXT
	RETURN aArray

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevalold/*" />
FUNCTION AEvalOld(aArray AS ARRAY ,cbBlock AS ICodeblock,nStart  AS USUAL ,nCount AS USUAL) AS ARRAY
	ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF nCount, "AEvalOld")
	RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart,nCount , FALSE)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevalold/*" />
FUNCTION AEvalOld(aArray AS ARRAY ,cbBlock AS ICodeblock,nStart  AS USUAL ) AS ARRAY
	LOCAL uCount	 := NIL AS USUAL
    ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF nStart, REF uCount, "AEvalOld")
	RETURN ArrayHelpers.AEval( aArray, cbBlock, nStart,uCount , FALSE)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/aevalold/*" />
FUNCTION AEvalOld(aArray AS ARRAY ,cbBlock AS ICodeblock) AS ARRAY
	LOCAL uStart	 := NIL AS USUAL
	LOCAL uCount	 := NIL AS USUAL
	ArrayHelpers.AEvalCheckArgs(aArray, cbBlock, REF uStart, REF uCount, "AEvalOld")
	RETURN ArrayHelpers.AEval( aArray, cbBlock, uStart,uCount , FALSE)