Quantcast
--[[
##############################################################################
_____/\\\\\\\\\\\____/\\\________/\\\__/\\\________/\\\__/\\\\\\\\\\\_       #
 ___/\\\/////////\\\_\/\\\_______\/\\\_\/\\\_______\/\\\_\/////\\\///__      #
  __\//\\\______\///__\//\\\______/\\\__\/\\\_______\/\\\_____\/\\\_____     #
   ___\////\\\__________\//\\\____/\\\___\/\\\_______\/\\\_____\/\\\_____    #
    ______\////\\\________\//\\\__/\\\____\/\\\_______\/\\\_____\/\\\_____   #
     _________\////\\\______\//\\\/\\\_____\/\\\_______\/\\\_____\/\\\_____  #
      __/\\\______\//\\\______\//\\\\\______\//\\\______/\\\______\/\\\_____ #
       _\///\\\\\\\\\\\/________\//\\\________\///\\\\\\\\\/____/\\\\\\\\\\\_#
        ___\///////////___________\///___________\/////////_____\///////////_#
##############################################################################
S U P E R - V I L L A I N - U I   By: Munglunch                              #
############################################################################## ]]--
--[[ 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 tostring      = _G.tostring;
local error         = _G.error;
local getmetatable  = _G.getmetatable;
local setmetatable  = _G.setmetatable;
local string    = _G.string;
local math      = _G.math;
local table     = _G.table;
--[[ STRING METHODS ]]--
local upper = string.upper;
local format, find, match, gsub = string.format, string.find, string.match, string.gsub;
--[[ MATH METHODS ]]--
local floor = math.floor
--[[ TABLE METHODS ]]--
local twipe, tsort, tconcat = table.wipe, table.sort, table.concat;

--[[ LOCALS ]]--

local SVUINameSpace, SVUICore = ...;
local SVUIVersion = GetAddOnMetadata(..., "Version");
local clientVersion, internalVersion, releaseDate, uiVersion = GetBuildInfo();
local callbacks = {};
local numCallbacks = 0;
local playerClass = select(2,UnitClass("player"));
local dumb = function() return end

local messagePattern = "|cffFF2F00%s:|r"
local debugPattern = "|cffFF2F00%s|r [|cff992FFF%s|r]|cffFF2F00:|r"
local PLUGIN_LISTING = "";
local ModuleQueue, ScriptQueue = {},{};

local INFO_BY = "%s |cff0099FFby %s|r";
local INFO_VERSION = "%s%s |cff33FF00Version: %s|r";
local INFO_NAME = "Plugins";
local INFO_HEADER = "Supervillain UI (version %.3f): Plugins";

if GetLocale() == "ruRU" then
    INFO_BY = "%s |cff0099FFот %s|r";
    INFO_VERSION = "%s%s |cff33FF00Версия: %s|r";
    INFO_NAME = "Плагины";
    INFO_HEADER = "Supervillain UI (устарела %.3f): Плагины";
end

local actualWidth, actualHeight = UIParent:GetSize()

--[[  CONSTANTS ]]--

BINDING_HEADER_SVUI = "Supervillain UI";
SLASH_RELOADUI1 = "/rl"
SLASH_RELOADUI2 = "/reloadui"
SlashCmdList.RELOADUI = ReloadUI

--[[ MUNGLUNCH's FASTER ASSERT FUNCTION ]]--

function enforce(condition, ...)
   if not condition then
      if next({...}) then
         local fn = function (...) return(string.format(...)) end
         local s,r = pcall(fn, ...)
         if s then
            error("Error!: " .. r, 2)
         end
      end
      error("Error!", 2)
   end
end
local assert = enforce;

--[[ META METHODS ]]--

local rootstring = function(self) return self.___addonName end

--[[ ENSURE META METHODS ]]--

local function SaveMetaMethods(obj)
    local mt = {}
    local old = getmetatable(obj)
    if old then
        for k, v in pairs(old) do mt[k] = v end
    end
    mt.__tostring = rootstring
    setmetatable(obj, mt)
end

--[[ LOCALIZATION HELPERS ]]--

local failsafe = function() assert(false) end

local metaread = {
    __index = function(self, key)
        rawset(self, key, key)
        return key
    end
}

local activeLocale

local defaultwrite = setmetatable({}, {
    __newindex = function(self, key, value)
        if not rawget(activeLocale, key) then
            rawset(activeLocale, key, value == true and key or value)
        end
    end,
    __index = failsafe
})

local metawrite = setmetatable({}, {
    __newindex = function(self, key, value)
        rawset(activeLocale, key, value == true and key or value)
    end,
    __index = failsafe
})

local Localization = setmetatable({}, metaread);

--[[ CLASS COLOR LOCALS ]]--

local function formatValueString(text)
    if "string" == type(text) then
        text = gsub(text,"\n","\\n")
        if match(gsub(text,"[^'\"]",""),'^"+$') then
            return "'"..text.."'";
        else
            return '"'..gsub(text,'"','\\"')..'"';
        end
    else
        return tostring(text);
    end
end

local function formatKeyString(text)
    if "string"==type(text) and match(text,"^[_%a][_%a%d]*$") then
        return text;
    else
        return "["..formatValueString(text).."]";
    end
end

local function RegisterCallback(self, m, h)
    assert(type(m) == "string" or type(m) == "function", "Bad argument #1 to :RegisterCallback (string or function expected)")
    if type(m) == "string" then
        assert(type(h) == "table", "Bad argument #2 to :RegisterCallback (table expected)")
        assert(type(h[m]) == "function", "Bad argument #1 to :RegisterCallback (m \"" .. m .. "\" not found)")
        m = h[m]
    end
    callbacks[m] = h or true
    numCallbacks = numCallbacks + 1
end

local function UnregisterCallback(self, m, h)
    assert(type(m) == "string" or type(m) == "function", "Bad argument #1 to :UnregisterCallback (string or function expected)")
    if type(m) == "string" then
        assert(type(h) == "table", "Bad argument #2 to :UnregisterCallback (table expected)")
        assert(type(h[m]) == "function", "Bad argument #1 to :UnregisterCallback (m \"" .. m .. "\" not found)")
        m = h[m]
    end
    callbacks[m] = nil
    numCallbacks = numCallbacks + 1
end

local function DispatchCallbacks()
    if (numCallbacks < 1) then return end
    for m, h in pairs(callbacks) do
        local ok, err = pcall(m, h ~= true and h or nil)
        if not ok then
            print("ERROR:", err)
        end
    end
end

--[[ BUILD CLASS COLOR GLOBAL ]]--

SVUI_CLASS_COLORS = {};
do
    local classes = {};
    local supercolors = {
        ["HUNTER"]        = { r = 0.454, g = 0.698, b = 0 },
        ["WARLOCK"]       = { r = 0.286, g = 0,     b = 0.788 },
        ["PRIEST"]        = { r = 0.976, g = 1,     b = 0.839 },
        ["PALADIN"]       = { r = 0.956, g = 0.207, b = 0.733 },
        ["MAGE"]          = { r = 0,     g = 0.796, b = 1 },
        ["ROGUE"]         = { r = 1,     g = 0.894, b = 0.117 },
        ["DRUID"]         = { r = 1,     g = 0.513, b = 0 },
        ["SHAMAN"]        = { r = 0,     g = 0.38,  b = 1 },
        ["WARRIOR"]       = { r = 0.698, g = 0.36,  b = 0.152 },
        ["DEATHKNIGHT"]   = { r = 0.847, g = 0.117, b = 0.074 },
        ["MONK"]          = { r = 0.015, g = 0.886, b = 0.38 },
    };
    for class in pairs(RAID_CLASS_COLORS) do
        tinsert(classes, class)
    end
    tsort(classes)
    setmetatable(SVUI_CLASS_COLORS,{
        __index = function(t, k)
            if k == "RegisterCallback" then return RegisterCallback end
            if k == "UnregisterCallback" then return UnregisterCallback end
            if k == "DispatchCallbacks" then return DispatchCallbacks end
        end
    });
    for i, class in ipairs(classes) do
        local color = supercolors[class]
        local r, g, b = color.r, color.g, color.b
        local hex = ("ff%02x%02x%02x"):format(r * 255, g * 255, b * 255)
        if not SVUI_CLASS_COLORS[class] or not SVUI_CLASS_COLORS[class].r or not SVUI_CLASS_COLORS[class].g or not SVUI_CLASS_COLORS[class].b then
            SVUI_CLASS_COLORS[class] = {
                r = r,
                g = g,
                b = b,
                colorStr = hex,
            }
        end
    end
    classes = nil
end

--[[ APPENDED LUA METHODS ]]--

function math.parsefloat(value,decimal)
    if decimal and decimal > 0 then
        local calc1 = 10 ^ decimal;
        local calc2 = (value * calc1) + 0.5;
        return floor(calc2) / calc1
    end
    return floor(value + 0.5)
end

function table.dump(targetTable)
    local dumpTable = {};
    local dumpCheck = {};
    for key,value in ipairs(targetTable) do
        tinsert(dumpTable, formatValueString(value));
        dumpCheck[key] = true;
    end
    for key,value in pairs(targetTable) do
        if not dumpCheck[key] then
            tinsert(dumpTable, "\n    "..formatKeyString(key).." = "..formatValueString(value));
        end
    end
    local output = tconcat(dumpTable, ", ");
    return "{ "..output.." }";
end

function table.copy(targetTable,deepCopy,mergeTable)
    mergeTable = mergeTable or {};
    if targetTable==nil then return nil end
    if mergeTable[targetTable] then return mergeTable[targetTable] end
    local replacementTable = {}
    for key,value in pairs(targetTable)do
        if deepCopy and type(value) == "table" then
            replacementTable[key] = table.copy(value, deepCopy, mergeTable)
        else
            replacementTable[key] = value
        end
    end
    setmetatable(replacementTable, table.copy(getmetatable(targetTable), deepCopy, mergeTable))
    mergeTable[targetTable] = replacementTable;
    return replacementTable
end

function string.trim(this)
    return this:find('^%s*$') and '' or this:match('^%s*(.*%S)')
end

function string.color(this, color)
    return ("|cff%s%s|r"):format(color, this)
end

function string.link(this, prefix, text, color)
    text = tostring(text)
    local colorstring = tostring(this):color(color or "ffffff")
    return ("|H%s:%s|h%s|h"):format(prefix, text, colorstring)
end

function string.explode(str, delim)
   local res = { }
   local pattern = string.format("([^%s]+)%s()", delim, delim)
   while (true) do
      line, pos = str:match(pattern, pos)
      if line == nil then break end
      table.insert(res, line)
   end
   return res
end

--[[ CORE ENGINE CONSTRUCT ]]--

local Core_StaticPopup_Show = function(self, arg)
    if arg == "ADDON_ACTION_FORBIDDEN" then
        StaticPopup_Hide(arg)
    end
end

local Core_ResetAllUI = function(self, confirmed)
    if InCombatLockdown()then
        SendAddonMessage(ERR_NOT_IN_COMBAT)
        return
    end
    if(not confirmed) then
        self:StaticPopup_Show('RESET_UI_CHECK')
        return
    end
    self:ResetInstallation()
end

local Core_ResetUI = function(self, confirmed)
    if InCombatLockdown()then
        SendAddonMessage(ERR_NOT_IN_COMBAT)
        return
    end
    if(not confirmed) then
        self:StaticPopup_Show('RESETMOVERS_CHECK')
        return
    end
    self:ResetMovables()
end

local Core_ToggleConfig = function(self)
    if InCombatLockdown() then
        SendAddonMessage(ERR_NOT_IN_COMBAT)
        self.UIParent:RegisterEvent('PLAYER_REGEN_ENABLED')
        return
    end
    if not IsAddOnLoaded("SVUI_ConfigOMatic") then
        local _,_,_,_,_,state = GetAddOnInfo("SVUI_ConfigOMatic")
        if state ~= "MISSING" and state ~= "DISABLED" then
            LoadAddOn("SVUI_ConfigOMatic")
            local config_version = GetAddOnMetadata("SVUI_ConfigOMatic", "Version")
            if(tonumber(config_version) < 4) then
                self:StaticPopup_Show("CLIENT_UPDATE_REQUEST")
            end
        else
            self:AddonMessage("|cffff0000Error -- Addon 'SVUI_ConfigOMatic' not found or is disabled.|r")
            return
        end
    end
    local aceConfig = LibStub("AceConfigDialog-3.0")
    local switch = not aceConfig.OpenFrames["SVUI"] and "Open" or "Close"
    aceConfig[switch](aceConfig, "SVUI")
    GameTooltip:Hide()
end

--/script SVUI[1]:TaintHandler("SVUI", "Script", "Function")
local Core_TaintHandler = function(self, taint, sourceName, sourceFunc)
    if GetCVarBool('scriptErrors') ~= 1 then return end
    local errorString = ("Error Captured: %s->%s->{%s}"):format(taint, sourceName or "Unknown", sourceFunc or "Unknown")
    self:AddonMessage(errorString)
    self:StaticPopup_Show("TAINT_RL")
end

local function _sendmessage(msg, prefix)
    if(type(msg) == "table") then
        msg = tostring(msg)
    end

    if(not msg) then return end

    if(prefix) then
        local outbound = ("%s %s"):format(prefix, msg);
        print(outbound)
    else
        print(msg)
    end
end

local Core_Debugger = function(self, msg)
    if(not self.DebuggingMode) then return end
    local outbound = (debugPattern):format("SVUI", "DEBUG")
    _sendmessage(msg, outbound)
end

local Core_AddonMessage = function(self, msg)
    local outbound = (messagePattern):format("SVUI")
    _sendmessage(msg, outbound)
end

local Core_SetLocaleStrings = function(self, locale, isDefault)
    local gameLocale = GetLocale()
    if gameLocale == "enGB" then gameLocale = "enUS" end

    activeLocale = Localization

    if isDefault then
        return defaultwrite
    elseif(locale == GAME_LOCALE or locale == gameLocale) then
        return metawrite
    end
end

local Core_Prototype = function(self, name)
    local version = GetAddOnMetadata(name, "Version")
    local schema = GetAddOnMetadata(name, "X-SVUI-Schema")

    self.Configs[schema] = {["enable"] = false}

    local obj = {
        ___addonName = name,
        ___version = version,
        ___schema = schema
    }

    local mt = {}
    local old = getmetatable(obj)
    if old then
        for k, v in pairs(old) do mt[k] = v end
    end
    mt.__tostring = rootstring
    setmetatable(obj, mt)
    return obj
end

--[[ REGISTRY CONSTRUCT ]]--

local changeDBVar = function(self, value, key, sub1, sub2, sub3)
    local core = self.___core
    local schema = self.___schema
    local config = core.db[schema]

    if((sub1 and sub2 and sub3) and (config[sub1] and config[sub1][sub2] and config[sub1][sub2][sub3])) then
        core.db[schema][sub1][sub2][sub3][key] = value
    elseif((sub1 and sub2) and (config[sub1] and config[sub1][sub2])) then
        core.db[schema][sub1][sub2][key] = value
    elseif(sub1 and config[sub1]) then
        core.db[schema][sub1][key] = value
    else
        core.db[schema][key] = value
    end

    self.db = core.db[schema]

    if(self.UpdateLocals) then
        self:UpdateLocals()
    end
end

local innerOnEvent = function(self, event, ...)
    local obj = self.module
    if self[event] and type(self[event]) == "function" then
        self[event](obj, event, ...)
    end
end

local registerEvent = function(self, eventname, eventfunc)
    if not self.___eventframe then
        self.___eventframe = CreateFrame("Frame", nil)
        self.___eventframe.module = self
        self.___eventframe:SetScript("OnEvent", innerOnEvent)
    end

    if(not self.___eventframe[eventname]) then
        local fn = eventfunc
        if type(eventfunc) == "string" then
            fn = self[eventfunc]
        elseif(not fn and self[eventname]) then
            fn = self[eventname]
        end
        self.___eventframe[eventname] = fn
    end

    self.___eventframe:RegisterEvent(eventname)
end

local unregisterEvent = function(self, event, ...)
    if(self.___eventframe) then
        self.___eventframe:UnregisterEvent(event)
    end
end

local innerOnUpdate = function(self, elapsed)
    if self.elapsed and self.elapsed > (self.throttle) then
        local obj = self.module
        local core = obj.___core
        local callbacks = self.callbacks

        for name, fn in pairs(callbacks) do
            local _, error = pcall(fn, obj)
            if(error and core.Debugging) then
                print(error)
            end
        end

        self.elapsed = 0
    else
        self.elapsed = (self.elapsed or 0) + elapsed
    end
end

local registerUpdate = function(self, updatefunc, throttle)
    if not self.___updateframe then
        self.___updateframe = CreateFrame("Frame", nil);
        self.___updateframe.module = self;
        self.___updateframe.callbacks = {};
        self.___updateframe.elapsed = 0;
        self.___updateframe.throttle = throttle or 0.2;
    end

    if(updatefunc and type(updatefunc) == "string" and self[updatefunc]) then
        self.___updateframe.callbacks[updatefunc] = self[updatefunc]
    end

    self.___updateframe:SetScript("OnUpdate", innerOnUpdate)
end

local unregisterUpdate = function(self, updatefunc)
    if(updatefunc and type(updatefunc) == "string" and self.___updateframe.callbacks[updatefunc]) then
        self.___updateframe.callbacks[updatefunc] = nil
        if(#self.___updateframe.callbacks == 0) then
            self.___updateframe:SetScript("OnUpdate", nil)
        end
    else
        self.___updateframe:SetScript("OnUpdate", nil)
    end
end

local add_OptionsIndex = function(self, index, data)
    local addonName = self.___addonName
    local schema = self.___schema
    local core = self.___core
    local header = GetAddOnMetadata(addonName, "X-SVUI-Header")

    core.Options.args.plugins.args.pluginOptions.args[schema].args[index] = data
end

local function SetPluginString(addonName)
    local pluginString = PLUGIN_LISTING or ""
    local author = GetAddOnMetadata(addonName, "Author") or "Unknown"
    local Pname = GetAddOnMetadata(addonName, "Title") or addonName
    local version = GetAddOnMetadata(addonName, "Version") or "???"
    pluginString = INFO_BY:format(pluginString, author)
    pluginString = ("%s %s"):format(pluginString, Pname)
    pluginString = INFO_VERSION:format(pluginString, "|cff00FF00", version)
    pluginString = ("%s|r\n"):format(pluginString)

    PLUGIN_LISTING = pluginString
end

local function SetInternalModule(obj, core, schema)
    local addonmeta = {}
    local oldmeta = getmetatable(obj)
    if oldmeta then
        for k, v in pairs(oldmeta) do addonmeta[k] = v end
    end
    addonmeta.__tostring = rootstring
    setmetatable( obj, addonmeta )

    local addonName = ("SVUI [%s]"):format(schema)

    obj.___addonName = addonName
    obj.___schema = schema
    obj.___core = core

    obj.initialized = false
    obj.CombatLocked = false
    obj.ChangeDBVar = changeDBVar
    obj.RegisterEvent = registerEvent
    obj.UnregisterEvent = unregisterEvent
    obj.RegisterUpdate = registerUpdate
    obj.UnregisterUpdate = unregisterUpdate

    return obj
end

local function SetExternalModule(obj, core, schema, addonName, header, lod)
    local addonmeta = {}
    local oldmeta = getmetatable(obj)
    if oldmeta then
        for k, v in pairs(oldmeta) do addonmeta[k] = v end
    end
    addonmeta.__tostring = rootstring
    setmetatable( obj, addonmeta )

    obj.___addonName = addonName
    obj.___schema = schema
    obj.___header = header
    obj.___core = core
    obj.___lod = lod

    obj.initialized = false
    obj.CombatLocked = false
    obj.ChangeDBVar = changeDBVar
    obj.RegisterEvent = registerEvent
    obj.UnregisterEvent = unregisterEvent
    obj.RegisterUpdate = registerUpdate
    obj.UnregisterUpdate = unregisterUpdate
    obj.AddOption = add_OptionsIndex

    if(lod) then
        -- print("PLUGIN: " .. addonName)
        core.Options.args.plugins.args.pluginOptions.args[schema] = {
            type = "group",
            name = header,
            childGroups = "tree",
            args = {
                enable = {
                    order = 1,
                    type = "execute",
                    width = "full",
                    name = function()
                        local nameString = "Disable"
                        if(not IsAddOnLoaded(addonName)) then
                            nameString = "Enable"
                        end
                        return nameString
                    end,
                    func = function()
                        if(not IsAddOnLoaded(addonName)) then
                            local loaded, reason = LoadAddOn(addonName)
                            core:UpdateDatabase()
                            obj:ChangeDBVar(true, "enable")
                        else
                            obj:ChangeDBVar(false, "enable")
                            core:StaticPopup_Show("RL_CLIENT")
                        end
                    end,
                }
            }
        }
    else
        core.Options.args.plugins.args.pluginOptions.args[schema] = {
            type = "group",
            name = header,
            childGroups = "tree",
            args = {
                enable = {
                    order = 1,
                    type = "toggle",
                    name = "Enable",
                    get = function() return obj.db.enable end,
                    set = function(key, value) obj:ChangeDBVar(value, "enable"); core:StaticPopup_Show("RL_CLIENT") end,
                }
            }
        }
    end

    return obj
end

local Registry_NewCallback = function(self, fn)
    if(fn and type(fn) == "function") then
        self.Callbacks[#self.Callbacks+1] = fn
    end
end

local Registry_NewScript = function(self, fn)
    if(fn and type(fn) == "function") then
        ScriptQueue[#ScriptQueue+1] = fn
    end
end

local Registry_NewPackage = function(self, obj, schema)
    local core = self.___core
    if(core[schema]) then return end

    ModuleQueue[#ModuleQueue+1] = schema
    self.Modules[#self.Modules+1] = schema

    core[schema] = SetInternalModule(obj, core, schema)

    if(core.AddonLaunched) then
        if(core[schema].Load) then
            core[schema]:Load()
        end
    end
end

local Registry_NewPlugin = function(self, obj)
    local core = self.___core
    local coreName = core.___addonName
    local addonName = obj.___addonName

    if(addonName and addonName ~= coreName) then
        local schema = GetAddOnMetadata(addonName, "X-SVUI-Schema");
        local header = GetAddOnMetadata(addonName, "X-SVUI-Header");
        local lod = IsAddOnLoadOnDemand(addonName)
        if(not schema) then return end

        ModuleQueue[#ModuleQueue+1] = schema
        self.Modules[#self.Modules+1] = schema

        SetPluginString(addonName)

        core[schema] = SetExternalModule(obj, core, schema, addonName, header, lod)

        if(core.AddonLaunched and core[schema].Load) then
            core[schema]:Load()
            --print(schema)
        end
    end
end

local Registry_NewAddon = function(self, addonName, schema, header)
    local core = self.___core
    self.Addons[addonName] = schema;

    core.Options.args.plugins.args.pluginOptions.args[schema] = {
        type = "group",
        name = header,
        childGroups = "tree",
        args = {
            enable = {
                order = 1,
                type = "execute",
                width = "full",
                name = function()
                    local nameString = "Disable"
                    if(not IsAddOnLoaded(addonName)) then
                        nameString = "Enable"
                    end
                    return nameString
                end,
                func = function()
                    if(not IsAddOnLoaded(addonName)) then
                        local loaded, reason = LoadAddOn(addonName)
                        core:UpdateDatabase()
                        core.db[schema].enable = true
                        self:LoadPackages()
                    else
                        core.db[schema].enable = false
                        core:StaticPopup_Show("RL_CLIENT")
                    end
                end,
            }
        }
    }
end

local Registry_FetchAddons = function(self)
    local addonCount = GetNumAddOns()
    local core = self.___core

    for i = 1, addonCount do
        local addonName, _, _, _, _, reason = GetAddOnInfo(i)
        local lod = IsAddOnLoadOnDemand(i)
        local header = GetAddOnMetadata(i, "X-SVUI-Header")
        local schema = GetAddOnMetadata(i, "X-SVUI-Schema")

        if(lod and schema) then
            self:NewAddon(addonName, schema, header)
        end
    end
end

local Registry_RunCallbacks = function(self)
    local callbacks = self.Callbacks
    for i=1, #callbacks do
        local fn = callbacks[i]
        if(fn and type(fn) == "function") then
            fn()
        end
    end
end

local Registry_Update = function(self, name, dataOnly)
    local core = self.___core
    local obj = core[name]
    if obj then
        if core.db[name] then
            obj.db = core.db[name]
        end
        if obj.ReLoad and not dataOnly then
            obj:ReLoad()
        end
    end
end

local Registry_UpdateAll = function(self)
    local modules = self.Modules
    local core = self.___core
    for _,name in pairs(modules) do
        local obj = core[name]

        if core.db[name] then
            obj.db = core.db[name]
        end

        if obj and obj.ReLoad then
            obj:ReLoad()
        end
    end
end

local Registry_LoadOnDemand = function(self)
    local core = self.___core
    local addons = self.Addons
    for name,schema in pairs(addons) do
        local config = core.db[schema]
        if(config and (config.enable or config.enable ~= false)) then
            if(not IsAddOnLoaded(name)) then
                local loaded, reason = LoadAddOn(name)
            end
            EnableAddOn(name)
        end
    end
end

local Registry_Load = function(self)
    if not ModuleQueue then return end
    local core = self.___core

    for i=1,#ModuleQueue do
        local name = ModuleQueue[i]
        local obj = core[name]
        if obj and not obj.initialized then
            if core.db[name] then
                obj.db = core.db[name]
            end

            if obj.Load then
                local halt = false
                if(obj.db.incompatible) then
                    for addon,_ in pairs(obj.db.incompatible) do
                        if IsAddOnLoaded(addon) then halt = true end
                    end
                end
                if(not halt) then
                    obj:Load()
                    obj.Load = nil
                    --print(name)
                end
            end
            obj.initialized = true;
        end
    end

    twipe(ModuleQueue)

    if not ScriptQueue then return end
    for i=1, #ScriptQueue do
        local fn = ScriptQueue[i]
        if(fn and type(fn) == "function") then
            fn()
        end
    end

    ScriptQueue = nil
end
--[[
#####################################################################################
  /$$$$$$  /$$    /$$ /$$   /$$ /$$$$$$        /$$$$$$   /$$$$$$  /$$$$$$$  /$$$$$$$$
 /$$__  $$| $$   | $$| $$  | $$|_  $$_/       /$$__  $$ /$$__  $$| $$__  $$| $$_____/
| $$  \__/| $$   | $$| $$  | $$  | $$        | $$  \__/| $$  \ $$| $$  \ $$| $$
|  $$$$$$ |  $$ / $$/| $$  | $$  | $$        | $$      | $$  | $$| $$$$$$$/| $$$$$
 \____  $$ \  $$ $$/ | $$  | $$  | $$        | $$      | $$  | $$| $$__  $$| $$__/
 /$$  \ $$  \  $$$/  | $$  | $$  | $$        | $$    $$| $$  | $$| $$  \ $$| $$
|  $$$$$$/   \  $/   |  $$$$$$/ /$$$$$$      |  $$$$$$/|  $$$$$$/| $$  | $$| $$$$$$$$
 \______/     \_/     \______/ |______/       \______/  \______/ |__/  |__/|________/
#####################################################################################
]]--
local SVUI = {
    ___addonName = SVUINameSpace,
    ___version = GetAddOnMetadata(SVUINameSpace, "Version"),
    ___interface = tonumber(uiVersion),

    db = {},
    Global = { Accountant = {}, profiles = {}, profileKeys = {} },
    Configs = {},
    Media = {},
    DisplayAudit = {},
    DynamicOptions = {},
    Dispellable = {},
    Snap = {},
    class = playerClass,
    fubar = dumb,
    ClassRole = "",
    UnitRole = "NONE",
    ConfigurationMode = false,
    DebuggingMode = false,
    EffectiveScale = 1,
    ActualHeight = actualHeight,
    ActualWidth = actualWidth,
    yScreenArea = (actualHeight * 0.33),
    xScreenArea = (actualWidth * 0.33),
    SetLocaleStrings = Core_SetLocaleStrings,
    Prototype = Core_Prototype,
    AddonMessage = Core_AddonMessage,
    Debugger = Core_Debugger,
    StaticPopup_Show = Core_StaticPopup_Show,
    ResetAllUI = Core_ResetAllUI,
    ResetUI = Core_ResetUI,
    ToggleConfig = Core_ToggleConfig,
    TaintHandler = Core_TaintHandler,
    Options = {
        type = "group",
        name = "|cff339fffConfig-O-Matic|r",
        args = {
            plugins = {
                order = -2,
                type = "group",
                name = "Plugins",
                childGroups = "tab",
                args = {
                    pluginheader = {
                        order = 1,
                        type = "header",
                        name = "Supervillain Plugins",
                    },
                    pluginOptions = {
                        order = 2,
                        type = "group",
                        name = "",
                        args = {
                            pluginlist = {
                                order = 1,
                                type = "group",
                                name = "Summary",
                                args = {
                                    active = {
                                        order = 1,
                                        type = "description",
                                        name = function() return PLUGIN_LISTING end
                                    }
                                }
                            },
                        }
                    }
                }
            }
        }
    }
}

SaveMetaMethods(SVUI)

--[[ UTILITY FRAMES ]]--

SVUI.UIParent = CreateFrame("Frame", "SVUIParent", UIParent);
SVUI.UIParent:SetFrameLevel(UIParent:GetFrameLevel());
SVUI.UIParent:SetPoint("CENTER", UIParent, "CENTER");
SVUI.UIParent:SetSize(UIParent:GetSize());
SVUI.Snap[1] = SVUI.UIParent;

SVUI.Cloaked = CreateFrame("Frame", nil, UIParent);
SVUI.Cloaked:Hide();

local Registry = {
    ___core = SVUI,
    Modules = {},
    Addons = {},
    Callbacks = {},
    INFO_VERSION = INFO_VERSION,
    INFO_NEW = INFO_NEW,
    INFO_NAME = INFO_NAME,
    INFO_HEADER = INFO_HEADER,
    NewCallback = Registry_NewCallback,
    NewScript = Registry_NewScript,
    NewPackage = Registry_NewPackage,
    NewPlugin = Registry_NewPlugin,
    NewAddon = Registry_NewAddon,
    FindAddons = Registry_FetchAddons,
    LoadRegisteredAddons = Registry_LoadOnDemand,
    RunCallbacks = Registry_RunCallbacks,
    Update = Registry_Update,
    UpdateAll = Registry_UpdateAll,
    LoadPackages = Registry_Load,
}

SaveMetaMethods(Registry)

--[[ COMMON FUNCTIONS ]]--

SVUICore[1] = SVUI
SVUICore[2] = Localization
SVUICore[3] = Registry

--[[ SET MASTER GLOBAL ]]--

_G[SVUINameSpace] = SVUICore;