local jostle = JostleLib:GetInstance('1.0')

private = {}
local private = private

local SPACING_FROM_SIDES = 5

local MINOR_VERSION = tonumber(string.sub("$Revision: 2223 $", 12, -3))
if not FUBAR_REVISION or MINOR_VERSION > FUBAR_REVISION then
	FUBAR_REVISION = MINOR_VERSION
end

local bgFile = "Interface\\AddOns\\FuBar\\background"

local function getsecond(_, value)
	return value
end

local topTexture
local bottomTexture

PanelClass = {}
PanelClass._id = 0
PanelClass._panels = {}
local PanelClass = PanelClass
local PanelClass_mt = { __index = PanelClass }
MinimapContainer = {}
local MinimapContainer = MinimapContainer

local backdropsPerPanel = ceil(GetScreenWidth() / 256)

function PanelClass:SetBackground(bg)
	if bgFile ~= bg then
		bgFile = bg
		for i = 1, FuBar:GetNumPanels() do
			FuBar:GetPanel(i):UpdateTexture()
		end
	end
end

function PanelClass:IsBackground(bg)
	return bgFile == bg
end

function PanelClass:Create(attachPoint)
	PanelClass._id = PanelClass._id + 1
	
	if not FuBar.data.panels then
		FuBar.data.panels = {}
	end
	if not FuBar.data.panels[PanelClass._id] then
		table.insert(FuBar.data.panels, {})
	end
	if not FuBar.data.detached then
		FuBar.data.detached = {}
	end
	
	local t = {
		data = FuBar.data.panels[PanelClass._id],
		id = PanelClass._id,
		frame = getglobal("FuBarFrame" .. PanelClass._id),
		plugins = {
			left = {},
			center = {},
			right = {},
		},
	}
	setmetatable(t, PanelClass_mt)

	if not t.frame then
		local frame = CreateFrame("Frame", "FuBarFrame" .. PanelClass._id, UIParent)
		if not topTexture then
			topTexture = frame:CreateTexture("FuBarFrameTopTexture", "ARTWORK")
			bottomTexture = frame:CreateTexture("FuBarFrameTopTexture", "ARTWORK")
			topTexture:SetTexture(1, 1, 1)
			topTexture:SetGradientAlpha("VERTICAL", 1, 1, 1, 0, 1, 1, 1, 0.5 * FuBar:GetTransparency())
			bottomTexture:SetTexture(1, 1, 1)
			bottomTexture:SetGradientAlpha("VERTICAL", 1, 1, 1, 0.5 * FuBar:GetTransparency(), 1, 1, 1, 0)
			topTexture:Hide()
			bottomTexture:Hide()
		end
		
		t.frame = frame
		frame:SetFrameStrata("HIGH")
		frame:EnableMouse(true)
		frame:SetMovable(true)
		frame:SetResizable(true)
		frame:SetWidth(500)
		frame:SetHeight(24)
		frame:SetPoint("TOP", UIParent, "TOP")
		local left = CreateFrame("Frame", frame:GetName() .. "Left", frame)
		left:SetPoint("TOPLEFT", frame, "TOPLEFT")
		left:SetPoint("BOTTOMRIGHT", frame, "BOTTOMLEFT", 5, 0)
		left:EnableMouse(true)
		left:Show()
		local right = CreateFrame("Frame", frame:GetName() .. "Right", frame)
		right:SetPoint("TOPRIGHT", frame, "TOPRIGHT")
		right:SetPoint("BOTTOMLEFT", frame, "BOTTOMRIGHT", -5, 0)
		right:EnableMouse(true)
		right:Show()
		frame.panel = t
		frame.left = left
		left.panel = t
		frame.right = right
		right.panel = t
		if PanelClass._id == 1 then
			frame:SetScript("OnMouseUp", function()
				if arg1 == "RightButton" then
					this.panel:OpenMenu()
				elseif arg1 == "LeftButton" then
					this.panel:StopDrag()
					HideDropDownMenu(1)
				end
			end)
			frame:SetScript("OnMouseDown", function()
				if arg1 == "LeftButton" then
					this.panel:StartDrag()
				end
			end)
			frame:SetScript("OnDragStart", function()
				this.panel:StartDrag()
			end)
			frame:SetScript("OnDragStop", function()
				this.panel:StopDrag()
			end)
			frame:SetScript("OnEnter", function()
				FuBar:Panel_OnEnter(this.panel:GetAttachPoint())
			end)
			frame:SetScript("OnLeave", function()
				FuBar:Panel_OnLeave(this.panel:GetAttachPoint())
			end)
			frame:SetScript("OnSizeChanged", function()
				local panel = this.panel
				panel.data.width = panel.frame:GetWidth()
				panel:UpdateCenteredPosition()
				panel:UpdateTexture()
			end)
			left:SetScript("OnEnter", function()
				if not this.panel:IsLocked() then
					SetCursor("ATTACK_ERROR_CURSOR")
				end
			end)
			left:SetScript("OnLeave", ResetCursor)
			right:SetScript("OnEnter", left:GetScript("OnEnter"))
			right:SetScript("OnLeave", ResetCursor)
			left:SetScript("OnMouseDown", function()
				if arg1 == "LeftButton" then
					this.panel:StartSizing("LEFT")
				end
			end)
			left:SetScript("OnMouseUp", function()
				if arg1 == "RightButton" then
					this.panel:OpenMenu()
				elseif arg1 == "LeftButton" then
					this.panel:StopDrag()
				end
			end)
			right:SetScript("OnMouseDown", function()
				if arg1 == "LeftButton" then
					this.panel:StartSizing("RIGHT")
				end
			end)
			right:SetScript("OnMouseUp", function()
				if arg1 == "RightButton" then
					this.panel:OpenMenu()
				elseif arg1 == "LeftButton" then
					this.panel:StopDrag()
				end
			end)
		else
			frame:SetScript("OnMouseUp", FuBarFrame1:GetScript("OnMouseUp"))
			frame:SetScript("OnMouseDown", FuBarFrame1:GetScript("OnMouseDown"))
			frame:SetScript("OnDragStart", FuBarFrame1:GetScript("OnDragStart"))
			frame:SetScript("OnDragStop", FuBarFrame1:GetScript("OnDragStop"))
			frame:SetScript("OnEnter", FuBarFrame1:GetScript("OnEnter"))
			frame:SetScript("OnLeave", FuBarFrame1:GetScript("OnLeave"))
			frame:SetScript("OnSizeChanged", FuBarFrame1:GetScript("OnSizeChanged"))
			left:SetScript("OnEnter", FuBarFrame1Left:GetScript("OnEnter"))
			left:SetScript("OnLeave", FuBarFrame1Left:GetScript("OnLeave"))
			left:SetScript("OnMouseDown", FuBarFrame1Left:GetScript("OnMouseDown"))
			left:SetScript("OnMouseUp", FuBarFrame1Left:GetScript("OnMouseUp"))
			right:SetScript("OnEnter", left:GetScript("OnEnter"))
			right:SetScript("OnLeave", left:GetScript("OnLeave"))
			right:SetScript("OnMouseDown", FuBarFrame1Right:GetScript("OnMouseDown"))
			right:SetScript("OnMouseUp", FuBarFrame1Right:GetScript("OnMouseUp"))
		end
		t.bgTextures = {}
		frame.bgTextures = t.bgTextures
		local lastTexture
		for i = 1, backdropsPerPanel do
			local texture = frame:CreateTexture(frame:GetName() .. "Texture" .. i, "BACKGROUND")
			texture:SetWidth(256)
			texture:SetHeight(256)
			if not lastTexture then
				texture:SetPoint("TOPLEFT", frame, "TOPLEFT")
			else
				texture:SetPoint("LEFT", lastTexture, "RIGHT")
			end
			texture:SetTexture(bgFile)
			table.insert(t.bgTextures, texture)
			lastTexture = texture
		end
	end
	
	t.bgTextures = t.frame.bgTextures
	t.frame.panel = t
	t.frame.left.panel = t
	t.frame.right.panel = t
	
	if not PanelClass._panels then
		PanelClass._panels = {}
	end
	
	if not PanelClass._panels[t.id] then
		table.insert(PanelClass._panels, t)
	else
		PanelClass._panels[t.id] = t
	end
	
	if not t.data.attachPoint then
		t.data.attachPoint = attachPoint or "TOP"
	end
	
	if not t.data.plugins then
		t.data.plugins = {
			left = {},
			right = {},
			center = {},
		}
	elseif not t.data.plugins.center then
		t.data.plugins.center = {}
		if t.data.centeredText then
			t.data.plugins.center, t.data.plugins.left = t.data.plugins.left, t.data.plugins.center
		end
	end
	
	if not t.frame:IsShown() then
		t.frame:Show()
	end
	
	t.stopUpdates = {}
	
	for i = 1, PanelClass._id do
		FuBar:GetPanel(i):Update()
		FuBar:GetPanel(i):UpdateTexture()
	end
	if t.data.attachPoint == "TOP" then
		jostle:RegisterTop(t.frame)
	elseif t.data.attachPoint == "BOTTOM" then
		jostle:RegisterBottom(t.frame)
	end
	FuBar:TriggerEvent("FUBAR_CHANGED_PANELS")
	jostle:Refresh()
	return t
