------------------------------------------------
--                  CT_Core                   --
--                                            --
-- Core addon for doing basic and popular     --
-- things in an intuitive way.                --
-- Please do not modify or otherwise          --
-- redistribute this without the consent of   --
-- the CTMod Team. Thank you.                 --
------------------------------------------------

local _G = getfenv(0);
local module = _G.CT_Core;
local NUM_CHAT_WINDOWS = NUM_CHAT_WINDOWS;

--------------------------------------------
-- Quest Levels

local displayLevels = false;

local oldGetQuestLogTitle = GetQuestLogTitle;
function GetQuestLogTitle(...)
	local questLogTitleText, level, questTag, unknown, isHeader, isCollapsed, isComplete = oldGetQuestLogTitle(...);
	
	if ( displayLevels and questLogTitleText and level and level > 0 and not isHeader ) then
		if ( questTag == ELITE ) then
			questLogTitleText = "[" .. level .. "+] " .. questLogTitleText;
		elseif ( questTag == RAID ) then
			questLogTitleText = "[" .. level .. "R] " .. questLogTitleText;
		elseif ( questTag == PVP ) then
			questLogTitleText = "[" .. level .. "P] " .. questLogTitleText;
		elseif ( questTag == LFG_TYPE_DUNGEON ) then
			questLogTitleText = "[" .. level .. "D] " .. questLogTitleText;
		else
			questLogTitleText = "[" .. level .. "] " .. questLogTitleText;
		end
	end
	return questLogTitleText, level, questTag, unknown, isHeader, isCollapsed, isComplete;
end

local function toggleDisplayLevels(enable)
	displayLevels = enable;
	pcall(QuestLog_Update);
end

--------------------------------------------
-- Hail Mod

local function hail()
	local targetName = UnitName("target");
	if ( targetName ) then
		SendChatMessage("Hail, " .. targetName .. (((UnitIsDead("target") or UnitIsCorpse("target")) and "'s Corpse") or ""));
	else
		SendChatMessage("Hail");
	end
end

module.hail = hail;
module:setSlashCmd(hail, "/hail");

--------------------------------------------
-- Block trades when bank is open

local blockTrades;
local oldCVar;

local onShow = BankFrame:GetScript("OnShow");
local onHide = BankFrame:GetScript("OnHide");
BankFrame:SetScript("OnShow", function(self, ...)
	if ( onShow ) then
		onShow(self, ...);
	end
	if ( blockTrades ) then
		oldCVar = GetCVar("blockTrades");
		SetCVar("blockTrades", 1);
	else
		oldCVar = nil;
	end
end);
BankFrame:SetScript("OnHide", function(self, ...)
	if ( onHide ) then
		onHide(self, ...);
	end
	if ( oldCVar ) then
		SetCVar("blockTrades", oldCVar);
	end
end);

local function toggleBlockTrades(enable)
	blockTrades = enable;
end

--------------------------------------------
-- Quest Tracker

-- Common code for Quest Tracker & Tooltip Reanchoring
	local tooltipText = "Left click to drag\nRight click to rotate";
	local function getPositions(anchor, anchorMode)
		if ( anchorMode == 2 ) then
			return "ANCHOR_CURSOR";
		else
			if ( anchor == 1 ) then
				return "ANCHOR_NONE", "TOPLEFT", "BOTTOM", "Top Left";
			elseif ( anchor == 2 ) then
				return "ANCHOR_NONE", "TOPRIGHT", "BOTTOM", "Top Right";
			elseif ( anchor == 3 ) then
				return "ANCHOR_NONE", "BOTTOMRIGHT", "TOP", "Bottom Right";
			elseif ( anchor == 4 ) then
				return "ANCHOR_NONE", "BOTTOMLEFT", "TOP", "Bottom Left";
			end
		end
	end
	local function onMouseDownFunc(self, button)
		if ( button == "LeftButton" ) then
			module:moveMovable(self.movable);
		end
	end
	local function anchorFrameSkeleton()
		-- Updates the text

		return "button#st:HIGH#tl:mid:350:-200#s:100:30", {
			"backdrop#tooltip#0:0:0:0.75",
			"font#v:GameFontNormal#i:text",
			["onleave"] = module.hideTooltip,
			["onmousedown"] = onMouseDownFunc
		};
	end
