TARGETCHARMS_VERSION = GetAddOnMetadata("TargetCharms", "Version");
TARGETCHARMS_DB_VERSION = "1.5.5 (9/4/2012)";

local Defaults =
{   ["Version"] = TARGETCHARMS_VERSION,
	["TargetCharms"] = {
		["show"] = 2,
		["barscale"] = 1.0,
		["Xspacing"] = 0,
		["Yspacing"] = 0,
		["draggable"] = 1,
		["toggleicon"] = 0,
		["alphaVal"] = 0.5,
		["showontarget"] = 1,
		["buttonSetup"] = ">1>5v6<2v3>7v8<4vX>0",
		},
	["ReadyCharm"] = {
		["show"] = 2,
		["barscale"] = 1.0,			
		["draggable"] = 1,
		["alphaVal"] = 0.5,
		["width"] = 60,
		["pullWidth"] = 60,
		["pullSpacing"] = 4,
		["text"] = TARGETCHARMS_READYCHECK_TEXT,
		["pullTimer"] = 10,
		},
};
local frameNames = {"TargetCharms","TopCharm","ReadyCharm","TopReady","TargetCharmsSetup"};
local pullTimerButtonName = "PullCharm";
local pullTimerMenuFrame = nil;
local pullActive = false;
local pullEndTime = nil;
local pullStateFrame = nil;
local pullClickCooldown = 0.5;
local pullCancelCooldown = 0.5;
local pullStartTime = nil;
local pullCancelReady = false;
local lastPullClickTime = 0;
local initialVisibilityFrame = nil;
local readyVisibilityRefreshPending = false;

local function GetPullTimerSeconds()
	local seconds = TargetCharms_Options and TargetCharms_Options[frameNames[3]] and TargetCharms_Options[frameNames[3]]["pullTimer"];
	if not seconds then
		seconds = 10;
		if TargetCharms_Options and TargetCharms_Options[frameNames[3]] then
			TargetCharms_Options[frameNames[3]]["pullTimer"] = seconds;
		end
	end
	return seconds;
end

function GetPullButtonWidth()
	local readyOptions = TargetCharms_Options and TargetCharms_Options[frameNames[3]];
	if not readyOptions then
		return Defaults["ReadyCharm"]["pullWidth"];
	end
	local pullWidth = readyOptions["pullWidth"];
	if not pullWidth then
		pullWidth = readyOptions["width"] or Defaults["ReadyCharm"]["pullWidth"];
		readyOptions["pullWidth"] = pullWidth;
	end
	return pullWidth;
end

function GetPullButtonSpacing()
	local readyOptions = TargetCharms_Options and TargetCharms_Options[frameNames[3]];
	if not readyOptions then
		return Defaults["ReadyCharm"]["pullSpacing"];
	end
	local spacing = readyOptions["pullSpacing"];
	if spacing == nil then
		spacing = Defaults["ReadyCharm"]["pullSpacing"];
		readyOptions["pullSpacing"] = spacing;
	end
	return spacing;
end

function UpdateReadyBarLayout()
	if not TargetCharms_Options or not TargetCharms_Options[frameNames[3]] then
		return;
	end
	local readyOptions = TargetCharms_Options[frameNames[3]];
	local readyButton = _G[frameNames[3]];
	local pullButton = _G[pullTimerButtonName];
	local topReady = _G[frameNames[4]];
	local readyWidth = readyOptions["width"];
	local pullWidth = GetPullButtonWidth();
	local spacing = GetPullButtonSpacing();
	if topReady then
		topReady:SetWidth(readyWidth + pullWidth + spacing);
	end
	if readyButton then
		readyButton:SetWidth(readyWidth);
		readyButton:SetText(readyOptions["text"]);
	end
	if pullButton and readyButton then
		pullButton:SetWidth(pullWidth);
		pullButton:ClearAllPoints();
		pullButton:SetPoint("TOPLEFT", readyButton, "TOPRIGHT", spacing, 0);
		UpdatePullCharmText();
	end