end

function PanelClass:Destroy()
	assert(PanelClass._id ~= 1, "Cannot destroy only panel.")
	
	if topTexture.attachedTo == self then
		topTexture:ClearAllPoints()
		topTexture:Hide()
		topTexture.attachedTo = nil
	end
	if bottomTexture.attachedTo == self then
		bottomTexture:ClearAllPoints()
		bottomTexture:Hide()
		bottomTexture.attachedTo = nil
	end
	
	for h = 1, 3 do
		local t, position
		if h == 1 then
			t = self.plugins.left
			position = "LEFT"
		elseif h == 2 then
			t = self.plugins.center
			position = "CENTER"
		else
			t = self.plugins.right
			position = "RIGHT"
		end
		for i = table.getn(t), 1, -1 do
			local plugin = t[i]
			self:RemovePlugin(i, position)
			plugin:Hide()
		end
	end
	
	for i = self.id + 1, PanelClass._id do
		if FuBar:GetPanel(i):GetAttachPoint() == self.data.attachPoint then
			self:SwitchWithPanel(i)
		end
	end
	
	jostle:Unregister(self.frame)
	self:SetAttachPoint("NONE")
	self.frame:Hide()
	
	table.remove(FuBar.data.panels, self.id)
	table.remove(PanelClass._panels, self.id)
	
	--getglobal("FuBarFrame" .. PanelClass._id):Hide()
	
	PanelClass._id = PanelClass._id - 1
	FuBar:TriggerEvent("FUBAR_CHANGED_PANELS")
	for i = 1, PanelClass._id do
		FuBar:GetPanel(i).id = i
		FuBar:GetPanel(i):UpdateTexture()
		FuBar:GetPanel(i):Update()
	end
	
	jostle:Refresh()