-- End common code

local enablePoint = true;
local trackerAnchorMode = 1;
local trackerAnchorEnabled;
local trackerAnchorFrame;
local trackerAnchorDisplay;
local questWatchFrame = QuestWatchFrame;

local function updateTrackerAnchorVisibility()
	if ( trackerAnchorFrame ) then
		if ( trackerAnchorEnabled and trackerAnchorDisplay ) then
			trackerAnchorFrame:Show();
			enablePoint = false;
		else
			trackerAnchorFrame:Hide();
			enablePoint = true;
		end
	end
end

local function updateTrackerText()
	if ( trackerAnchorFrame ) then
		local _, text;
		_, _, _, text = getPositions(trackerAnchorMode);
		trackerAnchorFrame.text:SetText(text);
	end
end

local function reanchorTracker()
	local oldValue = enablePoint;
	enablePoint = true;
	questWatchFrame:ClearAllPoints();
	if ( trackerAnchorEnabled ) then
		if ( not trackerAnchorFrame ) then
			createTrackerAnchorFrame();
		end
		local _, pt, relpt = getPositions(trackerAnchorMode);
		questWatchFrame:SetPoint(pt, trackerAnchorFrame, relpt);
	else
		questWatchFrame:SetPoint("TOPRIGHT", MinimapCluster, "BOTTOMRIGHT", 0, 10);
	end
	enablePoint = oldValue;
end

local function updateTrackerAnchorMode(mode)
	if ( mode ) then
		trackerAnchorMode = mode;
		reanchorTracker();
		updateTrackerText();
	end
end

local function createTrackerAnchorFrame()
	local movable = "TRACKERANCHOR";	
	trackerAnchorFrame = module:getFrame(anchorFrameSkeleton);
	updateTrackerText(trackerAnchorFrame);
	updateTrackerAnchorVisibility();
	
	module:registerMovable(movable, trackerAnchorFrame);
	trackerAnchorFrame.movable = movable;
	trackerAnchorFrame:SetScript("OnEnter", function(self) module:displayTooltip(self, tooltipText); end);
	trackerAnchorFrame:SetScript("OnMouseUp", function(self, button)
		if ( button == "LeftButton" ) then
			module:stopMovable(self.movable);
		elseif ( button == "RightButton" ) then
			-- Update anchor & text
			trackerAnchorMode = trackerAnchorMode + 1;
			if ( trackerAnchorMode > 4 ) then
				trackerAnchorMode = 1;
			end
			module:setOption("questTrackerMode", trackerAnchorMode, true);
			updateTrackerAnchorMode(trackerAnchorMode);

			-- Display tooltip & play sound
			self:GetScript("OnEnter")(self);
			PlaySound("UChatScrollButton");
		end
	end);
end

local function updateTrackerHook()
	if ( trackerAnchorEnabled and not trackerAnchorFrame ) then
		createTrackerAnchorFrame();
	end
	updateTrackerAnchorVisibility();
	reanchorTracker(trackerAnchorFrame);
end

local function toggleTrackerAnchor(enable)
	trackerAnchorEnabled = enable;
	updateTrackerHook();
end

local function toggleTrackerAnchorVisibility(show)
	trackerAnchorDisplay = show;
	updateTrackerAnchorVisibility();
end

local oldQuestWatchFrameSetPoint = questWatchFrame.SetPoint;
questWatchFrame.SetPoint = function(...)
	if ( not enablePoint ) then
		return;
	end
	oldQuestWatchFrameSetPoint(...);
end

--------------------------------------------
-- Tooltip Reanchoring

local tooltipAnchor = 1;
local tooltipAnchorMode = 0;
local tooltipAnchorDisplay = true;
local tooltipAnchorFrame;

local function updateTooltipAnchorVisibility()
	if ( tooltipAnchorFrame ) then
		if ( tooltipAnchorMode == 3 and tooltipAnchorDisplay ) then
			tooltipAnchorFrame:Show();
		else
			tooltipAnchorFrame:Hide();
		end
	end
end

local function updateTooltipText(self)
	local _, text;
	_, _, _, text = getPositions(tooltipAnchor, tooltipAnchorMode);
	self.text:SetText(text);
