Quantcast
local GridStatus = Grid:GetModule("GridStatus");
local GridRoster = Grid:GetModule("GridRoster");
local GridFrame = Grid:GetModule("GridFrame");
--
local MapData = LibStub("LibMapData-1.0");

local APP = "GridStatusSmartHealing";
GridStatusSmartHealing = GridStatus:NewModule(APP);
GridStatusSmartHealing.menuName = "Smart Healing - by Tirds";

-- Settings var from self.db.profile;
local Settings;
-- Timer used to measure time between updates
local Timer = 0;
-- Blank frame used to run OnUpdate
local BlankFrame = CreateFrame("Frame");
local NumEnabled = 0;

-- TODO make language files
local function L(text)
    return text;
end

GridStatusSmartHealing.defaultDB =
{
    debug = false,
    cycle = 0.2,
}
GridStatusSmartHealing.extraOptions =
{
    ["frequency"] =
    {
        order = 101,
        type = "range",
        name = "Refresh time",
        desc = "Secounds between each refresh",
        width = "full",
        min = 0.01,
        max = 2,
        step = 0.01,
        get = function()
            return GridStatusSmartHealing.db.profile.cycle;
        end,
        set = function(info, v)
            GridStatusSmartHealing.db.profile.cycle = v;
        end
    },
    --[[
    ["test"] =
    {
        name = "test",
        order = 102,
        type = "toggle",
        width = "full",
        get = function()
            return false;
        end,
        set = function()
            local asdf = GridStatus.options.args;
            print(asdf);
            for key, value in pairs(asdf) do
                print(key, " = ", value);
                if (key == APP) then
                    print("-------");
                    for key2, value2 in pairs(value) do
                        print(key2, " = ", value2);
                    end
                    print("-------");
                end
            end
        end
    }
    ]]--;
}
GridStatusSmartHealing.statusModules = {};

-- module stuff
GridStatusSmartHealing.modulePrototype = GridStatus.modulePrototype;
GridStatusSmartHealing.core = GridStatusSmartHealing;

function GridStatusSmartHealing.modulePrototype:RegisterStatus(status, desc, options, inMainMenu, order)
    GridStatus:RegisterStatus(status, desc, self.moduleName or true);


    options["enabled"] =
    {
        name = L("Enable"),
        desc = string.format(L("Enable %s"), desc),
        order = 10,
        width = "full",
        type = "toggle",
        get = function()
            return self.db.profile.enable;
        end,
        set = function(info, v)
            self.db.profile.enable = v;
            if (v) then
                if (self["OnStatusEnable"]) then
                    self:OnStatusEnable(status);
                end
            else
                if (self["OnStatusDisable"]) then
                    self:OnStatusDisable(status);
                end
            end
        end
    };
    options["color"] =
    {
        name = L("Color"),
        desc = string.format(L("Color for %s"), desc),
        order = 20,
        type = "color",
        hasAlpha = true,
        get = function()
            local color = self.db.profile.color
            return color.r, color.g, color.b, color.a
        end,
        set = function(_, r, g, b, a)
            local color = self.db.profile.color
            color.r = r
            color.g = g
            color.b = b
            color.a = a or 1
        end,
    };
    options["priority"] =
    {
        name = L("Priority"),
        desc = string.format(L("Priority for %s"), desc),
        order = 30,
        type = "range", max = 99, min = 0, step = 1,
        get = function()
            return self.db.profile.priority
        end,
        set = function(_, v)
            self.db.profile.priority = v
        end,
    };

    GridStatusSmartHealing.options.args[desc] =
    {
        type = "group",
        name = desc,
        desc = "Options for " .. desc,
        args = options,
    };
end

function GridStatusSmartHealing:OnModuleCreated(statusModule)
    statusModule.super = self.modulePrototype;

    GridStatusSmartHealing.statusModules[statusModule.name] = statusModule;
end

GridStatusSmartHealing:SetDefaultModulePrototype(GridStatusSmartHealing.modulePrototype);

function GridStatusSmartHealing:OnInitialize()
    self.super.OnInitialize(self);
    self.roster = {};------------------------

    -- Do now so modulePrototype can register Options for modules
    self:InitializeOptions();

    Settings = self.db.profile;
end

function GridStatusSmartHealing:PostEnable()
    for name, statusModule in pairs(self.statusModules) do
        if (self:Enabled(statusModule)) then
            statusModule:OnStatusEnable(nil);----------------
            NumEnabled = NumEnabled + 1;
        end
    end

    if (NumEnabled > 0) then
        self:DoEnable(true);
    end
end

function GridStatusSmartHealing:IsEnabled()
    return NumEnabled > 0;
end