end
local buttonCharm = {["TargetCharms"]={}};
local texturePaths = {"interface\\targetingframe\\UI-RaidTargetingIcons.blp","interface\\buttons\\UI-Quickslot.blp","interface\\buttons\\UI-GroupLoot-Pass-Up.blp","interface\\icons\\ability_hunter_snipershot.blp"};
function TargetCharms_msg(text)
	DEFAULT_CHAT_FRAME:AddMessage(TARGETCHARMS_MSG_TAG..text);
end

function TargetCharms_Command(msg)
	orig_msg = msg
	msg = string.lower(msg)
	a,b,cmd,arg = string.find(msg,"(%S+)%s*(%S*)")	
	if cmd==TargetCharms_CMDS[1] then
		TargetCharms_Options = Defaults;
		local tmpFrame = _G[frameNames[1]];
		tmpFrame:SetScale(TargetCharms_Options[frameNames[1]]["barscale"]);
		tmpFrame:SetPoint("TOPLEFT", 0, 0);
		tmpFrame = _G[frameNames[2]];
		tmpFrame:ClearAllPoints() 
		tmpFrame:SetPoint("TOPLEFT", _G["UIParent"],"TOP", 0, -20);
		tmpFrame:SetAlpha(TargetCharms_Options[frameNames[1]]["alphaVal"]);
		tmpFrame = _G[frameNames[4]];
		tmpFrame:SetAlpha(1);
		tmpFrame:SetScale(1);
		tmpFrame:ClearAllPoints();
		tmpFrame:SetPoint("TOPLEFT",_G["UIParent"],"TOP", 0, 0);
		tmpFrame = _G[frameNames[3]];
		tmpFrame:SetAlpha(TargetCharms_Options[frameNames[3]]["alphaVal"]);
		tmpFrame:SetScale(1);
		tmpFrame:ClearAllPoints();
		tmpFrame:SetPoint("TOPLEFT", 0, 0);
		UpdateReadyBarLayout();
		tmpFrame = _G[frameNames[5]];
		if (tmpFrame~=nil) then
			tmpFrame:ClearAllPoints();
			tmpFrame:SetPoint("CENTER", offset, 0);	
		end
		TargetCharms_msg("Position and Values Reset");
	elseif cmd==TargetCharms_CMDS[2] then
		ShowSetup();
	else
		TargetCharms_msg(TARGETCHARMS_CMD_HELP);
	end
    CheckReadyButtonViewState();
    CheckFrameViewState();
end

function resetTop(frame,offset)
		
end

function TargetCharms_OnLoad(self)
	self:RegisterEvent("VARIABLES_LOADED");
	self:RegisterEvent("PLAYER_ENTERING_WORLD");
	self:RegisterEvent("PLAYER_REGEN_ENABLED");
	self:RegisterEvent("PARTY_LEADER_CHANGED");
	self:RegisterEvent("PARTY_MEMBERS_CHANGED");
	self:RegisterEvent("PLAYER_TARGET_CHANGED");
	self:RegisterEvent("GROUP_ROSTER_UPDATE");
	SetTargetHideShow();
	SLASH_TargetCharms1 = TARGETCHARMS_SLASH1;
	SLASH_TargetCharms2 = TARGETCHARMS_SLASH2;
	SlashCmdList["TargetCharms"] = TargetCharms_Command;
end

--Code by Grayhoof (SCT)
function CloneTable(t)				-- return a copy of the table t
	local new = {};					-- create a new table
	local i, v = next(t, nil);		-- i is an index of t, v = t[i]
	while i do
		if type(v)=="table" then 
			v=CloneTable(v);
		end 
		new[i] = v;
		i, v = next(t, i);			-- get next index
	end
	return new;
end

function CopyOldValues(t,f)	
	if(f~=nil) then
		for i=1,3,2 do
			if ( f[frameNames[i]]~=nil) then
				for key,value in pairs(f[frameNames[i]]) do 
					t[frameNames[i]][key]=value ;
				end
			end	
		end 
	end
	return t;
