--[[
	Wowshell Configure Center Panel.
	Author: wolftankk@gmail.com
--]]
local parent, ns = ...;
local FrameTitle_Prefix = "WSConfigPanelFrame";
local L = wsLocale:GetLocale("WoWShell");

WS_GUI = {};
ns.WS_GUI = WS_GUI;
WS_GUI.AddonList = WS_GUI.AddonList or {}
WS_GUI.FramesList = WS_GUI.FramesList or {}

local AddonList = WS_GUI.AddonList;--addons' list
local FramesList = WS_GUI.FramesList;--frame list
local queueList = {};
local loadPluginsList = {};
local filters = {};
local isFilterMode = false;
local _, pclass = UnitClass("player");
pclass = pclass:lower();

local ICONS_LIST = GetMacroIcons({});

local Addons_per_page = 12;
local AddonsCategoryType1 = "general";
local AddonsCategoryType2 = "raid";
local AddonsCategoryType3 = "monomer";

local PY = LibStub("LibPinyin-1.0");
local cfgreg = LibStub("AceConfigRegistry-3.0");
local acd = LibStub("WSConfigDialog-3.0");
local acegui = LibStub("AceGUI-3.0");

--local lua func MAGIC
local ceil = ceil
local tinsert = table.insert
local tconcat = table.concat
local tsort = table.sort

--插件列表排序
local function compareAddon(a, b)
	return a and b and a.order < b.order
end

local first = true
function WS_GUI:ToggleFrame(forceshow)
	--第一次打开时候 对插件列表进行排序
	if first --[[and (not WSConfigPanelFrame:IsShown())]] then
		for k, v in next, AddonList do
			table.sort(v, compareAddon)
		end
		first = false
	end

	if forceshow == true then
		WSConfigPanelFrame:Show();
		WSConfigSettingPanel:Hide();
	elseif forceshow == false then
		WSConfigPanelFrame:Hide();
	else
		if WSConfigPanelFrame:IsShown() then
			WSConfigPanelFrame:Hide();
		else
			WSConfigPanelFrame:Show();
			WSConfigSettingPanel:Hide();
		end
	end
	self:CloseAll();
end

