-- XPerl_OptionsFrame_SelectFrame
function XPerl_OptionsFrame_SelectFrame(frame)
	XPerl_Options:Show()

	if (frame == "player") then
		XPerl_Options_Player:Show()
		XPerl_Options_Party:Hide()
		XPerl_Options_Raid:Hide()

	elseif (frame == "party") then
		XPerl_Options_Player:Hide()
		XPerl_Options_Party:Show()
		XPerl_Options_Raid:Hide()

	elseif (frame == "raid") then
		XPerl_Options_Player:Hide()
		XPerl_Options_Party:Hide()
		XPerl_Options_Raid:Show()
	end
end

-- XPerl_OptionsSetMyText
function XPerl_OptionsSetMyText(f, str)

	if (f and str) then
		local textFrame = getglobal(f:GetName().."Text")

		if (textFrame) then
			textFrame:SetText(getglobal(str))
			f.tooltipText = getglobal(str.."_DESC")

			if (f:GetFrameType() == "CheckButton") then
				f:SetHitRectInsets(0, -(textFrame:GetStringWidth()), 0, 0)
			end

		elseif (f:GetFrameType() == "Button") then
			f:SetText(getglobal(str))
			f.tooltipText = getglobal(str.."_DESC")
		end

		setglobal(str, nil)
		setglobal(str.."_DESC", nil)
	end
end

-- XPerl_GetCheck
function XPerl_GetCheck(f)
	if (f:GetChecked()) then
	        return 1
	else
	        return 0
	end
end

-- XPerl_Options_GetSibling(sibling)
function XPerl_Options_GetSibling(sibling)
	return getglobal(this:GetParent():GetName().."_"..sibling)
end

-- XPerl_Options_EnableSibling
function XPerl_Options_EnableSibling(sibling, check2nd, check3rd)

	local siblingName = this:GetParent():GetName().."_"..sibling
	local siblingFrame = getglobal(siblingName)
	local second = true
	local condition = "and"

	if (type(check2nd) == "string" and (check2nd == "or" or check2nd == "and")) then
		condition = check2nd
		check2nd = check3rd
	end
	if (check2nd) then
		if (type(check2nd) == "table") then
			second = check2nd:GetChecked()
		elseif (type(check2nd) == "string") then
			local sib2 = this:GetParent():GetName().."_"..check2nd
			local sibf2 = getglobal(sib2)
			if (sibf2) then
				second = sibf2:GetChecked()
			else
				DEFAULT_CHAT_FRAME:AddMessage("|c00FF0000X-Perl|r - No 2nd sibling called '"..sib2.."'")
			end
		else
			second = check2nd
		end
	end

	local result
	if (condition == "and") then
		result = (this:GetChecked() and second)
	elseif (condition == "or") then
		result = (this:GetChecked() or second)
	end

	if (siblingFrame) then
		if (siblingFrame:GetFrameType() == "Button") then
			if (result) then
				siblingFrame:Enable()
			else
				siblingFrame:Disable()
			end
		elseif (siblingFrame:GetFrameType() == "CheckButton") then
			XPerl_Options_EnableCheck(siblingFrame, result)

		elseif (siblingFrame:GetFrameType() == "Slider") then
			if (result) then
				siblingFrame:EnableSlider()
			else
				siblingFrame:DisableSlider()
			end

		else
			DEFAULT_CHAT_FRAME:AddMessage("|c00FF0000X-Perl|r - No code to disable '"..siblingFrame:GetName().."' type: "..siblingFrame:GetFrameType())
		end
	else
		DEFAULT_CHAT_FRAME:AddMessage("|c00FF0000X-Perl|r - No sibling found called '"..siblingName.."'")
	end
end