end

local function createTooltipAnchorFrame()
	local movable = "TOOLTIPANCHOR";	
	tooltipAnchorFrame = module:getFrame(anchorFrameSkeleton);
	updateTooltipText(tooltipAnchorFrame);
	updateTooltipAnchorVisibility();
	
	module:registerMovable(movable, tooltipAnchorFrame);
	tooltipAnchorFrame.movable = movable;
	tooltipAnchorFrame:SetScript("OnEnter", function(self) module:displayTooltip(self, tooltipText, true); end);
	tooltipAnchorFrame:SetScript("OnMouseUp", function(self, button)
		if ( button == "LeftButton" ) then
			module:stopMovable(self.movable);
		elseif ( button == "RightButton" ) then
			-- Update anchor & text
			tooltipAnchor = tooltipAnchor + 1;
			if ( tooltipAnchor > 4 ) then
				tooltipAnchor = 1;
			end
			module:setOption("tooltipAnchor", tooltipAnchor, true);
			updateTooltipText(self);

			-- Display tooltip & play sound
			self:GetScript("OnEnter")(self);
			PlaySound("UChatScrollButton");
		end
	end);
end

local function reanchorTooltip(tooltip, parent)
	local owner, pt, relPt = getPositions(tooltipAnchor, tooltipAnchorMode);
	tooltip:SetOwner(parent, owner);
	if ( pt ) then
		if ( not tooltipAnchorFrame ) then
			createTooltipAnchorFrame();
		end
		tooltip:ClearAllPoints();
		tooltip:SetPoint(pt, tooltipAnchorFrame, relPt);
	end
end

local oldGameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor;
function GameTooltip_SetDefaultAnchor(tooltip, parent, ...)
	if ( tooltip == GameTooltip and tooltipAnchorMode and tooltipAnchorMode > 1 ) then
		reanchorTooltip(tooltip, parent);
	else
		oldGameTooltip_SetDefaultAnchor(tooltip, parent, ...);
	end
end

local function setTooltipRelocationStyle(tooltipStyle)
	tooltipAnchorMode = tooltipStyle;
	updateTooltipAnchorVisibility();
end

local function toggleTooltipAnchorVisibility(show)
	tooltipAnchorDisplay = show;
	
	if ( not tooltipAnchorFrame and show ) then
		createTooltipAnchorFrame();
	else
		updateTooltipAnchorVisibility();
	end
end

local function setTooltipAnchor(anchor)
	tooltipAnchor = anchor or tooltipAnchor;
	
	if ( tooltipAnchorDisplay ) then
		if ( not tooltipAnchorFrame ) then
			createTooltipAnchorFrame();
		end
		updateTooltipText(tooltipAnchorFrame);
	end
end

--------------------------------------------
-- Tick Mod

local tickFrame;
local tickDisplayType = 1;

local tickFormatHealth_1 = "Health: %d";
local tickFormatHealth_2 = "HP/Tick: %d";
local tickFormatHealth_3 = "HP: %d";
local tickFormatMana_1 = "Mana: %d";
local tickFormatMana_2 = "MP/Tick: %d";
local tickFormatMana_3 = "MP: %d";

local tickFrameWidth;
local tickCounter = 0.05;
local lastTickHealth, lastTickMana;

local function fadeObject(self)
	local alpha = self.alpha;
	if ( alpha and alpha > 0.25 ) then
		alpha = alpha - 0.03;
		self.alpha = alpha;
		self:SetAlpha(alpha);
		return true;
	end
end

local function fadeTicks(self, elapsed)
	tickCounter = tickCounter - elapsed;
	if ( tickCounter < 0 ) then
		local fadedHealth = fadeObject(self.health);
		local fadedMana = fadeObject(self.mana);
		if ( not fadedHealth and not fadedMana ) then
			self:SetScript("OnUpdate", nil);
		end
		tickCounter = 0.05;
	end
end

local function updateTickDisplay(key, diff)
	local obj = tickFrame[key];
	obj:SetText(format(obj.strFormat, diff));
	obj:SetAlpha(1);
	obj.alpha = 1;
	
	if ( tickFrameWidth ) then
		tickFrame:SetWidth(tickFrameWidth);
	end
	
	counter = 0.05;
	tickFrame:SetScript("OnUpdate", fadeTicks);
