#include "${LavishScript.HomeDirectory}/Scripts/mr/common/StringHelpers.iss"

variable jsonvalue stealthRequiredEffects = "[ \"I need to be stealthed!\", \"You must be in stealth to use this!\", \"You must be sneaking to use this ability.\"]"
variable jsonvalue flankingRequiredEffects = "[ \"Must be flanking or behind\" ]"
variable jsonvalue noEpicEffects = "[ \"Does not affect Epic targets\"]"
variable jsonvalue interruptEffects = "[ \"Interrupts target\" ]"
variable jsonvalue stunEffects = "[ \"Stuns target\" ]"

function:bool matchesItemInArray(jsonvalueref arr, string val)
{

    if !${arr.Type.Equal[array]}
    {
        echo "effects is not an array ${arr.Type}"
        return FALSE
    }

    
    variable jsoniterator iter
    arr:GetIterator[iter]

    if ${iter:First(exists)}
    {
        do
        {
            if ${val.Equal["${iter.Value}"]}
            {
                return TRUE
            }
        }
        while ${iter:Next(exists)}
    }

    return FALSE
}

function:bool hasMatchingEffect(jsonvalueref effects, jsonvalueref specialEffects)
{
    if !${effects.Type.Equal[array]}
    {
        echo "effects is not an array ${effects.Type}"
        return FALSE
    }
   
    variable jsoniterator effectIterator
    effects:GetIterator[effectIterator]

    if ${effectIterator:First(exists)}
    {
        do
        {
           call matchesItemInArray specialEffects "${effectIterator.Value.Get["description"]}"
           if ${Return}
           {
               return TRUE
           }
        }
        while ${effectIterator:Next(exists)}
    }

    return FALSE
}

function:jsonvalueref extractDamageFromEffect(jsonvalueref effectJo)
{
    variable string description
    description:Set["${effectJo.Get["description"]}"]


    if ${description.Left[8].NotEqual["Inflicts"]}
    {
       return "{}"
    }

    variable int64 minDamage
    variable int64 maxDamage
    variable string damageType

    minDamage:Set["${description.Token[2, " "].Replace[",", ""]}"]
    if ${description.Token[3, " "].Equal["-"]}
    {
        maxDamage:Set["${description.Token[4, " "].Replace[",", ""]}"]
        damageType:Set["${description.Token[5, " "]}"]
    }
    else
    {
        maxDamage:Set["${description.Token[2, " "].Replace[",", ""]}"]
        damageType:Set["${description.Token[3, " "]}"]
    }

    variable jsonvalue damage
    damage:SetValue["$$>{
        "type": "${damageType}",
        "min": ${minDamage},
        "max": ${maxDamage}
    }<$$"]
    
    if !${damageType(exists)}
    {
        echo "huh?: ${description}"
    }

    return ${damage.AsJSON~}
}