end

function CheckFrameViewState()
	local charmBar = _G[frameNames[2]];
	
	if IsInSetup() then
		if(charmBar:IsShown()~=1) then
			charmBar:Show();
		end
	else
		if TargetCharms_Options["TargetCharms"]["show"] == 2 then
			SetHideShow(frameNames[2]);
		elseif TargetCharms_Options["TargetCharms"]["show"] == 3 then
	    		if(charmBar:IsShown()==1) then
				charmBar:Hide();
			end
		else
			local isRaidOfficer = type(IsRaidOfficer) == "function" and IsRaidOfficer() or false;
			local isRaidLeader = type(IsRaidLeader) == "function" and IsRaidLeader() or false;
			if (((GetNumGroupMembers()>0) and not UnitInRaid("player")) or (UnitInRaid("player") and (isRaidOfficer or isRaidLeader)))  then
				SetHideShow(frameNames[2]);
			else
				if(charmBar:IsShown()==1) then
					charmBar:Hide();
				end               
			end
		end
	end	
end

function CheckReadyButtonViewState()
	local topReady = _G[frameNames[4]];
	local readyButton = _G[frameNames[3]];
	local pullButton = _G[pullTimerButtonName];
	local inCombatLockdown = type(InCombatLockdown) == "function" and InCombatLockdown();

	if inCombatLockdown then
		readyVisibilityRefreshPending = true;
		return;
	end
	readyVisibilityRefreshPending = false;

	if IsInSetup() then
		if topReady and topReady:IsShown() ~= 1 then
			topReady:Show();
		end
		if readyButton and readyButton:IsShown() ~= 1 then
			readyButton:Show();
		end
		if pullButton then
			pullButton:Show();
		end
		return;
	end

	local showMode = TargetCharms_Options[frameNames[3]]["show"];
	local isGrouped = (GetNumPartyMembers() > 0) or (GetNumRaidMembers() > 0);
	local isRaidOfficer = type(IsRaidOfficer) == "function" and IsRaidOfficer() or false;
	local isRaidLeader = type(IsRaidLeader) == "function" and IsRaidLeader() or false;
	local canLead = (UnitInRaid("player") and (isRaidOfficer or isRaidLeader)) or ((not UnitInRaid("player")) and UnitIsPartyLeader("player"));
	local shouldShow = (showMode == 2) or (showMode ~= 3 and isGrouped and canLead);

	if shouldShow then
		if topReady and topReady:IsShown() ~= 1 then
			topReady:Show();
		end
		if readyButton and readyButton:IsShown() ~= 1 then
			readyButton:Show();
		end
		if pullButton then
			pullButton:Show();
		end
	else
		if readyButton and readyButton:IsShown() == 1 then
			readyButton:Hide();
		end
		if topReady and topReady:IsShown() == 1 then
			topReady:Hide();
		end
		if pullButton then
			pullButton:Hide();
		end
	end
end

function IsInSetup()
 local TargetCharmsSetup = _G[frameNames[5]];
 if TargetCharmsSetup~=nil then
	if TargetCharmsSetup:IsShown()==1 then
		return true;
	end
 end 
 return false;
end

function SetHideShow(frame)
 local charmBar = _G[frame];
 local showOnTarget = TargetCharms_Options[frameNames[1]]["showontarget"];
 local showOnTargetNum = tonumber(showOnTarget);
 local useTargetFilter = (showOnTarget == true or showOnTargetNum == 1);
 if useTargetFilter then
	
	if UnitExists("target") then
		if (charmBar:IsShown()~=1) then
			charmBar:Show();
		end
	else
		if (charmBar:IsShown()==1) then
			charmBar:Hide();
		end
	end
 else	
	if (charmBar:IsShown()~=1) then
		charmBar:Show();
	end	
 end
end

function SetTargetHideShow()
	RegisterUnitWatch(_G[frameNames[2]], true) 