end

local function tickFrameSkeleton()
	return "button#tl:mid:350:-200#s:90:40", {
		"backdrop#tooltip",
		"font#i:health#t:0:-8",
		"font#i:mana#b:0:8",
		["onload"] = function(self)
			self:RegisterEvent("UNIT_HEALTH");
			self:RegisterEvent("UNIT_MANA");
			self:SetBackdropColor(0, 0, 0, 0.75);
			module:registerMovable("TICKMOD", self, true);
		end,
		["onevent"] = function(self, event, unit)
			if ( unit == "player" ) then
				if ( event == "UNIT_HEALTH" ) then
					local health = UnitHealth("player");
					local diff = health-lastTickHealth;
					if ( diff > 0 ) then
						updateTickDisplay("health", diff);
					end
					lastTickHealth = health;
				else
					local mana = UnitMana("player");
					local diff = mana-lastTickMana;
					if ( diff > 0 ) then
						updateTickDisplay("mana", diff);
					end
					lastTickMana = mana;
				end
			end
		end,
		["onenter"] = function(self)
			module:displayPredefinedTooltip(self, "DRAG");
		end,
		["onleave"] = module.hideTooltip,
		["onmousedown"] = function(self, button)
			if ( button == "LeftButton" ) then
				module:moveMovable("TICKMOD");
			end
		end,
		["onmouseup"] = function(self, button)
			if ( button == "LeftButton" ) then
				module:stopMovable("TICKMOD");
			elseif ( button == "RightButton" ) then
				module:resetMovable("TICKMOD");
				self:ClearAllPoints();
				self:SetPoint("CENTER", UIParent);
			end
		end
	};
end

local function updateTickFrameOptions()
	if ( not tickFrame ) then
		return;
	end
	
	-- Height
	local _, class = UnitClass("player");
	if ( UnitPowerType("player") == 0 or class == "DRUID" ) then
		tickFrame:SetHeight(40);
	else
		tickFrame:SetHeight(30);
	end
	
	-- Width & Format
	if ( not tickDisplayType or tickDisplayType == 1 ) then
		tickFrameWidth = 90;
		tickFrame.health.strFormat = tickFormatHealth_1;
		tickFrame.mana.strFormat = tickFormatMana_1;
	elseif ( tickDisplayType == 2 ) then
		tickFrameWidth = 100;
		tickFrame.health.strFormat = tickFormatHealth_2;
		tickFrame.mana.strFormat = tickFormatMana_2;
	elseif ( tickDisplayType == 3 ) then
		tickFrameWidth = 80;
		tickFrame.health.strFormat = tickFormatHealth_3;
		tickFrame.mana.strFormat = tickFormatMana_3;
	end
end

local function toggleTick(enable)
	if ( enable ) then
		if ( not tickFrame ) then
			tickFrame = module:getFrame(tickFrameSkeleton);
		end
		tickFrame:Show();
		updateTickFrameOptions();
		lastTickHealth, lastTickMana = UnitHealth("player"), UnitMana("player");

	elseif ( tickFrame ) then
		tickFrame:Hide();
	end
end

local function setTickDisplayType(mode)
	tickDisplayType = mode;
	updateTickFrameOptions();
end

--------------------------------------------
-- Casting Bar Timer

local displayTimers;

-- Create our frames
	local countDownText = CastingBarFrame:CreateFontString(nil, "ARTWORK", "GameFontHighlight");
	countDownText:SetPoint("TOPRIGHT", 2, 5);
	countDownText:SetPoint("BOTTOMLEFT", CastingBarFrame, "BOTTOMRIGHT", -50, 2);
	CastingBarFrame.countDownText = countDownText;
	CastingBarFrame.ctElapsed = 0;
	
	local countDownTargetText = TargetFrameSpellBar:CreateFontString(nil, "ARTWORK", "GameFontHighlight");
	countDownTargetText:SetPoint("TOPRIGHT", 0, 5);
	countDownTargetText:SetPoint("BOTTOMLEFT", TargetFrameSpellBar, "BOTTOMRIGHT", -60, 0);
	TargetFrameSpellBar.countDownText = countDownTargetText;
	TargetFrameSpellBar.ctElapsed = 0;