do
	--初始页面为第一页
	local prevBtn = _G["WSConfigPanelFramePageNavigationFramePrevPageButton"]
	local nextBtn = _G["WSConfigPanelFramePageNavigationFrameNextPageButton"]

	function WS_GUI:UpdatePages(frame)
		prevBtn = prevBtn or _G["WSConfigPanelFramePageNavigationFramePrevPageButton"]
		nextBtn = nextBtn or _G["WSConfigPanelFramePageNavigationFrameNextPageButton"]
		if not frame then
			frame = WSConfigPanelFrame
		end
		local currentTab = frame.currentTab;
		local currentType = currentTab.type;
		local AddonCount = 0;
		if (AddonList[currentType] ~= nil) then	
			for i = 1, #AddonList[currentType] do
				local addon = AddonList[currentType][i];
				if addon.hidden == false then
					AddonCount = AddonCount + 1;
				end
			end
		end
		currentTab.maxPage = ceil(AddonCount/Addons_per_page);
		if currentTab.currentPage == nil then
			currentTab.currentPage = 1;
		end
		if (currentTab.maxPage == 0) then
			return
		end
		if currentTab.currentPage > currentTab.maxPage then
			currentTab.currentPage = currentTab.maxPage;
			if (currentTab.currentPage == 1) then
				prevBtn:Disable();
			else
				prevBtn:Enable()
			end
			if (currentTab.currentPage == currentTab.maxPage) then
				nextBtn:Disable();
			else
				nextBtn:Enable();
			end
		end
		if (currentTab.currentPage == 1) then
			prevBtn:Disable();
		else
			prevBtn:Enable()
		end
		if (currentTab.currentPage == currentTab.maxPage) then
			nextBtn:Disable();
		else
			nextBtn:Enable();
		end

		WSConfigPanelFramePageNavigationFramePageText:SetFormattedText(PAGE_NUMBER, currentTab.currentPage)
	end

	function WS_GUI:UpdatePageArrows()
		local frame = WSConfigPanelFrame;
		local currentTab = frame.currentTab;
		local currentType = currentTab.type;
		local AddonCount = 0;
		for i = 1, #AddonList[currentType] do
			local addon = AddonList[currentType][i];
			if (addon.hidden == false) then
				AddonCount = AddonCount + 1;
			end
		end

		local maxPage = ceil(AddonCount/Addons_per_page);
		if currentTab.currentPage == 1 then
			prevBtn:Disable();
		else
			prevBtn:Enable();
		end
		if currentTab.currentPage == maxPage then
			nextBtn:Disable();
		else
			nextBtn:Enable();
		end
		--update page text
		WSConfigPanelFramePageNavigationFramePageText:SetFormattedText(PAGE_NUMBER, currentTab.currentPage)
	end

	function WS_GUI:PrevPage()
		local currentTab = WSConfigPanelFrame.currentTab;
		currentTab.currentPage = currentTab.currentPage - 1;
		self:UpdatePageArrows();
		self:UpdateAddOnList();
	end

	function WS_GUI:NextPage()
		local currentTab = WSConfigPanelFrame.currentTab;
		currentTab.currentPage = currentTab.currentPage + 1;
		self:UpdatePageArrows();
		self:UpdateAddOnList();
	end

	local function resetAllButton()
		for count=1, 12 do
			local button = _G["WSConfigPanelFrameAddOnIconsFrameAddOnButton"..count];			
			if not button:IsShown() and button.clicked == nil then return end
			if button.clicked then
				--hide
				_G[button:GetName().."SelectedSlotFrame"]:Hide();
				_G[button:GetName().."SelectedTextBackground"]:Hide();
				_G[button:GetName().."Background"]:Show();
				_G[button:GetName().."TextBackground"]:Show();
				button.clicked = nil;
			end
		end
	end
	
	--init list
	function WS_GUI:UpdateAddOnList(frame)
		if not frame then
			frame = WSConfigPanelFrame;
		end
		local currentTab = frame.currentTab;
		local currentType = currentTab.type
		if currentTab.currentPage == nil then currentTab.currentPage = 1 end
		local offset = Addons_per_page * (currentTab.currentPage - 1);
		local count, cache = 0, {};

		if (AddonList[currentType] ~= nil) then
			for i = 1, #AddonList[currentType] do
				local addon = AddonList[currentType][i];
				if addon.hidden == false then
					tinsert(cache, addon);
				end
			end

			for count=1, 12 do
				local button = _G["WSConfigPanelFrameAddOnIconsFrameAddOnButton"..count];	
				if (cache[offset+count] ~= nil and type(cache[offset+count]) == "table") then
					local addon = cache[offset+count];
					self:ResetButtonStatus(button);
					button.category = addon.category;
					button.addonName = addon.addonName;
					button.appName = addon.appName;
					button.name = addon.name
					button.description = addon.description;
					button.icon = addon.icon
					button.order = addon.order
					button.configable = addon.configable;
					button.isNew = addon.isNew;
					button.addon = addon; --copy

					if (addon.callback ~= nil) and type(addon.callback) == "function" then
						button.callback = addon.callback
					end

					self:UpdateButton(button)
				else
					button:Hide();
				end
			end
		else
			button:Hide();
		end

		resetAllButton();
	end

	function WS_GUI:UpdateLayout()
		self:UpdatePages();
		self:UpdateAddOnList();
		self:UpdatePageArrows();
	end

	function WS_GUI:ResetButtonStatus(button)
		if button then
			button.category = nil
			button.addonName = nil
			button.appName = nil
			button.name = nil
			button.description = nil
			button.icon = nil
			button.order = nil
			button.options = nil
			button.callback = nil
			button.configable = nil
			button.addon = nil;
			button:Hide();
		end
	end

	function WS_GUI:ToggleAddon(button)
		local addonName = button.addonName;

		local loaded = IsAddOnLoaded(addonName);
		local demand = IsAddOnLoadOnDemand(addonName);

		if button.addonToggleButton:GetChecked() then
			button.addon.preload = true;
		else
			button.addon.preload = false;
		end

		if button.addon.preload then
			EnableAddOn(addonName);
			if demand then
				LoadAddOn(addonName);
			end
		elseif button.addon.preload == false then
			DisableAddOn(addonName);
		end

		self:UpdateButton(button);
	end

	function WS_GUI:UpdateButton(button)
		local iconBg = _G[button:GetName().."IconTextureBg"];
		local icon = _G[button:GetName().."IconTexture"];
		local addonName = _G[button:GetName().."AddonName"];
		local slotFrame = _G[button:GetName().."SlotFrame"];
		local newFeature = _G[button:GetName().."NewFeature"];

		addonName.shadowX, addonName.shadowY = 1, -1;
		icon:SetTexture(button.icon);

		if button.icon ~= nil then
			iconBg:Show();
			icon:Show()
		else
			iconBg:Hide();
			icon:Hide();
		end
		if button.isNew then
			--button.name = "|TInterface\\OptionsFrame\\UI-OptionsFrame-NewFeatureIcon:0:0:0:-1|t"..button.name;
		end
		addonName:SetText(button.name);
		addonName:Show();
		button:Show();

		local name = button.addonName;
		local loaded = IsAddOnLoaded(name);

		if (loaded and not button.addon.disabled) then
			slotFrame:Show();
			button.UnlearnedFrame:Hide();
			icon:SetAlpha(1)
			icon:SetDesaturated(0)
			addonName:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
			addonName:SetShadowOffset(addonName.shadowX, addonName.shadowY);
			button.addonToggleButton:SetChecked(1);
		else
			slotFrame:Hide();
			icon:SetAlpha(0.5)
			icon:SetDesaturated(true)
			button.UnlearnedFrame:Show();
			addonName:SetTextColor(0.25, 0.12, 0);
			addonName:SetShadowOffset(0, 0)
			button.addonToggleButton:SetChecked(0)
		end

		if button.isNew then
			newFeature:Show();
		else
			newFeature:Hide();
		end

		if button.addon.preload == true then
			button.addonToggleButton:SetChecked(1);
		elseif button.addon.preload == false then
			button.addonToggleButton:SetChecked(0);
		end
	end

	function WS_GUI:CloseAll()
		for k, v in pairs(acd.OpenFrames) do
			if v and v:IsShown() then
				v:Hide();
			end
		end
		--call dialog func
		--acd:CloseAll();
	end

	local function updateButtonState(button)
		if button.clicked then
			_G[button:GetName().."SelectedSlotFrame"]:Show();
			_G[button:GetName().."SelectedTextBackground"]:Show();
			_G[button:GetName().."Background"]:Hide();
			_G[button:GetName().."TextBackground"]:Hide();
		else
			_G[button:GetName().."SelectedSlotFrame"]:Hide();
			_G[button:GetName().."SelectedTextBackground"]:Hide();
			_G[button:GetName().."Background"]:Show();
			_G[button:GetName().."TextBackground"]:Show();
		end
	end

	--it will show Config-Panel in the rightPanel when click the sub addon
	function WS_GUI:ModButton_OnClick(frame)
		local addonName = frame.addonName;
		local loaded = IsAddOnLoaded(addonName);
		if (not loaded) then
			return;
		end
		if (frame.addon.disabled) then return; end

		--first clear
		self:CloseAll();
		WSConfigSettingPanelTitleText:SetText("");
		--Wowshell_GUI_OptionFrame_AddonSettingInfo:Hide();
		--open/create new
		resetAllButton();
		if frame.clicked == nil then
			frame.clicked = true;
		else
			frame.clicked = nil;
		end
		updateButtonState(frame);
		WSConfigSettingPanel:Hide();
		if frame.configable then
			if (frame.callback ~= nil) and type(frame.callback) == "function" then
				frame.callback();
			else
				acd:Open(frame.appName)
				WSConfigSettingPanel:Show();
				WSConfigSettingPanelTitleText:SetText(frame.name.. ' '.. L["设置"])
			end
		else

		end
	end

	local function getDepMissing(addonName)
			if addonName == nil then return end
			local deps = {GetAddOnDependencies(addonName)};
			local result = {};
			for c in next, deps do
				local dep = deps[c];
				local _name, _, _, _enabled, _loadable, _reason = GetAddOnInfo(dep);
				if (_reason and _loadable == nil and _enabled == nil) then
					table.insert(result, _name);
				end
			end

			wipe(deps);
			return result;
	end

	function WS_GUI:GetAddonStatus(addon, tooltip)
		local name, title, notes, enabled, loadable, reason, security = GetAddOnInfo(addon.addonName);
		local loaded = IsAddOnLoaded(addon.addonName);
		local isondemand = IsAddOnLoadOnDemand(addon.addonName)
		local deps = getDepMissing(addon.addonName);
	
		if addon.addon.reason then
			tooltip:AddLine(addon.addon.reason, 1, 0.4, 0.2, 1);
			tooltip:AddLine("            ");
		end

		if reason then
			if reason == "DISABLED" then
				tooltip:AddLine(title.."("..name..")".."已被禁用。请点击启用勾选框重新启用此插件。", 1, 0.4, 0.2, 1);
			elseif reason:match("^DEP") then 
				if reason == "DEP_MISSING" then
					tooltip:AddLine("依赖缺失, 需要启用以下插件才能正常使用。");
				elseif reason == "DEP_DISABLED" then
					tooltip:AddLine("依赖被禁用, 需要启用以下插件才能正常使用。");
				end

				for id in next, deps do
					tooltip:AddDoubleLine("   ", deps[id], 1, 0.4, 0.2, 1, 0.4, 0.2);
				end
			elseif reason == "NOT_DEMAND_LOADED" then

			end
		end
	end

	--susnow marks here
	function WS_GUI:ModButton_OnEnter(frame)
		local addonName = frame.addonName;
		local name, title, notes, enabled, loadable, reason, security = GetAddOnInfo(addonName);
		local author = GetAddOnMetadata(name, "Author");
		local deps = {GetAddOnDependencies(name)}
		local tipMem = string.upper(GetAddOnMetadata(name, "X-TipMemory"))
		local tipSuggest = GetAddOnMetadata(name, "X-TipSuggest")

		GameTooltip:Hide();
		GameTooltip:SetOwner(frame, "ANCHOR_RIGHT");
		GameTooltip:AddLine(frame.name, 1, 1, 1);
		--if (frame.description) then
		--	GameTooltip:AddLine(frame.description, 1, 0.78, 0, 1);
		--else
		GameTooltip:AddLine(notes, 1, 0.78, 0, 1);
		--end

		GameTooltip:AddDoubleLine(GetLocale == "zhCN" and "插件目录" or "插件目錄", name);
		if author then
			GameTooltip:AddDoubleLine(GetLocale == "zhCN" and "作者" or "作者", author);
		end

		UpdateAddOnMemoryUsage();
		local mem = GetAddOnMemoryUsage(name);
		local text2
		if mem > 1024 then
			text2 = ("|cff8080ff%.2f|r MiB"):format(mem / 1024);
		else
			text2 = ("|cff8080ff%.0f|r KiB"):format(mem);
		end
		GameTooltip:AddDoubleLine(GetLocale == "zhCN" and "内存占用" or "內存佔用", text2);
		local tex = "Interface\\AddOns\\Wowshell\\texture\\wsLogo2"
		if tipMem then 
			if tipMem == "LOW" then
				GameTooltip:AddDoubleLine("评估   ","此插件在运行时占用硬件资源很低,基本不会影响游戏的流畅度");
			elseif tipMem == "MIDDLE" then
				GameTooltip:AddDoubleLine("评估   ","此插件在运行时占用硬件资源中等,有很小概率会影响游戏的流畅度");
			elseif tipMem == "HIGH" then
				GameTooltip:AddDoubleLine("评估   ","此插件在运行时占用硬件资源较高,有很大概率会影响游戏的流畅度");
			elseif tipMem == "VERYHIGH" then
				GameTooltip:AddDoubleLine("评估   ","此插件在运行时占用硬件资源极高,建议在使用完毕后及时禁用,确保游戏的流畅度");
			end
		end
		if tipSuggest then
			GameTooltip:AddTexture(tex)
			GameTooltip:AddDoubleLine("提示   ",tipSuggest);
		end

			GameTooltip:AddTexture(tex)
		if reason or frame.addon.reason then
			GameTooltip:AddLine("            ");
			self:GetAddonStatus(frame, GameTooltip);
		end

		GameTooltip:Show();
	end