end

local function RefreshVisibilityNextFrame()
	if initialVisibilityFrame then
		return;
	end
	local charmBar = _G[frameNames[2]];
	if charmBar and charmBar:IsShown() == 1 then
		charmBar:Hide();
	end
	initialVisibilityFrame = CreateFrame("Frame");
	local elapsed = 0;
	initialVisibilityFrame:SetScript("OnUpdate", function(self, dt)
		elapsed = elapsed + (dt or 0);
		if TargetCharms_Options and TargetCharms_Options[frameNames[1]] then
			self:SetScript("OnUpdate", nil);
			initialVisibilityFrame = nil;
			CheckReadyButtonViewState();
			CheckFrameViewState();
			return;
		end
		if elapsed >= 1 then
			self:SetScript("OnUpdate", nil);
			initialVisibilityFrame = nil;
		end
	end);
end

function TargetCharms_OnEvent(self, event)
	if event=="VARIABLES_LOADED" then
		if TargetCharms_Options == nil or TARGETCHARMS_DB_VERSION ~= TargetCharms_Options["Version"] then
			TargetCharms_Options = CopyOldValues(CloneTable(Defaults),TargetCharms_Options);
			TargetCharms_Options["Version"] = TARGETCHARMS_DB_VERSION;
		end
		if TargetCharms_Options and TargetCharms_Options[frameNames[1]] then
			local showOnTarget = TargetCharms_Options[frameNames[1]]["showontarget"];
			if type(showOnTarget) == "string" then
				showOnTarget = tonumber(showOnTarget);
			end
			if showOnTarget == true then
				TargetCharms_Options[frameNames[1]]["showontarget"] = 1;
			elseif showOnTarget == false then
				TargetCharms_Options[frameNames[1]]["showontarget"] = 0;
			elseif type(showOnTarget) == "number" then
				TargetCharms_Options[frameNames[1]]["showontarget"] = (showOnTarget == 1) and 1 or 0;
			end
		end
		local tmpFrame = _G[frameNames[1]];
		tmpFrame:SetScale(TargetCharms_Options[frameNames[1]]["barscale"]);
		tmpFrame = _G[frameNames[2]];
		tmpFrame:SetAlpha(TargetCharms_Options[frameNames[1]]["alphaVal"]);
	
		SetupButtons(frameNames[1],frameNames[1]);	
		SetUpReadyButton();

		TargetCharms_msg(TARGETCHARMS_VERSION.." - "..TARGETCHARMS_LOADED);
		RefreshVisibilityNextFrame();
	end
	if event~= "PLAYER_TARGET_CHANGED" then
		CheckReadyButtonViewState();
	end
	CheckFrameViewState();
	if event == "PLAYER_ENTERING_WORLD" then
		RefreshVisibilityNextFrame();
	end
	
end

function SetUpReadyButton()
	local tmpFrame = _G[frameNames[4]];
	tmpFrame:SetAlpha(TargetCharms_Options[frameNames[3]]["alphaVal"]);
	tmpFrame:SetScale(TargetCharms_Options[frameNames[3]]["barscale"]);
	UpdateReadyBarLayout();
end

function MakeButton(frame, buttonNum, isMacro)
	local button = _G[frame.."Charm"..buttonNum];
	local template = "CharmTemplate";
	if isMacro then 
		template = "SecureCharmTemplate";
	end
	if button == nil then
		button = CreateFrame("Button", frame.."Charm"..buttonNum, _G[frame], template) 
		button:RegisterForClicks("AnyDown");
		button:SetID(buttonNum);
		button:SetHeight(32);
		button:SetWidth(32);
		local texture = button:CreateTexture(button:GetName().."CharmTex");
		if isMacro then
			button:SetAttribute("type", "macro")
			button:SetHeight(32);
			button:SetWidth(32);
			local textureColor = button:CreateTexture(button:GetName().."TextureColor");
			textureColor:SetPoint("TOPLEFT", button,"TOPLEFT", 4, -4);
			textureColor:SetPoint("BOTTOMRIGHT", button,"BOTTOMRIGHT", -4.5, 4.5);
			local textureIcon = button:CreateTexture(button:GetName().."TextureIcon");
			textureColor:SetPoint("TOPLEFT", button,"TOPLEFT", 4, -4)
			textureColor:SetPoint("BOTTOMRIGHT", button,"BOTTOMRIGHT", -4.5, 4.5)
		end
	end
	return button;