-- Preparation for repositioning the normal texts
	local castingBarText = CastingBarFrameText;
	local castingBarTargetText = TargetFrameSpellBarText;

-- Hook the CastingBarFrame's OnUpdate
local oldCastingBarFrame_OnUpdate = CastingBarFrame_OnUpdate;
function CastingBarFrame_OnUpdate()
	oldCastingBarFrame_OnUpdate();
	
	local elapsed = this.ctElapsed - arg1;
	if ( elapsed < 0 ) then
		if ( displayTimers ) then
			-- We need to update
			if ( this.casting ) then
				this.countDownText:SetText(format("(%.1fs)", max(this.maxValue - GetTime(),0)));
			elseif ( this.channeling ) then
				this.countDownText:SetText(format("(%.1fs)", max(this.endTime - GetTime(),0)));
			else
				this.countDownText:SetText("");
			end
		end
		this.ctElapsed = 0.1;
	else
		this.ctElapsed = elapsed;
	end
end

local function toggleCastingTimers(enable)
	displayTimers = enable;
	castingBarText:ClearAllPoints();
	castingBarTargetText:ClearAllPoints();
	if ( enable ) then
		countDownText:Show();
		countDownTargetText:Show();
		
		castingBarText:SetPoint("TOPLEFT", 0, 5);
		castingBarText:SetPoint("BOTTOMRIGHT", countDownText, "BOTTOMLEFT", 10, 0);
		
		castingBarTargetText:SetPoint("TOPLEFT", 2, 5);
		castingBarTargetText:SetPoint("BOTTOMRIGHT", countDownTargetText, "BOTTOMLEFT", 10, 0);
	else
		countDownText:Hide();
		countDownTargetText:Hide();
		
		castingBarText:SetWidth(0);
		castingBarText:SetPoint("TOP", 0, 5);
		
		castingBarTargetText:SetWidth(0);
		castingBarTargetText:SetPoint("TOP", 0, 5);
	end
end

--------------------------------------------
-- Player Notes

local guildNotes, friendNotes, ignoreNotes;
local playerNoteButtons;

local function updatePlayerNotes(save)
	if ( save ) then
		module:setOption("guildNotes", guildNotes, true);
		module:setOption("friendNotes", friendNotes, true);
		module:setOption("ignoreNotes", ignoreNotes, true);
	else
		guildNotes, friendNotes, ignoreNotes =
			module:getOption("guildNotes"),
			module:getOption("friendNotes"),
			module:getOption("ignoreNotes");
	end
end

local function updateNote(playerName)
	local text = _G[this:GetParent():GetName().."EditBox"]:GetText();
	if ( text ~= "" ) then
		currentNoteType[playerName] = text;
	else
		currentNoteType[playerName] = nil;
	end
	if ( currentNoteType == guildNotes ) then
		GuildStatus_Update();
	elseif ( currentNoteType == friendNotes ) then
		FriendsList_Update();
	else
		IgnoreList_Update();
	end
	updatePlayerNotes(true);
end

local function getNoteDialogTable()
	return {
		text = module:getText("EDITING"),
		button1 = TEXT(ACCEPT),
		button2 = TEXT(CANCEL),
		hasEditBox = 1,
		maxLetters = 128,
		whileDead = 1,
		OnAccept = updateNote,
		timeout = 0,
		EditBoxOnEnterPressed = function(playerName)
			updateNote(playerName);
			this:GetParent():Hide();
		end,
		EditBoxOnEscapePressed = function(playerName)
			this:GetParent():Hide();
		end,
		hideOnEscape = 1
	};
end

local function editNote(playerName, noteType)
	if ( not StaticPopupDialogs["PLAYERNOTE_EDIT"] ) then
		StaticPopupDialogs["PLAYERNOTE_EDIT"] = getNoteDialogTable();
	end
	
	local coloredName;
	if ( noteType == ignoreNotes ) then
		coloredName = "|c00FF0000"..playerName.."|r";
	else
		coloredName = "|c0000FF00"..playerName.."|r";
	end
	
	local dialog = StaticPopup_Show("PLAYERNOTE_EDIT", coloredName);
	local staticPopupName = StaticPopup_Visible("PLAYERNOTE_EDIT");
	local editBox = _G[staticPopupName.."EditBox"];
	
	currentNoteType = noteType;
	dialog.data = playerName;
	editBox:SetText(noteType[playerName] or "");
	editBox:HighlightText();