end

do
	--crate ace-gui frame
	local Type = "WSGUI_Frame";
	local Version = 1

	local function frameOnClose(this)
		this.obj:Fire("OnClose")
	end

	local function closeOnClick(this)
		this.obj:Hide()
	end

	local function frameOnMouseDown(this)
		acegui:ClearFocus()
	end

	local function Hide(self)
		self.frame:Hide();
	end

	local function Show(self)
		self.frame:Show();
	end

	local function OnAcquire(self)
		self.frame:SetParent(WSConfigSettingPanel)
		self.frame:SetFrameStrata("MEDIUM")
		self:ApplyStatus()
	end

	local function OnRelease(self)
		self.status = nil
		for k in pairs(self.localstatus) do
			self.localstatus[k] = nil
		end
	end

	local function ApplyStatus(self)
		local status = self.status or self.localstatus
		local frame = self.frame
		self:SetWidth(270)
		self:SetHeight(440)
		if status.top and status.left then
			frame:SetPoint("TOPLEFT", WSConfigSettingPanel,"TOPLEFT", 10, -15)
		else
			frame:SetPoint("TOPLEFT", WSConfigSettingPanel,"TOPLEFT", 10, -15)
		end
	end

	local function OnWidthSet(self, width)
	end

	local function OnHeightSet(self, height)
	end

	local function Constructor()
		local frame = CreateFrame('Frame', FrameTitle_Prefix..WS_GUI:GetNewID(), UIParent);
		local self = {}
		self.type = "WSGUI_Frame"

		self.Hide = Hide
		self.Show = Show
		self.OnRelease = OnRelease
		self.OnAcquire = OnAcquire
		self.ApplyStatus = ApplyStatus
		--self.closeOnClick = closeOnClick;

		self.localstatus = {}

		self.frame = frame
		frame.obj = self
		frame:SetWidth(275);
		frame:SetHeight(440);
		frame:SetPoint("TOPLEFT", WSConfigSettingPanel, "TOPLEFT", 0, 0);
		frame:EnableMouse();
		frame:SetScript("OnMouseDown", frameOnMouseDown)
		frame:SetScript("OnHide", frameOnClose)
		--local t = frame:CreateTexture(nil, "OVERLAY");
		--t:SetAllPoints(frame);
		--t:SetTexture(0, 0.3, 0, 0.6);
		--frame:SetToplevel(true)

		local content = CreateFrame("Frame",nil,frame)
		self.content = content
		content.obj = self
		content:SetPoint("TOPLEFT",frame,"TOPLEFT", 5 , -35)
		content:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT", -5 , -35)

		acegui:RegisterAsContainer(self)
		return self
	end

	acegui:RegisterWidgetType(Type, Constructor, Version);