-- XPerl_Options_EnableCheck
function XPerl_Options_EnableCheck(self, on)
	local textFrame = getglobal(self:GetName().."Text")
	if (on) then
		self:Enable()
		textFrame:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b)
	else
		self:Disable()
		textFrame:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b)
	end

	if (self:GetFrameType() == "Button") then
		local normalTexture = getglobal(self:GetName().."NormalTexture")
		local icon = getglobal(self:GetName().."Icon")
		if (normalTexture and icon) then
			if (on) then
				icon:SetVertexColor(1, 1, 1)
				normalTexture:SetVertexColor(1, 1, 1)
			else
				icon:SetVertexColor(0.5, 0.5, 0.5)
				normalTexture:SetVertexColor(0.5, 0.5, 0.5)
			end
		end
	end
end

-- XPerl_Options_IncrementSibling
function XPerl_Options_IncrementSibling(sibling)
	local siblingName = this:GetParent():GetName().."_"..sibling
	local siblingFrame = getglobal(siblingName)

	if (siblingFrame and siblingFrame:GetFrameType() == "EditBox") then
        	local n = tonumber(siblingFrame:GetText())
		n = n + 1
		siblingFrame:SetText(n)
		return n
	end
end

-- XPerl_Options_DecrementSibling
function XPerl_Options_DecrementSibling(sibling)
	local siblingName = this:GetParent():GetName().."_"..sibling
	local siblingFrame = getglobal(siblingName)

	if (siblingFrame and siblingFrame:GetFrameType() == "EditBox") then
        	local n = tonumber(siblingFrame:GetText())
		n = n - 1
		siblingFrame:SetText(n)
		return n
	end
end

-- XPerl_Options_CheckRadio
function XPerl_Options_CheckRadio(buttons)
	local prefix = this:GetParent():GetName().."_"

	for i,name in pairs(buttons) do
		if (prefix..name == this:GetName()) then
			getglobal(prefix..name):SetChecked(true)
		else
			getglobal(prefix..name):SetChecked(false)
		end
	end
end

-- XPerl_Options_GetSiblingChecked
function XPerl_Options_GetSiblingChecked(name)
	local prefix = this:GetParent():GetName().."_"
	return getglobal(prefix..name):GetChecked()
end

-- XPerl_Raid_OptionActions
function XPerl_Raid_OptionActions()
	if (XPerl_Raid_Position) then
        	XPerl_Raid_Position()
		XPerl_Raid_Set_Bits()
		XPerl_Raid_UpdateDisplayAll()
	end
end

-- XPerl_Options_OnUpdate
function XPerl_Options_OnUpdate()

	if (this.Fading) then
	        local alpha = this:GetAlpha()
	        if (this.Fading == "in") then
	                alpha = alpha + (arg1 * 2)		-- elapsed * 2 == fade in/out in 1/2 second
	                if (alpha > 1) then
	                        alpha = 1
	                end
	        elseif (this.Fading == "out") then
	                alpha = alpha - (arg1 * 2)
	                if (alpha < 0) then
	                        alpha = 0
	                end
	        end
	        this:SetAlpha(alpha)
	        if (alpha == 0) then
	                this.Fading = nil
	                this:Hide()
	        elseif (alpha == 1) then
	                this.Fading = nil
	        end
	else
		local f = GetMouseFocus()
		if (f and f:GetName()) then
			if (strfind(f:GetName(), "XPerl_Player") or strfind(f:GetName(), "XPerl_Target")) then
				XPerl_OptionsFrame_SelectFrame("player")
			elseif (strfind(f:GetName(), "XPerl_party%d")) then
				XPerl_OptionsFrame_SelectFrame("party")
			elseif (strfind(f:GetName(), "XPerl_Raid")) then
				XPerl_OptionsFrame_SelectFrame("raid")
			end
		end
	end
end

-- XPerl_Options_MaxScaleSet
local Sliders = {}
function XPerl_Options_MaxScaleSet()

	for i,slider in pairs(Sliders) do
        	local old = slider:GetValue()
		local max = floor(XPerlConfig.MaximumScale * 100 + 0.5)

        	getglobal(slider:GetName().."High"):SetText(format("%d"..PERCENT_SYMBOL, max))
        	slider:SetMinMaxValues(50, max)

		if (old > max) then
			slider:SetValue(max)
		end
	end
end