function GridStatusSmartHealing:DoEnable(force)
    if (NumEnabled > 0 and not force) then
        NumEnabled = NumEnabled + 1;
        return;
    end
    GridStatus:Debug("Enabling", self.moduleName);
    self:UpdateRoster();

    self:RegisterEvent("PLAYER_MEMBERS_CHANGED", "UpdateRoster");
    self:RegisterEvent("RAID_ROSTER_UPDATE", "UpdateRoster");

    BlankFrame:SetScript("OnUpdate", function(_, timer)
        return self:OnUpdate(timer);
    end);

    if (not force) then
        NumEnabled = 1;
    end

    --
    self.state =
    {
        x = 0,
        y = 0,
        mapWidth = 0,
        mapHeight = 0,
        data = {},
    };
end

function GridStatusSmartHealing:DoDisable()
    if (NumEnabled == 0) then
        return;
    end

    NumEnabled = NumEnabled - 1;

    if (NumEnabled == 0) then
        GridStatus:Debug("Disabling", self.moduleName);
        BlankFrame:SetScript("OnUpdate", nil);
        self:UnregisterEvent("PLAYER_MEMBERS_CHANGED");
        self:UnregisterEvent("RAID_ROSTER_UPDATE");
    end
end

function GridStatusSmartHealing:ClearAll()
    for name, statusModule in pairs(self.statusModules) do
        if (self:Enabled(statusModule) and statusModule['ClearAll']) then
            statusModule:ClearAll(statusModule);
        end
    end
end

function GridStatusSmartHealing:UpdateAll()
    for name, statusModule in pairs(self.statusModules) do
        if (self:Enabled(statusModule) and statusModule['Update']) then
            statusModule:Update();
        end
    end
end

function GridStatusSmartHealing:OnUpdate(elapsed)
    Timer = Timer + elapsed;

    if (NumEnabled == 0) then
        return;
    end

    if (Timer >= Settings.cycle) then
        Timer = 0;
        --self:UpdateRoster();
        if (self:UpdateMap()) then
            self:UpdateData();
            self:UpdateAll();
        else
            self:ClearAll();
        end
    end
end

function GridStatusSmartHealing:UpdateData()
    self.state.data = {};
    self.state.x = self.state.x * self.state.mapWidth;
    self.state.y = self.state.y * self.state.mapHeight;

    for i = 1, 8 do
        for _, unitId in pairs(self.roster[i]) do
            local unitX, unitY = GetPlayerMapPosition(unitId);
            if (unitX ~= 0 or unitY ~= 0 and IsValidTarget(unitId)) then
                local health = UnitHealth(unitId);
                local maxHealth = UnitHealthMax(unitId);

                self.state.data[unitId] =
                {
                    guid = UnitGUID(unitId),
                    x = unitX * self.state.mapWidth,
                    y = unitY * self.state.mapHeight,
                    health = health,
                    maxHealth = maxHealth,
                    missingHealth = maxHealth - health,
                    percent = maxHealth / health,
                };
            end
        end
    end
end

function GridStatusSmartHealing:UpdateMap()
    self.state.x, self.state.y = GetPlayerMapPosition('player');

    if (self.state.x <= 0 or self.state.y <= 0) then
        return false;
    end

    local fileName = GetMapInfo();
    local currentLevel = GetCurrentMapDungeonLevel();

    self.state.mapWidth, self.state.mapHeight = MapData:MapArea(fileName, currentLevel);

    if (self.state.mapWidth ~= 0 and self.state.mapHeight ~= 0) then
        return true;
    end

    return false;
end

function GridStatusSmartHealing:UpdateRoster()
    self.roster = { [1] = {}, [2] = {}, [3] = {}, [4] = {}, [5] = {}, [6] = {}, [7] = {}, [8] = {} };

    local RaidMemberNum = GetNumRaidMembers();

    if (RaidMemberNum == 0) then
        tinsert(self.roster[1], "player");
        player_group = 1;
        for i = 1, 4 do
            local unitid = "party" .. i;
            if UnitExists(unitid) then
                tinsert(self.roster[1], unitid);
            end
        end
    else
        for i = 1, RaidMemberNum do
            local name, _, group = GetRaidRosterInfo(i);
            local unitid = "raid" .. i;
            if (name and UnitExists(unitid)) then
                tinsert(self.roster[group], unitid)
                if (UnitIsUnit("player", unitid)) then
                    player_group = group;
                end
            end
        end
    end
end

function GridStatusSmartHealing:Enabled(statusModule)
    return statusModule.db.profile.enable;
end

function GridStatusSmartHealing:Distance(p1, p2)
    local x = p2.x - p1.x;
    local y = p2.y - p1.y;
    return x*x + y*y;
end

function GridStatusSmartHealing:HasGlyph(glyph_id)
    for i = 1, 9 do
        local _, _, _, id = GetGlyphSocketInfo(i);
        if (id and glyph_id == id) then
            return true;
        end
    end
    return false;
end

function GridStatusSmartHealing:IsValidHealTarget(unitId)
    return not UnitIsDeadOrGhost(unitId) and
        UnitIsConnected(unitId) and
        UnitIsVisible(unitId) and
        not (UnitIsCharmed(unitId) and UnitIsEnemy("player", unitId));
end