end

do
	local frameCount = 0;
	function WS_GUI:GetNewID()
		frameCount = frameCount + 1;
		return frameCount;
	end

	function WS_GUI:IsPresent()
		return frameCount;
	end
end

local function FrameOnClose(widget, event)
	local appName = widget:GetUserData('appName');
	acd.OpenFrames[appName] = nil;
	FramesList[appName] = nil
	acegui:Release(widget)
end

function WSConfigPanel_OnMouseWheel(self, delta)
	--print(self, delta)
	--local prevBtn = _G["WSConfigPanelFramePageNavigationFramePrevPageButton"]
	--local nextBtn = _G["WSConfigPanelFramePageNavigationFrameNextPageButton"]
	local btn = delta > 0 and WSConfigPanelFramePageNavigationFramePrevPageButton or WSConfigPanelFramePageNavigationFrameNextPageButton
	if(btn and btn:IsEnabled() == 1) then
		btn:Click()
	end
end

------------------------
-- tab handling
function WS_GUI:TabResize(tab, padding, absoluteSize, maxWidth, absoluteTextSize)
	local tabName = tab:GetName();

	local buttonMiddle = _G[tabName.."Middle"];
	local buttonMiddleDisabled = _G[tabName.."MiddleDisabled"];
	local sideWidths = 2 * _G[tabName.."Left"]:GetWidth();
	local tabText = _G[tab:GetName().."Text"];
	local width, tabWidth;
	local textWidth;
	if ( absoluteTextSize ) then
		textWidth = absoluteTextSize;
	else
		textWidth = tabText:GetWidth();
	end
	-- If there's an absolute size specified then use it
	if ( absoluteSize ) then
		if ( absoluteSize < sideWidths) then
			width = 1;
			tabWidth = sideWidths
		else
			width = absoluteSize - sideWidths;
			tabWidth = absoluteSize
		end
		tabText:SetWidth(width);
	else
		-- Otherwise try to use padding
		if ( padding ) then
			width = textWidth + padding;
		else
			width = textWidth + 24;
		end
		-- If greater than the maxWidth then cap it
		if ( maxWidth and width > maxWidth ) then
			if ( padding ) then
				width = maxWidth + padding;
			else
				width = maxWidth + 24;
			end
			tabText:SetWidth(width);
		else
			tabText:SetWidth(0);
		end
		tabWidth = width + sideWidths;
	end

	if ( buttonMiddle ) then
		buttonMiddle:SetWidth(width);
	end
	if ( buttonMiddleDisabled ) then
		buttonMiddleDisabled:SetWidth(width);
	end

	tab:SetWidth(tabWidth);
	local highlightTexture = _G[tabName.."HighlightTexture"];
	if ( highlightTexture ) then
		highlightTexture:SetWidth(tabWidth);
	end    