-- XPerl_SliderSetup(self)
function XPerl_SliderSetup(self)
	self.xperlSliderEnabled = true
	self.IsEnabled = function(self)
	        return self.xperlSliderEnabled
	end
	self.DisableSlider = function(self)
	        self.xperlSliderEnabled = false
	        OptionsFrame_DisableSlider(self)
	        getglobal(self:GetName().."Current"):SetVertexColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b)
	end
	self.EnableSlider = function(self)
	        self.xperlSliderEnabled = true
	        OptionsFrame_EnableSlider(self)
	        getglobal(self:GetName().."Current"):SetVertexColor(0.4, 0.4, 0.80)
	end
end

function XPerl_EditBoxSetup(self)
	self.xperlEditEnabled = true
	self.IsEnabled = function(self)
		return self.xperlEditEnabled
	end
	self.Enable = function(self)
		self.xperlEditEnabled = true
		self:EnableMouse(true)
	end
	self.Disable = function(self)
		self.xperlEditEnabled = false
		self:EnableMouse(false)
	end
end

-- XPerl_Options_RegisterScalingSlider
function XPerl_Options_RegisterScalingSlider(slider)

	XPerl_Options_RegisterProtected(slider)

	Sliders[slider:GetName()] = slider

        getglobal(slider:GetName().."Low"):SetText("50%")
        getglobal(slider:GetName().."High"):SetText(format("%d"..PERCENT_SYMBOL, floor((XPerlConfig.MaximumScale or 1.5) * 100 + 0.5)))

        slider:SetMinMaxValues(50, floor(XPerlConfig.MaximumScale * 100 + 0.5))
        slider:SetValueStep(1)
end

-- XPerl_Popup
function XPerl_Popup(question, onAccept)
	XPerl_OptionsQuestionDialogText:SetText(question)
	XPerl_OptionsQuestionDialog.onAccept = onAccept
	XPerl_OptionsQuestionDialog:SetScale(1.5)
	XPerl_OptionsQuestionDialog:Show()

	XPerl_OptionsQuestionDialog:SetPoint("CENTER", 0, 0)

	local w = XPerl_OptionsQuestionDialogText:GetStringWidth() + 20

	if (w > 320) then
		XPerl_OptionsQuestionDialog:SetWidth(320)
		XPerl_OptionsQuestionDialog:SetHeight(100)
	else
		XPerl_OptionsQuestionDialog:SetWidth(w)
		XPerl_OptionsQuestionDialog:SetHeight(80)
	end
end

-- Load settings menu
local MyIndex = 0
local function GetPlayerList()
	local ret = {}
	if (XPerlConfig_Global) then
		local me = GetRealmName().." / "..UnitName("player")
		for realmName, realmConfig in pairs(XPerlConfig_Global) do
			for playerName, settings in pairs(realmConfig) do
				local entry = realmName.." / "..playerName

				tinsert(ret, {name = entry, config = settings})

				if (entry == me) then
					MyIndex = #ret
				end
			end
		end
	end
	return ret
end

-- XPerl_Options_LoadSettings_OnLoad
function XPerl_Options_LoadSettings_OnLoad()
	this.displayMode = "MENU"
	UIDropDownMenu_Initialize(this, XPerl_Options_LoadSettings_Initialize)
	UIDropDownMenu_SetSelectedID(this, MyIndex, 1)
	UIDropDownMenu_SetWidth(140, XPerl_Options_DropDown_LoadSettings)
end

-- XPerl_Options_LoadSettings_Initialize
function XPerl_Options_LoadSettings_Initialize()
	local info
	local list = GetPlayerList()

	for i,entry in pairs(list) do
		info = {}
		info.text = entry.name
		info.func = XPerl_Options_LoadSettings_OnClick
		UIDropDownMenu_AddButton(info)
	end
end

-- XPerl_Options_Anchor_OnLoad
function XPerl_Options_Anchor_OnLoad(self)
	self.displayMode = "MENU"
	UIDropDownMenu_Initialize(self, XPerl_Options_Anchor_Initialize)
	UIDropDownMenu_SetSelectedID(self, MyIndex, 1)
	UIDropDownMenu_SetWidth(100, self)