end

function PanelClass:WarnDestroy()
	if self:GetNumPlugins("LEFT") + self:GetNumPlugins("CENTER") + self:GetNumPlugins("RIGHT") == 0 then
		self:Destroy()
	else
		if not StaticPopupDialogs["FUBAR_DESTROY_PANEL"] then
			StaticPopupDialogs["FUBAR_DESTROY_PANEL"] = {
				text = FuBarLocals.WARN_REMOVE_PANEL,
				button1 = FuBarLocals.MENU_REMOVE_PANEL,
				button2 = CANCEL,
				timeout = 0,
				whileDead = 1,
				hideOnEscape = 1,
			}
		end
		StaticPopupDialogs["FUBAR_DESTROY_PANEL"].OnAccept = function()
			self:Destroy()
		end
		StaticPopup_Show("FUBAR_DESTROY_PANEL")
	end
end

function PanelClass:SwitchWithPanel(id, preventUpdate)
	local other = FuBar:GetPanel(id)
	if not other or self.data.attachPoint ~= other.data.attachPoint then
		return
	end
	other.id, self.id = self.id, other.id
	other.frame, self.frame = self.frame, other.frame
	self.frame.panel = self
	other.frame.panel = other
	self.frame.left.panel = self
	other.frame.right.panel = other
	PanelClass._panels[other.id] = other
	PanelClass._panels[self.id] = self
	FuBar.data.panels[other.id], FuBar.data.panels[self.id] = FuBar.data.panels[self.id], FuBar.data.panels[other.id]
	self.bgTextures, other.bgTextures = other.bgTextures, self.bgTextures
	if not preventUpdate then
		other:Update()
		self:Update()
	end
	for i = 1, PanelClass._id do
		FuBar:GetPanel(i):UpdateTexture()
	end
	FuBar:TriggerEvent("FUBAR_CHANGED_PANELS")
	jostle:Refresh()
end

function PanelClass:GetAttachPoint()
	if not self.data then
		ReloadUI()
		return
	end
	return self.data.attachPoint
end

function PanelClass:SetAttachPoint(point)
	if self.data.attachPoint == point then
		return
	end
	jostle:Unregister(self.frame)
	if point == "NONE" then
		self.data.y = GetScreenHeight()/2 - FuBarFrame1:GetHeight()/2
	elseif point == "TOP" or point == "BOTTOM" then
		self.data.y = nil
	else
		assert(false, "Improper attach point given: " .. point)
	end
	
	local previous = self.data.attachPoint
	self.data.attachPoint = point
	for i = self.id, PanelClass._id do
		if previous == FuBar:GetPanel(i):GetAttachPoint() or point == FuBar:GetPanel(i):GetAttachPoint() then
			FuBar:GetPanel(i):Update()
		end
	end
	self:Update()
	
	jostle:Refresh()
	
	if self:IsLocked() then
		self:ToggleLocked()
	end
	
	if self.data.attachPoint == "TOP" then
		jostle:RegisterTop(self.frame)
	elseif self.data.attachPoint == "BOTTOM" then
		jostle:RegisterBottom(self.frame)
	end
	
	for i = 1, PanelClass._id do
		FuBar:GetPanel(i):UpdateTexture()
	end
	
	FuBar:TriggerEvent("FUBAR_CHANGED_PANELS")
	jostle:Refresh()
