Quantcast
--[[
##############################################################################
_____/\\\\\\\\\\\____/\\\________/\\\__/\\\________/\\\__/\\\\\\\\\\\_       #
 ___/\\\/////////\\\_\/\\\_______\/\\\_\/\\\_______\/\\\_\/////\\\///__      #
  __\//\\\______\///__\//\\\______/\\\__\/\\\_______\/\\\_____\/\\\_____     #
   ___\////\\\__________\//\\\____/\\\___\/\\\_______\/\\\_____\/\\\_____    #
    ______\////\\\________\//\\\__/\\\____\/\\\_______\/\\\_____\/\\\_____   #
     _________\////\\\______\//\\\/\\\_____\/\\\_______\/\\\_____\/\\\_____  #
      __/\\\______\//\\\______\//\\\\\______\//\\\______/\\\______\/\\\_____ #
       _\///\\\\\\\\\\\/________\//\\\________\///\\\\\\\\\/____/\\\\\\\\\\\_#
        ___\///////////___________\///___________\/////////_____\///////////_#
##############################################################################
S U P E R - V I L L A I N - U I   By: Munglunch                              #
##############################################################################
##########################################################
LOCALIZED LUA FUNCTIONS
##########################################################
]]--
--[[ GLOBALS ]]--
local _G = _G;
local unpack    = _G.unpack;
local select    = _G.select;
local pairs     = _G.pairs;
local type      = _G.type;
local rawset    = _G.rawset;
local rawget    = _G.rawget;
local tinsert   = _G.tinsert;
local tremove   = _G.tremove;
local string    = _G.string;
local table     = _G.table;
--[[ STRING METHODS ]]--
local format = string.format;
--[[ TABLE METHODS ]]--
local tdump = table.dump;
--[[ MUNGLUNCH's FASTER ASSERT FUNCTION ]]--
local assert = enforce;
--[[
##########################################################
GET ADDON DATA
##########################################################
]]--
local SuperVillain, L = unpack(select(2, ...));
local MAJOR = "SuperVillain Plugins";
local MINOR = GetAddOnMetadata(..., "Version");

local INFO_BY = "%s by %s";
local INFO_VERSION = "%s%s - Version: %d";
local INFO_NEW = "%s (Newest: %d)";
local INFO_NAME = "Plugins";
local INFO_HEADER = "SuperVillain UI (version %.3f): Plugins";

if GetLocale() == "ruRU" then
    INFO_BY = "%s от %s";
    INFO_VERSION = "%s%s - Версия: %d";
    INFO_NEW = "%s (Последняя: %d)";
    INFO_NAME = "Плагины";
    INFO_HEADER = "SuperVillain UI (устарела %.3f): Плагины";
end

local function SetPrototype(obj)
    obj.db = {}
    obj._loaded = false
    obj.CombatLocked = false
    obj.ChangeDBVar = function(obj, value, key, sub1, sub2, sub3)
        if((sub1 and sub2 and sub3) and (obj.db[sub1] and obj.db[sub1][sub2] and obj.db[sub1][sub2][sub3])) then
            obj.db[sub1][sub2][sub3][key] = value;
            SuperVillain.db[obj._name][sub1][sub2][sub3][key] = value;
        elseif((sub1 and sub2) and (obj.db[sub1] and obj.db[sub1][sub2])) then
            obj.db[sub1][sub2][key] = value;
            SuperVillain.db[obj._name][sub1][sub2][key] = value;
        elseif(sub1 and obj.db[sub1]) then
            obj.db[sub1][key] = value;
            SuperVillain.db[obj._name][sub1][key] = value;
        else
            obj.db[key] = value;
            SuperVillain.db[obj._name][key] = value;
        end
    end
    obj.Protect = function(obj, fnKey, autorun)
        SuperVillain.Security:Register(obj, fnKey, autorun);
    end
    obj.UnProtect = function(obj, fnKey)
        SuperVillain.Security:UnRegister(obj, fnKey);
    end
    obj.RegisterEvent = function(obj, eventname, eventfunc)
        if not obj.___eventframe then
            obj.___eventframe = CreateFrame("Frame", nil)
            obj.___eventframe:SetScript("OnEvent", function(self, event, ...)
                if self[event] and type(self[event]) == "function" then
                    self[event](obj, event, ...)
                end
            end)
        end
        local fn = eventfunc
        if type(eventfunc) == "string" then
            fn = obj[eventfunc]
        elseif(not fn and obj[eventname]) then
            fn = obj[eventname]
        end
        obj.___eventframe[eventname] = fn
        obj.___eventframe:RegisterEvent(eventname)
    end
    obj.UnregisterEvent = function(obj, event, func)
        if(obj.___eventframe) then
            obj.___eventframe:UnregisterEvent(event)
        end
    end
    return obj
end
--[[
##########################################################
REGISTRY MASTER METATABLE
##########################################################
]]--
local metapackage = {
    __index = function(t, k)
        return SuperVillain.db[t.dbKey][k]
    end,
}
local addontostring = function(t)
    return t._name
end
local _queue = {{},{},{},{}}
local METAREGISTRY = function()
    local methods = {
        _model = {plugin = {}, callback = {}},
        _loadDB = function(_, name)
            return setmetatable( {dbKey = name}, metapackage )
        end,
        _loadPkg = function(_, priority)
            if not _queue[priority] then return end;
            local pkgList = _queue[priority]
            for i=1,#pkgList do
                local name = pkgList[i]
                local obj = _._model[name]
                if obj and not obj._loaded then
                    if SuperVillain.db[name] then
                        obj.db = _:_loadDB(name)
                    end
                    if obj.Load then
                        obj:Load()
                        obj.Load = nil
                    end
                    obj._loaded = true;
                end
            end
        end,
        Expose = function(_, name)
            return _._model[name] or false
        end,
        SetCallback = function(_, fn)
            if(fn and type(fn) == "function") then
                _._model.callback[#_._model.callback + 1] = fn
            end
        end,
        NewScript = function(_, fn)
            if(fn and type(fn) == "function") then
                local i = #_queue[4]
                _queue[4][i + 1] = fn
            end
        end,
        NewPackage = function(_, obj, name, priority)
            if _._model[name] then return end
            obj._name = name
            if(priority == "pre") then
                tinsert(_queue[1], name)
            elseif(priority == "post") then
                tinsert(_queue[3], name)
            else
                tinsert(_queue[2], name)
            end

            local addonmeta = {}
            local oldmeta = getmetatable(obj)
            if oldmeta then
                for k, v in pairs(oldmeta) do addonmeta[k] = v end
            end
            addonmeta.__tostring = addontostring

            setmetatable( obj, addonmeta )
            _._model[name] = SetPrototype(obj)

            if(SuperVillain.CoreEnabled) then
                if(_._model[name].Load) then
                    _._model[name]:Load()
                end
            end
        end,
        FetchPlugins = function(_)
            local list = "";
            for _, plugin in pairs(_._model.plugin) do
                if plugin.name ~= MAJOR then
                    local author = GetAddOnMetadata(plugin.name, "Author")
                    local Pname = GetAddOnMetadata(plugin.name, "Title") or plugin.name
                    local color = plugin.old and SuperVillain:HexColor(1,0,0) or SuperVillain:HexColor(0,1,0)
                    list = list .. Pname
                    if author then
                      list = INFO_BY:format(list, author)
                    end
                    list = INFO_VERSION:format(list, color, plugin.version)
                    if plugin.old then
                      list = INFO_NEW:format(list, plugin.newversion)
                    end
                    list = ("%s|r\n"):format(list)
                end
            end
            return list
        end,
        NewPlugin = function(_, name, func)
            local plugin = _._model.plugin[name] or {}
            plugin.name = name
            plugin.version = name == MAJOR and MINOR or GetAddOnMetadata(name, "Version")
            plugin.callback = func
            local enable, loadable = select(4,GetAddOnInfo("SVUI_ConfigOMatic"))
            local loaded = IsAddOnLoaded("SVUI_ConfigOMatic")
            if(enable and loadable and not loaded) then
                if not plugin.PluginTempFrame then
                    local tempframe = CreateFrame("Frame")
                    tempframe:RegisterEvent("ADDON_LOADED")
                    tempframe:SetScript("OnEvent", function(self, event, addon)
                        if addon == "SVUI_ConfigOMatic" then
                            for i, plugin in pairs(_._model.plugin) do
                                if(plugin.callback) then
                                    plugin.callback()
                                end
                            end
                        end
                    end)
                    plugin.PluginTempFrame = tempframe
                end
            elseif(enable and loadable) then
                if name ~= MAJOR then
                    SuperVillain.Options.args.plugins.args.pluginlist.name = _:FetchPlugins()
                end
                if(func) then
                    func()
                end
            end
            _._model.plugin[name] = plugin
        end,
        RunCallbacks = function(_)
            for i=1, #_._model.callback do
                local fn = _._model.callback[i]
                if(fn and type(fn) == "function") then
                    fn()
                end
            end
        end,
        Update = function(_, name, dataOnly)
            local obj = _._model[name]
            if obj then
                if obj.ReLoad and not dataOnly then
                    obj:ReLoad()
                end
            end
        end,
        UpdateAll = function(_)
            local pkgList = _._model
            for name,obj in pairs(pkgList) do
                local name = obj._name
                if obj and obj.ReLoad then
                    obj:ReLoad()
                end
            end
        end,

        --construct stored classes

        Lights = function(_)
            _:_loadPkg(1)
        end,
        Camera = function(_)
            _:_loadPkg(2)
            _:_loadPkg(3)
        end,
        Action = function(_)
            local count = #_queue[4]
            for i=1, count do
                local fn = _queue[4][i]
                if(fn and type(fn) == "function") then
                    fn()
                end
            end
            _queue = nil
        end,
    };
    local mt = {
        __tostring = function(t) return "SuperVillain.Registry >>> ACCESS DENIED" end,
    };
    setmetatable(methods,  mt)
    return methods
end;
do
    SuperVillain.Registry = METAREGISTRY();
end;
--[[
##########################################################
LIB FUNCTIONS
##########################################################
]]--
local GetOptions = function()
    SuperVillain.Options.args.plugins = {
        order = -10,
        type = "group",
        name = INFO_NAME,
        guiInline = false,
        args = {
            pluginheader = {
                order = 1,
                type = "header",
                name = format(INFO_HEADER, MINOR),
            },
            pluginlist = {
                order = 2,
                type = "description",
                name = SuperVillain.Registry:FetchPlugins(),
            },
        }
    }
end;

SuperVillain.Registry:NewPlugin("SuperVillain Plugins", GetOptions)