end

-- XPerl_Options_Anchor_OnLoad
function XPerl_Options_Anchor_Initialize()
	local info
	local current = XPerlConfig[XPerl_Options_Party_Anchor.varName] or "TOP"

	for k,v in pairs(XPerl_AnchorList) do
		info = {}
		info.text = v
		info.func = XPerl_Options_Anchor_OnClick

		if (current == v) then
			MyIndex = k
		end

		UIDropDownMenu_AddButton(info)
	end
end

-- XPerl_Options_Anchor_OnClick
function XPerl_Options_Anchor_OnClick()
	local obj = getglobal(UIDROPDOWNMENU_OPEN_MENU)

	XPerlConfig[obj.varName] = XPerl_AnchorList[this:GetID()]
	MyIndex = this:GetID()
	UIDropDownMenu_SetSelectedID(obj, MyIndex, 1)

	if (XPerl_Party_SecureHeader) then
		XPerl_ProtectedCall(obj.setFunc)
		XPerl_RaidTitles()
		XPerl_Party_Virtual(true)
	end
end

-- CopySelectedSettings
local CopyFrom
local function CopySelectedSettings()
	--ChatFrame7:AddMessage("Copying settings from "..CopyFrom)
	--UIDropDownMenu_SetSelectedID(XPerl_Options_DropDown_LoadSettings, this:GetID(), 1)

	XPerlConfig = {}
	XPerl_SetMyGlobal()
	XPerl_Defaults()

	local level = 0
	local function SubCopy(from, to)
		level = level + 1
		if (level > 10) then
			return
		end
		for k,v in pairs(from) do
			if (type(v) == "table") then
				to[k] = {}
				SubCopy(v, to[k])
			else
				to[k] = v
			end
		end
		level = level - 1
	end

	SubCopy(CopyFrom.config, XPerlConfig)		-- Copy whole tree

	XPerl_StartupSpellRange()			-- Re-validate the spell range stuff

	XPerl_Options:Hide()
	XPerl_Options:Show()

	XPerl_OptionActions()
end

-- XPerl_Options_LoadSettings_OnClick
function XPerl_Options_LoadSettings_OnClick()

	local list = GetPlayerList()

	if (this:GetID() ~= MyIndex) then
		local entry = list[this:GetID()]

		if (entry) then
			CopyFrom = entry
			XPerl_Popup(format("Copy settings from %s?", entry.name), CopySelectedSettings)
		end
	end
end

-- XPerl_Options_SetTabColor
function XPerl_Options_SetTabColor(tab, color)
	for i,y in pairs({"Enabled", "Disabled"}) do
		for j,z in pairs({"Left", "Right", "Middle"}) do
			local f = getglobal(tab:GetName()..y..z)
			f:SetVertexColor(color.r, color.g, color.b, color.a)
		end
	end
end

-- XPerl_Options_EnableTab
function XPerl_Options_EnableTab(tab, enable)
	for i,y in pairs({"Enabled", "Disabled"}) do
		for j,z in pairs({"Left", "Right", "Middle"}) do
			local f = getglobal(tab:GetName()..y..z)

			if ((i == 1 and enable) or (i == 2 and not enable)) then
				f:Show()
			else
				f:Hide()
			end
		end
	end
end

local protected = {}

-- XPerl_Options_InCombatChange
function XPerl_Options_InCombatChange(inCombat)

	for k,v in pairs(protected) do
		if (k:GetFrameType() == "CheckButton") then
			local textFrame = getglobal(k:GetName().."Text")

			if (inCombat) then
				k.wasChecked = k:GetChecked()
				k.combatIcon:Show()
				protected[k] = k:IsEnabled()
				k:SetChecked(false)
				k:Disable()
				k:EnableMouse(false)
				textFrame:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b)
			else
				k:EnableMouse(true)
				k.combatIcon:Hide()

				if (v) then
					k:Enable()
					textFrame:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b)
				else
					k:Disable()
					textFrame:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b)
				end

				if (k.wasChecked) then
					k:SetChecked(true)
				end
			end

		elseif (k:GetFrameType() == "Slider") then
			if (inCombat) then
				k.combatIcon:Show()
				k:DisableSlider()
			else
				k.combatIcon:Hide()

				if (v) then
					k:EnableSlider()
				else
					k:DisableSlider()
				end
			end

		elseif (k:GetFrameType() == "Button") then
			if (inCombat) then
				k.combatIcon:Show()
				k:Disable()
			else
				k.combatIcon:Hide()

				if (v) then
					k:Enable()
				else
					k:Disable()
				end
			end

		elseif (k:GetFrameType() == "EditBox") then
			if (inCombat) then
				k.combatIcon:Show()
				k:Disable()
			else
				k.combatIcon:Hide()

				if (v) then
					k:Enable()
				else
					k:Disable()
				end
			end

		end
	end