end

function SetupButtons(frameInfo,frameTarget)
	local buttonString = TargetCharms_Options[frameInfo]["buttonSetup"];
	local maxlen = strlen(buttonString);
	if mod(maxlen,2) == 1 then
		maxlen=maxlen-1
	end
	local buttonNum=1;
	if maxlen > 40 then
		maxlen = 40;
	end
	
	local t
	for t=1,maxlen,2 do
		MakeButton(frameTarget, buttonNum, false);
		FormatButton(frameTarget, buttonNum, strsub(buttonString,t,t), strsub(buttonString,t+1,t+1),TargetCharms_Options[frameInfo]["Xspacing"],TargetCharms_Options[frameInfo]["Yspacing"]);
		buttonNum=buttonNum+1;
	end

	for t=buttonNum,20 do
		local button = _G[frameTarget.."Charm"..buttonNum];
		if button ~= nil then 
			button:Hide();
		end
	end
end 

function FormatButton(frame, buttonNum ,posChar, typeNum, xSpacing, ySpacing)
	local button = _G[frame.."Charm"..buttonNum];
	button:ClearAllPoints();
	if strlower(posChar) == TARGETCHARMS_POSITION_DOWN then
		button:SetPoint("TOPLEFT", _G[frame.."Charm"..tostring(buttonNum-1)],"BOTTOMLEFT",0,0-ySpacing);
	elseif posChar == TARGETCHARMS_POSITION_UP then
		button:SetPoint("BOTTOMLEFT", _G[frame.."Charm"..tostring(buttonNum-1)],"TOPLEFT",0,0+ySpacing);
	elseif posChar == TARGETCHARMS_POSITION_RIGHT then
		button:SetPoint("TOPLEFT", _G[frame.."Charm"..tostring(buttonNum-1)],"TOPRIGHT",0+xSpacing,0);
	elseif posChar == TARGETCHARMS_POSITION_LEFT then
		button:SetPoint("TOPRIGHT", _G[frame.."Charm"..tostring(buttonNum-1)],"TOPLEFT",0-xSpacing,0);
	else
		--ERROR--
		button:SetPoint("TOPLEFT", _G[frame.."Charm"..tostring(buttonNum-1)],"TOPRIGHT",0,0-ySpacing);
		buttonCharm[frame][buttonNum] = 0;
        	button:Hide();
		print(TARGETCHARMS_ERROR_INVALIDCHAR); 
		return false;
	end
	if typeNum == TARGETCHARMS_CHARM0 then
		MakeCharm(frame,button,buttonNum,0,2,0.15,0.85,0.15,0.85,0,0,32,32);
	elseif typeNum == TARGETCHARMS_CHARM1 then
		MakeCharm(frame,button,buttonNum,1,1,0,0.25,0,0.25,2,-2,28,28);
	elseif typeNum == TARGETCHARMS_CHARM2 then
		MakeCharm(frame,button,buttonNum,2,1,0.25,0.5,0,0.25,2,-2,28,28);
	elseif typeNum == TARGETCHARMS_CHARM3 then
		MakeCharm(frame,button,buttonNum,3,1,0.5,0.75,0,0.25,2,-2,28,28);
	elseif typeNum == TARGETCHARMS_CHARM4 then
		MakeCharm(frame,button,buttonNum,4,1,0.75,1,0,0.25,2,-2,28,28);
	elseif typeNum == TARGETCHARMS_CHARM5 then
		MakeCharm(frame,button,buttonNum,5,1,0,0.25,0.25,0.5,2,-2,28,28);
	elseif typeNum == TARGETCHARMS_CHARM6 then
		MakeCharm(frame,button,buttonNum,6,1,0.25,0.5,0.25,0.5,2,-2,28,28);
	elseif typeNum == TARGETCHARMS_CHARM7 then
		MakeCharm(frame,button,buttonNum,7,1,0.5,0.75,0.25,0.5,2,-2,28,28);
	elseif typeNum == TARGETCHARMS_CHARM8 then
		MakeCharm(frame,button,buttonNum,8,1,0.75,1,0.25,0.5,2,-2,28,28);
	elseif typeNum == TARGETCHARMS_CHARM9 then
		MakeCharm(frame,button,buttonNum,9,4,0,1,0,1,0,0,32,32);
	else
    		button:Hide();
		return false;
	end
	button:Show();
	return true;