end

function PanelClass:IsLocked()
	return self.data and self.data.lock
end

function PanelClass:ToggleLocked()
	if self.data then
		self.data.lock = not self.data.lock
		return self.data.lock
	end
end

function PanelClass:GetPositionFromEdge()
	local num = 1
	local set = 0
	if self.data.attachPoint == "TOP" then
		for i = 1, FuBar:GetNumPanels() do
			local panel = FuBar:GetPanel(i)
			if panel == self then
				set = num
				num = num + 1
			elseif panel:GetAttachPoint() == "TOP" then
				num = num + 1
			end
		end
	elseif self.data.attachPoint == "BOTTOM" then
		for i = 1, FuBar:GetNumPanels() do
			local panel = FuBar:GetPanel(i)
			if panel == self then
				set = num
				num = num + 1
			elseif panel:GetAttachPoint() == "BOTTOM" then
				num = num + 1
			end
		end
	else
		return
	end
	return num - set
end

function PanelClass:UpdateTexture()
	if topTexture.attachedTo == self then
		topTexture:ClearAllPoints()
		topTexture:Hide()
		topTexture.attachedTo = nil
	end
	if bottomTexture.attachedTo == self then
		bottomTexture:ClearAllPoints()
		bottomTexture:Hide()
		bottomTexture.attachedTo = nil
	end
	local point = self:GetAttachPoint()
	local height = FuBar:GetFontSize() + FuBar:GetThickness()
	self.frame:SetHeight(height)
	
	local uiscale = 768 / GetScreenHeight()
	local texsize = 256 / uiscale
	local realLeft = self.frame:GetLeft()
	local left = mod(self.frame:GetLeft(), texsize)
	local width = self.frame:GetWidth()
	local fromEdge = self:GetPositionFromEdge()
	if fromEdge and self.bgTextures then
		local y1, y2
		if self.data.attachPoint == "TOP" then
			y1, y2 = 1-((height) / texsize) * fromEdge, 1-(height / 256) * (fromEdge - 1)
		else
			y1, y2 = ((height + 2) / texsize) * (fromEdge - 1), ((height+2) / 256) * fromEdge
		end
		for i,texture in ipairs(self.bgTextures) do
			texture:SetTexture(bgFile)
			local x = (i - 1) * texsize
			local xr = i * texsize
			texture:Show()
			texture:SetHeight(height)
			local x1, x2 = 0, 1
			local changed = false
			if i == 1 then
				x1 = left / texsize
				texture:SetWidth(texsize - left)
				changed = true
			end
			if width + left < xr then
				if i == 1 then
					texture:SetWidth(width)
					x2 = mod(width + left - x, texsize) / texsize
				else
					texture:SetWidth(mod(width + left - x, texsize))
					x2 = mod(width + left - x, texsize) / texsize
				end
			elseif not changed then
				texture:SetWidth(texsize)
			end
			texture:SetPoint("TOPLEFT", self.frame, "TOPLEFT", x + x1*texsize - left, 0)
			texture:SetTexCoord(x1, x2, y1, y2)
			texture:SetVertexColor(1, 1, 1, FuBar:GetTransparency())
		end
	elseif self.bgTextures then
		local y1, y2 = 0.5 - height / texsize / 2, 0.5 + height / texsize / 2
		for i,texture in ipairs(self.bgTextures) do
			texture:SetTexture(bgFile)
			local x = (i - 1) * texsize
			local xr = i * texsize
			texture:Show()
			texture:SetHeight(height)
			local changed = false
			local x1, x2 = 0, 1
			if width < xr then
				texture:SetWidth(mod(width - x, texsize))
				x2 = mod(width - x, texsize) / texsize
			else
				texture:SetWidth(texsize)
			end
			texture:SetTexCoord(x1, x2, y1, y2)
			texture:SetVertexColor(1, 1, 1, FuBar:GetTransparency())
		end
	end
end