end

local function playerNoteSkeleton()
	return "button#s:16:16#st:TOOLTIP#cache", {
		["onload"] = function(self)
			local normalTexture = self:CreateTexture();
			local highlightTexture = self:CreateTexture();
			normalTexture:SetAllPoints(self);
			highlightTexture:SetAllPoints(self);
			highlightTexture:SetBlendMode("ADD");
			
			self.normalTexture = normalTexture;
			self:SetNormalTexture(normalTexture);
			self:SetHighlightTexture(highlightTexture);
			self:SetDisabledTexture("Interface\\Buttons\\UI-GuildButton-PublicNote-Disabled");
			normalTexture:SetTexture("Interface\\Buttons\\UI-GuildButton-PublicNote-Up");
			highlightTexture:SetTexture("Interface\\Buttons\\UI-GuildButton-PublicNote-Up");
		end,
		["onclick"] = function(self)
			editNote(self.name, self.type);
		end,
		["onenter"] = function(self)
			local tooltip = GameTooltip;
			tooltip:SetOwner(self, "ANCHOR_RIGHT");
			tooltip:ClearLines();
			tooltip:AddLine(module:getText("CLICKEDIT"), 1, 0.7, 0);
			tooltip:AddLine(self.note);
			tooltip:Show();
		end,
		["onleave"] = module.hideTooltip
	};
end

local function getPlayerNoteButton(index)
	local obj = playerNoteButtons[index];
	if ( not obj ) then
		obj = module:getFrame(playerNoteSkeleton);
		playerNoteButtons[index] = obj;
	end
	return obj;
end

local function updateDisplay(offset, maxNum, framePrefix, frameOffset, tbl, nameFunc, parent)
	local numButtons, index, frame, name = 0;
	
	if ( playerNoteButtons ) then
		numButtons = #playerNoteButtons;
	else
		playerNoteButtons = { };
	end
	
	for i=1, max(maxNum, numButtons), 1 do
		btn = getPlayerNoteButton(i);
		if ( i > maxNum ) then
			btn:Hide();
		else
			index = offset + i;
			name = nameFunc(index);
			frame = _G[framePrefix..i];
			
			local note = tbl[name];
			if ( note ) then
				btn.note = note;
				btn.normalTexture:SetVertexColor(1.0, 1.0, 1.0);
			else
				btn.note = "";
				btn.normalTexture:SetVertexColor(0.5, 0.5, 0.5);
			end

			btn.type = tbl;
			btn.name = name;
			
			btn:SetParent(parent or frame);
			btn:ClearAllPoints();
			btn:SetPoint("RIGHT", frame, "LEFT", frameOffset, 0);
			btn:SetFrameLevel(frame:GetFrameLevel()+1);
			btn:Show();
		end
	end
end

-- Hooks for knowing which icons to display
local oldFriendsList_Update = FriendsList_Update;
function FriendsList_Update(...)
	oldFriendsList_Update(...);
	
	if ( not FriendsListFrame:IsVisible() ) then
		return;
	end
	
	local maxDisplay = FRIENDS_TO_DISPLAY;
	local maxNum = GetNumFriends();
	if ( maxNum > 0 and not friendNotes ) then
		friendNotes = { };
	end
	
	updateDisplay(FauxScrollFrame_GetOffset(FriendsFrameFriendsScrollFrame),
		min(maxNum, maxDisplay), "FriendsFrameFriendButton", 
		( ( maxDisplay >= maxNum ) and 315 ) or 290, friendNotes, GetFriendInfo);
end

local oldIgnoreList_Update = IgnoreList_Update;
function IgnoreList_Update(...)
	oldIgnoreList_Update(...);
	
	if ( not IgnoreListFrame:IsVisible() ) then
		return;
	end
	
	local maxDisplay = IGNORES_TO_DISPLAY;
	local maxNum = GetNumIgnores();
	if ( maxNum > 0 and not ignoreNotes ) then
		ignoreNotes = { };
	end
	
	updateDisplay(FauxScrollFrame_GetOffset(FriendsFrameFriendsScrollFrame),
		min(maxNum, maxDisplay), "FriendsFrameIgnoreButton", 
		( ( maxDisplay >= maxNum ) and 315 ) or 290, ignoreNotes, GetIgnoreName);