end

-- XPerl_Options_RegisterProtected
function XPerl_Options_RegisterProtected(object)

	if (object:GetFrameType() == "Slider") then
		XPerl_SliderSetup(object)
	elseif (object:GetFrameType() == "EditBox") then
		XPerl_EditBoxSetup(object)
	end

	protected[object] = object:IsEnabled()

	local icon = object:CreateTexture(object:GetName().."CombatIcon", "OVERLAY")
	object.combatIcon = icon

	icon:SetTexture("Interface\\CharacterFrame\\UI-StateIcon")
	icon:SetTexCoord(0.5, 1.0, 0.0, 0.5)

	icon:SetWidth(32)
	icon:SetHeight(32)
	icon:SetPoint("CENTER", 0, 0)
	icon:Show()

end

-- GetSpell
local function GetSpell()
	return XPerlConfig.RangeFinder[XPerl_Options.optRange].spell
end

-- GetItem
local function GetItem()
	return XPerlConfig.RangeFinder[XPerl_Options.optRange].item
end

-- XPerl_Options_GetRangeTexture
function XPerl_Options_GetRangeTexture(self)

	local spell = GetSpell()
	if (spell) then
	        local tex = GetSpellTexture(spell)
		return tex, spell
	end

	local item = GetItem()
	if (item) then
		local itemName, itemLink, itemRarity, itemLevel, itemMinLevel, itemType, itemSubType, itemStackCount, itemEquipLoc, invTexture = GetItemInfo(item)
		if (itemName) then
			return invTexture, itemName
		end
	end

	return ""
end

-- XPerl_Options_DoRangeTooltip
function XPerl_Options_DoRangeTooltip(self)

        GameTooltip:SetOwner(self, "ANCHOR_RIGHT", -15, 0)

	local spell = GetSpell()
	if (spell) then
		if (XPerlConfig.RangeFinder[XPerl_Options.optRange].spell) then
	        	GameTooltip:SetText(XPERL_CONF_CUSTOMSPELL_DESC)
		else
	        	GameTooltip:SetText(XPERL_CONF_CUSTOMSPELL_DESC2)
		end
		return
	end

	local item = GetItem()
	if (item) then
		local itemName, itemLink, itemRarity, itemLevel, itemMinLevel, itemType, itemSubType, itemStackCount, itemEquipLoc, invTexture = GetItemInfo(item)
		if (itemName) then
			local itemId = strmatch(itemLink, "item:(%d+):");
   			if (itemId) then
				local newLink = format("item:%d:0:0:0", itemId)
				GameTooltip:SetHyperlink(newLink)

				if (XPerlConfig.RangeFinder[XPerl_Options.optRange].CustomRangeItem) then
					GameTooltip:AddLine(XPERL_CONF_CUSTOMSPELL_DESC, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1)
				else
					GameTooltip:AddLine(XPERL_CONF_CUSTOMSPELL_DESC2, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1)
				end
				GameTooltip:Show()
			end
		end
	end
end