function PanelClass:AddPlugin(plugin, index, side)
	if FuBar:IsChangingProfile() then
		return
	end
	if plugin:GetPanel() then
		plugin:GetPanel():RemovePlugin(plugin)
	end
	plugin:SetPanel(self)
	FuBar.data.detached[plugin:GetTitle()] = nil
	plugin:GetFrame():SetParent(self.frame)
	if not side then
		side = "LEFT"
	end
	local positioned = false
	for h = 1, 3 do
		local t, dt
		if h == 1 then
			t = self.plugins.left
			dt = self.data.plugins.left
		elseif h == 2 then
			t = self.plugins.center
			dt = self.data.plugins.center
		else
			t = self.plugins.right
			dt = self.data.plugins.right
		end
		for i, value in ipairs(dt) do
			if value == plugin:GetTitle() then
				for j = i - 1, 1, -1 do
					local otherName = dt[j]
					for k, p in ipairs(t) do
						if p:GetTitle() == otherName then
							table.insert(t, k + 1, plugin)
							positioned = true
							break
						end
					end
					if positioned then
						break
					end
				end
				if not positioned then
					table.insert(t, 1, plugin)
					positioned = true
				end
				break
			end
		end
		if positioned then
			break
		end
	end
	
	if not positioned then
		local t, dt
		if side == "RIGHT" then
			t, dt = self.plugins.right, self.data.plugins.right
		elseif side == "CENTER" then
			t, dt = self.plugins.center, self.data.plugins.center
		else
			t, dt = self.plugins.left, self.data.plugins.left
		end
		if not index then
			table.insert(t, plugin)
			table.insert(dt, plugin:GetTitle())
		else
			if index == 1 then
				table.insert(t, index, plugin)
				table.insert(dt, 1, plugin:GetTitle())
			else
				table.insert(t, index, plugin)
				local name = t[index - 1]:GetTitle()
				local done = false
				for k, v in ipairs(dt) do
					if name == v then
						table.insert(dt, k + 1, plugin:GetTitle())
						done = true
						break
					end
				end
				if not done then
					table.insert(dt, plugin:GetTitle())
				end
			end
		end
	end
	plugin:GetFrame():Show()
	if plugin.minimapFrame then
		plugin.minimapFrame:Hide()
	end
	if not positioned then
		assert(self:GetPluginSide(plugin) == side)
	end
	self:Update()
	return true
end

function PanelClass:RemovePlugin(index, side)
	if FuBar:IsChangingProfile() then
		return
	end
	if type(index) == "table" then
		index, side = self:IndexOfPlugin(index)
		if not index then
			return
		end
	end
	
	local t, dt
	if side == "RIGHT" then
		t, dt = self.plugins.right, self.data.plugins.right
	elseif side == "CENTER" then
		t, dt = self.plugins.center, self.data.plugins.center
	else
		t, dt = self.plugins.left, self.data.plugins.left
	end
	
	local plugin = t[index]
	assert(plugin:GetPanel() == self, "Plugin has improper panel field")
	plugin:SetPanel(nil)
	if not PanelClass._stopUpdates then
		plugin:GetFrame():Hide()
		if plugin.minimapFrame then
			plugin.minimapFrame:Hide()
		end
	end
	for i = 1, table.getn(dt) do
		if dt[i] == plugin:GetTitle() then
			table.remove(dt, i)
		end
	end
	table.remove(t, index)
	FuBar.data.detached[plugin:GetTitle()] = true
	self:Update()
end

function PanelClass:GetPlugin(index, side)
	if not self.plugins then
		ReloadUI()
		return
	end
	if side == "RIGHT" then
		return self.plugins.right[index]
	elseif side == "CENTER" then
		return self.plugins.center[index]
	else
		return self.plugins.left[index]
	end
end

function PanelClass:GetNumPlugins(side)
	if side == "RIGHT" then
		return table.getn(self.plugins.right)
	elseif side == "CENTER" then
		return table.getn(self.plugins.center)
	else
		return table.getn(self.plugins.left)
	end
end

function PanelClass:IndexOfPlugin(plugin)
	for i = 1, self:GetNumPlugins("LEFT") do
		if self.plugins.left[i] == plugin then
			return i, "LEFT"
		end
	end
	for i = 1, self:GetNumPlugins("CENTER") do
		if self.plugins.center[i] == plugin then
			return i, "CENTER"
		end
	end
	for i = 1, self:GetNumPlugins("RIGHT") do
		if self.plugins.right[i] == plugin then
			return i, "RIGHT"
		end
	end
end

function PanelClass:HasPlugin(plugin)
	return self:IndexOfPlugin(plugin) ~= nil
end

function PanelClass:GetPluginSide(plugin)
	local index, side = self:IndexOfPlugin(plugin)
	assert(index, "Plugin not in panel")
	return side
end

function PanelClass:SetPluginSide(plugin, side)
	local oldSide = self:GetPluginSide(plugin)
	if oldSide ~= side then
		self:RemovePlugin(plugin)
		self:AddPlugin(plugin, nil, side)
		self:Update()
	end
