#ifndef _mr_json_helper_
#define _mr_json_helper_
objectdef MRJsonHelper
{

    ;;;
    ;;; Returns an array of property values from items from the given json array that match the given query string
    ;;; for example, given the following json array:
    ;;; [
    ;;;     {"Id": 1, "Name": "Obj1", "Type": { "Name": "Obj1Type" }},
    ;;;     {"Id": 2, "Name": "Obj2", "Type": { "Name": "Obj2Type" }},
    ;;; ]
    ;;; and the query string "Type.Name", the result would be:
    ;;; [
    ;;;     "Obj1Type",
    ;;;     "Obj2Type"
    ;;; ]
    ;;; @param jsonvalueref ref - The json array to query
    ;;; @param str queryString - The query string to use to filter the array, i.e. "Id" or "Type.Name"
    ;;; @return jsonvalueref An array of property values from items from the given json array that match the given query string
    static member:jsonvalueref QueryJsonArray(jsonvalueref ref, string queryString)
    {
        if !${ref.Type.Equal[array]}
        {
            echo "JsonHelper:QueryJsonArray - First parameter should be a json array, but it is currently ${ref.Type}"
            return NULL
        }

        variable jsonvalue result = "[]"
        variable jsoniterator refIterator
        variable int tokenCount
        variable int currentTokenNumber
        variable jsonvalue currentValue
        tokenCount:Set[${queryString.Count["."]}]
        tokenCount:Inc

         
        ref:GetIterator[refIterator]

        if ${refIterator:First(exists)}
        {
            do
            {
                currentValue:SetValue["${refIterator.Value.AsJSON~}"]
                
                if ${tokenCount.Equal[1]}
                {
                    currentValue:SetValue["${currentValue.Get["${queryString}"].AsJSON~}"]
                }
                else
                {
                    

                    for(currentTokenNumber:Set[1]; ${currentTokenNumber} <= ${tokenCount}; currentTokenNumber:Inc)
                    {
                        currentValue:SetValue["${currentValue.Get["${queryString.Token[${currentTokenNumber}, "."]}"].AsJSON~}"]
                    }
                    
                }

                result:Add[${currentValue.AsJSON~}]

            }
            while ${refIterator:Next(exists)}
        }


        return result
    }

    ;;;
    ;;; Returns a jsonvalue that contains the value of the given property from the given json object or array.
    ;;; if the given jsonvalue is an array, the result will be an array of values from the given property from each item in the array
    ;;;
    ;;; for example, given the following json array:
    ;;; [
    ;;;     {"Id": 1, "Name": "Obj1", "Type": { "Name": "Obj1Type" }},
    ;;;     {"Id": 2, "Name": "Obj2", "Type": { "Name": "Obj2Type" }},
    ;;; ]
    ;;; and the query string "Type.Name", the result would be:
    ;;; [
    ;;;     "Obj1Type",
    ;;;     "Obj2Type"
    ;;; ]
    ;;; @param jsonvalueref ref - The json array to query
    ;;; @param str queryString - The query string to use to filter the array, i.e. "Id" or "Type.Name"
    ;;; @return jsonvalueref A jsonvalue that contains the value of the given property from the given json object or array.
    static member:jsonvalueref QueryJson(jsonvalueref ref, string queryString)
    {
        if ${ref.Type.Equal[array]}
        {
            return ${This.QueryJsonArray[ref, ${queryString}]}
        }
    }

    static member:jsonvalueref FilterArray(jsonvalueref ref, string queryString, string operator, string value)
    {
        if !${ref.Type.Equal[array]}
        {
            echo "JsonHelper:FilterArray - First parameter should be a json array, but it is currently ${ref.Type}"
            return NULL
        }

        variable jsonvalue result = "[]"
        variable jsoniterator refIterator
        variable int tokenCount
        variable int currentTokenNumber
        variable jsonvalue currentValue
        tokenCount:Set[${queryString.Count["."]}]
        tokenCount:Inc

         
        ref:GetIterator[refIterator]

        if ${refIterator:First(exists)}
        {
            do
            {
                if ${tokenCount.Equal[1]}
                {
                    currentValue:SetValue["${refIterator.Value.Get["${queryString}"].AsJSON~}"]
                }
                else
                {
                    currentValue:SetValue["${refIterator.Value.AsJSON~}"]

                    for(currentTokenNumber:Set[1]; ${currentTokenNumber} <= ${tokenCount}; currentTokenNumber:Inc)
                    {
                        currentValue:SetValue["${currentValue.Get["${queryString.Token[${currentTokenNumber}, "."]}"].AsJSON~}"]
                    }
                    
                }

                if ${operator.Equal["=="]}
                {
                    echo "Checking equality"
                    echo "currentValue: ${currentValue.AsString}, value: ${value}"
                    echo "${currentValue.AsString.Equal[${value}]}"
                    if ${currentValue.AsString.Equal[${value}]}
                    {
                        
                        result:Add["${refIterator.Value.AsJSON~}"]
                    }
                }
                elseif ${operator.Equal[!=]}
                {
                    if ${currentValue.NotEqual[${value}]}
                    {
                        result:Add["${refIterator.Value.AsJSON~}"]
                    }
                }
                elseif ${operator.Equal[">"]}
                {
                    if ${currentValue} > ${value}
                    {
                        result:Add["${refIterator.Value.AsJSON~}"]
                    }
                }
                elseif ${operator.Equal["<"]}
                {
                    if ${currentValue} < ${value}
                    {
                        result:Add["${refIterator.Value.AsJSON~}"]
                    }
                }
                elseif ${operator.Equal[">="]}
                {
                    if ${currentValue} >= ${value}
                    {
                        result:Add["${refIterator.Value.AsJSON~}"]
                    }
                }
                elseif ${operator.Equal["<="]}
                {
                    if ${currentValue} <= ${value}
                    {
                        result:Add["${refIterator.Value.AsJSON~}"]
                    }
                }
                else
                {
                    echo "JsonHelper:FilterArray - Second parameter should be a valid operator, but it is currently ${operator}"
                    return NULL
                }

            }
            while ${refIterator:Next(exists)}
        }

        return result
    }

    static member:bool Any(jsonvalueref ref, weakref obj, string functionName)
    {
        if !${ref.Type.Equal[array]}
        {
            echo "JsonHelper:Any - First parameter should be a json array, but it is currently ${ref.Type}"
            return NULL
        }

        variable jsoniterator iter
        ref:GetIterator[iter]

        if ${iter:First(exists)}
        {
            do
            {
                if ${obj.${functionName}[iter.Value]}
                {
                    return true
                }
            }
            while ${iter:Next(exists)}
        }
    }

    static member:jsonvalueref Map(jsonvalueref arr, weakref mapFunc)
    {
        if !${arr.Type.Equal[array]}
        {
            echo "JsonHelper:Map - First parameter should be a json array, but it is currently ${arr.Type}"
            return NULL
        }

        variable jsonvalue result
        variable jsoniterator arrIterator
        arr:GetIterator[arrIterator]

        if ${arrIterator:First(exists)}
        {
            do
            {
                echo "current: ${arrIterator.Value}, type: ${arrIterator.Value.Type}"
                result:Add["mapFunc["arrIterator.Value"]"]
            }
            while ${arrIterator:Next(exists)}
        }


        return result

    }
}
#endif