end

local oldGuildStatus_Update = GuildStatus_Update;
function GuildStatus_Update(...)
	oldGuildStatus_Update(...);
	
	if ( not GuildFrame:IsVisible() ) then
		return;
	end
	
	local framePrefix;
	if ( FriendsFrame.playerStatusFrame ) then
		framePrefix = "GuildFrameGuildStatusButton";
	else
		framePrefix = "GuildFrameButton";
	end
	
	local maxDisplay = GUILDMEMBERS_TO_DISPLAY;
	local maxNum = GetNumGuildMembers();
	if ( maxNum > 0 and not guildNotes ) then
		guildNotes = { };
	end
	
	updateDisplay(FauxScrollFrame_GetOffset(GuildListScrollFrame), min(maxNum, maxDisplay),
		framePrefix, ( ( maxDisplay >= maxNum ) and 320 ) or 303,
		guildNotes, GetGuildRosterInfo, GuildFrame);
end

--------------------------------------------
-- Alt+Right-Click to buy full stack

local oldMerchantItemButton_OnModifiedClick = MerchantItemButton_OnModifiedClick;
function MerchantItemButton_OnModifiedClick(...)
	if ( IsAltKeyDown() ) then
		local id = this:GetID();
		local maxStack = GetMerchantItemMaxStack(id);
		local money = GetMoney();
		local _, _, price, quantity = GetMerchantItemInfo(id);
		
		if ( maxStack == 1 and quantity > 1 ) then
			-- We need to check max stack count
			local _, _, _, _, _, _, _, stackCount = GetItemInfo(GetMerchantItemLink(id));
			if ( stackCount and stackCount > 1 ) then
				maxStack = floor(stackCount/quantity);
			end
		end
	
		if ( maxStack*price > money ) then
			maxStack = floor(money/price);
		end
		BuyMerchantItem(id, maxStack);
	else
		oldMerchantItemButton_OnModifiedClick(...);
	end
end

--------------------------------------------
-- Hide Gryphons & World Map Minimap Button

local function toggleGryphons(hide)
	if ( hide ) then
		MainMenuBarLeftEndCap:Hide();
		MainMenuBarRightEndCap:Hide();
	else
		MainMenuBarLeftEndCap:Show();
		MainMenuBarRightEndCap:Show();
	end
end

local function toggleWorldMap(hide)
	if ( hide ) then
		MiniMapWorldMapButton:Hide();
	else
		MiniMapWorldMapButton:Show();
	end
end

--------------------------------------------
-- General Initializer

local modFunctions = {
	["castingTimers"] = toggleCastingTimers,
	["questLevels"] = toggleDisplayLevels,
	["blockBankTrades"] = toggleBlockTrades,
	["tickMod"] = toggleTick,
	["tickModFormat"] = setTickDisplayType,
	["tooltipRelocation"] = setTooltipRelocationStyle,
	["tooltipRelocationAnchor"] = toggleTooltipAnchorVisibility,
	["tooltipAnchor"] = setTooltipAnchor,
	["questTracker"] = toggleTrackerAnchor,
	["questTrackerMode"] = updateTrackerAnchorMode,
	["hideGryphons"] = toggleGryphons,
	["hideWorldMap"] = toggleWorldMap
};

local modFunctionsTrue = {
	["questTrackerAnchor"] = toggleTrackerAnchorVisibility
};


module.modupdate = function(self, type, value)
	if ( type == "init" ) then
		for key, value in pairs(modFunctions) do
			value(self:getOption(key));
		end
		
		for key, value in pairs(modFunctionsTrue) do
			value(self:getOption(key) ~= false);
		end
		updatePlayerNotes();
	else
		local func = modFunctions[type];
		if ( func ) then
			func(value);
		else
			func = modFunctionsTrue[type];
			if ( func ) then
				func(value ~= false);
			end
		end
	end
end