function main()
{
    variable index:ability MyAbilities
    variable iterator MyAbilitiesIterator
    
    variable jsonvalue abilityList = "{}"
    variable jsonvalue currentAbility = {}
    variable jsonvalue effects = []
    variable jsonvalue abilityEffect = {}
    
    variable string abilityLineName
    variable int idx = 1
    variable int Counter = 1
    variable int Timer = 0
    

        
    Me:QueryAbilities[MyAbilities]
    MyAbilities:GetIterator[MyAbilitiesIterator]
 
    if ${MyAbilitiesIterator:First(exists)}
    {
        do
        {
            if (!${MyAbilitiesIterator.Value.IsAbilityInfoAvailable})
            {
                do
                {
                    wait 2
                }
                while (!${MyAbilitiesIterator.Value.IsAbilityInfoAvailable} && ${Timer:Inc} < 1500)
            }

            wait 5
            echo "Exporting (${Counter} / ${MyAbilities.Used}) - ${MyAbilitiesIterator.Value.ToAbilityInfo.Name} (ID: ${MyAbilitiesIterator.Value.ID})"

            currentAbility:SetValue["$$>{
                "id": ${MyAbilitiesIterator.Value.ID},
                "name": "${MyAbilitiesIterator.Value.ToAbilityInfo.Name}",
                "description": ${MyAbilitiesIterator.Value.ToAbilityInfo.Description.AsJSON~},
                "level": ${MyAbilitiesIterator.Value.ToAbilityInfo.Class[${Me.SubClass}].Level},
                "tier": "${MyAbilitiesIterator.Value.ToAbilityInfo.Tier}",
                "healthCost": ${MyAbilitiesIterator.Value.ToAbilityInfo.HealthCost},
                "powerCost": ${MyAbilitiesIterator.Value.ToAbilityInfo.PowerCost},
                "dissonanceCost": ${MyAbilitiesIterator.Value.ToAbilityInfo.DissonanceCost},
                "savageryCost": ${MyAbilitiesIterator.Value.ToAbilityInfo.SavageryCost},
                "concentrationCost": ${MyAbilitiesIterator.Value.ToAbilityInfo.ConcentrationCost},
                "mainIconID": ${MyAbilitiesIterator.Value.ToAbilityInfo.MainIconID},
                "hoIconID": ${MyAbilitiesIterator.Value.ToAbilityInfo.HOIconID},
                "castingTime": ${MyAbilitiesIterator.Value.ToAbilityInfo.CastingTime},
                "recoveryTime": ${MyAbilitiesIterator.Value.ToAbilityInfo.RecoveryTime},
                "recastTime": ${MyAbilitiesIterator.Value.ToAbilityInfo.RecastTime},
                "maxDuration": ${MyAbilitiesIterator.Value.ToAbilityInfo.MaxDuration},
                "numClasses": ${MyAbilitiesIterator.Value.ToAbilityInfo.NumClasses},
                "numEffects": ${MyAbilitiesIterator.Value.ToAbilityInfo.NumEffects},
                "backDropIconID": ${MyAbilitiesIterator.Value.ToAbilityInfo.BackDropIconID},
                "healthCostPerTick": ${MyAbilitiesIterator.Value.ToAbilityInfo.HealthCostPerTick},
                "powerCostPerTick": ${MyAbilitiesIterator.Value.ToAbilityInfo.PowerCostPerTick},
                "dissonanceCostPerTick": ${MyAbilitiesIterator.Value.ToAbilityInfo.DissonanceCostPerTick},
                "savageryCostPerTick": ${MyAbilitiesIterator.Value.ToAbilityInfo.SavageryCostPerTick},
                "maxAOETargets": ${MyAbilitiesIterator.Value.ToAbilityInfo.MaxAOETargets},
                "isBeneficial": "${MyAbilitiesIterator.Value.ToAbilityInfo.IsBeneficial.AsJSON}",
                "doesNotExpire": "${MyAbilitiesIterator.Value.ToAbilityInfo.DoesNotExpire.AsJSON}",
                "groupRestricted": "${MyAbilitiesIterator.Value.ToAbilityInfo.GroupRestricted.AsJSON}",
                "allowRaid": "${MyAbilitiesIterator.Value.ToAbilityInfo.AllowRaid.AsJSON}",
                "effectRadius": ${MyAbilitiesIterator.Value.ToAbilityInfo.EffectRadius},
                "targetType": ${MyAbilitiesIterator.Value.ToAbilityInfo.TargetType},
                "spellBookType": ${MyAbilitiesIterator.Value.ToAbilityInfo.SpellBookType},
                "minRange": ${MyAbilitiesIterator.Value.ToAbilityInfo.MinRange},
                "maxRange": ${MyAbilitiesIterator.Value.ToAbilityInfo.MaxRange}
            }<$$"]



            for (idx:Set[1] ; ${idx} < ${MyAbilitiesIterator.Value.ToAbilityInfo.NumEffects} ; idx:Inc )
            {
                abilityEffect:SetValue["$$>{
                    "percentSuccess": ${MyAbilitiesIterator.Value.ToAbilityInfo.Effect[${idx}].PercentSuccess.AsJSON~},
                    "indentation": "${MyAbilitiesIterator.Value.ToAbilityInfo.Effect[${idx}].Indentation.AsJSON~}",
                    "description": ${MyAbilitiesIterator.Value.ToAbilityInfo.Effect[${idx}].Description.AsJSON~}
                }<$$"]

                effects:Add["${abilityEffect.AsJSON~}"]
                call matchesItemInArray stealthRequiredEffects ${abilityEffect.Get["description"]}
                if ${Return}
                {
                    currentAbility:Set["requiresStealth", ${Return.AsJSON~}]
                }

                call matchesItemInArray flankingRequiredEffects  ${abilityEffect.Get["description"]}
                if ${Return}
                {
                    currentAbility:Set["requiresFlanking", ${Return.AsJSON~}]
                }

                call matchesItemInArray noEpicEffects ${abilityEffect.Get["description"]}
                if ${Return}
                {
                    currentAbility:Set["noEpic", ${Return.AsJSON~}]
                }

                call matchesItemInArray stunEffects ${abilityEffect.Get["description"]}
                if ${Return}
                {
                    currentAbility:Set["stuns", ${Return.AsJSON~}]
                }

                call matchesItemInArray interruptEffects ${abilityEffect.Get["description"]}
                if ${Return}
                {
                    currentAbility:Set["interrupts", ${Return.AsJSON~}]
                }
                
                call extractDamageFromEffect abilityEffect
                if ${Return.Get["type"](exists)}
                {
                    variable string damageType
                    variable int64 minDamage

                    ; TODO: Add a loop to handle multiple damage effects.
                    ; TODO: Modify extractDmaageFromEffect to also calculate damage for
                    ;       damage over time effects.
                    damageType:Set["${Return.Get["type"]}"]
                    minDamage:Set["${Return.Get["min"]}"]

                    currentAbility:Set["doesDamage", TRUE]
                    if ${currentAbility.Has["damage", "${Return.Get["type"]}"]}
                    {
                        variable int64 currentMinDamageTotal

                        currentMinDamageTotal:Set["${currentAbility.Get["damage", ${damageType}]}"]
                        currentMinDamageTotal:Inc[${minDamage}]
                        
                        currentAbility.Get["damage", ${damageType}]:Set[${currentMinDamageTotal}]
                    }
                    else
                    {
                        if ${currentAbility.Has["damage"]}
                        {
                            currentAbility.Get["damage"]:Set["${damageType}", "${minDamage}"]
                        }
                        else
                        {
                            currentAbility:Set["damage", "$$>{
                                "${damageType}": ${minDamage},
                            }<$$"]
                        }
                    }
                }

                abilityEffect:Clear
            }

                

            currentAbility:Set["effects", "${effects.AsJSON~}"]
            effects:Clear

            abilityLineName:Set["${MRStringHelpers.StripRomanNumerals[${currentAbility.Get["name"]}]}"]
            if !${abilityList.Has["${abilityLineName}"]}
            {
                abilityList:Set["${abilityLineName}", "[${currentAbility.AsJSON~}]"]
            }
            else
            {
                abilityList.Get["${abilityLineName}"]:Add["${currentAbility.AsJSON~}"]
            }

            
            
            Counter:Inc
            Timer:Set[0]
        }
        while ${MyAbilitiesIterator:Next(exists)}
    }
    
    abilityList:WriteFile["${LavishScript.HomeDirectory}/Scripts/mr/bot/ability_exports/${Me.Name}_${Me.SubClass}.json", multiline]
}