; objectdef test
; {
;     member:string MapName(jsonvalueref obj)
;     {
;         if !${obj.Type.Equal[object]}
;         {
;             echo "JsonHelper:MapName - First parameter should be a json object, but it is currently ${obj.Type}"
;             return NULL
;         }

;         if !${obj.Has[Name]}
;         {
;             echo "JsonHelper:MapName - First parameter should be a json object with a Name property, but it is currently ${obj.Type}"
;             return NULL
;         }
        
;         return ${obj.Get[Name]}
;     }

;     member:jsonvalueref testArray()
;     {
;         ; variable jsonvalue testObj

;         ; testObj:SetValue[$$>"{
;         ;     "Name": "Obj1"
;         ; }"<$$]

;         ; echo "ObjTest: ${This.MapName[testObj]}"


;         variable jsonvalue testArray

;         testArray:SetValue[$$>"[
;             {"Id": 1, "Name": "Obj1", "Type": { "Name": "Obj1Type" }},
;             {"Id": 2, "Name": "Obj2", "Type": { "Name": "Obj2Type" }},
;             {"Id": 3, "Name": "Obj3", "Type": { "Name": "Obj3Type" }}

;         ]"<$$]


;         ;echo "${MRJsonHelper.QueryJson[testArray, "Type.Name"]}"
;         ;echo "${MRJsonHelper.Map[testArray, This.MapName]}"
;         echo "${MRJsonHelper.FilterArray[testArray, "Id", "<=", 2]}"

;         ; echo ${testArray.Get[, "Name"]}


;         ; results:SetValue[${}]
;     }
; }

; function main()
; {
;     variable test testObj

;     echo ${testObj.testArray}
; }