end

function WS_GUI:FrameOnShow(frame)
	frame:SetPoint("TOPLEFT", UIParent, "TOPLEFT", 15, -123);
	self:UpdateFrame(frame);
end

function WS_GUI:DeselectTab(tab)
	local name = tab:GetName();
	_G[name.."Left"]:Show();
	_G[name.."Middle"]:Show();
	_G[name.."Right"]:Show();

	tab:Enable();
	_G[name.."Text"]:SetPoint("CENTER", tab, "CENTER", 0, 2);

	_G[name.."LeftDisabled"]:Hide();
	_G[name.."MiddleDisabled"]:Hide();
	_G[name.."RightDisabled"]:Hide();
end

function WS_GUI:SelectTab(tab)
	local name = tab:GetName();
	_G[name.."Left"]:Hide();
	_G[name.."Middle"]:Hide();
	_G[name.."Right"]:Hide();

	tab:Disable();
	tab:SetDisabledFontObject(GameFontHighlightSmall)
	_G[name.."Text"]:SetPoint("CENTER", tab, "CENTER", 0, -3);

	_G[name.."LeftDisabled"]:Show();
	_G[name.."MiddleDisabled"]:Show();
	_G[name.."RightDisabled"]:Show();

end

function WS_GUI:UpdateFrame(frame)
	--update
	local tabbutton1 = _G[frame:GetName().."CategoryTabButton1"];
	tabbutton1.type = "general";
	tabbutton1:Show();
	local tabbutton2 = _G[frame:GetName().."CategoryTabButton2"]
	tabbutton2.type = "raid";
	tabbutton2:Show();
	local tabbutton3 = _G[frame:GetName().."CategoryTabButton3"];
	tabbutton3.type = "monomer";
	if (AddonList[tabbutton3.type]) then
		tabbutton3:Show();
	end

	for i = 1, 3 do
		local t = _G[frame:GetName().."CategoryTabButton"..i];
		self:TabResize(t);

		if t.type == "general" then
			self:SelectTab(t);
			frame.currentTab = t;
		else
			self:DeselectTab(t);
		end
	end

	self:UpdateAddOnList(frame);
	self:UpdatePages(frame);


	if self:GetFilter("name") ~= nil then
		frame.AddonFilter:SetText(ADDONS..SEARCH);
		self:SetFilter("name", nil, true);
	end