end

function PanelClass:PreventUpdate()
	PanelClass._stopUpdates = true
end

function PanelClass:StopPreventUpdate(code)
	PanelClass._stopUpdates = false
end

function PanelClass:Update()
	if PanelClass._stopUpdates then
		return
	end
	if not self.data.width or self.data.width >= GetScreenWidth() then
		self.data.width = GetScreenWidth() + 2
	end
	self.frame:SetWidth(self.data.width)
	
	if not self.data.x or not self.data.y then
		self.data.x = GetScreenWidth()/2 - self.data.width/2
		self.data.y = GetScreenHeight()/2 - self.frame:GetHeight()/2
	end
	if self:GetAttachPoint() == "TOP" then
		self.frame:ClearAllPoints()
		local hasTop = nil
		for i = self.id - 1, 1, -1 do
			if FuBar:GetPanel(i) and FuBar:GetPanel(i):GetAttachPoint() == "TOP" then
				hasTop = FuBar:GetPanel(i)
				break
			end
		end
		
		if not hasTop then
			self.frame:SetPoint("TOPLEFT", UIParent, "TOPLEFT", self.data.x, 1)
		else
			self.frame:SetPoint("TOPLEFT", hasTop.frame, "BOTTOMLEFT", self.data.x - hasTop.frame:GetLeft(), 0)
		end
	elseif self:GetAttachPoint(panelId) == "BOTTOM" then
		self.frame:ClearAllPoints()
		local hasBottom = nil
		for i = self.id - 1, 1, -1 do
			if FuBar:GetPanel(i) and FuBar:GetPanel(i):GetAttachPoint() == "BOTTOM" then
				hasBottom = FuBar:GetPanel(i)
				break
			end
		end
		if not hasBottom then
			self.frame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", self.data.x, -1)
		else
			self.frame:SetPoint("BOTTOMLEFT", hasBottom.frame, "TOPLEFT", self.data.x - hasBottom.frame:GetLeft(), 0)
		end
	else
		self.frame:ClearAllPoints()
		self.frame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", self.data.x, self.data.y)
	end
	
	local num = 0
	
	for h = 1, 3 do
		local t, side
		if h == 1 then
			t = self.plugins.left
			side = "LEFT"
		elseif h == 2 then
			t = self.plugins.center
			side = "CENTER"
		else
			t = self.plugins.right
			side = "RIGHT"
		end
		local i = 1
		while i <= self:GetNumPlugins(side) do
			assert(t[i], "nil plugin spot")
			if type(t[i].IsDisabled) == "function" and t[i]:IsDisabled() then
				self:RemovePlugin(i, side)
				i = i - 1
			end
			i = i + 1
		end
	end
	
	for h = 1, 3 do
		local t, side
		if h == 1 then
			t = self.plugins.left
			side = "LEFT"
		elseif h == 2 then
			t = self.plugins.center
			side = "CENTER"
		else
			t = self.plugins.right
			side = "RIGHT"
		end
		for i = 1, self:GetNumPlugins(side) do
			t[i]:CheckWidth()
			t[i].frame:SetParent(self.frame)
			t[i].frame:ClearAllPoints()
		end
	end
	
	for h = 1, 3 do
		local t, side, alpha, bravo, sideSpacing, spacing
		if h == 1 then
			t = self.plugins.left
			side = "LEFT"
			alpha, bravo = "LEFT", "RIGHT"
			sideSpacing = SPACING_FROM_SIDES
			spacing = FuBar:GetLeftSpacing()
		elseif h == 2 then
			t = self.plugins.center
			side = "CENTER"
			alpha, bravo = "LEFT", "RIGHT"
			sideSpacing = SPACING_FROM_SIDES
			spacing = FuBar:GetCenterSpacing()
		else
			t = self.plugins.right
			side = "RIGHT"
			alpha, bravo = "RIGHT", "LEFT"
			sideSpacing = -SPACING_FROM_SIDES
			spacing = -FuBar:GetRightSpacing()
		end
		for i = 1, self:GetNumPlugins(side) do
			t[i].frame:Show()
			if i == 1 then
				t[i].frame:SetPoint(alpha, self.frame, alpha, sideSpacing, 0)
			else
				t[i].frame:SetPoint(alpha, t[i-1].frame, bravo, spacing, 0)
			end
		end
	end
	
	self:UpdateCenteredPosition()
	self:CheckForOverlap()
end