-- XPerl_Options_LocalClass
function XPerl_Options_LocalClass(class)

	-- Try and get the localised class name from raid addon
	if (XPerl_Raid_GetLocalisedClassName) then
		local localClass = XPerl_Raid_GetLocalisedClassName(class)
		if (localClass) then
			return localClass
		end
	end

	-- Otherwise, use ones we know
	local list = {WARRIOR	= XPERL_LOC_CLASS_WARRIOR,
			MAGE	= XPERL_LOC_CLASS_MAGE,
			ROGUE	= XPERL_LOC_CLASS_ROGUE,
			DRUID	= XPERL_LOC_CLASS_DRUID,
			HUNTER	= XPERL_LOC_CLASS_HUNTER,
			SHAMAN	= XPERL_LOC_CLASS_SHAMAN,
			PRIEST	= XPERL_LOC_CLASS_PRIEST,
			WARLOCK	= XPERL_LOC_CLASS_WARLOCK,
			PALADIN	= XPERL_LOC_CLASS_PALADIN}
	return list[class]
end

-- ValidateClassNames
local function ValidateClassNames(self)
	-- This should never happen, but I'm sure someone will find a way to break it

	local list = {WARRIOR = false, MAGE = false, ROGUE = false, DRUID = false,
			HUNTER = false, SHAMAN = false, PRIEST = false,	WARLOCK = false, PALADIN = false}

	for i = 1,9 do
		list[XPerlConfig["RaidClass"..i]] = true
	end

	for k,v in pairs(list) do
		if (not v) then
			XPerl_DefaultRaidClasses(true)
			return
		end
	end
end

-- SetClassNames
local function SetClassNames(self)
	ValidateClassNames(self)

	local prefix = self:GetParent():GetParent():GetName().."_"
	for i = 1,9 do
		local f = getglobal(prefix.."ClassSel"..i.."_EnableText")
		if (f) then
	                local class = XPerlConfig["RaidClass"..i]
			f:SetText(XPerl_Options_LocalClass(class))
		end
	end
end


-- XPerl_Options_MoveRaidClassUp
function XPerl_Options_MoveRaidClassUp(self)
	local id = self:GetID()

	local save = XPerlConfig["RaidClass"..id]
	XPerlConfig["RaidClass"..id] = XPerlConfig["RaidClass"..(id - 1)]
	XPerlConfig["RaidClass"..(id - 1)] = save

	SetClassNames(self)
end

-- XPerl_Options_MoveRaidClassDown
function XPerl_Options_MoveRaidClassDown(self)
	local id = self:GetID()

	local save = XPerlConfig["RaidClass"..id]
	XPerlConfig["RaidClass"..id] = XPerlConfig["RaidClass"..(id + 1)]
	XPerlConfig["RaidClass"..(id + 1)] = save

	SetClassNames(self)

end

-- XPerl_Options_RaidSelectAll
function XPerl_Options_RaidSelectAll(self, enable)

	local val
	local prefix = self:GetParent():GetName().."_"

	if (enable) then val = 1 else val = 2 end

	for i = 1,9 do
		local f = getglobal(prefix.."Grp"..i)
		if (f) then
			f:SetChecked(enable)
			XPerlConfig["ShowGroup"..i] = val
		end

		f = getglobal(prefix.."ClassSel"..i.."_Enable")
		if (f) then
			f:SetChecked(enable)
			XPerlConfig["RaidClass"..i.."Enable"] = val
		end
	end

	XPerl_Raid_ChangeAttributes()
	XPerl_Raid_OptionActions()
end

-- XPerl_Options_SetupStatsFrames
function XPerl_Options_SetupStatsFrames()

	XPerl_StatsFrameSetup(XPerl_Player, {"druidBar", "xpBar", "repBar"})
	XPerl_StatsFrameSetup(XPerl_Player_Pet, {"xpBar"}, 2)

	XPerl_StatsFrameSetup(XPerl_Target)
	XPerl_StatsFrameSetup(XPerl_Focus)
	XPerl_StatsFrameSetup(XPerl_TargetTarget)
	XPerl_StatsFrameSetup(XPerl_TargetTargetTarget)

	for i = 1,4 do
		XPerl_StatsFrameSetup(getglobal("XPerl_party"..i))
		XPerl_StatsFrameSetup(getglobal("XPerl_partypet"..i), nil, 2)
	end
end
