
	local Loc = LibStub("AceLocale-3.0"):GetLocale( "Details" )
	local Details = _G.Details
	local PixelUtil = PixelUtil or DFPixelUtil
	local addonName, Details222 = ...
	local CreateFrame = CreateFrame
	local detailsFramework = DetailsFramework
	local UIParent = UIParent
	local UISpecialFrames = UISpecialFrames
	local breakdownWindowFrame = Details.BreakdownWindowFrame

	DETAILSPLUGIN_ALWAYSENABLED = 0x1 --[[GLOBAL]]

	local CONST_PLUGINWINDOW_MENU_WIDTH = 150
	local CONST_PLUGINWINDOW_MENU_HEIGHT = 22
	local CONST_PLUGINWINDOW_MENU_X = -5
	local CONST_PLUGINWINDOW_MENU_Y = -26
	local CONST_PLUGINWINDOW_WIDTH = 925
	local CONST_PLUGINWINDOW_HEIGHT = 600

	---default cooltip appearance for plugin tooltips
	function Details:SetCooltipForPlugins()
		local gameCooltip = GameCooltip
        gameCooltip:Preset(2)
		gameCooltip:SetOption("TextSize", Details.font_sizes.menus)
		gameCooltip:SetOption("TextFont", Details.font_faces.menus)
		gameCooltip:SetOption("LineHeightSizeOffset", 0)
		gameCooltip:SetOption("LineYOffset", 0)
		gameCooltip:SetOption("LinePadding", -1)
		gameCooltip:SetOption("FrameHeightSizeOffset", 0)
		gameCooltip:SetOption("FixedWidth", 280)
		gameCooltip:SetOption("StatusBarTexture", [[Interface\AddOns\Details\images\bar_serenity]])
		gameCooltip:SetOption("LeftTextWidth", 280 - 22 - 90)
		gameCooltip:SetOption("LeftTextHeight", 14)
		Details:SetTooltipMinWidth()
	end


	---comment
	---@param pluginAbsoluteName string
	---@return unknown
	function Details:GetPlugin(pluginAbsoluteName)
		return Details.SoloTables.NameTable[pluginAbsoluteName] or Details.RaidTables.NameTable[pluginAbsoluteName] or Details.ToolBar.NameTable[pluginAbsoluteName] or Details.StatusBar.NameTable[pluginAbsoluteName] or Details.PluginsLocalizedNames[pluginAbsoluteName] or Details.PluginsGlobalNames[pluginAbsoluteName]
	end

	---comment
	---@param pluginAbsoluteName string
	---@return unknown
	function Details:GetPluginSavedTable(pluginAbsoluteName)
		return Details.plugin_database[pluginAbsoluteName]
	end

	---comment
	function Details:UpdatePluginBarsConfig()
		---@type instance
		local instanceObject = self:GetPluginInstance()
		if (instanceObject) then
			self.row_info = self.row_info or {}
			Details.table.copy(self.row_info, instanceObject.row_info)
			self.bars_grow_direction = instanceObject.bars_grow_direction
			self.row_height = instanceObject.row_height
			self:SetBarGrowDirection()
		end
	end

	function Details:AttachToInstance()
		---@type instance
		local instanceObject = self:GetPluginInstance()
		if (instanceObject) then
			local width, height = instanceObject:GetSize()
			self.Frame:SetSize(width, height)
		end
	end

	---comment
	---@param pluginAbsoluteName string|nil
	---@return any
	function Details:GetPluginInstance(pluginAbsoluteName)
		local plugin = self
		if (pluginAbsoluteName) then
			plugin = Details:GetPlugin(pluginAbsoluteName)
		end

		local id = plugin.instance_id
		if (id) then
			return Details:GetInstance(id)
		end
	end

	function Details:IsPluginEnabled(pluginAbsoluteName)
		if (pluginAbsoluteName) then
			local plugin = Details.plugin_database[pluginAbsoluteName]
			if (plugin) then
				return plugin.enabled
			end
		else
			return self.__enabled
		end
	end

	---comment
	---@param desc string
	function Details:SetPluginDescription(desc)
		self.__description = desc
	end

	---get the description of a plugin
	---@return string
	function Details:GetPluginDescription()
		return self.__description or ""
	end

	---disable a plugin
	---@param pluginAbsoluteName string
	---@return boolean
	function Details:DisablePlugin(pluginAbsoluteName)
		local plugin = Details:GetPlugin(pluginAbsoluteName)

		if (plugin) then
			local savedTable = Details:GetPluginSavedTable(pluginAbsoluteName)
			savedTable.enabled = false
			plugin.__enabled = false

			Details:SendEvent("PLUGIN_DISABLED", plugin)
			Details:DelayOptionsRefresh()
			return true
		end

		return false
	end

	---check if the plugin saved table has all the default key and values
	---@param savedTable table
	---@param defaultSavedTable table
	function Details:CheckDefaultTable(savedTable, defaultSavedTable)
		for key, value in pairs(defaultSavedTable) do
			if (type(value) == "table") then
				if (type(savedTable[key]) ~= "table") then
					savedTable[key] = Details.CopyTable(value)
				else
					Details:CheckDefaultTable(savedTable[key], value)
				end
			else
				if (savedTable[key] == nil) then
					savedTable[key] = value
				end
			end
		end
	end

	function Details:InstallPlugin(pluginType, pluginName, pluginIcon, pluginObject, pluginAbsoluteName, minVersion, authorName, version, defaultSavedTable)
		if (minVersion and minVersion > Details.realversion) then
			print(pluginName, Loc["STRING_TOOOLD"])
			return Details:NewError("Details version is out of date.")
		end

		if (pluginType == "TANK") then
			pluginType = "RAID"
		end

		if (not pluginType) then
			return Details:NewError("InstallPlugin parameter 1 (plugin type) not especified")
		elseif (not pluginName) then
			return Details:NewError("InstallPlugin parameter 2 (plugin name) can't be nil")
		elseif (not pluginIcon) then
			return Details:NewError("InstallPlugin parameter 3 (plugin icon) can't be nil")
		elseif (not pluginObject) then
			return Details:NewError("InstallPlugin parameter 4 (plugin object) can't be nil")
		elseif (not pluginAbsoluteName) then
			return Details:NewError("InstallPlugin parameter 5 (plugin absolut name) can't be nil")
		end

		if (_G[pluginAbsoluteName]) then
			print(Loc["STRING_PLUGIN_NAMEALREADYTAKEN"] .. ": " .. pluginName .. " name: " .. pluginAbsoluteName)
			return
		else
			_G[pluginAbsoluteName] = pluginObject
			pluginObject.real_name = pluginAbsoluteName
		end

		pluginObject.__name = pluginName
		pluginObject.__author = authorName or "--------"
		pluginObject.__version = version or "v1.0.0"
		pluginObject.__icon = pluginIcon or[[Interface\ICONS\Trade_Engineering]]
		pluginObject.real_name = pluginAbsoluteName

		Details.PluginsGlobalNames[pluginAbsoluteName] = pluginObject
		Details.PluginsLocalizedNames[pluginName] = pluginObject

		local savedTable

		if (pluginType ~= "STATUSBAR") then
			savedTable = Details.plugin_database[pluginAbsoluteName]

			if (not savedTable) then
				savedTable = {enabled = true, author = authorName or "--------"}
				Details.plugin_database[pluginAbsoluteName] = savedTable
			end

			if (defaultSavedTable) then
				Details:CheckDefaultTable(savedTable, defaultSavedTable)
			end

			pluginObject.__enabled = savedTable.enabled
		end

		if (pluginType == "SOLO") then
			if (not pluginObject.Frame) then
				return Details:NewError("plugin doesn't have a Frame, please check case-sensitive member name: Frame")
			end

			Details.SoloTables.Plugins[#Details.SoloTables.Plugins+1] = pluginObject
			Details.SoloTables.Menu[#Details.SoloTables.Menu+1] = {pluginName, pluginIcon, pluginObject, pluginAbsoluteName}
			Details.SoloTables.NameTable[pluginAbsoluteName] = pluginObject
			Details:SendEvent("INSTALL_OKEY", pluginObject)
			Details.PluginCount.SOLO = Details.PluginCount.SOLO + 1

		elseif (pluginType == "RAID") then
			Details.RaidTables.Plugins[#Details.RaidTables.Plugins+1] = pluginObject
			Details.RaidTables.Menu[#Details.RaidTables.Menu+1] = {pluginName, pluginIcon, pluginObject, pluginAbsoluteName}
			Details.RaidTables.NameTable[pluginAbsoluteName] = pluginObject
			Details:SendEvent("INSTALL_OKEY", pluginObject)
			Details.PluginCount.RAID = Details.PluginCount.RAID + 1
			Details:InstanceCall("RaidPluginInstalled", pluginAbsoluteName)

		elseif (pluginType == "TOOLBAR") then
			Details.ToolBar.Plugins[#Details.ToolBar.Plugins+1] = pluginObject
			Details.ToolBar.Menu[#Details.ToolBar.Menu+1] = {pluginName, pluginIcon, pluginObject, pluginAbsoluteName}
			Details.ToolBar.NameTable[pluginAbsoluteName] = pluginObject
			Details:SendEvent("INSTALL_OKEY", pluginObject)
			Details.PluginCount.TOOLBAR = Details.PluginCount.TOOLBAR + 1

		elseif (pluginType == "STATUSBAR") then
			Details.StatusBar.Plugins[#Details.StatusBar.Plugins+1] = pluginObject
			Details.StatusBar.Menu[#Details.StatusBar.Menu+1] = {pluginName, pluginIcon}
			Details.StatusBar.NameTable[pluginAbsoluteName] = pluginObject
			Details:SendEvent("INSTALL_OKEY", pluginObject)
			Details.PluginCount.STATUSBAR = Details.PluginCount.STATUSBAR + 1
		end

		if (savedTable) then
			pluginObject.db = savedTable
		end

		if (pluginObject.__enabled) then
			return true, savedTable, true
		else
			return true, savedTable, false
		end
	end

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--internal functions

	---@type table<plugintype, number>
	Details.PluginCount = {
		["SOLO"] = 0,
		["RAID"] = 0,
		["TOOLBAR"] = 0,
		["STATUSBAR"] = 0
	}

	local onEnableFunction = function(self)
		self.__parent.Enabled = true
		---@type instance
		local instanceObject = Details:GetInstance(self.__parent.instance_id)
		if (instanceObject) then
			self:SetParent(instanceObject.baseframe)
		end
		Details:SendEvent("SHOW", self.__parent)
	end

	local onDisableFunction = function(self)
		Details:SendEvent("HIDE", self.__parent)
		if (bit.band(self.__parent.__options, DETAILSPLUGIN_ALWAYSENABLED) == 0) then
			self.__parent.Enabled = false
		end
	end

	local buildDefaultStatusBarMembers = function(self)
		self.childs = {}
		self.__index = self
		function self:Setup()
			Details.StatusBar:OpenOptionsForChild(self)
		end
	end

	local temp_event_function = function()
		print("=====================")
		print("Hello There plugin developer!")
		print("Please make sure you are declaring")
		print("A member called 'OnDetailsEvent' on your plugin object")
		print("With a function to receive the events like bellow:")
		print("function PluginObject:OnDetailsEvent(event, ...) end")
		print("Thank You Sir!===================")
	end

	local registerEventFunc = function(self, event)
		self.Frame:RegisterEvent(event)
	end

	local unregisterEventFunc = function(self, event)
		self.Frame:UnregisterEvent(event)
	end

	---@param frameName string
	---@param pluginFlag number
	---@param pluginType plugintype
	function Details:NewPluginObject(frameName, pluginFlag, pluginType)
		pluginFlag = pluginFlag or 0x0
		local newPluginObject = {__options = pluginFlag, __enabled = true, RegisterEvent = registerEventFunc, UnregisterEvent = unregisterEventFunc}

		local pluginFrame = CreateFrame("Frame", frameName, UIParent, "BackdropTemplate")
		pluginFrame:RegisterEvent("PLAYER_LOGIN")
		pluginFrame:RegisterEvent("PLAYER_LOGOUT")
		pluginFrame:SetFrameStrata("HIGH")
		pluginFrame:SetFrameLevel(6)
		pluginFrame:Hide()
		pluginFrame:SetScript("OnShow", onEnableFunction)
		pluginFrame:SetScript("OnHide", onDisableFunction)
		pluginFrame.__parent = newPluginObject

		pluginFrame:SetScript("OnEvent", function(self, event, ...)
			if (newPluginObject.OnEvent) then
				if (event == "PLAYER_LOGIN") then
					newPluginObject:OnEvent(self, "ADDON_LOADED", newPluginObject.Frame:GetName())
					newPluginObject.Frame:Hide()
					return
				end
				return newPluginObject:OnEvent(self, event, ...)
			end
		end)

		if (bit.band(pluginFlag, DETAILSPLUGIN_ALWAYSENABLED) ~= 0) then
			newPluginObject.Enabled = true
		else
			newPluginObject.Enabled = false
		end

		--default members
		if (pluginType == "STATUSBAR") then
			buildDefaultStatusBarMembers(newPluginObject)
		end

		newPluginObject.Frame = pluginFrame
		newPluginObject.OnDetailsEvent = temp_event_function
		setmetatable(newPluginObject, Details)

		return newPluginObject
	end

	function Details:CreatePluginOptionsFrame(name, title, template)
		template = template or 1

		if (template == 2) then
			local optionsFrame = CreateFrame("frame", name, UIParent, "ButtonFrameTemplate, BackdropTemplate")
			table.insert(UISpecialFrames, name)
			optionsFrame:SetSize(500, 200)
			optionsFrame:SetMovable(true)
			optionsFrame:EnableMouse(true)
			optionsFrame:SetFrameStrata("DIALOG")
			optionsFrame:SetToplevel(true)
			optionsFrame:SetPoint("center", UIParent, "center")
			optionsFrame:Hide()

			optionsFrame:SetScript("OnMouseDown", function(self, button)
				if (button == "RightButton") then
					if (self.moving) then
						self.moving = false
						self:StopMovingOrSizing()
					end
					return optionsFrame:Hide()
				elseif (button == "LeftButton" and not self.moving) then
					self.moving = true
					self:StartMoving()
				end
			end)

			optionsFrame:SetScript("OnMouseUp", function(self)
				if (self.moving) then
					self.moving = false
					self:StopMovingOrSizing()
				end
			end)

			return optionsFrame

		elseif (template == 1) then
			local optionsFrame = CreateFrame("frame", name, UIParent, "BackdropTemplate")
			table.insert(UISpecialFrames, name)
			optionsFrame:SetSize(500, 200)
			optionsFrame:SetMovable(true)
			optionsFrame:EnableMouse(true)
			optionsFrame:SetFrameStrata("DIALOG")
			optionsFrame:SetToplevel(true)
			optionsFrame:SetPoint("center", UIParent, "center", 0, 0)
			optionsFrame:Hide()

			optionsFrame:SetScript("OnMouseDown", function(self, button)
				if (button == "RightButton") then
					if (self.moving) then
						self.moving = false
						self:StopMovingOrSizing()
					end
					return optionsFrame:Hide()
				elseif (button == "LeftButton" and not self.moving) then
					self.moving = true
					self:StartMoving()
				end
			end)

			optionsFrame:SetScript("OnMouseUp", function(self)
				if (self.moving) then
					self.moving = false
					self:StopMovingOrSizing()
				end
			end)

			optionsFrame:SetBackdrop({bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", tile = true, tileSize = 16,
			edgeFile = [[Interface\AddOns\Details\images\border_2]], edgeSize = 32,
			insets = {left = 1, right = 1, top = 1, bottom = 1}})
			optionsFrame:SetBackdropColor(0, 0, 0, .7)

			detailsFramework:ApplyStandardBackdrop(optionsFrame)
			detailsFramework:CreateTitleBar(optionsFrame, title)

			local bigDogTexture = detailsFramework:NewImage(optionsFrame, [[Interface\MainMenuBar\UI-MainMenuBar-EndCap-Human]], 110, 120, nil, {1, 0, 0, 1}, "backgroundBigDog", "$parentBackgroundBigDog")
			bigDogTexture:SetPoint("bottomright", optionsFrame, "bottomright", -3, 0)
			bigDogTexture:SetAlpha(.25)

			return optionsFrame
		end
	end

	function Details:CreatePluginWindowContainer()
		local pluginContainerFrame = CreateFrame("frame", "DetailsPluginContainerWindow", UIParent, "BackdropTemplate")
		pluginContainerFrame:EnableMouse(true)
		pluginContainerFrame:SetMovable(true)
		pluginContainerFrame:SetPoint("center", UIParent, "center", 0, 0)
		pluginContainerFrame:SetBackdrop(Details.PluginDefaults and Details.PluginDefaults.Backdrop or {bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", tile = true, tileSize = 16, edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1})
		pluginContainerFrame:SetBackdropColor(0, 0, 0, 0.3)
		pluginContainerFrame:SetBackdropBorderColor(0, 0, 0, 1)
		table.insert(UISpecialFrames, "DetailsPluginContainerWindow")

		local scaleBar = DetailsFramework:CreateScaleBar(pluginContainerFrame, Details.options_window)
		scaleBar:SetFrameStrata("fullscreen")
		pluginContainerFrame:SetScale(Details.options_window.scale)

		pluginContainerFrame:Hide()

		--members
		pluginContainerFrame.MenuX = CONST_PLUGINWINDOW_MENU_X
		pluginContainerFrame.MenuY = CONST_PLUGINWINDOW_MENU_Y
		pluginContainerFrame.MenuButtonWidth = CONST_PLUGINWINDOW_MENU_WIDTH
		pluginContainerFrame.MenuButtonHeight = CONST_PLUGINWINDOW_MENU_HEIGHT
		pluginContainerFrame.FrameWidth = CONST_PLUGINWINDOW_WIDTH
		pluginContainerFrame.FrameHeight = CONST_PLUGINWINDOW_HEIGHT
		pluginContainerFrame.TitleHeight = 20

		--store button references for the left menu
		pluginContainerFrame.MenuButtons = {}
		--store all plugins embed
		pluginContainerFrame.EmbedPlugins = {}

		--lib window
		pluginContainerFrame:SetSize(pluginContainerFrame.FrameWidth, pluginContainerFrame.FrameHeight)
		local LibWindow = LibStub("LibWindow-1.1")
		LibWindow.RegisterConfig(pluginContainerFrame, Details.plugin_window_pos)
		LibWindow.RestorePosition(pluginContainerFrame)
		LibWindow.MakeDraggable(pluginContainerFrame)
		LibWindow.SavePosition(pluginContainerFrame)

		--menu background
		local menuBackground = CreateFrame("frame", "$parentMenuFrame", pluginContainerFrame, "BackdropTemplate")
		DetailsFramework:ApplyStandardBackdrop(menuBackground)

		--statusbar
		local statusBar = CreateFrame("frame", nil, menuBackground, "BackdropTemplate")
		statusBar:SetPoint("topleft", menuBackground, "bottomleft", 0, 1)
		statusBar:SetPoint("topright", pluginContainerFrame, "bottomright", 0, 1)
		statusBar:SetHeight(20)
		statusBar:SetAlpha(1)

		DetailsFramework:BuildStatusbarAuthorInfo(statusBar)
		DetailsFramework:ApplyStandardBackdrop(statusBar)

		local extraDarkTexture = statusBar:CreateTexture(nil, "background")
		extraDarkTexture:SetAllPoints()
		extraDarkTexture:SetColorTexture(.2, .2, .2, .8)

		local rightClickToBackLabel = detailsFramework:CreateLabel(statusBar, "right click to close", 10, "gray")
		rightClickToBackLabel:SetPoint("bottomright", statusBar, "bottomright", -1, 5)
		rightClickToBackLabel:SetAlpha(.4)

		menuBackground:SetPoint("topright", pluginContainerFrame, "topleft", -2, 0)
		menuBackground:SetPoint("bottomright", pluginContainerFrame, "bottomleft", -2, 0)
		menuBackground:SetWidth(pluginContainerFrame.MenuButtonWidth + 6)

		local bigDogTexture = detailsFramework:NewImage(menuBackground, [[Interface\MainMenuBar\UI-MainMenuBar-EndCap-Human]], 180*0.7, 200*0.7, "overlay", {0, 1, 0, 1}, "backgroundBigDog", "$parentBackgroundBigDog")
		bigDogTexture:SetPoint("bottomleft", custom_window, "bottomleft", 0, 1)
		bigDogTexture:SetAlpha(0.3)

		local gradientBelowTheLine = DetailsFramework:CreateTexture(menuBackground, {gradient = "vertical", fromColor = {0, 0, 0, 0.45}, toColor = "transparent"}, 1, 95, "artwork", {0, 1, 0, 1}, "dogGradient")
		gradientBelowTheLine:SetPoint("bottoms")

		local bigDogRowTexture = menuBackground:CreateTexture(nil, "artwork")
		bigDogRowTexture:SetPoint("bottomleft", menuBackground, "bottomleft", 1, 1)
		bigDogRowTexture:SetPoint("bottomright", menuBackground, "bottomright", -1, 1)
		bigDogRowTexture:SetHeight(20)
		bigDogRowTexture:SetColorTexture(.5, .5, .5, .1)
		bigDogRowTexture:Hide()

		--plugins menu title bar
		local titleBarPlugins = CreateFrame("frame", nil, menuBackground, "BackdropTemplate")
		PixelUtil.SetPoint(titleBarPlugins, "topleft", menuBackground, "topleft", 2, -3)
		PixelUtil.SetPoint(titleBarPlugins, "topright", menuBackground, "topright", -2, -3)
		titleBarPlugins:SetHeight(pluginContainerFrame.TitleHeight)
		titleBarPlugins:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\AddOns\Details\images\background]], tileSize = 64, tile = true})
		titleBarPlugins:SetBackdropColor(.5, .5, .5, 1)
		titleBarPlugins:SetBackdropBorderColor(0, 0, 0, 1)

		--title label
		local titleBarPlugins_TitleLabel = detailsFramework:NewLabel(titleBarPlugins, titleBarPlugins, nil, "titulo", "Plugins", "GameFontHighlightLeft", 12, {227/255, 186/255, 4/255})
		PixelUtil.SetPoint(titleBarPlugins_TitleLabel, "center", titleBarPlugins , "center", 0, 0)
		PixelUtil.SetPoint(titleBarPlugins_TitleLabel, "top", titleBarPlugins , "top", 0, -5)

		--plugins menu title bar
		local titleBarTools = CreateFrame("frame", nil, menuBackground, "BackdropTemplate")
		titleBarTools:SetHeight(pluginContainerFrame.TitleHeight)
		titleBarTools:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\AddOns\Details\images\background]], tileSize = 64, tile = true})
		titleBarTools:SetBackdropColor(.5, .5, .5, 1)
		titleBarTools:SetBackdropBorderColor(0, 0, 0, 1)

		--title label
		local titleBarTools_TitleLabel = detailsFramework:NewLabel(titleBarTools, titleBarTools, nil, "titulo", "Tools", "GameFontHighlightLeft", 12, {227/255, 186/255, 4/255})
		PixelUtil.SetPoint(titleBarTools_TitleLabel, "center", titleBarTools , "center", 0, 0)
		PixelUtil.SetPoint(titleBarTools_TitleLabel, "top", titleBarTools , "top", 0, -5)

		--check if the window isn't out of screen
		pluginContainerFrame:SetScript("OnShow", function()
			C_Timer.After(1, function()
				local right = pluginContainerFrame:GetRight()
				if (right and right > GetScreenWidth() + 500) then
					pluginContainerFrame:ClearAllPoints()
					pluginContainerFrame:SetPoint("center", UIParent, "center", 0, 0)
					LibWindow.SavePosition(pluginContainerFrame)
					Details:Msg("detected options panel out of screen, position has reset")
				end

				local scaleFactor = pluginContainerFrame:GetScale()
				if (scaleFactor < 0.65) then
					pluginContainerFrame:SetScale(0.65)
					Details:Msg("detected options panel scale issue, scale has reset, please reload the UI")
				end
			end)
		end)

		pluginContainerFrame:SetScript("OnHide", function()
		end)

		pluginContainerFrame:SetScript("OnMouseDown", function(self, button)
			if (button == "RightButton") then
				pluginContainerFrame.ClosePlugin()
			end
		end)

		pluginContainerFrame.Debug = false
		function pluginContainerFrame.DebugMsg(...)
			if (pluginContainerFrame.Debug) then
				print("[Details! Debug]", ...)
			end
		end

		local getPluginObject = function(pluginAbsoluteName)
			local pluginObject = Details:GetPlugin(pluginAbsoluteName)
			if (not pluginObject) then
				for index, plugin in ipairs(pluginContainerFrame.EmbedPlugins) do
					if (plugin.real_name == pluginAbsoluteName) then
						pluginObject = plugin
					end
				end

				if (not pluginObject) then
					pluginContainerFrame.DebugMsg("Plugin not found")
					return
				end
			end
			return pluginObject
		end

		local hideOtherPluginFrames = function(pluginObject)
			local bIsShowingAPlugin = Details222.BreakdownWindow.IsPluginShown()
			local pluginShownInBreakdownWindow = breakdownWindowFrame.GetShownPluginObject()

			for index, thisPluginObject in ipairs(pluginContainerFrame.EmbedPlugins) do
				if (thisPluginObject ~= pluginObject) then
					if (thisPluginObject.__isUtility) then
						--hide this plugin
						if (thisPluginObject.Frame:IsShown()) then
							thisPluginObject.Frame:Hide()
						end
					else
						if (bIsShowingAPlugin) then
							if (pluginShownInBreakdownWindow == thisPluginObject) then
								--do nothing yet
							else
								--hide this plugin
								if (thisPluginObject.Frame:IsShown()) then
									thisPluginObject.Frame:Hide()
								end
							end
						else
							--hide this plugin
							if (thisPluginObject.Frame:IsShown()) then
								thisPluginObject.Frame:Hide()
							end
						end
					end
				end
			end
		end

		local highlightPluginButton = function(pluginAbsoluteName)
			for index, button in ipairs(pluginContainerFrame.MenuButtons) do
				button:Show()

				if (button.PluginAbsName == pluginAbsoluteName) then
					button:SetTemplate(detailsFramework:GetTemplate("button", "DETAILS_PLUGINPANEL_BUTTONSELECTED_TEMPLATE"))
				else
					button:SetTemplate(detailsFramework:GetTemplate("button", "DETAILS_PLUGINPANEL_BUTTON_TEMPLATE"))
				end
			end
		end

		function pluginContainerFrame.OnMenuClick(_, _, pluginAbsoluteName, callRefresh)
			local pluginObject = getPluginObject(pluginAbsoluteName)
			if (not pluginObject) then
				return
			end

			--hide other plugin windows
			hideOtherPluginFrames(pluginObject)

			--re set the point of the frame within the main plugin window
			pluginContainerFrame.RefreshFrame(pluginObject.__var_Frame)
			C_Timer.After(0, function()
				pluginContainerFrame.RefreshFrame(pluginObject.__var_Frame)
			end)

			--show the plugin window
			if (pluginObject.RefreshWindow and callRefresh) then
				DetailsFramework:QuickDispatch(pluginObject.RefreshWindow)
			end

			--highlight the plugin button on the menu
			highlightPluginButton(pluginAbsoluteName)

			--show the container
			pluginContainerFrame:Show()

			--check if the plugin has a callback for when showing the frame
			if (pluginObject.__OnClickFromOptionsCallback) then
				--safe run the plugin callback
				DetailsFramework:QuickDispatch(pluginObject.__OnClickFromOptionsCallback)
			end

			return true
		end

		---create a button fro the plugin be selected in the options panel
		---@param self details
		---@param pluginObject any
		---@param bIsUtility any
		---@param parent frame
		---@param onClickFunc function
		---@param width number
		---@param height number
		---@return button
		function Details:CreatePluginMenuButton(pluginObject, bIsUtility, parent, onClickFunc, width, height)
			local newButton = detailsFramework:CreateButton(parent, onClickFunc, width, height, pluginObject.__name, pluginObject.real_name, true)
			newButton.PluginAbsName = pluginObject.real_name
			newButton.PluginName = pluginObject.__name
			newButton.IsUtility = bIsUtility
			pluginObject.__isUtility = bIsUtility

			newButton:SetTemplate(detailsFramework:GetTemplate("button", "DETAILS_PLUGINPANEL_BUTTON_TEMPLATE"))
			newButton:SetText(pluginObject.__name)
			newButton.textsize = 10
			newButton:SetIcon(pluginObject.__icon, nil, nil, nil, pluginObject.__iconcoords, pluginObject.__iconcolor, 4)

			return newButton
		end

		local onHide = function(self)
			DetailsPluginContainerWindow.ClosePlugin()
		end

		local setupFrameFunctions = function(frame)
			frame:SetScript("OnMouseDown", nil)
			frame:SetScript("OnMouseUp", nil)
			frame:HookScript("OnHide", onHide)
		end

		function pluginContainerFrame.RefreshFrame(frame, parent)
			frame:EnableMouse(false)
			frame:SetSize(pluginContainerFrame.FrameWidth, pluginContainerFrame.FrameHeight)
			frame:ClearAllPoints()
			PixelUtil.SetPoint(frame, "topleft", parent or pluginContainerFrame, "topleft", 0, 0)
			frame:SetParent(parent or pluginContainerFrame)
			frame:Show()
		end

		---a plugin has request to be embed into the main plugin window
		---@param pluginObject table can be the plugin object or any frame
		---@param frame frame any frame
		---@param bIsUtility boolean if true, the plugin is in fact a regular panel in the options panel
		---@param callback function a callback to run when the plugin is clicked
		function pluginContainerFrame.EmbedPlugin(pluginObject, frame, bIsUtility, callback)
			--check if the plugin has a frame
			if (not pluginObject.Frame) then
				pluginContainerFrame.DebugMsg("plugin doesn't have a frame.")
				return
			end

			--add it to menu table
			if (bIsUtility) then
				--create a button for this plugin
				local pluginButton = Details:CreatePluginMenuButton(pluginObject, bIsUtility, pluginContainerFrame, pluginContainerFrame.OnMenuClick, pluginContainerFrame.MenuButtonWidth, pluginContainerFrame.MenuButtonHeight)

				--only register button if it's a utility, plugins now are placed into the breakdown window
				table.insert(pluginContainerFrame.MenuButtons, pluginButton)

				pluginObject.__var_Frame = frame
				pluginObject.__var_Utility = true

				--sort buttons alphabetically, put utilities at the end
				table.sort(pluginContainerFrame.MenuButtons, function(t1, t2)
					if (t1.IsUtility and t2.IsUtility) then
						return t1.PluginName < t2.PluginName
					elseif (t1.IsUtility) then
						return false
					elseif (t2.IsUtility) then
						return true
					else
						return t1.PluginName < t2.PluginName
					end
				end)

				--reset the buttons points
				local addingTools = false
				for index, button in ipairs(pluginContainerFrame.MenuButtons) do
					button:ClearAllPoints()
					PixelUtil.SetPoint(button, "center", menuBackground, "center", 0, 0)

					if (button.IsUtility) then
						if (not addingTools) then
							--add the header
							addingTools = true
							--add -20 to add a gap between plugins and utilities
							PixelUtil.SetPoint(titleBarTools, "topleft", menuBackground, "topleft", 2, pluginContainerFrame.MenuY +((index-1) * -pluginContainerFrame.MenuButtonHeight ) - index - 20)
							PixelUtil.SetPoint(titleBarTools, "topright", menuBackground, "topright", -2, pluginContainerFrame.MenuY +((index-1) * -pluginContainerFrame.MenuButtonHeight ) - index - 20)
						end

						PixelUtil.SetPoint(button, "top", menuBackground, "top", 0, pluginContainerFrame.MenuY +((index-1) * -pluginContainerFrame.MenuButtonHeight ) - index - 40)
					else
						PixelUtil.SetPoint(button, "top", menuBackground, "top", 0, pluginContainerFrame.MenuY +((index-1) * -pluginContainerFrame.MenuButtonHeight ) - index)
					end
				end

				--format the plugin main frame
				pluginContainerFrame.RefreshFrame(frame)
				setupFrameFunctions(frame)

				--save the callback function for when clicking in the button from the options panel
				pluginObject.__OnClickFromOptionsCallback = callback

				--add the plugin to embed table
				table.insert(pluginContainerFrame.EmbedPlugins, pluginObject)
				frame:SetParent(pluginContainerFrame)

				pluginContainerFrame.DebugMsg("plugin added", pluginObject.__name)
			end
		end

		function pluginContainerFrame.OpenPlugin(pluginObject)
			if (pluginObject.__breakdownwindow) then
				breakdownWindowFrame.ShowPluginOnBreakdown(pluginObject)
				return
			end

			--simulate a click on the menu button
			pluginContainerFrame.OnMenuClick(_, _, pluginObject.real_name)
		end

		---hide all embed plugins
		function pluginContainerFrame.ClosePlugin()
			for index, plugin in ipairs(pluginContainerFrame.EmbedPlugins) do
				plugin.Frame:Hide()
			end
			--hide the main frame
			pluginContainerFrame:Hide()
		end

		--[=[
			Function to be used on macros to open a plugin, signature:
			Details:OpenPlugin(PLUGIN_ABSOLUTE_NAME)
			Details:OpenPlugin(PluginObject)
			Details:OpenPlugin("Plugin Name")
			Example: /run Details:OpenPlugin("Time Line")
		--]=]

		---function used when the user uses the macro command /run Details:OpenPlugin("Plugin Name")
		---@param wildCard any
		---@return any
		function Details:OpenPlugin(wildCard)
			local originalName = wildCard

			if (type(wildCard) == "string") then
				--check if passed a plugin absolute name
				local pluginObject = Details:GetPlugin(wildCard)
				if (pluginObject) then
					if (pluginObject.__breakdownwindow) then
						breakdownWindowFrame.ShowPluginOnBreakdown(pluginObject)
						return
					end
					pluginContainerFrame.OpenPlugin(pluginObject)
					return true
				end

				--check if passed a plugin name, remove spaces and make it lower case
				wildCard = string.lower(wildCard)
				wildCard = wildCard:gsub("%s", "")

				for index, pluginInfoTable in ipairs(Details.ToolBar.Menu) do
					local pluginName = pluginInfoTable[1]
					pluginName = string.lower(pluginName)
					pluginName = pluginName:gsub("%s", "")

					if (pluginName ==  wildCard) then
						local pluginObject = pluginInfoTable[3]
						if (pluginObject.__breakdownwindow) then
							breakdownWindowFrame.ShowPluginOnBreakdown(pluginObject)
							return
						end
						pluginContainerFrame.OpenPlugin(pluginObject)
						return true
					end
				end

			--check if passed a plugin object
			elseif (type(wildCard) == "table") then
				if (wildCard.__name) then
					pluginContainerFrame.OpenPlugin(wildCard)
					return true
				end
			end

			Details:Msg("|cFFFF7700plugin not found|r:|cFFFFFF00",(originalName or wildCard), "|rcheck if it is enabled in the addons control panel.") --localize-me
		end
	end