function PanelClass:UpdateCenteredPosition()
	if self:GetPlugin(1, "CENTER") then
		local num = self:GetNumPlugins("CENTER")
		local width = num * FuBar:GetCenterSpacing()
		for i = 1, num do
			width = width + self.plugins.center[i].frame:GetWidth()
		end
		
		local frame = self:GetPlugin(1, "CENTER").frame
		frame:ClearAllPoints()
		frame:SetPoint("LEFT", self.frame, "LEFT", (self.data.width - width) / 2, 0)
	end
end

function PanelClass:GetSavedOrder(side)
	if side == "RIGHT" then
		return self.data.plugins.right
	elseif side == "CENTER" then
		return self.data.plugins.center
	else
		return self.data.plugins.left
	end
end

function PanelClass:ResetSavedOrder(side)
	local t
	if side == "RIGHT" then
		t = self.data.plugins.right
	elseif side == "CENTER" then
		t = self.data.plugins.center
	else
		t = self.data.plugins.left
	end
	for key in pairs(t) do
		t[key] = nil
	end
end

local dewdrop = DewdropLib:GetInstance('1.0')
function PanelClass:OpenMenu()
	if dewdrop:IsOpen(self.frame) then
		dewdrop:Close()
		return
	end
	PanelClass._selectedPanel = self.id
	if not dewdrop:IsRegistered(FuBar:GetPanel(1).frame) then
		dewdrop:Register(FuBar:GetPanel(1).frame,
			'children', FuBar.menu,
			'point', function(parent)
				if parent:GetTop() < GetScreenHeight() / 2 then
					return "BOTTOM", "TOP"
				else
					return "TOP", "BOTTOM"
				end
			end,
			'cursorX', true,
			'dontHook', true
		)
	end
	dewdrop:Open(self.frame, FuBar:GetPanel(1).frame)
end

local closePanel
function PanelClass:StartSizing(direction)
	DropDownList1:Hide()
	if not self:IsLocked() then
		local x, y = FuBar:GetScaledCursorPosition()
		local left, right = self.frame:GetLeft(), self.frame:GetRight()
		if self:GetAttachPoint() ~= "NONE" then
			self.lastWidth = self.frame:GetWidth()
		end
		self.frame:StartSizing(direction)
		self.sizeFrom = direction
		closePanel = nil
		for i = self.id + 1, PanelClass._id do
			local panel = FuBar:GetPanel(i)
			if panel:GetAttachPoint() == self:GetAttachPoint() then
				closePanel = panel
				local x, y = closePanel.frame:GetLeft(), closePanel.frame:GetBottom()
				closePanel.frame:ClearAllPoints()
				closePanel.frame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", x, y)
				break
			end
		end
	end
end

local lastX, lastY

function PanelClass:StartDrag()
	if not self:IsLocked() and self:GetAttachPoint() == "NONE" then
		self.frame:StartMoving()
	elseif not self:IsLocked() then
		self.frame:StartMoving()
		closePanel = nil
		for i = self.id + 1, PanelClass._id do
			local panel = FuBar:GetPanel(i)
			if panel:GetAttachPoint() == self:GetAttachPoint() then
				closePanel = panel
				local x, y = closePanel.frame:GetLeft(), closePanel.frame:GetBottom()
				closePanel.frame:ClearAllPoints()
				closePanel.frame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", x, y)
				break
			end
		end
		lastX, lastY = self.frame:GetCenter()
	end
end

function PanelClass:StopDrag()
	self.frame:StopMovingOrSizing()
	local x, y = self.frame:GetCenter()
	if self.lastWidth then
