Quantcast
local GridStatus = Grid:GetModule("GridStatus");
local GridRoster = Grid:GetModule("GridRoster");
local SmartHealing = GridStatus:GetModule("GridStatusSmartHealing");

local GridStatusSmartHealing_ChainHeal = SmartHealing:NewModule("GridStatusSmartHealing_ChainHeal", "AceEvent-3.0");

local CenterTextOptions =
{
    bestTarget = "Best Target #",
    estimatedHeal = "Total Estimated Heal"
};

GridStatusSmartHealing_ChainHeal.defaultDB =
{
    enable = false,
    color = { r = 0, g = 0, b = 1, a = 1 },
    priority = 50,
    --
    minjumps = 2,
    color2 = { r = 0, g = 0.5, b = 1, a = 1 },
    maxTargets = 25,
    centerTextOption = "bestTarget",
}

local options =
{
    ["minjumps"] =
    {
        order = 100,
        type = "range",
        name = "Min Jumps",
        desc = "Threshold for a target to have, before it shows.",
        min = 0,
        max = 3,
        step = 1,
        width = "full",
        get = function()
            return GridStatusSmartHealing_ChainHeal.db.profile.minjumps;
        end,
        set = function(info, v)
            GridStatusSmartHealing_ChainHeal.db.profile.minjumps = v;
            GridStatusSmartHealing_ChainHeal:ClearAll();
            GridStatusSmartHealing_ChainHeal:RefreshAll();
        end
    },
    ["color2"] =
    {
        order = 21,
        type = "color",
        name = "Color x2",
        desc = string.format("Color for Chain Heal x2", desc),
        hasAlpha = true,
        get = function()
            local color = GridStatusSmartHealing_ChainHeal.db.profile.color2;
            return color.r, color.g, color.b, color.a;
        end,
        set = function(info, r, g, b, a)
            local color = GridStatusSmartHealing_ChainHeal.db.profile.color2;
            color.r = r;
            color.g = g;
            color.b = b;
            color.a = a or 1;
        end,
    },
    ["maxTargets"] =
    {
        order = 110,
        type = "range",
        name = "Max Status Targets",
        desc = "Max number of targets to show",
        min = 1,
        max = 40,
        step = 1,
        width = "full",
        get = function()
            return GridStatusSmartHealing_ChainHeal.db.profile.maxTargets;
        end,
        set = function(info, v)
           GridStatusSmartHealing_ChainHeal.db.profile.maxTargets = v;
           GridStatusSmartHealing_ChainHeal:ClearAll();
           GridStatusSmartHealing_ChainHeal:RefreshAll();
        end,
    },
    ["centerTextOption"] =
    {
        order = 120,
        type = "select",
        name = "Center Text Option",
        desc = "What center text will display (if selected in indicators)",
        values = CenterTextOptions,
        style = "radio",
        get = function()
            return GridStatusSmartHealing_ChainHeal.db.profile.centerTextOption;
        end,
        set = function(info, v)
            GridStatusSmartHealing_ChainHeal.db.profile.centerTextOption = v;
            GridStatusSmartHealing_ChainHeal:ClearAll();
            GridStatusSmartHealing_ChainHeal:RefreshAll();
        end,
    }
}

local thisStatus = "alert_gssh_chainheal";

local chainHealGlyph = 55437;

function GridStatusSmartHealing_ChainHeal:PostInitialize()
    SmartHealing:RegisterStatus(self, thisStatus, "Smart Healing - Chain Heal", options, false);

    Settings = self.db.profile;
end

function GridStatusSmartHealing_ChainHeal:OnStatusEnable(status)
    SmartHealing:DoEnable();

    self.spellInfo =
    {
        healingPower = nil,
        crit = nil,
        --sparkOfLife = nil,
        restoSpec = nil,
        --chGlyph = false,
        coef = 1,
    };
    self.chainHeal =
    {
        distance = 12.5^2,       -- square yards
        -- non-talented
        coef = 0.3535,          -- http://elitistjerks.com/f79/t121202-resto_raiding_4_1_updating_4_3_a/
        base = 3515,
        -- added by UpdateCoefs
        jumps = {},
    };

    self:RegisterEvent('PLAYER_EQUIPMENT_CHANGED', 'UpdateCoefs');
    self:RegisterEvent('PLAYER_TALENT_UPDATE', 'UpdateCoefs');
    -- skip for now.
    --self:RegisterEvent('UNIT_AURA', 'UpdateAuraCoefs');

    self:RefreshAll();
end

function GridStatusSmartHealing_ChainHeal:OnStatusDisable(status)
    SmartHealing:DoDisable();

    self:UnregisterEvent('PLAYER_EQUIPMENT_CHANGED');
    self:UnregisterEvent('PLAYER_TALENT_UPDATE');
    self:ClearAll();
end

function GridStatusSmartHealing_ChainHeal:ClearAll()
    self.core:SendStatusLostAllUnits(thisStatus);
end