end

function WS_GUI:TabSelect(frame)
	frame:Disable();
	if WSConfigPanelFrame.currentTab then
		WSConfigPanelFrame.currentTab:Enable();
	end
	WSConfigPanelFrame.currentTab = frame;

	for i = 1, 3 do
		local t = _G["WSConfigPanelFrameCategoryTabButton"..i];
		self:TabResize(t);

		if t.type == WSConfigPanelFrame.currentTab.type then
			self:SelectTab(t);
			WSConfigPanelFrame.currentTab = t;
		else
			self:DeselectTab(t);
		end
	end
	WSConfigSettingPanel:Hide()
	self:UpdateAddOnList();
	self:UpdatePages();
end

function WS_GUI:OnInitialize(frame)
	--check extra addons
	for i = 1, GetNumAddOns() do
		local x_reversion = GetAddOnMetadata(i, "X-Revision");
		if (x_reversion == nil or (x_reversion and x_reversion:lower() ~= "wowshell")) then
			local name, title, notes, enabled, loadable, reason, security = GetAddOnInfo(i);
			--register
			local icon = ICONS_LIST[math.random(1, #ICONS_LIST)];
			wsRegisterOption(AddonsCategoryType3, name, name, title, notes, icon);
		end
	end
end

--addon load
function WS_GUI:processQueue(...)
	local addonName = ...;

	if queueList[addonName] and type(queueList[addonName]) == "function" then
		local status, msg = pcall(queueList[addonName]);
		if (status) then
			queueList[addonName] = nil;
		else
			print(msg);
		end
	end
	
	if loadPluginsList[addonName] and type(loadPluginsList[addonName]) == "table" then
		if select("#", loadPluginsList[addonName]) > 0 then
			for a = 1, #loadPluginsList[addonName] do
				local plugin = loadPluginsList[addonName][a];
				local name, title, notes, enabled, loadable, reason, security = GetAddOnInfo(plugin);
				local demand = IsAddOnLoadOnDemand(plugin);
				if reason ~= nil then
					if reason == "DISABLED" then
						EnableAddOn(name);
					end
				end
			end
		end

		loadPluginsList[addonName] = nil;
	end
end

--first load?
function wsQueueLoad(addonName, infoTable, callback)
	local name, title, notes, enabled, loadable, reason, security = GetAddOnInfo(addonName);
	if callback == nil and type(infoTable) == "function" then
		callback = infoTable;
	end

	if (reason) then
		local category, addonName, appName, name, description, icon, order = unpack(infoTable);
		wsRegisterOption(category, addonName, appName, name, description, icon, nil, order);
	else
		--register queue load
		queueList[addonName] = callback;
	end
end

local function filterAddon(text)
	local _, list; 
	local patern = "";
	if text ~= nil then
		if text:utf8len() > 4 then
			patern = text;
		else
			for i = 1, text:utf8len() do
				local t = text:utf8sub(i, i);
				patern = patern .. t .. ".*";
			end
		end
	end
	for k, list in next, AddonList do
		for i = 1, #list do
			local addon = list[i];
			local name, pinyin, addonName = addon.name, addon.pinyin, addon.addonName:lower();
			if text == nil or text == "" then
				addon.hidden = false;
			else
				if (name:match(patern) ~= nil or pinyin:match(patern) ~= nil or addonName:match(patern) ~= nil) then
					addon.hidden = false;
				else
					addon.hidden = true;
				end
			end
		end
	end
end

function WS_GUI:SetFilter(key, value)
	if filters[key] ~= value then
		filters[key] = value;

		filterAddon(value);
		self:UpdateLayout();

		return true;
	end
end

function WS_GUI:GetFilter(key)
	return filters[key];
end

--[[
category:
name
description
icon
callback: function / table
order
]]
local _order = 30;
--update: category, addonName, appName, name, description, icon, options, order
function wsRegisterOption(...)
	local category, addonName, appName, name, description, icon, options, order, plugins, isNew = ...

	if (not addonName) then return end
	local _, title, notes, enabled, loadable, reason, security = GetAddOnInfo(addonName);
	local addon = {};
	appName = "WSGUI_"..appName;

	category = strlower(category);
	if category ~= "raid" then
		if category == AddonsCategoryType3 then
			category = AddonsCategoryType3;
		else
			category = "general";
		end
	end

	addon.category = category;
	addon.addonName = addonName;
	addon.appName = appName;
	addon.name = name
	addon.description = description;
	addon.hidden = false;
	addon.pinyin = PY:toPinyin(name, false, "");
	addon.disabled = false;
	addon.isNew = (type(isNew) == "boolean" and isNew == true) and true or false;

	if (type(icon) == "table") then
		print(addonName);
	end

	if (icon:find("^Interface")) then
		addon.icon = icon
	else
		addon.icon = "Interface\\Icons\\"..icon;
	end


	addon.configable = true;
	if type(options) == "table" then
		local ok, msg = pcall(cfgreg.RegisterOptionsTable, self, appName, options);
	elseif type(options) == "function" then
		addon.callback = options;
	else
		addon.configable = false;
	end

	if order then
		addon.order = order
	else
		_order = _order + 1;
		addon.order = _order
	end

	if addon.isNew then
		addon.order = addon.order - 150;
	end

	if plugins and type(plugins) == "table" then
		loadPluginsList[addonName] = plugins;
	end
	
	--处理特殊类插件
	--local loadon_class = GetAddOnMetadata(addonName, "X-LoadOn-Class");
	--if (loadon_class) then
	--	if loadon_class:lower() ~= pclass then
	--		print(pclass,loadon_class:lower())
	--		DisableAddOn(addonName);
	--		addon.reason = "本插件是职业专属插件, 与当前职业不符. 已自动禁用.";
	--		addon.configable = false;--将设置按钮变灰 不可用
	--		addon.disabled = true;
	--	end
	--end

	if (reason == "MISSING") then
		return;
	end

	if not AddonList[category] then
		AddonList[category] = {}
	end

	tinsert(AddonList[category], addon);
	first = true -- resort buttons
end

function WowshellGUIFilterDropDown_OnLoad(frame)
	UIDropDownMenu_Initialize(frame, WowshellGUIFilterDropDown_Initialize, "MENU");
	WowshellGUIFilterDropDownText:SetJustifyH("CENTER");
	WowshellGUIFilterDropDownButton:Show();
end

--[[
local AddonsCategories = {
	Achievements = {
		name = "成就"
	},
	ActionBars = {
		name = "动作条"
	},
	Auction = {
		name = "拍卖行"
	},
	Bags = {
		name = "背包"
	},
	BossEncounters = {
		name = "首领战"
	}
}
]]
function WowshellGUIFilterDropDown_Initialize(frame, level)
		if level == 1 then
		for k, v in pairs(AddonsCategories) do
			local info = UIDropDownMenu_CreateInfo();
			info.text = v.name;
			info.isNotRadio = true;
			UIDropDownMenu_AddButton(info, level)
		end
	end
end

--- minibutton ----
local x, y, centerX, centerY
function WS_GUI:MoveMinimapButton(frame)
	centerY, centerX = (Minimap:GetTop()-((Minimap:GetTop()-Minimap:GetBottom())/2)), 
	(Minimap:GetLeft()+((Minimap:GetRight()-Minimap:GetLeft())/2))
	x, y = GetCursorPosition();
	local s = WoWShellMiniButton:GetEffectiveScale();
	x, y =x/s, y/s;
	x, y = -(centerX - x), -(centerY - y);
	centerX, centerY = math.abs(x), math.abs(y)
	centerX, centerY = (centerX / sqrt((centerX * centerX) + (centerY * centerY))) * 76, (centerY / sqrt((centerX * 
	centerX) + (centerY * centerY))) * 76;
	if (x < 0 ) then
		centerX = -centerX;
	end

	if (y < 0) then
		centerY = -centerY;
	end

	WoWShellMiniButton:ClearAllPoints();
	WoWShellMiniButton:SetPoint("CENTER", centerX, centerY);
	WoWShellMiniButton:SetUserPlaced(true)

	do
		local button = MBB_MinimapButtonFrame
		if(button) then
			button:ClearAllPoints()
			button:SetPoint('CENTER', WoWShellMiniButton)
		end
	end
end

function WS_GUI:MinimapTooltip(frame)
	GameTooltip:SetOwner(frame, "ANCHOR_RIGHT");
	GameTooltip:SetText(L["鼠标拖动"])
	GameTooltip:AddLine(L["鼠标左击打开精灵设置面板"], 1, 1, 1);
	GameTooltip:AddLine(L["鼠标右击打开显示小地图按钮集"], 1, 1, 1);
	GameTooltip:AddLine(L["Shift-点击打开更新日志"]);
	GameTooltip:Show();
end

local function formatLog(str)
	local str = string.gsub(str, "\<br\/\>", "");
	local str = string.gsub(str, "\<h2\>", "|cffffd200");
	local str = string.gsub(str, "\<\/h2\>", "|r");
	return str;
end

do
	local wsloger
	function WS_GUI:OpenUpdateLog()
		self:CloseAll();
		if not wsloger then
			local ok, msg = pcall(cfgreg.RegisterOptionsTable, self, "WSUpdateLog", {
				type = "group",
				name = "魔兽精灵更新日志",
				args = {
					logger = {
						type = "description",
						name = formatLog(WSLog),
						fontSize = "medium"
					}
				},
			});
			wsloger = true;
		end
		--WSConfigPanelFrame:ToggleFrame(1)
		WS_GUI:ToggleFrame(true)
		WSConfigSettingPanel:Show();
		WSConfigSettingPanelTitleText:SetText("更新日志");
		acd:Open("WSUpdateLog");
	end
end

function WS_GUI:OpenToolBox()
	if(not WS_GUI.tool_box_registered) then
		WS_GUI.tool_box_registered = true

		local ok, msg = pcall(cfgreg.RegisterOptionsTable, self, "WSToolBox", {
			type = 'group',
			name = 'tool box',
			args = {
				reloadui = {
					type = 'execute',
					order = order(),
					name = '重载界面',
					func = function() ReloadUI() end,
				},
			},
		})
	end
	self:CloseAll()
	--Wowshell_GUI_OptionFrame_AddonSettingInfo:Hide();
	acd:Open('WSToolBox');
end

function WS_CONFIG_BUTTON_SET_FONT_SIZE()
	for i = 1, 12 do
		local button = _G['WSConfigPanelFrameAddOnIconsFrameAddOnButton'..i]
		local addonName = _G[button:GetName()..'AddonName'];

		local font, size, flag = addonName:GetFont()
		addonName:SetFont(font, 18, flag)
	end
end