--		self.frame:SetWidth(self.frame:GetWidth() * 2 - self.lastWidth)
		self.lastWidth = nil
	end
	local offsetX = 0
	if self.frame:GetWidth() < 50 then
		if self.sizeFrom == "LEFT" then
			offsetX = self.frame:GetWidth() - 50
		end
		self.frame:SetWidth(50)
	elseif self.frame:GetWidth() > GetScreenWidth() then
		if self.sizeFrom == "RIGHT" then
			offsetX = self.frame:GetWidth() - self.frame:GetRight()
		else
			offsetX = -self.frame:GetLeft()
		end
		self.frame:SetWidth(GetScreenWidth())
	end
	self.sizeFrom = nil
	self.data.x = self.frame:GetLeft() + offsetX
	self.data.y = self.frame:GetBottom()
	self.data.width = self.frame:GetWidth()
	if self.data.x < 0 then
		self.data.x = 0
	elseif self.data.x + self.data.width > GetScreenWidth() then
		self.data.x = GetScreenWidth() - self.data.width
	end
	self:Update()
	if closePanel then
		closePanel:Update()
		closePanel = nil
	end
	if lastY then
		if self:GetAttachPoint() == "TOP" then
			if y < GetScreenHeight() / 2 then
				self:SetAttachPoint("BOTTOM")
			end
		else
			if y > GetScreenHeight() /2 then
				self:SetAttachPoint("TOP")
			end
		end
		if self:GetAttachPoint() == "TOP" then
			local position = 0
			for i = 1, FuBar:GetNumPanels() do
				if i ~= self.id then
					local other = FuBar:GetPanel(i)
					if other:GetAttachPoint() == "TOP" then
						if y <= getsecond(other.frame:GetCenter()) then
							position = i
						end
					end
				else
					if y <= lastY then
						position = i
					end
				end
			end
			lastY = nil
			if position < self.id then
				position = position + 1
			end
			local shift = position - self.id
			local num = 0
			if shift < 0 then
				for i = 1, -shift do
					num = num + 1
					if FuBar:GetPanel(self.id - num):GetAttachPoint() == "TOP" then
						self:SwitchWithPanel(self.id - num)
						num = 0
					end
				end
			elseif shift > 0 then
				for i = 1, shift do
					num = num + 1
					if FuBar:GetPanel(self.id + num):GetAttachPoint() == "TOP" then
						self:SwitchWithPanel(self.id + num)
						num = 0
					end
				end
			end
		elseif self:GetAttachPoint() == "BOTTOM" then
			local position = 0
			for i = 1, FuBar:GetNumPanels() do
				if i ~= self.id then
					local other = FuBar:GetPanel(i)
					if other:GetAttachPoint() == "BOTTOM" then
						if y >= getsecond(other.frame:GetCenter()) then
							position = i
						end
					end
				else
					if y >= lastY then
						position = i
					end
				end
			end
			lastY = nil
			if position < self.id then
				position = position + 1
			end
			local shift = position - self.id
			local num = 0
			if shift < 0 then
				for i = 1, -shift do
					num = num + 1
					if FuBar:GetPanel(self.id - num):GetAttachPoint() == "BOTTOM" then
						self:SwitchWithPanel(self.id - num)
						num = 0
					end
				end
			elseif shift > 0 then
				for i = 1, shift do
					num = num + 1
					if FuBar:GetPanel(self.id + num):GetAttachPoint() == "BOTTOM" then
						self:SwitchWithPanel(self.id + num)
						num = 0
					end
				end
			end
		end
	end
	self:UpdateTexture()
end

function PanelClass:HasOverlap()
	local leftNum, centerNum, rightNum = self:GetNumPlugins("LEFT"), self:GetNumPlugins("CENTER"), self:GetNumPlugins("RIGHT")
	local left = self:GetPlugin(leftNum, "LEFT")
	local right = self:GetPlugin(rightNum, "RIGHT")
	local centerLeft = self:GetPlugin(1, "CENTER")
	local centerRight = self:GetPlugin(centerNum, "CENTER")
	
	if centerLeft then
		if left and left.frame:GetRight() and centerLeft.frame:GetLeft() then
			if left and left.frame:GetRight() >= centerLeft.frame:GetLeft() - 5 then
				return true
			end
		end
		return right and right.frame:GetLeft() and centerRight.frame:GetRight() and right.frame:GetLeft() <= centerRight.frame:GetRight() + 5
	elseif left and right then
		if left.frame:GetRight() and right.frame:GetLeft() then
			return left.frame:GetRight() >= right.frame:GetLeft() - 5
		end
	elseif left then
		if left.frame:GetRight() and self.frame:GetRight() then
			return left.frame:GetRight() > self.frame:GetRight() - 5
		end
	elseif right then
		if right.frame:GetLeft() and self.frame:GetLeft() then
			return right.frame:GetLeft() < self.frame:GetLeft() + 5
		end
	end
	
	return false
end

function PanelClass:CheckForOverlap()
	if FuBar:IsOverflowing() and self:HasOverlap() then
		local side = "CENTER"
		local plugin = self:GetPlugin(self:GetNumPlugins(side), side)
		if not plugin then
			side = "LEFT"
			plugin = self:GetPlugin(self:GetNumPlugins(side), side)
			if not plugin then
				side = "RIGHT"
				plugin = self:GetPlugin(self:GetNumPlugins(side), side)
			end
		end
		local panel
		for i = self.id + 1, PanelClass._id do
			if FuBar:GetPanel(i):GetAttachPoint() == self:GetAttachPoint() then
				panel = FuBar:GetPanel(i)
			end
		end
		if not panel then
			panel = PanelClass:Create(self:GetAttachPoint())
		end
		PanelClass:PreventUpdate()
		self:RemovePlugin(plugin)
		panel:AddPlugin(plugin, 1, side)
		PanelClass:StopPreventUpdate()
		panel:Update()
		self:Update()
	end
end