function GridStatusSmartHealing_ChainHeal:RefreshAll()
    self:UpdateCoefs(nil, nil);
end

function GridStatusSmartHealing_ChainHeal:Update()
    self:ClearAll();

    -- all players missing health
    local deficits = {};

    for guid, unitId in GridRoster:IterateRoster() do
        local info = SmartHealing:GetUnitInfo(guid);
        -- if info == nil, probably a pet.
        if (info ~= nil and unitId and info.missingHealth > 0 and SmartHealing:IsValidHealTarget(unitId)) then
            table.insert(deficits, info);
        end
    end

    -- sort highest missing health first
    table.sort(deficits, function(a, b)
        return a.missingHealth > b.missingHealth;
    end);

    -- Chain Heal Paths
    local paths = {};
    local numDeficits = #deficits;

    self:Debug("NumDeficts", numDeficits);

    for i = 1, numDeficits do
        local curUnit = deficits[i];
        --[[
        local unitDistance = SmartHealing:Distance(SmartHealing.state, curUnit);
        if (UnitInRange(curUnit.unitId)) then
        end
        ]]--
        -- TotalHeal that can be made
        curUnit.totalHeal = curUnit.missingHealth;
        curUnit.jumps = {};
        -- targets are other units jumped to
        curUnit.targets = {};

        -- TODO count for earth shield..
        -- TODO count for riptide
        curUnit.jumps[1] = (self.chainHeal.jumps[1] > curUnit.missingHealth) and curUnit.missingHealth or self.chainHeal.jumps[1];

        -- now find who we can jump to
        for x = 1, numDeficits do
            -- cant jump to self : )
            if (i ~= x) then
                local curUnit2 = deficits[x];
                local distance = SmartHealing:Distance(curUnit, curUnit2);
                local jump = #curUnit.jumps + 1;
                if (jump > 4) then
                    break;
                end
                if (distance and distance <= self.chainHeal.distance) then
                    curUnit.jumps[jump] = (self.chainHeal.jumps[jump] > curUnit2.missingHealth) and curUnit2.missingHealth or self.chainHeal.jumps[jump];
                    curUnit.totalHeal = curUnit.totalHeal + curUnit.jumps[jump];
                    -- add curUnit2 to targets
                    table.insert(curUnit.targets, curUnit2);
                end
            end
        end

        if (curUnit and curUnit.jumps and #curUnit.jumps >= (Settings.minjumps + 1)) then
            table.insert(paths, curUnit);
        end
    end

    table.sort(paths, function(a, b)
        return a.totalHeal > b.totalHeal;
    end);

    self:Debug("Paths found: ", #paths);

    if (#paths == 0) then
        return;
    end

    for i, path in pairs(paths) do
        if (i > Settings.maxTargets) then
            return;
        end

        local text = '';
        if (Settings.centerTextOption == "bestTarget") then
            text = string.format("#%s", i);
        else
            text = string.format("^%.1fk", path.totalHeal / 1000);
            --text = path.totalHeal;
        end

        self.core:SendStatusGained(path.guid, thisStatus, Settings.priority, nil, i == 1 and Settings.color or Settings.color2, string.format("%s", text), 1, nil, nil);
    end
end

function GridStatusSmartHealing_ChainHeal:UpdateCoefs(e, ...)
    self.spellInfo.healingPower = GetSpellBonusHealing();
    self.spellInfo.crit = GetSpellCritChance(2);
    self.spellInfo.restoSpec = GetSpecialization() == 3;
    --self.spellInfo.restoSpec = GetSpecialization()

    local _, _, _, _, spark = GetTalentInfo(3, 3);

    -- 2%, 4%, 6% -- 3 differnt ranks
    -- spark = 1-3
    --self.spellInfo.sparkOfLife = (spark * 2) / 100;
    --self.spellInfo.chGlyph = SmartHealing:HasGlyph(ChainHealGlyph);

    if (self.spellInfo.restoSpec) then
        self.spellInfo.coef = 1 + 0.25;
    end

    -- jump1 really isnt a jump its the main target.
    local jump1, jump2, jump3, jump4;

    --[[
    if (self.spellInfo.chGlyph) then
        local coef = self.spellInfo.coef - 0.10;
        jump1 = (self.chainHeal.base + self.spellInfo.healingPower * self.chainHeal.coef) * coef;
        jump2 = (jump1 * 0.70) * 1.15;
        jump3 = (jump2 * 0.70) * 1.15;
        jump4 = (jump3 * 0.70) * 1.15;
    else
    ]]--
    jump1 = (self.chainHeal.base + self.spellInfo.healingPower * self.chainHeal.coef) * self.spellInfo.coef;
    jump2 = (jump1 * 0.70);
    jump3 = (jump2 * 0.70);
    jump4 = (jump3 * 0.70);
    --end

    self.chainHeal.jumps[1] = jump1;
    self.chainHeal.jumps[2] = jump2;
    self.chainHeal.jumps[3] = jump3;
    self.chainHeal.jumps[4] = jump4;
end