end

function MakeCharm(frame, button, buttonNum, id, textureID, o1,o2,o3,o4,a1,a2,w,h)
	buttonCharm[frame][buttonNum] = id;
	local texture = _G[button:GetName().."CharmTex"];
	SetTexture(button, texture, textureID, o1,o2,o3,o4,a1,a2,w,h);
end

function SetTexture(button, texture, textureID, o1,o2,o3,o4,a1,a2,w,h)
	texture:SetPoint("TOPLEFT", button,"TOPLEFT",a1,a2);
	texture:SetWidth(w);
	texture:SetHeight(h);
	texture:SetTexture(texturePaths[textureID]);
	texture:SetTexCoord(o1,o2,o3,o4)
end

function SelectTarget(frameId, targetId)
	local charmId = buttonCharm[frameNames[frameId]][tonumber(targetId)];
	if (TargetCharms_Options[frameNames[1]]["toggleicon"]~=1) then
		if (GetRaidTargetIndex("target")~=charmId) then
			SetRaidTarget("target", charmId)
		end
	else
		SetRaidTargetIcon("target", charmId)
	end
end

function SetFrameScale(scale,id)
	local tmpFrame = _G[frameNames[id]];
	tmpFrame:SetScale(scale);
end

function FormDropDownType_Initialize()
	local info;
	local currentShow = TargetCharms_Options and TargetCharms_Options[frameNames[1]] and TargetCharms_Options[frameNames[1]]["show"];
	for i = 1, getn(TargetCharms_ShowTypes), 1 do
		local showValue = i;
		info = {
			text = TargetCharms_ShowTypes[i];
			func = function() FormDropDownType_OnClickValue(showValue); end;
			arg1 = i;
			value = i;
			checked = (currentShow == i);
		};
		UIDropDownMenu_AddButton(info);
	end
end

function FormDropDownType2_Initialize()
	local info;
	local currentShow = TargetCharms_Options and TargetCharms_Options[frameNames[3]] and TargetCharms_Options[frameNames[3]]["show"];
	for i = 1, getn(TargetCharms_ShowTypes), 1 do
		local showValue = i;
		info = {
			text = TargetCharms_ShowTypes[i];
			func = function() FormDropDownType2_OnClickValue(showValue); end;
			arg1 = i;
			value = i;
			checked = (currentShow == i);
		};
		UIDropDownMenu_AddButton(info);
	end
end

local function TargetCharms_SetDropdownSelection(dropdown, selectedId, text)
	if type(dropdown) ~= "table" then
		return;
	end
	dropdown.selectedID = selectedId;
	if text then
		UIDropDownMenu_SetText(dropdown, text);
	end
end


function FormDropDownType_OnShow()
	UIDropDownMenu_Initialize(FormDropDownType, FormDropDownType_Initialize);
	local selectedShow = TargetCharms_Options and TargetCharms_Options[frameNames[1]] and TargetCharms_Options[frameNames[1]]["show"];
	if (selectedShow) then
		TargetCharms_SetDropdownSelection(FormDropDownType, selectedShow, TargetCharms_ShowTypes[selectedShow]);
	end
	UIDropDownMenu_SetWidth(FormDropDownType,100);
	CheckFrameViewState();
end

function FormDropDownType2_OnShow()
	UIDropDownMenu_Initialize(FormDropDownType2, FormDropDownType2_Initialize);
	local selectedShow = TargetCharms_Options and TargetCharms_Options[frameNames[3]] and TargetCharms_Options[frameNames[3]]["show"];
	if (selectedShow) then
		TargetCharms_SetDropdownSelection(FormDropDownType2, selectedShow, TargetCharms_ShowTypes[selectedShow]);
	end
	UIDropDownMenu_SetWidth(FormDropDownType2,100);
	CheckReadyButtonViewState();
end


function FormDropDownType_OnClickValue(showValue)
	if not TargetCharms_Options then
		return;
	end
	if not showValue then
		return;
	end
	TargetCharms_Options[frameNames[1]]["show"] = showValue;
	TargetCharms_SetDropdownSelection(FormDropDownType, showValue, TargetCharms_ShowTypes[showValue]);
	CheckFrameViewState();
end

function FormDropDownType2_OnClickValue(showValue)
	if not TargetCharms_Options then
		return;
	end
	if not showValue then
		return;
	end
	TargetCharms_Options[frameNames[3]]["show"] = showValue;
	TargetCharms_SetDropdownSelection(FormDropDownType2, showValue, TargetCharms_ShowTypes[showValue]);
	CheckReadyButtonViewState();
end

function FormDropDownType_OnClick(self, arg1)
	local showValue = arg1 or self.value or self:GetID();
	FormDropDownType_OnClickValue(showValue);
end

function FormDropDownType2_OnClick(self, arg1)
	local showValue = arg1 or self.value or self:GetID();
	FormDropDownType2_OnClickValue(showValue);
end


function DropDownPresetOptions_Initialize()
	local info;
	for i = 1, getn(TargetCharms_LayoutDefaults), 1 do
		local layoutIndex = i;
		info = {
			text = TargetCharms_LayoutDefaults[i][1];
			func = function() DropDownPresetOptions_OnClickValue(layoutIndex); end;
			arg1 = i;
			value = i;
		};
		UIDropDownMenu_AddButton(info);
	end
end

function DropDownPresetOptions_OnShow(di)
	UIDropDownMenu_Initialize(DropDownPresetOptions , DropDownPresetOptions_Initialize);
	local label = TargetCharms_LayoutDefaults[di] and TargetCharms_LayoutDefaults[di][1];
	TargetCharms_SetDropdownSelection(DropDownPresetOptions, di, label);
	UIDropDownMenu_SetWidth(DropDownPresetOptions,100);
end

function DropDownPresetOptions_OnClickValue(i)
	if not i then
		return;
	end
	local label = TargetCharms_LayoutDefaults[i] and TargetCharms_LayoutDefaults[i][1];
	TargetCharms_SetDropdownSelection(DropDownPresetOptions, i, label);
	local tmpEditBox = _G["EditBox"];
	tmpEditBox:SetText(TargetCharms_LayoutDefaults[i][2]);
end

function DropDownPresetOptions_OnClick(self, arg1)
	local i = arg1 or self.value or self:GetID();
	DropDownPresetOptions_OnClickValue(i);
end

function UpdatePullCharmText()
	local pullButton = _G[pullTimerButtonName];
	if pullButton == nil then
		return;
	end
	if pullActive then
		if pullCancelReady then
			pullButton:SetText("Cancel");
		else
			pullButton:SetText("Pulling");
		end
		if not InCombatLockdown() then
			if pullCancelReady then
				pullButton:SetAttribute("type1", "macro");
				pullButton:SetAttribute("macrotext1", "/pull cancel");
			else
				pullButton:SetAttribute("type1", nil);
				pullButton:SetAttribute("macrotext1", nil);
			end
			pullButton:SetAttribute("type2", nil);
			pullButton:SetAttribute("macrotext2", nil);
		end
		return;
	end
	local seconds = GetPullTimerSeconds();
	pullButton:SetText("Pull "..tostring(seconds));
	if not InCombatLockdown() then
		pullButton:SetAttribute("type1", "macro");
		pullButton:SetAttribute("macrotext1", "/pull "..tostring(seconds));
		pullButton:SetAttribute("type2", nil);
		pullButton:SetAttribute("macrotext2", nil);
	end
end

function InitializePullCharm(pullButton)
	if pullButton == nil then
		return;
	end
	UpdatePullCharmText();
end

function PullTimerMenu_OnClickValue(seconds)
	if not TargetCharms_Options then
		return;
	end
	if not seconds then
		return;
	end
	TargetCharms_Options[frameNames[3]]["pullTimer"] = seconds;
	UpdatePullCharmText();
end

function PullTimerMenu_Initialize()
	local info;
	local currentSeconds = TargetCharms_Options and TargetCharms_Options[frameNames[3]] and TargetCharms_Options[frameNames[3]]["pullTimer"];
	for i = 5, 10, 1 do
		local seconds = i;
		info = {
			text = tostring(i);
			func = function() PullTimerMenu_OnClickValue(seconds); end;
			checked = (currentSeconds == i);
		};
		UIDropDownMenu_AddButton(info);
	end
end

function ShowPullTimerMenu()
	if pullTimerMenuFrame == nil then
		pullTimerMenuFrame = CreateFrame("Frame", "TargetCharmsPullTimerMenu", UIParent, "UIDropDownMenuTemplate");
	end
	UIDropDownMenu_Initialize(pullTimerMenuFrame, PullTimerMenu_Initialize, "MENU");
	ToggleDropDownMenu(1, nil, pullTimerMenuFrame, "cursor", 0, 0);
end

function PullCharm_OnMouseDown(self, mouseButton)
	if mouseButton == "RightButton" then
		if IsControlKeyDown() then
			ShowSetup();
		else
			ShowPullTimerMenu();
		end
	end
end

local function PullCharm_OnUpdate()
	if not pullActive or not pullEndTime then
		return;
	end
	if not pullCancelReady and pullStartTime and (GetTime() - pullStartTime) >= pullCancelCooldown then
		pullCancelReady = true;
		UpdatePullCharmText();
	end
	if GetTime() >= pullEndTime then
		pullEndTime = nil;
		pullActive = false;
		pullStartTime = nil;
		pullCancelReady = false;
		UpdatePullCharmText();
	end
end

local function StartPullCancelTimer(seconds)
	if not seconds or seconds <= 0 then
		return;
	end
	pullEndTime = GetTime() + seconds;
	if not pullStateFrame then
		pullStateFrame = CreateFrame("Frame");
	end
	pullStateFrame:SetScript("OnUpdate", PullCharm_OnUpdate);
end

function PullCharm_OnPostClick(self, mouseButton)
	if mouseButton ~= "LeftButton" then
		return;
	end
	local now = GetTime();
	if (now - lastPullClickTime) < pullClickCooldown then
		return;
	end
	lastPullClickTime = now;
	if pullActive then
		if not pullCancelReady then
			return;
		end
		pullActive = false;
		pullEndTime = nil;
		pullStartTime = nil;
		pullCancelReady = false;
		UpdatePullCharmText();
		return;
	end
	local seconds = GetPullTimerSeconds();
	pullActive = true;
	pullStartTime = now;
	pullCancelReady = false;
	UpdatePullCharmText();
	StartPullCancelTimer(seconds);
end


function ShowSetup()
	local setupFrame = _G[frameNames[5]];
	if setupFrame == nil then
		setupFrame = CreateFrame("Frame",frameNames[5],UIParent,"TargetCharmsSetupTemplate");
	end
	setupFrame:Show();
end

function HideSetup()
	local setupFrame = _G[frameNames[5]];
	if setupFrame ~= nil then
		setupFrame:Hide();
	end
end
