QUESTGURU_QUESTS_DISPLAYED = 27;
UPDATE_DELAY = 0.1;
QUESTLOG_QUEST_HEIGHT = 16;

QUESTGURU_VERSION = GetAddOnMetadata("QuestGuru", "Version");
QUESTGURU_NUMTABS = 5;

QuestGuru_Quests = {};
QuestGuru_QuestLog = {};
QuestGuru_QuestLogHeader = {};
QuestGuru_Items = {};
QuestGuru_Settings = {};
QuestGuru_Settings.Tracker = {};
QuestGuru_Settings.ShowLevels = {};
QuestGuru_QuestStart = {};
QuestGuru_Player = "";
QuestGuru_RealmName = "";
QuestGuru_WorldMapIconInfo = { cont = 0, zone = 0, x = 0, y = 0, NPCName = QG_UNKNOWN, QuestName = QG_NONE };
QuestGuru_WorldmapQuestIconInfo = {};
for i=1, MAX_QUESTS do
	temp = CreateFrame("BUTTON", "QuestGuru_WorldmapQuestIcon"..i, WorldmapFrame, "QuestGuru_WorldmapQuestIconTemplate");
	QuestGuru_WorldmapQuestIconInfo[i] = { cont = 0, zone = 0, x = 0, y = 0, NPCName = QG_UNKNOWN, QuestName = QG_NONE, state = 0 };
	-- state: 0=None, 1=quest in progress, 2=daily available, 4=quest available, 8=quest complete
end

do
	local temp, i;

	QuestGuru_QuestStartInfoFrame = CreateFrame("FRAME", "QuestGuru_QuestStartInfoFrame", QuestGuru_QuestLogFrame);
	QuestGuru_QuestStartInfoFrame:Hide();
	QuestGuru_QuestStartInfoFrame:EnableMouse();
	QuestGuru_QuestStartInfoFrame:SetMovable(1);
	QuestGuru_QuestStartInfoFrame:SetResizable(1);
	QuestGuru_QuestStartInfoFrame:SetToplevel(1);
	QuestGuru_QuestStartInfoFrame:SetFrameStrata("TOOLTIP");
	QuestGuru_QuestStartInfoFrame:SetClampedToScreen(true);
	QuestGuru_QuestStartInfoFrame:SetWidth(240);
	QuestGuru_QuestStartInfoFrame:SetHeight(94);
	QuestGuru_QuestStartInfoFrame:SetScale(0.8);
	QuestGuru_QuestStartInfoFrame:SetPoint("TOPLEFT", QuestGuru_QuestLogFrame);
	QuestGuru_QuestStartInfoFrame:SetBackdrop({
			edgeFile="Interface\\Tooltips\\UI-Tooltip-Border",
			edgeSize=16, insets={left=3, right=4, top=4, bottom=4}
		});
		
	temp = QuestGuru_QuestStartInfoFrame:CreateTexture("QuestGuru_QuestStartInfoBG", "BACKGROUND");
	temp:SetPoint("TOPLEFT", 4, -4);
	temp:SetPoint("BOTTOMRIGHT", -4, 4);
	temp:SetTexture("Interface\\Stationery\\StationeryTest1");
	temp:SetTexCoord(0.5, 1, 0, 0.25);

	temp = QuestGuru_QuestStartInfoFrame:CreateFontString("QuestGuru_QuestStartInfoTitle", "BACKGROUND", "QuestTitleFont");
	temp:SetPoint("TOP", 0, -8);
	temp:SetJustifyH("CENTER");
	temp:SetWidth(0);
	temp:SetHeight(12);

	temp = QuestGuru_QuestStartInfoFrame:CreateFontString("QuestGuru_QuestStartInfoNPC", "BACKGROUND", "QuestFont");
	temp:SetPoint("TOPLEFT", 8, -26);
	temp:SetJustifyH("LEFT");
	temp:SetWidth(0);
	temp:SetHeight(10);

	temp = QuestGuru_QuestStartInfoFrame:CreateFontString("QuestGuru_QuestStartInfoPOS", "BACKGROUND", "QuestFont");
	temp:SetPoint("TOPRIGHT", -10, -26);
	temp:SetJustifyH("RIGHT");
	temp:SetWidth(0);
	temp:SetHeight(12);

	temp = QuestGuru_QuestStartInfoFrame:CreateFontString("QuestGuru_QuestStartInfoArea", "BACKGROUND", "QuestFont");
	temp:SetPoint("TOPLEFT", QuestGuru_QuestStartInfoNPC, "BOTTOMLEFT", 0, -4);
	temp:SetJustifyH("LEFT");
	temp:SetWidth(0);
	temp:SetHeight(12);

	temp = QuestGuru_QuestStartInfoFrame:CreateFontString("QuestGuru_QuestStartInfoTimeLabel", "BACKGROUND", "QuestFont");
	temp:SetPoint("TOPLEFT", 8, -56);
	temp:SetJustifyH("LEFT");
	temp:SetWidth(0);
	temp:SetHeight(12);

	temp = QuestGuru_QuestStartInfoFrame:CreateFontString("QuestGuru_QuestStartInfoTime", "BACKGROUND", "QuestFont");
	temp:SetPoint("TOPRIGHT", -10, -56);
	temp:SetJustifyH("RIGHT");
	temp:SetWidth(0);
	temp:SetHeight(12);

	temp = QuestGuru_QuestStartInfoFrame:CreateFontString("QuestGuru_QuestStartInfoLevelLabel", "BACKGROUND", "QuestFont");
	temp:SetPoint("TOPLEFT", QuestGuru_QuestStartInfoTimeLabel, "BOTTOMLEFT", 0, -4);
	temp:SetJustifyH("LEFT");
	temp:SetWidth(0);
	temp:SetHeight(12);

	temp = QuestGuru_QuestStartInfoFrame:CreateFontString("QuestGuru_QuestStartInfoLevel", "BACKGROUND", "QuestFont");
	temp:SetPoint("TOPLEFT", QuestGuru_QuestStartInfoTime, "BOTTOMLEFT", 0, -4);
	temp:SetJustifyH("LEFT");
	temp:SetWidth(0);
	temp:SetHeight(12);

	QuestGuru_QuestFinishInfoFrame = CreateFrame("FRAME", "QuestGuru_QuestFinishInfoFrame", QuestGuru_QuestLogFrame);
	QuestGuru_QuestFinishInfoFrame:Hide();
	QuestGuru_QuestFinishInfoFrame:EnableMouse();
	QuestGuru_QuestFinishInfoFrame:SetMovable(1);
	QuestGuru_QuestFinishInfoFrame:SetResizable(1);
	QuestGuru_QuestFinishInfoFrame:SetToplevel(1);
	QuestGuru_QuestFinishInfoFrame:SetFrameStrata("TOOLTIP");
	QuestGuru_QuestFinishInfoFrame:SetClampedToScreen(true);
	QuestGuru_QuestFinishInfoFrame:SetWidth(240);
	QuestGuru_QuestFinishInfoFrame:SetHeight(60);
	QuestGuru_QuestFinishInfoFrame:SetScale(0.8);
	QuestGuru_QuestFinishInfoFrame:SetPoint("TOPLEFT", QuestGuru_QuestLogFrame);
	QuestGuru_QuestFinishInfoFrame:SetBackdrop({
			edgeFile="Interface\\Tooltips\\UI-Tooltip-Border",
			edgeSize=16, insets={left=3, right=4, top=4, bottom=4}
		});
		
	temp = QuestGuru_QuestFinishInfoFrame:CreateTexture("QuestGuru_QuestFinishInfoBG", "BACKGROUND");
	temp:SetPoint("TOPLEFT", 4, -4);
	temp:SetPoint("BOTTOMRIGHT", -4, 4);
	temp:SetTexture("Interface\\Stationery\\StationeryTest1");
	temp:SetTexCoord(0.5, 1, 0, 0.25);

	temp = QuestGuru_QuestFinishInfoFrame:CreateFontString("QuestGuru_QuestFinishInfoTitle", "BACKGROUND", "QuestTitleFont");
	temp:SetPoint("TOP", 0, -8);
	temp:SetJustifyH("CENTER");
	temp:SetWidth(0);
	temp:SetHeight(12);

	temp = QuestGuru_QuestFinishInfoFrame:CreateFontString("QuestGuru_QuestFinishInfoNPC", "BACKGROUND", "QuestFont");
	temp:SetPoint("TOPLEFT", 8, -26);
	temp:SetJustifyH("LEFT");
	temp:SetWidth(0);
	temp:SetHeight(10);

	temp = QuestGuru_QuestFinishInfoFrame:CreateFontString("QuestGuru_QuestFinishInfoPOS", "BACKGROUND", "QuestFont");
	temp:SetPoint("TOPRIGHT", -10, -26);
	temp:SetJustifyH("RIGHT");
	temp:SetWidth(0);
	temp:SetHeight(12);

	temp = QuestGuru_QuestFinishInfoFrame:CreateFontString("QuestGuru_QuestFinishInfoArea", "BACKGROUND", "QuestFont");
	temp:SetPoint("TOPLEFT", QuestGuru_QuestFinishInfoNPC, "BOTTOMLEFT", 0, -4);
	temp:SetJustifyH("LEFT");
	temp:SetWidth(0);
	temp:SetHeight(12);
end

function QuestGuru_ExpandCollapse()
	local currTab = PanelTemplates_GetSelectedTab(QuestGuru_QuestLogFrame);
	local i, qH;
	local collapsed=true;
	
	if (currTab == 1) then -- Quest Log
		for i, qH in ipairs(QuestGuru_QuestLog) do
			if (qH.isHeader and ((QuestGuru_QuestLogHeader[qH.Title] == true) or (QuestGuru_QuestLogHeader[qH.Title] == nil))) then collapsed=false; end
		end
		QuestGuru_QuestLogHeader = {};
		if (collapsed) then
			for i, qH in ipairs(QuestGuru_QuestLog) do
				if (qH.isHeader) then QuestGuru_QuestLogHeader[qH.Title] = true; end
			end                                               
		else
			for i, qH in ipairs(QuestGuru_QuestLog) do
				if (qH.isHeader) then QuestGuru_QuestLogHeader[qH.Title] = false; end
			end
		end
		FauxScrollFrame_SetOffset(QuestGuru_QuestLogListScrollFrame, 0);
		QuestLog_Update();
	elseif (currTab == 2) then -- History
		for i, qH in ipairs(QuestGuru_History) do
			if (QuestGuru_HistoryHeaders[qH.Header]) then collapsed=false; end
		end
		if (collapsed) then
			for i, qH in ipairs(QuestGuru_History) do
				QuestGuru_HistoryHeaders[qH.Header] = true;
			end
			QuestLog_SetHistorySelection(2);
		else
			for i, qH in ipairs(QuestGuru_History) do
				QuestGuru_HistoryHeaders[qH.Header] = false;
			end
			QuestLog_SetHistorySelection(0);
		end
		FauxScrollFrame_SetOffset(QuestGuru_QuestHistoryListScrollFrame, 0);
		QuestGuru_UpdateHistory();
	elseif (currTab == 3) then -- Abandon
		for i, qH in ipairs(QuestGuru_Abandon) do
			if (QuestGuru_AbandonHeaders[qH.Header]) then collapsed=false; end
		end
		if (collapsed) then
			for i, qH in ipairs(QuestGuru_Abandon) do
				QuestGuru_AbandonHeaders[qH.Header] = true;
			end
			QuestLog_SetAbandonSelection(2);
		else
			for i, qH in ipairs(QuestGuru_Abandon) do
				QuestGuru_AbandonHeaders[qH.Header] = false;
			end
			QuestLog_SetAbandonSelection(0);
		end
		FauxScrollFrame_SetOffset(QuestGuru_QuestAbandonListScrollFrame, 0);
		QuestGuru_UpdateAbandon();
	end
end

function QuestGuru_TabClick(id)
	local i;
	
	HideDropDownMenu(1);
	
	PanelTemplates_SetTab(QuestGuru_QuestLogFrame, id);

	for i=1, QUESTGURU_NUMTABS do
		getglobal("QuestGuru_TabPage"..i):Hide();
	end
	getglobal("QuestGuru_TabPage"..id):Show();
	
	if (id == 1) then
	    QuestLog_SetSelection(QuestGuru_QuestLogFrame.selectedButtonID);
	end

	if (id == 2) then --History
		local scrollOffset = FauxScrollFrame_GetOffset(QuestGuru_QuestHistoryListScrollFrame)
		local n = QuestGuru_currHistory - scrollOffset;
		if ((n > 0) and (n <= QUESTGURU_QUESTS_DISPLAYED)) then
			getglobal("QuestGuru_QuestHistoryTitle"..n):Click();
		end
	end

	if (id == 3) then --Abandon
		local scrollOffset = FauxScrollFrame_GetOffset(QuestGuru_QuestAbandonListScrollFrame)
		local n = QuestGuru_currAbandon - scrollOffset;
		if ((n > 0) and (n <= QUESTGURU_QUESTS_DISPLAYED)) then
			getglobal("QuestGuru_QuestAbandonTitle"..n):Click();
		end
	end
end

function QuestGuru_UpdateTabs()
	local i;
	local lastTab = 1;

	PanelTemplates_TabResize(getglobal("QuestGuru_QuestLogFrameTab1"), 8);	
	for i=2, QUESTGURU_NUMTABS do
		local tab = getglobal("QuestGuru_QuestLogFrameTab"..i);
		local t= tab:GetText();
		if (t) then
	      	if (string.find(t, "%(0%)")) then
				tab:Hide();
			else
				tab:SetPoint("LEFT", "QuestGuru_QuestLogFrameTab"..lastTab, "RIGHT", 0, 0);
				PanelTemplates_TabResize(tab, 8);
				tab:Show();
				lastTab = i;
			end
		end
	end
end

local old_ToggleQuestLog = ToggleQuestLog;
function ToggleQuestLog()
	if ( QuestGuru_QuestLogFrame:IsShown() ) then
		HideUIPanel(QuestGuru_QuestLogFrame);
	else
		ShowUIPanel(QuestGuru_QuestLogFrame);
	end
end

local old_QuestLogTitleButton_OnLoad = QuestLogTitleButton_OnLoad;
function QuestLogTitleButton_OnLoad(self)
	self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
	self:RegisterEvent("UNIT_QUEST_LOG_CHANGED");
	self:RegisterEvent("PARTY_MEMBER_ENABLE");
	self:RegisterEvent("PARTY_MEMBER_DISABLE");
end

local old_QuestLogTitleButton_OnEvent = QuestLogTitleButton_OnEvent;
function QuestLogTitleButton_OnEvent(self, event, ...)
	if (event == nil) then
	    event = self;
	    self = this;
	end
	if (GameTooltip:IsOwned(self)) then
		GameTooltip:Hide();
		QuestLog_UpdatePartyInfoTooltip(self);
	end
end

function QuestGuru_QuestLogTitleMenu_OnLoad()
	if (string.find(this:GetName(), "QuestLogTitleMenu")) then return; end
	local info = UIDropDownMenu_CreateInfo();
	info.func = QuestGuru_QuestLogTitleMenu_OnClick;
	info.arg1 = this:GetID();
	if (this.qID) then info.arg1 = this.qID; end
	info.checked = nil;
	info.icon = nil;

	local questLogTitleText, level, questTag, suggestedGroup, isHeader, isCollapsed, isComplete, isDaily = GetQuestLogTitle(info.arg1);
	if (IsQuestWatched(info.arg1)) then
	    info.text = QG_UNTRACK.." "..questLogTitleText;
	    info.value = "untrack";
	    UIDropDownMenu_AddButton(info, 1);
	else
	    info.text = QG_TRACK.." "..questLogTitleText;
	    info.value = "track";
	    UIDropDownMenu_AddButton(info, 1);
	end

	if (not this.isHeader) then
		if (GetQuestLogPushable() and ( GetRealNumPartyMembers() > 0 or GetRealNumRaidMembers() > 0) ) then
			info.disabled = nil;
		else
			info.disabled = 1;
		end
		info.text = QG_SHARE_QUEST;
		info.value = "share";
		UIDropDownMenu_AddButton(info, 1);
		info.disabled = nil;

		info.text = QG_ABANDON_QUEST;
		info.value = "abandon";
		UIDropDownMenu_AddButton(info, 1);
	end

	info.text = "--------------------";
	info.value = "-";
	info.isTitle = 1;
	UIDropDownMenu_AddButton(info, 1);

	info = UIDropDownMenu_CreateInfo();
	info.func = QuestGuru_QuestLogTitleMenu_OnClick;
	info.checked = nil;
	info.icon = nil;
	info.text = CANCEL;
	info.value = "cancel";
	UIDropDownMenu_AddButton(info, 1);
end

function QuestGuru_QuestLogTitleMenu_OnClick()
	if (this.value == "abandon") then
		QuestGuru_AbandonQuest();
	elseif (this.value == "share") then
		QuestLogPushQuest();
	elseif (this.value == "track") then
		AddQuestWatch(this.arg1);
		QuestLog_Update();
	elseif (this.value == "untrack") then
		RemoveQuestWatch(this.arg1);
		QuestLog_Update();
	end
end

local old_QuestLogTitleButton_OnClick = QuestLogTitleButton_OnClick;
function QuestLogTitleButton_OnClick(self, button, down)
	local questName = self:GetText();
	local questLevel = getglobal(self:GetName().."Level"):GetText();
	local questIndex = self:GetID() + FauxScrollFrame_GetOffset(QuestGuru_QuestLogListScrollFrame);
	if (QuestGuru_QuestLog[questIndex]) then questIndex = QuestGuru_QuestLog[questIndex].Index; end

	HideDropDownMenu(1);
	
	if (button == "LeftButton") then
		if ( IsShiftKeyDown() ) then
			-- If header then return
			if ( self.isHeader ) then
				local questCheck = getglobal(self:GetName().."Check");
				if (questCheck:GetChecked()) then
					RemoveQuestWatch(questIndex);
				else
					AddQuestWatch(questIndex);
				end
				QuestLog_Update();
				QuestWatch_Update();
				return;
			end
			-- Try to track it or put it into chat
			if ( ChatFrameEditBox:IsVisible() and (not self.isHeader) ) then
				ChatFrameEditBox:Insert(GetQuestLink(questIndex));
			else
				-- Shift-click toggles quest-watch on this quest.
				if ( IsQuestWatched(questIndex) ) then
					RemoveQuestWatch(questIndex);
				else
					AddQuestWatch(questIndex);
				end
				QuestLog_Update();
				QuestWatch_Update();
				return;
			end
		else
			QuestLog_SetSelection(questIndex, button);
		end
	elseif (button == "RightButton") then
		QuestLog_SetSelection(questIndex, button);
		ToggleDropDownMenu(1, nil, QuestGuru_QuestLogTitleMenu, self:GetName(), 0, 0)
	end
	QuestLog_Update();
end

function QuestLogTitleButtonCheck_OnClick(self, button, down)
	local index = self:GetParent():GetID() + FauxScrollFrame_GetOffset(QuestGuru_QuestLogListScrollFrame);
	index = QuestGuru_QuestLog[index].Index;
	
	if (self:GetChecked()) then
		if (not AddQuestWatch(index)) then
			self:SetChecked(0);
		end
	else
		RemoveQuestWatch(index);
	end
	QuestWatch_Update();
	QuestLog_Update();
end

local old_QuestLogTitleButton_OnEnter = QuestLogTitleButton_OnEnter;
function QuestLogTitleButton_OnEnter(self, motion)
	-- Set highlight
	getglobal(self:GetName().."Tag"):SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
	getglobal(self:GetName().."Level"):SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);

	-- Set group info tooltip
	QuestLog_UpdatePartyInfoTooltip(self);
end

local old_QuestLogTitleButton_OnLeave = QuestLogTitleButton_OnLeave;
function QuestLogTitleButton_OnLeave(self, motion)
	if (QuestGuru_QuestLog[self:GetID()].Index ~= (QuestGuru_QuestLogFrame.selectedButtonID - FauxScrollFrame_GetOffset(QuestLogListScrollFrame))) then
		getglobal(self:GetName().."Tag"):SetTextColor(self.r, self.g, self.b);
		getglobal(self:GetName().."Level"):SetTextColor(self.r, self.g, self.b);
	end
	GameTooltip:Hide();
end

function QuestGuru_QuestLogStart_OnEnter(self, motion)
	local tempWidth, maxWidth;
	local questName = QuestGuru_QuestLogQuestTitle:GetText();
	local NPCColor, AreaColor;
	if (QuestGuru_Settings.Colorize.NPCNames.Enabled) then
		NPCColor = QuestGuru_Settings.Colorize.NPCNames.Color;
	else
		NPCColor = { r=0, g=0, b=0 };
	end
	if (QuestGuru_Settings.Colorize.AreaNames.Enabled) then
		AreaColor = QuestGuru_Settings.Colorize.AreaNames.Color;
	else
		AreaColor = { r=0, g=0, b=0 };
	end
	
	if (QuestGuru_QuestStart[questName] ~= nil) then
		local startQuest = QuestGuru_QuestStart[questName];

		QuestGuru_QuestStartInfoFrame:ClearAllPoints();
        QuestGuru_QuestStartInfoFrame:SetPoint("BOTTOM", QuestGuru_QuestLogStart, "TOP");
        QuestGuru_QuestStartInfoTitle:SetText(QG_QSTART_HEAD);
        maxWidth = QuestGuru_QuestStartInfoTitle:GetWidth();

        QuestGuru_QuestStartInfoNPC:SetText(startQuest.NPCName);
		QuestGuru_QuestStartInfoNPC:SetTextColor(NPCColor.r, NPCColor.g, NPCColor.b);

        QuestGuru_QuestStartInfoPOS:SetText("("..startQuest.PosX..","..startQuest.PosY..")");
		QuestGuru_QuestStartInfoPOS:SetTextColor(AreaColor.r, AreaColor.g, AreaColor.b);
		tempWidth = QuestGuru_QuestStartInfoNPC:GetWidth() + QuestGuru_QuestStartInfoPOS:GetWidth() + 8;
		if (tempWidth > maxWidth) then maxWidth = tempWidth; end

        QuestGuru_QuestStartInfoArea:SetText(startQuest.NPCZone);
		QuestGuru_QuestStartInfoArea:SetTextColor(AreaColor.r, AreaColor.g, AreaColor.b);
		tempWidth = QuestGuru_QuestStartInfoArea:GetWidth();
		if (tempWidth > maxWidth) then maxWidth = tempWidth; end
		
		QuestGuru_QuestStartInfoTimeLabel:SetText(QG_QSTART_TIME);
		QuestGuru_QuestStartInfoTime:SetText(startQuest.StartTime);
		tempWidth = QuestGuru_QuestStartInfoTimeLabel:GetWidth() + QuestGuru_QuestStartInfoTime:GetWidth() + 8;
		if (tempWidth > maxWidth) then maxWidth = tempWidth; end

		QuestGuru_QuestStartInfoLevelLabel:SetText(QG_QSTART_LEVEL);
		QuestGuru_QuestStartInfoLevel:SetText(startQuest.Level);
		tempWidth = QuestGuru_QuestStartInfoLevelLabel:GetWidth() + QuestGuru_QuestStartInfoLevel:GetWidth() + 8;
		if (tempWidth > maxWidth) then maxWidth = tempWidth; end

		QuestGuru_QuestStartInfoFrame:SetWidth(maxWidth + 18);
        QuestGuru_QuestStartInfoFrame:Show();
	end
end

function QuestGuru_QuestLogStart_OnClick(self, button, down)
	local questIndex = GetQuestLogSelection();
	local questLogTitleText, level, questTag, suggestedGroup, isHeader, isCollapsed, isComplete, isDaily = GetQuestLogTitle(questIndex);
	if (QuestGuru_QuestStart[questLogTitleText] ~= nil) then
		local startQuest = QuestGuru_QuestStart[questLogTitleText];
		if (isDaily) then
			QuestGuru_WorldmapIconTexture:SetTexCoord(0.375, 0.5, 0.5, 1);
		else
			QuestGuru_WorldmapIconTexture:SetTexCoord(0.125, 0.25, 0.5, 1);
		end
		QuestGuru_ShowMap(startQuest.NPCZone, startQuest.PosX, startQuest.PosY, startQuest.NPCName, questLogTitleText);
	end
end

function QuestGuru_QuestLogFinish_OnEnter(self, motion)
	local tempWidth, maxWidth;
	local NPCColor, AreaColor;
	if (QuestGuru_Settings.Colorize.NPCNames.Enabled) then
		NPCColor = QuestGuru_Settings.Colorize.NPCNames.Color;
	else
		NPCColor = { r=0, g=0, b=0 };
	end
	if (QuestGuru_Settings.Colorize.AreaNames.Enabled) then
		AreaColor = QuestGuru_Settings.Colorize.AreaNames.Color;
	else
		AreaColor = { r=0, g=0, b=0 };
	end
	
	local questIndex = GetQuestLogSelection();
	local questLink = GetQuestLink(questIndex);
	if (questLink == nil) then return; end
	local qli, qlj, questNum = string.find(questLink, ":(%d+):");
	
	if (questNum and QuestGuru_Quests[QuestGuru_RealmName][questNum] and QuestGuru_Quests[QuestGuru_RealmName][questNum].FinishInfo) then
		local qsi, qsj, qsNPC, qsZone, qsX, qsY = string.find(QuestGuru_Quests[QuestGuru_RealmName][questNum].FinishInfo, "(.*);(.*);(.*);(.*)");
		if (qsi and qsj) then
			QuestGuru_QuestFinishInfoFrame:ClearAllPoints();
			QuestGuru_QuestFinishInfoFrame:SetPoint("BOTTOM", QuestGuru_QuestLogFinish, "TOP");
			QuestGuru_QuestFinishInfoTitle:SetText(QG_QFINISH_HEAD);
			maxWidth = QuestGuru_QuestFinishInfoTitle:GetWidth();

			QuestGuru_QuestFinishInfoNPC:SetText(qsNPC);
			QuestGuru_QuestFinishInfoNPC:SetTextColor(NPCColor.r, NPCColor.g, NPCColor.b);

			QuestGuru_QuestFinishInfoPOS:SetText("("..qsX..","..qsY..")");
			QuestGuru_QuestFinishInfoPOS:SetTextColor(AreaColor.r, AreaColor.g, AreaColor.b);
			tempWidth = QuestGuru_QuestFinishInfoNPC:GetWidth() + QuestGuru_QuestFinishInfoPOS:GetWidth() + 8;
			if (tempWidth > maxWidth) then maxWidth = tempWidth; end

			QuestGuru_QuestFinishInfoArea:SetText(gsub(qsZone, " in ", ", "));
			QuestGuru_QuestFinishInfoArea:SetTextColor(AreaColor.r, AreaColor.g, AreaColor.b);
			tempWidth = QuestGuru_QuestFinishInfoArea:GetWidth();
			if (tempWidth > maxWidth) then maxWidth = tempWidth; end

			QuestGuru_QuestFinishInfoFrame:SetWidth(maxWidth + 18);
			QuestGuru_QuestFinishInfoFrame:Show();
		end
	end
end

function QuestGuru_QuestLogFinish_OnClick(self, button, down)
	local questIndex = GetQuestLogSelection();
	local questLogTitleText, level, questTag, suggestedGroup, isHeader, isCollapsed, isComplete, isDaily = GetQuestLogTitle(questIndex);
	local questLink = GetQuestLink(questIndex);
	if (questLink == nil) then return; end
	local qli, qlj, questNum = string.find(questLink, ":(%d+):");
	
	if (questNum and QuestGuru_Quests[QuestGuru_RealmName][questNum] and QuestGuru_Quests[QuestGuru_RealmName][questNum].FinishInfo) then
		local qsi, qsj, qsNPC, qsZone, qsX, qsY = string.find(QuestGuru_Quests[QuestGuru_RealmName][questNum].FinishInfo, "(.*);(.*);(.*);(.*)");
		if (qsi and qsj) then
			if (isDaily) then
				QuestGuru_WorldmapIconTexture:SetTexCoord(0.5, 0.625, 0.5, 1);
			else
				QuestGuru_WorldmapIconTexture:SetTexCoord(0.25, 0.375, 0.5, 1);
			end
			QuestGuru_ShowMap(qsZone, qsX, qsY, qsNPC, questLogTitleText);
		end
	end
end

function QuestGuru_Tooltip_Hook()
	local itemName, itemLink = this:GetItem();
	local numEntries, numQuests = GetNumQuestLogEntries();
	local questID, i;

	if (itemName == nil) then return; end
	if (QuestGuru_Settings == nil) then return; end
	if (QuestGuru_Settings.TooltipText ~= true) then return; end
	for questID=1, numEntries, 1 do
		local questLogTitleText, level, questTag, suggestedGroup, isHeader, isCollapsed, isComplete, isDaily = GetQuestLogTitle(questID);
		local numObjectives = GetNumQuestLeaderBoards(questID);
		
		if (numObjectives ~= nil) then
			for i=1, numObjectives, 1 do
				local text, type, finished = GetQuestLogLeaderBoard(i,questID);

				if (type == "item") then
					local x, y, name, numItems, numNeeded = string.find(text,QG_ITEM_REQ_STR);
					if (name == nil) then return; end
					if (name == itemName) then
				    	GameTooltip:AddDoubleLine(questLogTitleText, numItems.."/"..numNeeded);
						GameTooltip:Show();
					end
				end
			end
		end
	end
	return true;
end

local old_QuestLog_OnLoad = QuestLog_OnLoad;
function QuestLog_OnLoad(self)
	ExpandQuestHeader(0);
	self.selectedButtonID = 2;
	getglobal("QuestGuru_QuestLogTitle"..self.selectedButtonID):Click();

	self:RegisterEvent("CHAT_MSG_ADDON");
	self:RegisterEvent("CHAT_MSG_COMBAT_FACTION_CHANGE");
	self:RegisterEvent("CHAT_MSG_COMBAT_XP_GAIN");
	self:RegisterEvent("GOSSIP_SHOW");
	self:RegisterEvent("PARTY_MEMBER_DISABLE");
	self:RegisterEvent("PARTY_MEMBER_ENABLE");
	self:RegisterEvent("PARTY_MEMBERS_CHANGED");
	self:RegisterEvent("PLAYER_LEAVING_WORLD");
	self:RegisterEvent("PLAYER_LOGIN");
	self:RegisterEvent("QUEST_COMPLETE");
	self:RegisterEvent("QUEST_DETAIL");
	self:RegisterEvent("QUEST_GREETING");
	self:RegisterEvent("QUEST_LOG_UPDATE");
	self:RegisterEvent("QUEST_PROGRESS");
	self:RegisterEvent("QUEST_WATCH_UPDATE");
	self:RegisterEvent("UI_INFO_MESSAGE");
	self:RegisterEvent("UNIT_QUEST_LOG_CHANGED");
	self:RegisterEvent("UPDATE_FACTION");
	self:RegisterEvent("UPDATE_MOUSEOVER_UNIT");
	self:RegisterEvent("VARIABLES_LOADED");
	self:RegisterEvent("WORLD_MAP_UPDATE");

	tinsert(UISpecialFrames, "QuestGuru_QuestLogFrame");
	QuestGuru_QuestLogTitleText:SetText("QuestGuru v"..QUESTGURU_VERSION);
	QuestGuru_QuestLogFrame:SetClampRectInsets(0, -40, 0, 0);

	GameTooltip:HookScript("OnTooltipSetItem",QuestGuru_Tooltip_Hook);

	setglobal("QuestLogFrame", QuestGuru_QuestLogFrame);
	setglobal("QuestLogListScrollFrame", QuestGuru_QuestLogListScrollFrame);
	setglobal("QuestLogDetailScrollChildFrame", QuestGuru_QuestLogDetailScrollChildFrame);
	setglobal("QuestLogQuestTitle", QuestGuru_QuestLogQuestTitle);
end

local old_QuestLog_OnEvent = QuestLog_OnEvent;
function QuestLog_OnEvent(self, event, arg1, arg2, arg3, arg4)
	if ( (event == "QUEST_LOG_UPDATE") or (event == "UPDATE_FACTION") or ((event == "UNIT_QUEST_LOG_CHANGED") and (arg1 == "player"))) then
		QuestLog_Update();
		QuestWatch_Update();
		if ( QuestGuru_QuestLogFrame:IsVisible() ) then
			QuestLog_UpdateQuestDetails(1);
		end
		QuestGuru_UpdateQuestsDB();
	elseif (event == "QUEST_WATCH_UPDATE") then
		if (AUTO_QUEST_WATCH == "1") then
			AddQuestWatch(arg1);
		end
--		if (QuestLogFrame:IsShown()) then QuestLog_Update(); end
--		QuestWatch_Update();
	elseif (event=="QUEST_COMPLETE") then
		-- Save Current Quest info
		local qNum = GetQuestLogIndexByName(GetTitleText());
		if (qNum) then QuestGuru_LastCompleteQuest.Link = GetQuestLink(qNum); end
		QuestGuru_SaveLastQuest();
		if (QuestGuru_Settings.AutoComplete and (GetNumQuestChoices() == 0)) then
			QuestRewardCompleteButton_OnClick();
		end
	elseif (event=="QUEST_GREETING") then
	    QuestGuru_QuestFrameGreetingPanel_OnShow();
	elseif (event=="QUEST_DETAIL") then
		QuestGuru_QuestDetailShow();
	elseif (event=="QUEST_PROGRESS") then
	    QuestGuru_QuestProgressShow();
		if (QuestGuru_Settings.AutoComplete and IsQuestCompletable()) then
			CompleteQuest();
		end	    
	elseif (event=="GOSSIP_SHOW") then
		QuestGuru_GossipShow();
	elseif (event=="UI_INFO_MESSAGE") then
		QuestGuru_UIInfoMessage(arg1);
	elseif (event == "CHAT_MSG_ADDON") then
		if ((arg1 == "QuGu") and (arg4 ~= QuestGuru_Player) and not QuestGuru_Settings.DisableComm) then
		    QuestGuru_CommProcessMsg(arg4, arg3, arg2);
		end
	elseif (event == "CHAT_MSG_COMBAT_FACTION_CHANGE") then
		if (QuestGuru_LastXPRep == nil) then
			QuestGuru_LastXPRep = {};
		end
		local repi, repj, repFaction, repGain = string.find(arg1, QG_REP_GAIN);
		if (repFaction and repGain) then
			QuestGuru_LastXPRep[repFaction] = repGain;
		end
		local repi, repj, repFaction, repGain = string.find(arg1, QG_REP_DEC);
		if (repFaction and repGain) then
			QuestGuru_LastXPRep[repFaction] = -repGain;
		end
	elseif (event == "CHAT_MSG_COMBAT_XP_GAIN") then
		if (QuestGuru_LastXPRep == nil) then
			QuestGuru_LastXPRep = {};
		end
		local xpi, xpj, xp = string.find(arg1, QG_XP_GAIN);
		if (xp) then
			QuestGuru_LastXPRep.XP = xp;
		end
	elseif (event=="WORLD_MAP_UPDATE") then
		if ((arg1) and (arg1 == "panel-hide")) then
			QuestGuru_WorldMapIconInfo = { cont = 0, zone = 0, x = 0, y = 0, NPCName = QG_UNKNOWN };
		end
		if (WorldMapFrame:IsShown()) then
			QuestGuru_ShowWorldmapIcon();
			QuestGuru_ShowWorldmapQuestIcons();
		end
	elseif (event == "PLAYER_LOGIN") then
		if (IsInGuild()) then
			QuestGuru_CommSendMessage("GUILD", "0001", QUESTGURU_VERSION);
			QuestGuru_CommAddTimer(5, 1, QuestGuru_SendCurrentQuestStatus, "GUILD");
		end
	elseif (event == "PLAYER_LEAVING_WORLD") then
		QuestGuru_CommSendPGMessage("000F");
	elseif (event == "VARIABLES_LOADED") then
		PanelTemplates_SetNumTabs(QuestGuru_QuestLogFrame, QUESTGURU_NUMTABS);

		QuestGuru_Player = UnitName("player");
		QuestGuru_RealmName = GetRealmName();
		
		if (QuestGuru_Quests == nil) then
			QuestGuru_Quests = {};
		end
		if (QuestGuru_Quests[QuestGuru_RealmName] == nil) then
			QuestGuru_Quests[QuestGuru_RealmName] = {};
		end
		if (QuestGuru_Items == nil) then
			QuestGuru_Items = {};
		end
		if (QuestGuru_Items[QuestGuru_RealmName] == nil) then
			QuestGuru_Items[QuestGuru_RealmName] = {};
		end
		QuestGuru_UpdateQuestsDB();
		QuestGuru_UpdateHistoryDB();
		QuestGuru_UpdateAbandonDB();
		
		if (QuestGuru_History == nil) then
			QuestGuru_History = {};
		end
		QuestGuru_CheckHistoryVersion();
		QuestGuru_UpdateHistory();
		
		if (QuestGuru_Abandon == nil) then
		    QuestGuru_Abandon = {};
		end
		QuestGuru_CheckAbandon();
		QuestGuru_UpdateAbandon();

		if (QuestGuru_StartTime ~= nil) then
		    QuestGuru_UpdateStartTimes();
		end
		
		if (QuestGuru_Settings == nil) then
			QuestGuru_Settings = {};
		end
		QuestGuru_QuestWatchLoadSettings();
		QuestGuru_QuestAnnounceLoadSettings();
		QuestGuru_OptionsSoundsLoadSettings();
		
		if (QuestGuru_Settings.AutoComplete ~= true) then
		    QuestGuru_Settings.AutoComplete = false;
		end
		QuestGuru_OptionsFrameAutoCompleteToggle:SetChecked(QuestGuru_Settings.AutoComplete);
		
		if (QuestGuru_Settings.ShowObjItemIcons ~= true) then
			QuestGuru_Settings.ShowObjItemIcons = false;
		end
		QuestGuru_OptionsFrameShowObjItemIconsToggle:SetChecked(QuestGuru_Settings.ShowObjItemIcons);
		
		if (QuestGuru_Settings.ShowWorldMapIcons ~= false) then
			QuestGuru_Settings.ShowWorldMapIcons = true;
		end
		QuestGuru_OptionsFrameShowWorldMapIconsToggle:SetChecked(QuestGuru_Settings.ShowWorldMapIcons);
		
		if (QuestGuru_Settings.DisableComm ~= true) then
		    QuestGuru_Settings.DisableComm = false;
		end
		QuestGuru_OptionsFrameDisableCommToggle:SetChecked(QuestGuru_Settings.DisableComm);

		if (QuestGuru_Settings.HeaderQuests ~= false) then
		    QuestGuru_Settings.HeaderQuests = true;
		end
		QuestGuru_OptionsFrameShowHeaderQuestsToggle:SetChecked(QuestGuru_Settings.HeaderQuests);

		if (QuestGuru_Settings.TooltipText ~= false) then
			QuestGuru_Settings.TooltipText = true;
		end
		QuestGuru_OptionsFrameShowTooltipTextToggle:SetChecked(QuestGuru_Settings.TooltipText);
		
		if (QuestGuru_Settings.ShowAltStatus ~= false) then
			QuestGuru_Settings.ShowAltStatus = true;
		end
		QuestGuru_OptionsFrameAltStatusToggle:SetChecked(QuestGuru_Settings.ShowAltStatus);

		if (QuestGuru_Settings.ShowGuildStatus ~= false) then
			QuestGuru_Settings.ShowGuildStatus = true;
		end
		QuestGuru_OptionsFrameGuildStatusToggle:SetChecked(QuestGuru_Settings.ShowGuildStatus);
		if (QuestGuru_Settings.ShowGuildStatus) then
		    QuestGuru_OptionsFrameSimpleGuildStatusToggle:Enable();
		else
		    QuestGuru_OptionsFrameSimpleGuildStatusToggle:Disable();
		end
		if (QuestGuru_Settings.ShowSimpleGuildStatus ~= true) then
			QuestGuru_Settings.ShowSimpleGuildStatus = false;
		end
		QuestGuru_OptionsFrameSimpleGuildStatusToggle:SetChecked(QuestGuru_Settings.ShowSimpleGuildStatus);

		if (QuestGuru_Settings.ShowLevels == nil) then
		    QuestGuru_Settings.ShowLevels = {};
		end
		if (QuestGuru_Settings.ShowLevels.QuestLog ~= false) then
		    QuestGuru_Settings.ShowLevels.QuestLog = true;
		end
		QuestGuru_OptionsFrameShowLevelsQuestLogToggle:SetChecked(QuestGuru_Settings.ShowLevels.QuestLog);
		if (QuestGuru_Settings.ShowLevels.History ~= false) then
		    QuestGuru_Settings.ShowLevels.History = true;
		end
		QuestGuru_OptionsFrameShowLevelsHistoryToggle:SetChecked(QuestGuru_Settings.ShowLevels.History);
		if (QuestGuru_Settings.ShowLevels.Abandon ~= false) then
		    QuestGuru_Settings.ShowLevels.Abandon = true;
		end
		QuestGuru_OptionsFrameShowLevelsAbandonToggle:SetChecked(QuestGuru_Settings.ShowLevels.Abandon);

		if (QuestGuru_Settings.Colorize == nil) then
			QuestGuru_Settings.Colorize = {};
		end
		if (QuestGuru_Settings.Colorize.PlayerName == nil) then
			QuestGuru_Settings.Colorize.PlayerName = {};
		end
		if (QuestGuru_Settings.Colorize.PlayerName.Enabled ~= false) then
			QuestGuru_Settings.Colorize.PlayerName.Enabled = true;
		end
		QuestGuru_OptionsFrameColorizePlayerNameToggle:SetChecked(QuestGuru_Settings.Colorize.PlayerName.Enabled);

		if (QuestGuru_Settings.Colorize.PlayerName.Color == nil) then
			QuestGuru_Settings.Colorize.PlayerName.Color = { r=0, g=0.4, b=0.8 };
		end
		QuestGuru_OptionsFrameColorizePlayerNameColorSwatch:SetTexture(QuestGuru_Settings.Colorize.PlayerName.Color.r, QuestGuru_Settings.Colorize.PlayerName.Color.g, QuestGuru_Settings.Colorize.PlayerName.Color.b, 1.0);
		if (QuestGuru_Settings.Colorize.AreaNames == nil) then
			QuestGuru_Settings.Colorize.AreaNames = {};
		end
		if (QuestGuru_Settings.Colorize.AreaNames.Enabled ~= false) then
			QuestGuru_Settings.Colorize.AreaNames.Enabled = true;
		end
		QuestGuru_OptionsFrameColorizeAreaNamesToggle:SetChecked(QuestGuru_Settings.Colorize.AreaNames.Enabled);
		if (QuestGuru_Settings.Colorize.AreaNames.Color == nil) then
			QuestGuru_Settings.Colorize.AreaNames.Color = { r=0, g=0.4, b=0.8 };
		end
		QuestGuru_OptionsFrameColorizeAreaNamesColorSwatch:SetTexture(QuestGuru_Settings.Colorize.AreaNames.Color.r, QuestGuru_Settings.Colorize.AreaNames.Color.g, QuestGuru_Settings.Colorize.AreaNames.Color.b, 1.0);
		if (QuestGuru_Settings.Colorize.NPCNames == nil) then
			QuestGuru_Settings.Colorize.NPCNames = {};
		end
		if (QuestGuru_Settings.Colorize.NPCNames.Enabled ~= false) then
			QuestGuru_Settings.Colorize.NPCNames.Enabled = true;
		end
		QuestGuru_OptionsFrameColorizeNPCNamesToggle:SetChecked(QuestGuru_Settings.Colorize.NPCNames.Enabled);
		if (QuestGuru_Settings.Colorize.NPCNames.Color == nil) then
			QuestGuru_Settings.Colorize.NPCNames.Color = { r=0, g=0.4, b=0.8 };
		end
		QuestGuru_OptionsFrameColorizeNPCNamesColorSwatch:SetTexture(QuestGuru_Settings.Colorize.NPCNames.Color.r, QuestGuru_Settings.Colorize.NPCNames.Color.g, QuestGuru_Settings.Colorize.NPCNames.Color.b, 1.0);
		
		QuestLog_SetHistorySelection(QuestGuru_currHistory);
		QuestLog_SetAbandonSelection(QuestGuru_currAbandon);
		QuestWatch_Update();
	elseif (event == "UPDATE_MOUSEOVER_UNIT") then
		local numEntries, numQuests = GetNumQuestLogEntries();
		local questID, i;
		local moUnit = UnitName("mouseover");

		if (QuestGuru_Settings == nil) then return; end
		if (QuestGuru_Settings.TooltipText ~= true) then return; end
		if (UnitIsPlayer("mouseover") == nil) then
			for questID=1, numEntries, 1 do
				local questLogTitleText, level, questTag, suggestedGroup, isHeader, isCollapsed, isComplete, isDaily = GetQuestLogTitle(questID);
				local numObjectives = GetNumQuestLeaderBoards(questID);
	
				if (numObjectives ~= nil) then
					for i=1, numObjectives, 1 do
						local text, type, finished = GetQuestLogLeaderBoard(i,questID);
		
						if (type == "monster") then
							local x, y, name, numItems, numNeeded = string.find(text,QG_ITEM_REQ_STR);
						    if (name == moUnit.." slain") then
						    	GameTooltip:AddDoubleLine(questLogTitleText,numItems.."/"..numNeeded);
						    	GameTooltip:Show();
							end
						end
					end
				end
			end
		end
	else
--		QuestLog_Update();
		if ( event == "PARTY_MEMBERS_CHANGED" ) then
			-- Determine whether the selected quest is pushable or not
			if (GetQuestLogPushable() and ( GetRealNumPartyMembers() > 0 or GetRealNumRaidMembers() > 0) ) then
				QuestGuru_QuestFramePushQuestButton:Enable();
			else
				QuestGuru_QuestFramePushQuestButton:Disable();
			end
			if (not QuestGuru_CommPendingPartyUpdate) then
				QuestGuru_CommPendingPartyUpdate = true;
				QuestGuru_CommAddTimer(5, 1, QuestGuru_CommUpdateParty);
			end
		end
	end
end

function QuestGuru_AbandonQuest()
	SetAbandonQuest();
	local qNum = GetQuestLogIndexByName(GetAbandonQuestName());
	if (qNum) then QuestGuru_LastCompleteQuest.Link = GetQuestLink(qNum); end
	QuestGuru_SaveLastQuest();

	local items = GetAbandonQuestItems();
	if ( items ) then
		StaticPopup_Hide("ABANDON_QUEST");
		StaticPopup_Show("ABANDON_QUEST_WITH_ITEMS", GetAbandonQuestName(), items);
	else
		StaticPopup_Hide("ABANDON_QUEST_WITH_ITEMS");
		StaticPopup_Show("ABANDON_QUEST", GetAbandonQuestName());
	end
end

local old_QuestRewardCompleteButton_OnClick = QuestRewardCompleteButton_OnClick;
function QuestRewardCompleteButton_OnClick(self, button, down)
	local inserted = false;
	local i, qH;
	local qLink = QuestGuru_LastCompleteQuest.Link;
	
	if (GetNumQuestChoices() > 0) then
		if (QuestFrameRewardPanel.itemChoice == 0) then
			old_QuestRewardCompleteButton_OnClick();
			return;
		else
			if (QuestGuru_LastCompleteQuest.Choice) then
				for i, choice in ipairs(QuestGuru_LastCompleteQuest.Choice) do
					if (i == QuestFrameRewardPanel.itemChoice) then
						choice.Selected = true;
					end
				end
			end
		end
	end
	
	if (QuestGuru_LastCompleteQuest.Level ==  nil) then
		old_QuestRewardCompleteButton_OnClick();
		return;
	end

	local qID = QuestGuru_LastCompleteQuest.qID;
	local qLinki, qLinkj, qLinkNum;
	for i, qH in ipairs(QuestGuru_History) do
		if (qH.Header == QuestGuru_LastCompleteQuest.Header) then
			if (qH.Level == QuestGuru_LastCompleteQuest.Level) then
				if (qH.qID == qID) then
					if (qH.Count == nil) then qH.Count = 1; end
					QuestGuru_LastCompleteQuest.Count = qH.Count + 1;
					--qH = QuestGuru_LastCompleteQuest;
					tremove(QuestGuru_History, i);
					tinsert(QuestGuru_History, i, QuestGuru_LastCompleteQuest);
					inserted = true;
					break;
				end
				if (qH.Title > QuestGuru_LastCompleteQuest.Title) then
					tinsert(QuestGuru_History, i, QuestGuru_LastCompleteQuest);
					inserted = true;
					break;
				end
			elseif (qH.Level > QuestGuru_LastCompleteQuest.Level) then
				tinsert(QuestGuru_History, i, QuestGuru_LastCompleteQuest);
				inserted = true;
				break;
			end
		elseif (qH.Header > QuestGuru_LastCompleteQuest.Header) then
			tinsert(QuestGuru_History, i, QuestGuru_LastCompleteQuest);
			inserted = true;
			break;
		end
		if (inserted == true) then
			qLinki, qLinkj, qLinkNum = string.find(qH.Link, (":(%d+):"));
		end
	end
	if (not inserted) then
		tinsert(QuestGuru_History, QuestGuru_LastCompleteQuest);
		inserted = true;
	end
	QuestGuru_LastXPRep = {};
	QuestGuru_CommAddTimer(3, 1, QuestGuru_SaveLastXPRep, qLink);

	QuestGuru_WatchList[QuestGuru_LastCompleteQuest.Title] = nil;
	QuestGuru_QuestStart[QuestGuru_LastCompleteQuest.Title] = nil;
	QuestGuru_LastCompleteQuest = {};
	QuestGuru_UpdateHistory();
	if (qLinkNum) then
		QuestGuru_CommSendPGMessage("010A", qLinkNum);
	end
	QuestGuru_Quests[QuestGuru_RealmName][qID][QuestGuru_Player] = "Complete";
	old_QuestRewardCompleteButton_OnClick();
	QuestLog_SetSelection(2);
end

local old_QuestDetailAcceptButton_OnClick = QuestDetailAcceptButton_OnClick;
function QuestDetailAcceptButton_OnClick(self, button, down)
	local questTitle = GetTitleText();
	local objText = GetObjectiveText();
	local descText = GetQuestText();
	local qID = QuestGuru_GetQuestID(questTitle, objText, descText);

	if (QuestGuru_QuestStart[questTitle] == nil) then
		QuestGuru_QuestStart[questTitle] = {};
	end
	QuestGuru_QuestStart[questTitle].StartTime = date(QG_DATETIME);
	QuestGuru_QuestStart[questTitle].Level = UnitLevel("player");

	SetMapToCurrentZone();
	local player_x, player_y = GetPlayerMapPosition("player");
	QuestGuru_QuestStart[questTitle].PosX = floor(player_x * 10000) / 100;
	QuestGuru_QuestStart[questTitle].PosY = floor(player_y * 10000) / 100;

	if ((not UnitName("npc")) or UnitIsPlayer("npc")) then
		QuestGuru_QuestStart[questTitle].NPCName = QG_UNKNOWN;
		QuestGuru_QuestStart[questTitle].NPCZone = QG_UNKNOWN;
	else
      	QuestGuru_QuestStart[questTitle].NPCName = UnitName("npc");
		local mmzText = GetMinimapZoneText();
		local zText = GetRealZoneText();
		if (mmzText == zText) then
		    QuestGuru_QuestStart[questTitle].NPCZone = zText;
		else
		    QuestGuru_QuestStart[questTitle].NPCZone = mmzText .. ", " .. zText;
		end
	end
   
	QuestGuru_CommAddTimer(2, 1, QuestGuru_SendQuestStatusByName, questTitle);
	QuestGuru_CommAddTimer(2, 1, QuestGuru_DoAnnounceByTitle, questTitle, QG_ANNOUNCE_QUESTACCEPT_DEFAULT);
   	QuestGuru_DeleteAbandon(qID);

	if (QuestFlagsPVP()) then
		QuestFrame.dialog = StaticPopup_Show("CONFIRM_ACCEPT_PVP_QUEST");
	else
		AcceptQuest();
	end

	QuestLog_SetSelection(2);
	if (QuestGuru_Settings.Tracker.AutoTrack) then
		if (QuestGuru_Settings.Tracker.Enabled) then
			if (QuestGuru_WatchList[questTitle] == nil) then
			    QuestGuru_WatchList[questTitle] = {};
			end
			if (QuestGuru_WatchList[questTitle].Watched) then
			    return true;
			end
			QuestGuru_WatchList[questTitle].Watched = true;
		end
	end
	
	QuestGuru_CommAddTimer(5, 1, QuestGuru_UpdateQuestsDB);
end

local old_QuestLog_OnShow = QuestLog_OnShow;
function QuestLog_OnShow()
	UpdateMicroButtons();

	if ( QuestGuru_QuestLogFrame:IsShown() ) then
		QuestLogMicroButton:SetButtonState("PUSHED", 1);
	else
		QuestLogMicroButton:SetButtonState("NORMAL");
	end

	QuestGuru_TabClick(1);

	PlaySound("igQuestLogOpen");
	QuestLog_Update();
end

local old_QuestLog_OnHide = QuestLog_OnHide;
function QuestLog_OnHide()
	UpdateMicroButtons();

	if ( QuestGuru_QuestLogFrame:IsShown() ) then
		QuestLogMicroButton:SetButtonState("PUSHED", 1);
	else
		QuestLogMicroButton:SetButtonState("NORMAL");
	end

	PlaySound("igQuestLogClose");

	QuestGuru_WorldMapIconInfo = { cont = 0, zone = 0, x = 0, y = 0, NPCName = QG_UNKNOWN, QuestName = QG_NONE };
end

local old_QuestLog_OnUpdate = QuestLog_OnUpdate;
function QuestLog_OnUpdate(self, elapsed)
	if ( QuestGuru_QuestLogFrame.hasTimer ) then
		self.timePassed = self.timePassed + elapsed;
		if ( self.timePassed > UPDATE_DELAY ) then
			QuestGuru_QuestLogTimerText:SetText(TIME_REMAINING.." "..SecondsToTime(GetQuestLogTimeLeft()));
			self.timePassed = 0;
		end
	end
	if (IsAddOnLoaded("LightHeaded")) then
		if ((LightHeaded.db.profile.open == false) and (LightHeaded.db.profile.lhopen == true) and ((LightHeadedFrameSub.justclosed == false) or (LightHeadedFrameSub.justclosed == nil))) then
		    LightHeadedFrame:SetPoint("LEFT", QuestLogFrame, "RIGHT", -370, 19)
		end
	end
end

local old_QuestLog_Update = QuestLog_Update;
function QuestLog_Update()
	local numEntries, numQuests = GetNumQuestLogEntries();
	local i, j;
	
	local currTab = PanelTemplates_GetSelectedTab(QuestGuru_QuestLogFrame);
	if ( numEntries == 0 ) then
	    if (currTab == 1) then
	        QuestGuru_QuestLogNoQuestsText:SetText(QUESTLOG_NO_QUESTS_TEXT);
			QuestGuru_EmptyQuestLogFrame:Show();
		end
		QuestGuru_QuestLogFrameAbandonButton:Disable();
		QuestGuru_QuestLogFrame.hasTimer = nil;
		QuestGuru_QuestLogDetailScrollFrame:Hide();
	else
	    if (currTab == 1) then
			QuestGuru_EmptyQuestLogFrame:Hide();
		end
		QuestGuru_QuestLogFrameAbandonButton:Enable();
		QuestGuru_QuestLogDetailScrollFrame:Show();
	end

	QuestGuru_CommUpdateGuild();
	
	-- Update Quest Count
	QuestLogUpdateQuestCount(numQuests);
	QuestGuru_QuestLogFrameTab1:SetText(QG_TAB_CURRENT.." ("..numQuests..")");
	QuestGuru_UpdateTabs();
	
	-- Update the quest listing
	QuestGuru_QuestLogHighlightFrame:Hide();

	-- If no selection then set it to the first available quest
	if ( GetQuestLogSelection() == 0 ) then
		QuestLog_SetFirstValidSelection();
	end
	local oldSelection = GetQuestLogSelection();

	-- Clear WorldmapIcons
	for i=1, MAX_QUESTS do
		QuestGuru_WorldmapQuestIconInfo[i] = { cont = 0, zone = 0, x = 0, y = 0, NPCName = QG_UNKNOWN, QuestName = QG_NONE, state = 0 };
		-- state: 0=None, 1=quest in progress, 2=daily available, 4=quest available, 8=quest complete
	end

	local questIndex, questLogTitle, questTitleTag, questNumGroupMates, questNumGuildMates, questLevel, questNormalText, questHighlight, questCheck;
	local questLogTitleText, level, questTag, suggestedGroup, isHeader, isCollapsed, isComplete, isDaily, color, questCount;
	local numPartyMembers, partyMembersOnQuest, guildMembersOnQuest, tempWidth, textWidth;
	local questTagText, strLvl, textLeft;
	local headerWatched = true;
	local lastHeader = 0;
	local currHeader = "";
	local currHeaderQuests = 0;
	local logLineCount = 0;
	
	QuestGuru_QuestLog = {};
	
	for i=1, numEntries do
		questLogTitleText, level, questTag, suggestedGroup, isHeader, isCollapsed, isComplete, isDaily = GetQuestLogTitle(i);
		logLineCount = logLineCount + 1;
		if (isHeader and (questLogTitleText ~= currHeader)) then
			currHeader = questLogTitleText;
			if (lastHeader > 0) then
				QuestGuru_QuestLog[lastHeader].Watched = headerWatched;
				if (QuestGuru_Settings.HeaderQuests) then QuestGuru_QuestLog[lastHeader].QuestCount = currHeaderQuests; end
			end
			lastHeader = logLineCount;
			headerWatched = true;
			currHeaderQuests = 0;
		else
			currHeaderQuests = currHeaderQuests + 1;
		end
		QuestGuru_QuestLog[logLineCount] = {};
		QuestGuru_QuestLog[logLineCount].Title = questLogTitleText;
		QuestGuru_QuestLog[logLineCount].Level = level;
		QuestGuru_QuestLog[logLineCount].Tag = questTag;
		QuestGuru_QuestLog[logLineCount].GroupNum = suggestedGroup;
		QuestGuru_QuestLog[logLineCount].isHeader = isHeader;
		QuestGuru_QuestLog[logLineCount].isCollapsed = QuestGuru_QuestLogHeader[questLogTitleText];
		QuestGuru_QuestLog[logLineCount].Complete = isComplete;
		QuestGuru_QuestLog[logLineCount].Daily = isDaily;
		QuestGuru_QuestLog[logLineCount].Link = GetQuestLink(i);
		QuestGuru_QuestLog[logLineCount].Index = i;
		QuestGuru_QuestLog[logLineCount].Selected = (i == GetQuestLogSelection());
		QuestGuru_QuestLog[logLineCount].QuestCount = 0;
		if (IsQuestWatched(i)) then
			QuestGuru_QuestLog[logLineCount].Watched = true;
		else
			QuestGuru_QuestLog[logLineCount].Watched = false;
			if (not isHeader) then headerWatched = false; end
		end
		if ((QuestGuru_QuestLogHeader[currHeader] == false) and not isHeader) then logLineCount = logLineCount - 1; end
		if (QuestGuru_QuestStart[questLogTitleText]) then
			local startQuest = QuestGuru_QuestStart[questLogTitleText];
			if (startQuest.NPCZone and startQuest.NPCName and startQuest.PosX and startQuest.PosY) then
				for j=1, MAX_QUESTS do
					local currIcon = QuestGuru_WorldmapQuestIconInfo[j];
					if ((currIcon.NPCName == QG_UNKNOWN) or (currIcon.NPCName == startQuest.NPCName)) then
						if (currIcon.NPCName == QG_UNKNOWN) then currIcon.state = 0; end
						currIcon.NPCName = startQuest.NPCName;
						currIcon.x = startQuest.PosX;
						currIcon.y = startQuest.PosY;
						if (currIcon.QuestName and currIcon.QuestName ~= QG_NONE) then
							currIcon.QuestName = currIcon.QuestName.."\n"..questLogTitleText;
						else
							currIcon.QuestName = questLogTitleText;
						end
						if (isComplete or (currIcon.state == 8)) then
							currIcon.state = 8;
						else
							currIcon.state = 1;
						end
						local zone = startQuest.NPCZone
						local z = string.find(zone, ", ");
						if (z) then zone = string.sub(zone, z+2); end
						if (zone == "City of Ironforge") then zone = "Ironforge"; end
						local continentNames, key, val = { GetMapContinents() } ;
						for key, val in pairs(continentNames) do
							local ZoneNames = { GetMapZones(key) } ;
							local x, y;
							for x, y in pairs(ZoneNames) do
								if (zone == y) then
									currIcon.cont = key;
									currIcon.zone = x;
								end
							end
						end
						break;
					end
				end
			end
		end
	end
	if (lastHeader > 0) then
		QuestGuru_QuestLog[lastHeader].Watched = headerWatched;
		if (QuestGuru_Settings.HeaderQuests) then QuestGuru_QuestLog[lastHeader].QuestCount = currHeaderQuests; end
	end

	-- ScrollFrame update
	FauxScrollFrame_Update(QuestGuru_QuestLogListScrollFrame, logLineCount, QUESTGURU_QUESTS_DISPLAYED, QUESTLOG_QUEST_HEIGHT, nil, nil, nil, QuestGuru_QuestLogHighlightFrame, 293, 316 )
	
	for i=1, QUESTGURU_QUESTS_DISPLAYED do
		questIndex = i + FauxScrollFrame_GetOffset(QuestGuru_QuestLogListScrollFrame);
		questLogTitle = getglobal("QuestGuru_QuestLogTitle"..i);
		questTitleTag = getglobal("QuestGuru_QuestLogTitle"..i.."Tag");
		questNumGroupMates = getglobal("QuestGuru_QuestLogTitle"..i.."GroupMates");
		questNumGuildMates = getglobal("QuestGuru_QuestLogTitle"..i.."GuildMates");
		questLevel = getglobal("QuestGuru_QuestLogTitle"..i.."Level");
		questCheck = getglobal("QuestGuru_QuestLogTitle"..i.."Check");
		questNormalText = getglobal("QuestGuru_QuestLogTitle"..i.."NormalText");
		questHighlight = getglobal("QuestGuru_QuestLogTitle"..i.."Highlight");
		
		if (questIndex <= logLineCount) then
			questLogTitleText = QuestGuru_QuestLog[questIndex].Title;
			level = QuestGuru_QuestLog[questIndex].Level;
			questTag = QuestGuru_QuestLog[questIndex].Tag;
			suggestedGroup = QuestGuru_QuestLog[questIndex].GroupNum;
			isHeader = QuestGuru_QuestLog[questIndex].isHeader;
			isCollapsed = QuestGuru_QuestLog[questIndex].isCollapsed;
			isComplete = QuestGuru_QuestLog[questIndex].Complete;
			isDaily = QuestGuru_QuestLog[questIndex].Daily;
			questCount = QuestGuru_QuestLog[questIndex].QuestCount;
			
			if (QuestGuru_QuestStart[questLogTitleText] ~= nil) then
				if (QuestGuru_QuestStart[questLogTitleText].StartTime == nil) then
					QuestGuru_QuestStart[questLogTitleText].StartTime = date(QG_DATETIME);
				end
			end
			if ( isHeader ) then
				if ( questLogTitleText ) then
					questLogTitle:SetText(questLogTitleText);
					if (QuestGuru_Settings.HeaderQuests) then questLogTitle:SetText(questLogTitleText.." ("..questCount..")"); end
				else
					questLogTitle:SetText("");
				end
				textLeft = 32;
				questNormalText:SetPoint("LEFT", textLeft, 0);
				if ( QuestGuru_QuestLogHeader[questLogTitleText] == false ) then
					questLogTitle:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up");
				else
					questLogTitle:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up"); 
				end
				questHighlight:SetTexture("Interface\\Buttons\\UI-PlusButton-Hilight");
				questNumGroupMates:SetText("");
				questNumGuildMates:SetText("");
				questCheck:Show();
				questCheck:SetChecked(QuestGuru_QuestLog[questIndex].Watched);
				questLevel:SetText("");
			else
				strLvl = level
				if (isDaily) then
				    strLvl = strLvl.."Y";
				end
				if (questTag ~= nil) then
					if ((questTag == "Group") and (suggestedGroup > 0)) then
						strLvl = strLvl.."G"..suggestedGroup;
					elseif (questTag == "Dungeon") then
						strLvl = strLvl.."D";
					else
						strLvl = strLvl.."+"
					end
				end
	
				if (QuestGuru_Settings.ShowLevels == nil) then
				    QuestGuru_Settings.ShowLevels = {};
				end
				if (QuestGuru_Settings.ShowLevels.QuestLog) then
				    questLevel:Show();
					textLeft = 62;
				else
				    questLevel:Hide();
					textLeft = 32;
				end
				questLevel:SetText(strLvl);
				questNormalText:SetPoint("LEFT", textLeft, 0);
				questLogTitle:SetText(questLogTitleText);
	
				QuestGuru_QuestLogDummyText:SetText(questLogTitleText);
	
				questLogTitle:SetNormalTexture("");
				questHighlight:SetTexture("");
	
				-- If not a header see if any nearby group mates are on this quest
				numPartyMembers = GetNumPartyMembers();
				partyMembersOnQuest = 0;
				for j=1, numPartyMembers do
					if ( IsUnitOnQuest(QuestGuru_QuestLog[questIndex].Index, "party"..j) ) then
							partyMembersOnQuest = partyMembersOnQuest + 1;
					end
				end
				if ( partyMembersOnQuest > 0 ) then
					questNumGroupMates:SetText(partyMembersOnQuest);
				else
					questNumGroupMates:SetText("");
				end
					
				guildMembersOnQuest = 0;
				local qLink = QuestGuru_QuestLog[questIndex].Link;
				local qLinki, qLinkj, qLinkNum = string.find(qLink, (":(%d+):"));
				local qli, qlv;
				for qli, qlv in pairs(QuestGuru_CommGuild) do
				    if (qlv[qLinkNum] and (qli ~= QuestGuru_Player)) then
						guildMembersOnQuest = guildMembersOnQuest + 1;
					end
				end
				if (guildMembersOnQuest > 0) then
					questNumGuildMates:SetText(guildMembersOnQuest);
				else
					questNumGuildMates:SetText("");
				end
				questCheck:Show();
	
				-- Show check if quest is being watched
				questCheck:SetChecked(QuestGuru_QuestLog[questIndex].Watched);
			end
			-- Save if its a header or not
			questLogTitle.isHeader = isHeader;
	
			if ( isComplete and isComplete < 0 ) then
				questTag = FAILED;
			elseif ( isComplete and isComplete > 0 ) then
				questTag = COMPLETE;
			elseif ( isDaily ) then
				if ( questTag ) then
					questTag = format(DAILY_QUEST_TAG_TEMPLATE, questTag);
				else
					questTag = DAILY;
				end
			end
			if ( questTag ) then
			    if ((questTag == "Group") and (suggestedGroup == 0)) then
			        questTag = "Elite";
				end
				questTagText = "("..questTag
				if ((suggestedGroup ~= nil) and (suggestedGroup > 0) and (questTag ~= COMPLETE)) then
					questTagText = questTagText..":"..suggestedGroup;
				end
				questTagText = questTagText..")";
				questTitleTag:SetText(questTagText);
				-- Shrink text to accomdate quest tags without wrapping
				tempWidth = 300 - textLeft - 8 - questTitleTag:GetWidth();
					
				if ( QuestGuru_QuestLogDummyText:GetWidth() > tempWidth ) then
					textWidth = tempWidth;
				else
					textWidth = QuestGuru_QuestLogDummyText:GetWidth();
				end
				
				questNormalText:SetWidth(tempWidth);
			else
				questTitleTag:SetText("");
				questNormalText:SetWidth(300 - textLeft);
			end
	
				-- Color the quest title and highlight according to the difficulty level
			local playerLevel = UnitLevel("player");
			if ( isHeader ) then
				color = QuestDifficultyColor["header"];
			else
				color = GetDifficultyColor(level);
			end
			questTitleTag:SetTextColor(color.r, color.g, color.b);
			questLevel:SetTextColor(color.r, color.g, color.b);
			questLogTitle:SetNormalFontObject(color.font);
			questNumGroupMates:SetTextColor(color.r, color.g, color.b);
				
			local info = ChatTypeInfo["GUILD"];
			questNumGuildMates:SetTextColor(info.r, info.g, info.b);
   	
			local info = ChatTypeInfo["PARTY"];
			questNumGroupMates:SetTextColor(info.r, info.g, info.b);

			questLogTitle.r = color.r;
			questLogTitle.g = color.g;
			questLogTitle.b = color.b;
			questLogTitle:Show();
	
			-- Place the highlight and lock the highlight state
			if ( QuestGuru_QuestLogFrame.selectedButtonID and QuestGuru_QuestLog[questIndex].Selected) then
				QuestGuru_QuestLogHighlightFrame:SetPoint("TOPLEFT", "QuestGuru_QuestLogTitle"..i, "TOPLEFT", 0, 0);
				QuestGuru_QuestLogSkillHighlight:SetVertexColor(questLogTitle.r, questLogTitle.g, questLogTitle.b);
				QuestGuru_QuestLogHighlightFrame:Show();
				questTitleTag:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
				questLevel:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
				questLogTitle:LockHighlight();
			else
				questLogTitle:UnlockHighlight();
			end
		else
			questLogTitle:Hide();
		end
	end

	-- Determine whether the selected quest is pushable or not
	if ( numEntries == 0 ) then
		QuestGuru_QuestFramePushQuestButton:Disable();
	elseif (GetQuestLogPushable() and ( GetRealNumPartyMembers() > 0 or GetRealNumRaidMembers() > 0) ) then
		QuestGuru_QuestFramePushQuestButton:Enable();
	else
		QuestGuru_QuestFramePushQuestButton:Disable();
	end
end

local old_QuestLog_SetSelection = QuestLog_SetSelection;
function QuestLog_SetSelection(questID, button)
	if ( questID == 0 ) then
		QuestGuru_QuestLogDetailScrollFrame:Hide();
		return;
	end

	local questLogTitleText, level, questTag, suggestedGroup, isHeader, isCollapsed = GetQuestLogTitle(questID);
	if ( isHeader ) then
	    if (button and (button ~= "RightButton")) then
			if ( QuestGuru_QuestLogHeader[questLogTitleText] == false ) then
				QuestGuru_QuestLogHeader[questLogTitleText] = true;
				return;
			else
				QuestGuru_QuestLogHeader[questLogTitleText] = false;
				return;
			end
		end
	else
		SelectQuestLogEntry(questID);
		QuestGuru_QuestLogFrame.selectedButtonID = questID;
	end
	QuestLog_UpdateQuestDetails();
end

local old_QuestLog_UpdateQuestDetails = QuestLog_UpdateQuestDetails;
function QuestLog_UpdateQuestDetails(doNotScroll)
	local questID = GetQuestLogSelection();
	local questTitle = GetQuestLogTitle(questID);
	local questLink = GetQuestLink(questID);
	local qli, qlj, questNum;
	if (questLink) then qli, qlj, questNum = string.find(questLink, (":(%d+):")); end
	local lastObjective, i, NPCColor, PosColor;
	
	if ( not questTitle ) then
		questTitle = "";
	end

	local questDescription, questObjectives = GetQuestLogQuestText();
	
	QuestGuru_QuestLogObjectivesText:SetPoint("TOPLEFT", "QuestGuru_QuestLogQuestTitle", "BOTTOMLEFT", 0, -5);
	QuestGuru_QuestLogStart:Hide();
	if (QuestGuru_QuestStart[questTitle] == nil) then
		QuestGuru_QuestStart[questTitle] = {};
	end
	if ((QuestGuru_QuestStart[questTitle].NPCName == nil) or (QuestGuru_QuestStart[questTitle].NPCName == QG_UNKNOWN) or (QuestGuru_QuestStart[questTitle].NPCName == "Unknown")) then
    	if (questNum and QuestGuru_Quests[QuestGuru_RealmName] and QuestGuru_Quests[QuestGuru_RealmName][questNum] and QuestGuru_Quests[QuestGuru_RealmName][questNum].StartInfo) then
       	    local qsi, qsj, qsNPC, qsZone, qsX, qsY = string.find(QuestGuru_Quests[QuestGuru_RealmName][questNum].StartInfo, "(.*);(.*);(.*);(.*)");
       	    if (qsi and qsj) then
       	        QuestGuru_QuestStart[questTitle].NPCName = qsNPC;
       	        QuestGuru_QuestStart[questTitle].NPCZone = qsZone;
       	        QuestGuru_QuestStart[questTitle].PosX = qsX;
       	        QuestGuru_QuestStart[questTitle].PosY = qsY;
        	end
        end
    end
	if ((QuestGuru_QuestStart[questTitle].NPCName ~= nil) and (QuestGuru_QuestStart[questTitle].NPCName ~= QG_UNKNOWN) and (QuestGuru_QuestStart[questTitle].NPCName ~= "Unknown") and (QuestGuru_QuestStart[questTitle].PosX ~= nil) and (QuestGuru_QuestStart[questTitle].PosY ~= nil)) then
		QuestGuru_QuestLogStartNPCName:SetText(QuestGuru_QuestStart[questTitle].NPCName);
		if (QuestGuru_Settings.Colorize.NPCNames.Enabled) then
			NPCColor = QuestGuru_Settings.Colorize.NPCNames.Color;
		else
			NPCColor = { r=0, g=0, b=0 };
		end
		QuestGuru_QuestLogStartNPCName:SetTextColor(NPCColor.r, NPCColor.g, NPCColor.b);
		QuestGuru_QuestLogStartPos:SetText("(" .. floor(QuestGuru_QuestStart[questTitle].PosX) .. "," .. floor(QuestGuru_QuestStart[questTitle].PosY) .. ")");
		if (QuestGuru_Settings.Colorize.AreaNames.Enabled) then
			PosColor = QuestGuru_Settings.Colorize.AreaNames.Color;
		else
			PosColor = { r=0, g=0, b=0 };
		end
		QuestGuru_QuestLogStartPos:SetTextColor(PosColor.r, PosColor.g, PosColor.b);
		local tempWidth = QuestGuru_QuestLogStartLabel:GetWidth() + QuestGuru_QuestLogStartPos:GetWidth();
		QuestGuru_QuestLogStartNPCName:SetWidth(285 - tempWidth);
		QuestGuru_QuestLogStart:Show();
		QuestGuru_QuestLogObjectivesText:SetPoint("TOPLEFT", "QuestGuru_QuestLogStart", "BOTTOMLEFT", 0, -8);
	else
		if (questNum) then
			QuestGuru_CommSendPGMessage("0209", questNum);
		end
	end
	QuestGuru_QuestLogFinish:Hide();
   	if (questNum and QuestGuru_Quests[QuestGuru_RealmName] and QuestGuru_Quests[QuestGuru_RealmName][questNum] and QuestGuru_Quests[QuestGuru_RealmName][questNum].FinishInfo) then
		local qsi, qsj, qsNPC, qsZone, qsX, qsY = string.find(QuestGuru_Quests[QuestGuru_RealmName][questNum].FinishInfo, "(.*);(.*);(.*);(.*)");
		if (qsi and qsj) then
			QuestGuru_QuestLogFinishNPCName:SetText(qsNPC);
			if (QuestGuru_Settings.Colorize.NPCNames.Enabled) then
				NPCColor = QuestGuru_Settings.Colorize.NPCNames.Color;
			else
				NPCColor = { r=0, g=0, b=0 };
			end
			QuestGuru_QuestLogFinishNPCName:SetTextColor(NPCColor.r, NPCColor.g, NPCColor.b);
			QuestGuru_QuestLogFinishPos:SetText("("..floor(qsX)..","..floor(qsY)..")");
			if (QuestGuru_Settings.Colorize.AreaNames.Enabled) then
				PosColor = QuestGuru_Settings.Colorize.AreaNames.Color;
			else
				PosColor = { r=0, g=0, b=0 };
			end
			QuestGuru_QuestLogFinishPos:SetTextColor(PosColor.r, PosColor.g, PosColor.b);
			local tempWidth = QuestGuru_QuestLogFinishLabel:GetWidth() + QuestGuru_QuestLogStartPos:GetWidth();
			QuestGuru_QuestLogFinishNPCName:SetWidth(285 - tempWidth);
			QuestGuru_QuestLogFinish:Show();
			QuestGuru_QuestLogObjectivesText:SetPoint("TOPLEFT", "QuestGuru_QuestLogFinish", "BOTTOMLEFT", 0, -8);
        end
	else
		if (questNum) then
			QuestGuru_CommSendPGMessage("020B", questNum);
		end
    end

	if ( IsCurrentQuestFailed() ) then
		questTitle = questTitle.." - ("..FAILED..")";
	end
	QuestGuru_QuestLogQuestTitle:SetText(questTitle);

	questObjectives = QuestGuru_ColorizeText(questObjectives);
	QuestGuru_QuestLogObjectivesText:SetText(questObjectives);

	local questTimer = GetQuestLogTimeLeft();
	if ( questTimer ) then
		QuestGuru_QuestLogFrame.hasTimer = 1;
		QuestGuru_QuestLogFrame.timePassed = 0;
		QuestGuru_QuestLogTimerText:Show();
		QuestGuru_QuestLogTimerText:SetText(TIME_REMAINING.." "..SecondsToTime(questTimer));
		QuestGuru_QuestLogObjective1:SetPoint("TOPLEFT", "QuestGuru_QuestLogTimerText", "BOTTOMLEFT", 0, -10);
	else
		QuestGuru_QuestLogFrame.hasTimer = nil;
		QuestGuru_QuestLogTimerText:Hide();
		QuestGuru_QuestLogObjective1:SetPoint("TOPLEFT", "QuestGuru_QuestLogObjectivesText", "BOTTOMLEFT", 0, -10);
	end
	
	-- Show Quest Watch if track quest is checked
	local numObjectives = GetNumQuestLeaderBoards();
	local currObj, objItems = 0, 0;
	
	for i=1, 10 do
		getglobal("QuestGuru_QuestLogObjective"..i):Hide();
		getglobal("QuestGuru_QuestLogObjectiveItem"..i):Hide();
		getglobal("QuestGuru_QuestLogObjectiveItem"..i).timerEnabled = false;
	end

	for i=1, numObjectives, 1 do
		local text, type, finished = GetQuestLogLeaderBoard(i);
		if ((type ~= "item") or not QuestGuru_Settings.ShowObjItemIcons) then
			currObj = currObj + 1;
			local questObj = getglobal("QuestGuru_QuestLogObjective"..currObj);
			setglobal("QuestLogObjective"..currObj, questObj);
			if ( not text or strlen(text) == 0 ) then
				text = type;
			end
			if ( finished ) then
				questObj:SetTextColor(0.2, 0.2, 0.2);
				text = text.." ("..COMPLETE..")";
			else
				questObj:SetTextColor(0, 0, 0);
			end
			questObj:SetText(text);
			questObj:Show();
			questObj:SetAlpha(1);
			QuestFrame_SetAsLastShown(questObj);
			lastObjective = questObj;
		end
	end

	if (QuestGuru_Settings.ShowObjItemIcons) then
		local currObjItem = 0;
		for i=1, numObjectives, 1 do
			local text, type, finished = GetQuestLogLeaderBoard(i);
			local count;
			if (type == "item") then
				currObj = currObj + 1;
				local questObj = getglobal("QuestGuru_QuestLogObjective"..currObj);
				setglobal("QuestLogObjective"..currObj, questObj);
				if ( not text or strlen(text) == 0 ) then
					text = type;
				end
				if ( finished ) then
					questObj:SetTextColor(0.2, 0.2, 0.2);
					text = text.." ("..COMPLETE..")";
				else
					questObj:SetTextColor(0, 0, 0);
				end
				questObj:SetText(text);
				questObj:Show();
				questObj:SetAlpha(0);
				QuestFrame_SetAsLastShown(questObj);
				lastObjective = questObj;

				currObjItem = currObjItem + 1;
				local questItem = getglobal("QuestGuru_QuestLogObjectiveItem"..currObjItem);
				questItem.type = "required";
				local x, y, name, numItems, numNeeded = string.find(text,QG_ITEM_REQ_STR);
				local iiName, itemLink, itemRarity, itemLevel, itemMinLevel, itemType, itemSubType, itemStackCount, itemEquipLoc, texture = GetItemInfo(name);

				if ((not itemLink) and QuestGuru_Items[QuestGuru_RealmName][name]) then
					iiName, itemLink, itemRarity, itemLevel, itemMinLevel, itemType, itemSubType, itemStackCount, itemEquipLoc, texture = GetItemInfo(QuestGuru_Items[QuestGuru_RealmName][name]);
				end
				if (not itemLink) then
					texture = "Interface\\Icons\\INV_Misc_QuestionMark";
					count = 0;
					SetItemButtonTextureVertexColor(questItem, 0.4, 0.4, 0.4);
					QuestGuru_CommSendPGMessage("0301", name);
				else
					if (texture == nil) then
						GameTooltip:SetHyperlink(itemLink);
						GameTooltip:Show();
						GameTooltip:Hide();
						questItem.timerEnabled = true;
					end
					count = GetItemCount(itemLink);
					SetItemButtonTextureVertexColor(questItem, 0.8, 0.8, 0.8);
				end
				questItem:SetID(currObjItem)
				-- For the tooltip
				questItem.rewardType = "item"
				questItem.link = itemLink;
				QuestFrame_SetAsLastShown(questItem);
				getglobal("QuestGuru_QuestLogObjectiveItem"..currObjItem.."Name"):SetText(name);
				getglobal("QuestGuru_QuestLogObjectiveItem"..currObjItem.."Count"):SetText(count.." /"..numNeeded);
				SetItemButtonTexture(questItem, texture);
				SetItemButtonNameFrameVertexColor(questItem, 1, 1, 1);
				if ( currObjItem  > 1 ) then
					if ( mod(currObjItem ,2) == 1 ) then
						questItem:SetPoint("TOPLEFT", "QuestGuru_QuestLogObjectiveItem"..(currObjItem - 2), "BOTTOMLEFT", 0, -2);
						lastObjective = questItem;
					else
						questItem:SetPoint("TOPLEFT", "QuestGuru_QuestLogObjectiveItem"..(currObjItem - 1), "TOPRIGHT", 1, 0);
						lastObjective = getglobal("QuestGuru_QuestLogObjectiveItem"..(currObjItem)-1);
					end
				else
					if (currObj > 1) then
						questItem:SetPoint("TOPLEFT", "QuestGuru_QuestLogObjective"..(currObj - 1), "BOTTOMLEFT", 0, -5);
					elseif (questTimer) then
						questItem:SetPoint("TOPLEFT", "QuestGuru_QuestLogTimerText", "BOTTOMLEFT", 0, -10);
					else
						questItem:SetPoint("TOPLEFT", "QuestGuru_QuestLogObjectivesText", "BOTTOMLEFT", 0, -10);
					end
					lastObjective = questItem;
				end
				questItem:Show();
			end
		end
	end
		
	-- If there's money required then anchor and display it
	if ( GetQuestLogRequiredMoney() > 0 ) then
		if ( numObjectives > 0 ) then
			QuestGuru_QuestLogRequiredMoneyText:SetPoint("TOPLEFT", lastObjective, "BOTTOMLEFT", 0, -4);
		else
			QuestGuru_QuestLogRequiredMoneyText:SetPoint("TOPLEFT", "QuestGuru_QuestLogObjectivesText", "BOTTOMLEFT", 0, -10);
		end
		
		MoneyFrame_Update("QuestGuru_QuestLogRequiredMoneyFrame", GetQuestLogRequiredMoney());
		
		if ( GetQuestLogRequiredMoney() > GetMoney() ) then
			-- Not enough money
			QuestGuru_QuestLogRequiredMoneyText:SetTextColor(0, 0, 0);
			SetMoneyFrameColor("QuestGuru_QuestLogRequiredMoneyFrame", "red");
		else
			QuestGuru_QuestLogRequiredMoneyText:SetTextColor(0.2, 0.2, 0.2);
			SetMoneyFrameColor("QuestGuru_QuestLogRequiredMoneyFrame", "white");
		end
		QuestGuru_QuestLogRequiredMoneyText:Show();
		QuestGuru_QuestLogRequiredMoneyFrame:Show();
	else
		QuestGuru_QuestLogRequiredMoneyText:Hide();
		QuestGuru_QuestLogRequiredMoneyFrame:Hide();
	end

	if ( GetQuestLogGroupNum() > 0 ) then
		local suggestedGroupString = format(QUEST_SUGGESTED_GROUP_NUM, GetQuestLogGroupNum());
		QuestGuru_QuestLogSuggestedGroupNum:SetText(suggestedGroupString);
		QuestGuru_QuestLogSuggestedGroupNum:Show();
		QuestGuru_QuestLogSuggestedGroupNum:ClearAllPoints();
		if ( GetQuestLogRequiredMoney() > 0 ) then
			QuestGuru_QuestLogSuggestedGroupNum:SetPoint("TOPLEFT", "QuestGuru_QuestLogRequiredMoneyText", "BOTTOMLEFT", 0, -4);
		elseif ( numObjectives > 0 ) then
			QuestGuru_QuestLogSuggestedGroupNum:SetPoint("TOPLEFT", lastObjective, "BOTTOMLEFT", 0, -4);
		elseif ( questTimer ) then
			QuestGuru_QuestLogSuggestedGroupNum:SetPoint("TOPLEFT", "QuestGuru_QuestLogTimerText", "BOTTOMLEFT", 0, -10);
		else
			QuestGuru_QuestLogSuggestedGroupNum:SetPoint("TOPLEFT", "QuestGuru_QuestLogObjectivesText", "BOTTOMLEFT", 0, -10);
		end
	else
		QuestGuru_QuestLogSuggestedGroupNum:Hide();
	end

	if ( GetQuestLogGroupNum() > 0 ) then
		QuestGuru_QuestLogDescriptionTitle:SetPoint("TOPLEFT", "QuestGuru_QuestLogSuggestedGroupNum", "BOTTOMLEFT", 0, -10);
	elseif ( GetQuestLogRequiredMoney() > 0 ) then
		QuestGuru_QuestLogDescriptionTitle:SetPoint("TOPLEFT", "QuestGuru_QuestLogRequiredMoneyText", "BOTTOMLEFT", 0, -10);
	elseif ( numObjectives > 0 ) then
		QuestGuru_QuestLogDescriptionTitle:SetPoint("TOPLEFT", lastObjective, "BOTTOMLEFT", 0, -10);
	else
		if ( questTimer ) then
			QuestGuru_QuestLogDescriptionTitle:SetPoint("TOPLEFT", "QuestGuru_QuestLogTimerText", "BOTTOMLEFT", 0, -10);
		else
			QuestGuru_QuestLogDescriptionTitle:SetPoint("TOPLEFT", "QuestGuru_QuestLogObjectivesText", "BOTTOMLEFT", 0, -10);
		end
	end
	if ( questDescription ) then
		questDescription = QuestGuru_ColorizeText(questDescription);
		QuestGuru_QuestLogQuestDescription:SetText(questDescription);
		QuestFrame_SetAsLastShown(QuestGuru_QuestLogQuestDescription);
	end
	local numRewards = GetNumQuestLogRewards();
	local numChoices = GetNumQuestLogChoices();
	local money = GetQuestLogRewardMoney();
	local honor = GetQuestLogRewardHonor();
	local talents;
	talents = GetQuestLogRewardTalents();
	local playerTitle = GetQuestLogRewardTitle();

	if ( playerTitle or ((numRewards + numChoices + money + honor + talents) > 0) ) then
		QuestGuru_QuestLogRewardTitleText:Show();
		QuestFrame_SetAsLastShown(QuestGuru_QuestLogRewardTitleText);
	else
		QuestGuru_QuestLogRewardTitleText:Hide();
	end

	QuestFrameItems_Update("QuestLog");
	if ( not doNotScroll ) then
		QuestGuru_QuestLogDetailScrollFrameScrollBar:SetValue(0);
	end
--	QuestGuru_QuestLogDetailScrollFrame:UpdateScrollChildRect();
end

function QuestGuru_GetQuestItemLink(i, questNum)
	if (i == nil) then return; end
	local text, type, finished = GetQuestLogLeaderBoard(i, questNum);
	local x, y, name, numItems, numNeeded = string.find(text, QG_ITEM_REQ_STR);
	local bag, slot;

	local iiName, link, itemRarity, itemLevel, itemMinLevel, itemType, itemSubType, itemStackCount, itemEquipLoc, texture = GetItemInfo(name);
	if (link ~= nil) then
		return link;
	end
	
	local iItemCount = 0;	
	for bag = 4, 0, -1 do
		local size = GetContainerNumSlots(bag);
		if (size > 0) then
			for slot=1, size, 1 do
				local itemIcon, itemQuantity = GetContainerItemInfo(bag, slot);
				if (itemQuantity) then
					local itemName = GetItemInfo(GetContainerItemLink(bag,slot)); 
					if ((itemName) and (itemName ~= "")) then
						--**
						if(itemName == name) then
							return GetContainerItemLink(bag,slot);
						end
						--**
					end
				end
			end
		end
	end	
	local size = GetContainerNumSlots(KEYRING_CONTAINER);
	if (size > 0) then
		for slot=1, size, 1 do
			local itemIcon, itemQuantity = GetContainerItemInfo(KEYRING_CONTAINER, slot);
			if (itemQuantity) then
				local itemName = GetItemInfo(GetContainerItemLink(KEYRING_CONTAINER, slot));
				if ((itemName) and (itemName ~= "")) then
					--**
					if(itemName == name) then
						return GetContainerItemLink(KEYRING_CONTAINER, slot);
					end
					--**
				end
			end
		end
	end
	return nil;
end

--Used to attach an empty spacer frame to the last shown object
local old_QuestFrame_SetAsLastShown = QuestFrame_SetAsLastShown;
function QuestFrame_SetAsLastShown(frame, spacerFrame)
	if ( not spacerFrame ) then
		spacerFrame = QuestLogSpacerFrame;
	end
	spacerFrame:SetPoint("TOP", frame, "BOTTOM", 0, 0);
end

local old_QuestLog_UpdatePartyInfoTooltip = QuestLog_UpdatePartyInfoTooltip;
function QuestLog_UpdatePartyInfoTooltip(self)
	local index, qID;
	if (string.find(this:GetName(), "QuestWatch")) then
		index = self.qID;
	else
		index = self:GetID() + FauxScrollFrame_GetOffset(QuestGuru_QuestLogListScrollFrame);
		index = QuestGuru_QuestLog[index].Index;
	end

	local numPartyMembers = GetNumPartyMembers();
	if (self.isHeader ) then return; end
	GameTooltip_SetDefaultAnchor(GameTooltip, self);
	
	local questLogTitleText = GetQuestLogTitle(index);
	GameTooltip:SetText(questLogTitleText);
	
	local partyMemberOnQuest, i, j;
	for i=1, numPartyMembers do
		local pName = UnitName("party"..i);
		if ((IsUnitOnQuest(index, "party"..i)) or (QuestGuru_CommParty[pName] and QuestGuru_CommParty[pName][qNum] and UnitInParty(pName))) then
			if ( not partyMemberOnQuest ) then
				GameTooltip:AddLine(HIGHLIGHT_FONT_COLOR_CODE..PARTY_QUEST_STATUS_ON..FONT_COLOR_CODE_CLOSE);
				partyMemberOnQuest = 1;
			end
			GameTooltip:AddLine(LIGHTYELLOW_FONT_COLOR_CODE..pName..FONT_COLOR_CODE_CLOSE);
			if (QuestGuru_CommParty[pName]) then
				local qIDi, qIDj, qNum = string.find(GetQuestLink(index), (":(%d+):"));
				local qNumStatus = QuestGuru_CommParty[pName][qNum];
				if (qNumStatus and qNumStatus.Status) then
					local currStatus = { strsplit(";", qNumStatus.Status) };
					local numObjectives = GetNumQuestLeaderBoards(index);

					if (numObjectives ~= nil) then
						for j=1, numObjectives, 1 do
							local text, type, finished = GetQuestLogLeaderBoard(j, index);

							if ((type == "item") or (type == "monster") or (type == "object")) then
								local x, y, name, numItems, numNeeded = string.find(text, QG_ITEM_REQ_STR);
								if ((name ~= nil) and (currStatus[j] ~= nil) and (numNeeded ~= nil)) then
									GameTooltip:AddDoubleLine("  - "..name, currStatus[j].."/"..numNeeded, 1, 1, 1, 1, 1, 1);
								end
							else
								if (currStatus[j] == 1) then
									GameTooltip:AddDoubleLine("  - "..text, COMPLETE, 1, 1, 1, 0, 1, 0);
								else
									GameTooltip:AddDoubleLine("  - "..text, QG_INCOMPLETE, 1, 1, 1, 1, 0, 0);
								end
							end
						end
					end
				end
			end
		end
	end
	if ( not partyMemberOnQuest ) then
		GameTooltip:AddLine(HIGHLIGHT_FONT_COLOR_CODE..PARTY_QUEST_STATUS_NONE..FONT_COLOR_CODE_CLOSE);
	end
	
	local altOnQuest = false;
	if (QuestGuru_Settings.ShowAltStatus) then
		local li, lv;
		local qIDLink = GetQuestLink(index);
		if (qIDLink) then
			local qIDi, qIDj, qNum = string.find(qIDLink, (":(%d+):"));
			if (QuestGuru_Quests[QuestGuru_RealmName][qNum] ~= nil) then
				for li, lv in pairs(QuestGuru_Quests[QuestGuru_RealmName][qNum]) do
					altOnQuest = (altOnQuest or QuestGuru_AddPartyInfoTooltip(li, index));
				end
			end
		end
	end
	local guildOnQuest = false;
	if (QuestGuru_Settings.ShowGuildStatus) then
		guildOnQuest = guildOnQuest or QuestGuru_AddGuildInfoTooltip(index);
	end

	if (partyMemberOnQuest or altOnQuest or guildOnQuest) then
		GameTooltip:Show();
	else
	    GameTooltip:Hide();
	end
end

function QuestGuru_AddPartyInfoTooltip(qID, index)
	local i, j, v, altOnQuest;
	
	if (QuestGuru_Quests[QuestGuru_RealmName][qID] ~= nil) then
		for i, v in pairs(QuestGuru_Quests[QuestGuru_RealmName][qID]) do
			if ((i ~= "level") and (i ~= QuestGuru_Player) and (i ~= "_link")) then
				if (not altOnQuest) then
					GameTooltip:AddLine(QG_ALT_STATUS_HEAD);
					altOnQuest = 1;
				end
				if (v == "Complete") then
					GameTooltip:AddDoubleLine(i, COMPLETE, 1, 1, 1, 0, 1, 0);
				elseif (v == "Abandoned") then
					GameTooltip:AddDoubleLine(i, QG_ABANDONED, 1, 1, 1, 1, 0, 0);
				else
					GameTooltip:AddDoubleLine(i, QG_ACTIVE, 1, 1, 1, 0, 1, 1);
					local currStatus = { strsplit(";", v) };

					local numObjectives = GetNumQuestLeaderBoards(index);

					if (numObjectives ~= nil) then
						for j=1, numObjectives, 1 do
							local text, type, finished = GetQuestLogLeaderBoard(j, index);

							if ((type == "item") or (type == "monster") or (type == "object")) then
								local x, y, name, numItems, numNeeded = string.find(text,QG_ITEM_REQ_STR);
							    if ((name ~= nil) and (currStatus[j+1] ~= nil) and (numNeeded ~= nil)) then
							    	GameTooltip:AddDoubleLine("  - "..name, currStatus[j+1].."/"..numNeeded, 1, 1, 1, 1, 1, 1);
								end
							else
								if (currStatus[j+1] == 1) then
									GameTooltip:AddDoubleLine("  - "..text, COMPLETE, 1, 1, 1, 0, 1, 0);
								else
									GameTooltip:AddDoubleLine("  - "..text, QG_INCOMPLETE, 1, 1, 1, 1, 0, 0);
								end
							end
						end
					end
				end
			end
		end
	end
	return altOnQuest;
end

function QuestGuru_AddGuildInfoTooltip(index)
	local i, j, v, guildOnQuest;

	local qLink = GetQuestLink(index);
	local qLinki, qLinkj, qLinkNum = string.find(qLink, (":(%d+):"));
	if (not qLinkNum) then return; end
	local qli, qlv;
	for qli, qlv in pairs(QuestGuru_CommGuild) do
	    if (qlv[qLinkNum] and qlv[qLinkNum].Status and (qli ~= QuestGuru_Player) and (QuestGuru_CommParty[qli] == nil)) then
			if (not guildOnQuest) then
				GameTooltip:AddLine(QG_GUILD_STATUS_HEAD);
				guildOnQuest = 1;
			end
			local info = ChatTypeInfo["GUILD"];
			if (not QuestGuru_Settings.ShowSimpleGuildStatus) then GameTooltip:AddDoubleLine(qli, QG_ACTIVE, info.r, info.g, info.b, 0, 1, 1); end
			local currStatus = { strsplit(";", qlv[qLinkNum].Status) };
			local numObjectives = GetNumQuestLeaderBoards(index);
			local totItems, totNeeded = 0, 0;
			if (numObjectives ~= nil) then
				for j=1, numObjectives, 1 do
					local text, type, finished = GetQuestLogLeaderBoard(j, index);
					if ((type == "item") or (type == "monster") or (type == "object")) then
						local x, y, name, numItems, numNeeded = string.find(text, QG_ITEM_REQ_STR);
					    if ((name ~= nil) and (currStatus[j] ~= nil) and (numNeeded ~= nil)) then
					    	if (not QuestGuru_Settings.ShowSimpleGuildStatus) then GameTooltip:AddDoubleLine("  - "..name, currStatus[j].."/"..numNeeded, 1, 1, 1, 1, 1, 1); end
					    	totItems = totItems + numItems;
					    	totNeeded = totNeeded + numNeeded;
						end
					else
					    totNeeded = totNeeded + 1;
						if (currStatus[j] == 1) then
							if (not QuestGuru_Settings.ShowSimpleGuildStatus) then GameTooltip:AddDoubleLine("  - "..text, COMPLETE, 1, 1, 1, 0, 1, 0); end
							totItems = totItems + 1;
						else
							if (not QuestGuru_Settings.ShowSimpleGuildStatus) then GameTooltip:AddDoubleLine("  - "..text, QG_INCOMPLETE, 1, 1, 1, 1, 0, 0); end
						end
					end
				end
			end
			if (numObjectives == 0) then
			    totItems = 1;
			    totNeeded = 1;
			end
			if (QuestGuru_Settings.ShowSimpleGuildStatus) then
				local perComplete = math.floor((totItems * 100) / totNeeded);
				GameTooltip:AddDoubleLine(qli, perComplete.."%", info.r, info.g, info.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
			end
		end
	end
	return guildOnQuest;
end

local old_QuestLogRewardItem_OnClick = QuestLogRewardItem_OnClick;
function QuestLogRewardItem_OnClick(self, button, down)
	if ( IsControlKeyDown() ) then
		if ( self.rewardType ~= "spell" ) then
			DressUpItemLink(GetQuestLogItemLink(self.type, self:GetID()));
		end
	elseif ( IsShiftKeyDown() ) then
		if ( self.rewardType ~= "spell" ) then
			ChatEdit_InsertLink(GetQuestLogItemLink(self.type, self:GetID()));
		end
	end
end

local old_QuestLog_GetFirstSelectableQuest = QuestLog_GetFirstSelectableQuest;
function QuestLog_GetFirstSelectableQuest()
	local numEntries = GetNumQuestLogEntries();
	local index = 0;
	local questLogTitleText, level, questTag, suggestedGroup, isHeader, isCollapsed;
	local i;
	for i=1, numEntries, 1 do
		index = i;
		questLogTitleText, level, questTag, suggestedGroup, isHeader, isCollapsed = GetQuestLogTitle(i);
		if ( questLogTitleText and not isHeader ) then
			return index;
		end
	end
	return index;
end

local old_QuestLog_SetFirstValidSelection = QuestLog_SetFirstValidSelection;
function QuestLog_SetFirstValidSelection()
	local selectableQuest = QuestLog_GetFirstSelectableQuest();
	QuestLog_SetSelection(selectableQuest);
	QuestGuru_QuestLogListScrollFrameScrollBar:SetValue(0);
end

local old_GetQuestLogIndexByName = GetQuestLogIndexByName;
function GetQuestLogIndexByName(name)
	local numEntries = GetNumQuestLogEntries();
	local questLogTitleText, i;
	for i=1, numEntries, 1 do
		questLogTitleText = GetQuestLogTitle(i);
		if ( questLogTitleText == strtrim(name) ) then
			return i;
		end
	end
	return nil;
end

local old_QuestLogUpdateQuestCount = QuestLogUpdateQuestCount;
function QuestLogUpdateQuestCount(numQuests)
	QuestGuru_QuestLogQuestCount:SetText(format(QUEST_LOG_COUNT_TEMPLATE, numQuests, MAX_QUESTLOG_QUESTS));
	local width = QuestGuru_QuestLogQuestCount:GetWidth();
	local textHeight = 12;
	local hPadding = 15;
	local vPadding = 8;
	local dailyQuestsComplete = GetDailyQuestsCompleted();
	
	if ( dailyQuestsComplete > 0 ) then
		QuestGuru_QuestLogDailyQuestCount:SetText(format(QUEST_LOG_DAILY_COUNT_TEMPLATE, dailyQuestsComplete, GetMaxDailyQuests()));
		QuestGuru_QuestLogDailyQuestCount:Show();
		QuestGuru_DailyQuestCountButton:Show();
		-- Use this width
		if ( QuestGuru_QuestLogDailyQuestCount:GetWidth() > width ) then
			width = QuestGuru_QuestLogDailyQuestCount:GetWidth();
		end
		QuestGuru_QuestLogCount:SetHeight(textHeight*2+vPadding);
		QuestGuru_QuestLogCount:SetPoint("TOPRIGHT", QuestGuru_QuestLogFrame, "TOPRIGHT", -80, -18);
	else
		QuestGuru_QuestLogDailyQuestCount:Hide();
		QuestGuru_DailyQuestCountButton:Hide();
		width = QuestGuru_QuestLogQuestCount:GetWidth();
		QuestGuru_QuestLogCount:SetHeight(textHeight+8);
		QuestGuru_QuestLogCount:SetPoint("TOPRIGHT", QuestGuru_QuestLogFrame, "TOPRIGHT", -80, -23);
	end
	QuestGuru_QuestLogCount:SetWidth(width+hPadding);
end

local old_QuestFrameItems_Update = QuestFrameItems_Update;
function QuestFrameItems_Update(questState)
	local isQuestLog = 0;
	local i;
	
	if ( questState == "QuestLog" ) then
		isQuestLog = 1;
		questState = "QuestGuru_QuestLog";
	end
	local numQuestRewards;
	local numQuestChoices;
	local numQuestSpellRewards = 0;
	local money;
	local honor;
	local talents;
	local playerTitle;
	local spacerFrame;
	
	if ( isQuestLog == 1 ) then
		numQuestRewards = GetNumQuestLogRewards();
		numQuestChoices = GetNumQuestLogChoices();
		if ( GetQuestLogRewardSpell() ) then
			numQuestSpellRewards = 1;
		end
		money = GetQuestLogRewardMoney();
		honor = GetQuestLogRewardHonor();
		talents = GetQuestLogRewardTalents();
		playerTitle = GetQuestLogRewardTitle();
		spacerFrame = QuestGuru_QuestLogSpacerFrame;
	else
		numQuestRewards = GetNumQuestRewards();
		numQuestChoices = GetNumQuestChoices();
		if ( GetRewardSpell() ) then
			numQuestSpellRewards = 1;
		end
		money = GetRewardMoney();
		honor = GetRewardHonor();
		talents = GetRewardTalents();
		playerTitle = GetRewardTitle();
		spacerFrame = QuestGuru_QuestSpacerFrame;
	end

	local totalRewards = numQuestRewards + numQuestChoices + numQuestSpellRewards;
	local questItemName = questState.."Item";
	local material = QuestFrame_GetMaterial();
	local questItemReceiveText = getglobal(questState.."ItemReceiveText")
	local honorFrame = getglobal(questState.."HonorFrame");
	local talentFrame = getglobal(questState.."TalentFrame");
	local moneyFrame = getglobal(questState.."MoneyFrame");
	local playerTitleFrame = getglobal(questState.."PlayerTitleFrame");
	if ( totalRewards == 0 and money == 0 and honor == 0 and talents == 0 and not playerTitle ) then
		getglobal(questState.."RewardTitleText"):Hide();
	else
		getglobal(questState.."RewardTitleText"):Show();
		QuestFrame_SetTitleTextColor(getglobal(questState.."RewardTitleText"), material);
		QuestFrame_SetAsLastShown(getglobal(questState.."RewardTitleText"), spacerFrame);
	end
	if ( money == 0 ) then
		moneyFrame:Hide();
	else
		moneyFrame:Show();
		QuestFrame_SetAsLastShown(moneyFrame, spacerFrame);
		MoneyFrame_Update(questState.."MoneyFrame", money);
	end

	if (honor == 0) then
		honorFrame:Hide();
	else
		honorFrame:Show();
		QuestHonorFrame_Update(questState.."HonorFrame", honor);
		QuestFrame_SetAsLastShown(honorFrame, spacerFrame);
	end

	if (talents == 0) then
		talentFrame:Hide();
	else
		if ( honor ~= 0 ) then
			talentFrame:SetPoint("TOPLEFT", honorFrame, "BOTTOMLEFT", 0, -5);
		end
		talentFrame:Show();
		QuestTalentFrame_Update(questState.."TalentFrame", talents);
		QuestFrame_SetAsLastShown(talentFrame, spacerFrame);
	end

	if ( not playerTitle ) then
		playerTitleFrame:Hide();
	else
		local anchorFrame;
		if ( talents ~= 0 ) then
		    anchorFrame = talentFrame;
		elseif ( honor ~= 0 ) then
			anchorFrame = honorFrame;
		elseif ( money ~= 0 ) then
			anchorFrame = moneyFrame;
		else
			anchorFrame = getglobal(questState.."RewardTitleText");
		end
		playerTitleFrame:SetPoint("TOPLEFT", anchorFrame, "BOTTOMLEFT", 0, -5);
--		playerTitleFrame:SetPoint("LEFT", questState.."ItemReceiveText", "LEFT", -3, -5);
		getglobal(questState.."PlayerTitleFrameTitle"):SetText(playerTitle);
		playerTitleFrame:Show();
		QuestFrame_SetAsLastShown(playerTitleFrame, spacerFrame);
	end
	
	-- Hide unused rewards
	for i = 1, 10 do
		getglobal(questItemName..i):Hide();
	end

	local questItem, name, texture, isTradeskillSpell, isSpellLearned, quality, isUsable, numItems = 1;
	local rewardsCount = 0;

	-- Setup choosable rewards
	if ( numQuestChoices > 0 ) then
		local itemChooseText = getglobal(questState.."ItemChooseText");
		itemChooseText:Show();
		QuestFrame_SetTextColor(itemChooseText, material);
		QuestFrame_SetAsLastShown(itemChooseText, spacerFrame);

		local index;
		local baseIndex = rewardsCount;
		for i=1, numQuestChoices, 1 do
			index = i + baseIndex;
			questItem = getglobal(questItemName..index);
			questItem.type = "choice";
			numItems = 1;
			if ( isQuestLog == 1 ) then
				name, texture, numItems, quality, isUsable = GetQuestLogChoiceInfo(i);
			else
				name, texture, numItems, quality, isUsable = GetQuestItemInfo(questItem.type, i);
			end
			questItem:SetID(i)
			questItem:Show();
			-- For the tooltip
			questItem.rewardType = "item"
			QuestFrame_SetAsLastShown(questItem, spacerFrame);
			getglobal(questItemName..index.."Name"):SetText(name);
			SetItemButtonCount(questItem, numItems);
			SetItemButtonTexture(questItem, texture);
			if ( isUsable ) then
				SetItemButtonTextureVertexColor(questItem, 1.0, 1.0, 1.0);
				SetItemButtonNameFrameVertexColor(questItem, 1.0, 1.0, 1.0);
			else
				SetItemButtonTextureVertexColor(questItem, 0.9, 0, 0);
				SetItemButtonNameFrameVertexColor(questItem, 0.9, 0, 0);
			end
			if ( i > 1 ) then
				if ( mod(i,2) == 1 ) then
					questItem:SetPoint("TOPLEFT", questItemName..(index - 2), "BOTTOMLEFT", 0, -2);
				else
					questItem:SetPoint("TOPLEFT", questItemName..(index - 1), "TOPRIGHT", 1, 0);
				end
			else
				questItem:SetPoint("TOPLEFT", itemChooseText, "BOTTOMLEFT", -3, -5);
			end
			rewardsCount = rewardsCount + 1;
		end
	else
		getglobal(questState.."ItemChooseText"):Hide();
	end

	-- Setup spell rewards
	if ( numQuestSpellRewards > 0 ) then
		local learnSpellText = getglobal(questState.."SpellLearnText");
		learnSpellText:Show();
		QuestFrame_SetTextColor(learnSpellText, material);
		QuestFrame_SetAsLastShown(learnSpellText, spacerFrame);

		--Anchor learnSpellText if there were choosable rewards
		if ( rewardsCount > 0 ) then
			local rewardPoint;
			if ( mod(rewardsCount, 2) == 0 ) then
				rewardPoint = rewardsCount - 1;
			else
				rewardPoint = rewardsCount;
			end
			learnSpellText:SetPoint("TOPLEFT", questItemName..rewardPoint, "BOTTOMLEFT", 3, -5);
		else
			learnSpellText:SetPoint("TOPLEFT", questState.."RewardTitleText", "BOTTOMLEFT", 0, -5);
		end

		if ( isQuestLog == 1 ) then
			texture, name, isTradeskillSpell, isSpellLearned = GetQuestLogRewardSpell();
		else
			texture, name, isTradeskillSpell, isSpellLearned = GetRewardSpell();
		end

		if ( isTradeskillSpell ) then
			learnSpellText:SetText(REWARD_TRADESKILL_SPELL);
		elseif ( not isSpellLearned ) then
			learnSpellText:SetText(REWARD_AURA);
		else
			learnSpellText:SetText(REWARD_SPELL);
		end

		rewardsCount = rewardsCount + 1;
		questItem = getglobal(questItemName..rewardsCount);
		questItem:Show();
		-- For the tooltip
		questItem.rewardType = "spell";
		SetItemButtonCount(questItem, 0);
		SetItemButtonTexture(questItem, texture);
		getglobal(questItemName..rewardsCount.."Name"):SetText(name);
		questItem:SetPoint("TOPLEFT", learnSpellText, "BOTTOMLEFT", -3, -5);
	else
		getglobal(questState.."SpellLearnText"):Hide();
	end

	-- Setup mandatory rewards
	if ( numQuestRewards > 0 or money > 0 or honor > 0 or talents > 0) then
		QuestFrame_SetTextColor(questItemReceiveText, material);
		-- Anchor the reward text differently if there are choosable rewards
		if ( numQuestSpellRewards > 0  ) then
			questItemReceiveText:SetText(REWARD_ITEMS);
			questItemReceiveText:SetPoint("TOPLEFT", questItemName..rewardsCount, "BOTTOMLEFT", 3, -5);
		elseif ( numQuestChoices > 0  ) then
			questItemReceiveText:SetText(REWARD_ITEMS);
			local index = numQuestChoices;
			if ( mod(index, 2) == 0 ) then
				index = index - 1;
			end
			questItemReceiveText:SetPoint("TOPLEFT", questItemName..index, "BOTTOMLEFT", 3, -5);
		else
			questItemReceiveText:SetText(REWARD_ITEMS_ONLY);
			questItemReceiveText:SetPoint("TOPLEFT", questState.."RewardTitleText", "BOTTOMLEFT", 3, -5);
		end
		questItemReceiveText:Show();
		QuestFrame_SetAsLastShown(questItemReceiveText, spacerFrame);
		-- Setup mandatory rewards
		local index;
		local baseIndex = rewardsCount;
		for i=1, numQuestRewards, 1 do
			index = i + baseIndex;
			questItem = getglobal(questItemName..index);
			questItem.type = "reward";
			numItems = 1;
			if ( isQuestLog == 1 ) then
				name, texture, numItems, quality, isUsable = GetQuestLogRewardInfo(i);
			else
				name, texture, numItems, quality, isUsable = GetQuestItemInfo(questItem.type, i);
			end
			questItem:SetID(i)
			questItem:Show();
			-- For the tooltip
			questItem.rewardType = "item";
			QuestFrame_SetAsLastShown(questItem, spacerFrame);
			getglobal(questItemName..index.."Name"):SetText(name);
			SetItemButtonCount(questItem, numItems);
			SetItemButtonTexture(questItem, texture);
			if ( isUsable ) then
				SetItemButtonTextureVertexColor(questItem, 1.0, 1.0, 1.0);
				SetItemButtonNameFrameVertexColor(questItem, 1.0, 1.0, 1.0);
			else
				SetItemButtonTextureVertexColor(questItem, 0.5, 0, 0);
				SetItemButtonNameFrameVertexColor(questItem, 1.0, 0, 0);
			end

			if ( i > 1 ) then
				if ( mod(i,2) == 1 ) then
					questItem:SetPoint("TOPLEFT", questItemName..(index - 2), "BOTTOMLEFT", 0, -2);
				else
					questItem:SetPoint("TOPLEFT", questItemName..(index - 1), "TOPRIGHT", 1, 0);
				end
			elseif ( talents > 0 ) then
				questItem:SetPoint("TOPLEFT", talentFrame, "BOTTOMLEFT", -3, -5);
			elseif ( honor > 0 ) then
				questItem:SetPoint("TOPLEFT", questState.."HonorFrame", "BOTTOMLEFT", -3, -5);
			else
				questItem:SetPoint("TOPLEFT", questState.."ItemReceiveText", "BOTTOMLEFT", -3, -5);
			end
			rewardsCount = rewardsCount + 1;
		end
	else
		questItemReceiveText:Hide();
	end
	if ( questState == "QuestReward" ) then
		QuestFrameCompleteQuestButton:Enable();
		QuestFrameRewardPanel.itemChoice = 0;
		QuestRewardItemHighlight:Hide();
	end
end

function QuestGuru_ColorizeText(inText)
	if ((not inText) or (not QuestGuru_Settings.Colorize)) then
		return;
	end
	local outText = inText;
	inText = gsub(inText, "\n", "\. ");
	local strList = { strsplit(" ", inText) };
	local s,t,ss = "","","";
	local sentenceStart = true;
	local found = false;
	local i, v;
	
	for i, v in ipairs(strList) do
		t = tostring(v);

		if (strfind(t, "%u")) then
			s = strtrim(s.." "..t);
			if (not sentenceStart) then
				ss = strtrim(ss.." "..t);
			end
		end
		if ((t == "the") or (t == "of")) then
		    if (strlen(s) > 0) then
		        s = strtrim(s.." "..t);
			end
			if (strlen(ss) > 0) then
			    ss = strtrim(ss.." "..t);
			end
		end
		if ((i == #strList) or ((strlen(s)>0) and not (strfind(t, "%u") or (t == "the") or (t == "of"))) or (strfind(s, "[\.,\?!]$")) or (strfind(s, "'s$"))) then
			s = gsub(s, "[\.,\?!]", "");
			ss = gsub(ss, "[\.,\?!]", "");
			local st = gsub(s, "'s$", "");
			local sst = gsub(ss, "'s$", "");
			if (QuestGuru_AreaNames and QuestGuru_Settings.Colorize.AreaNames.Enabled) then
				if (QuestGuru_AreaNames[st]) then
					outText = gsub(outText, st.."([ \.,'\?!])", "|cFF"..colorToHex(QuestGuru_Settings.Colorize.AreaNames.Color)..st.."|r%1");
					found = true;
				end
				if (QuestGuru_AreaNames[sst]) then
					outText = gsub(outText, sst.."([ \.,'\?!])", "|cFF"..colorToHex(QuestGuru_Settings.Colorize.AreaNames.Color)..sst.."|r%1");
					found = true;
				end
			end
			if (QuestGuru_NPCNames and QuestGuru_Settings.Colorize.NPCNames.Enabled) then
				if (QuestGuru_NPCNames[st]) then
					outText = gsub(outText, st.."([ \.,'\?!])", "|cFF"..colorToHex(QuestGuru_Settings.Colorize.NPCNames.Color)..st.."|r%1");
					found = true;
				end
				if (QuestGuru_NPCNames[sst]) then
					outText = gsub(outText, sst.."([ \.,'\?!])", "|cFF"..colorToHex(QuestGuru_Settings.Colorize.NPCNames.Color)..sst.."|r%1");
					found = true;
				end
			end
			if ((not strfind(s, "'s$")) or found or ((not strfind(t, "%u")) and (t ~= "the") and (t ~= "of"))) then
				s = "";
				ss = "";
				found = false;
			end
		end
		if (strfind(t, "[.\?!]$")) then
			sentenceStart = true;
		else
		    sentenceStart = false;
		end
	end
	
	if (QuestGuru_Player and QuestGuru_Settings.Colorize.PlayerName.Enabled) then
		outText = gsub(outText, QuestGuru_Player, "|cFF"..colorToHex(QuestGuru_Settings.Colorize.PlayerName.Color)..QuestGuru_Player.."|r");
	end

	return outText
end

function colorToHex(color)
	return string.format("%02x%02x%02x", ceil((color.r * 255) - 0.5), ceil((color.g * 255) - 0.5), ceil((color.b * 255) - 0.5));
end

function QuestGuru_UpdateStartTimes()
	local k, v;
	
	for k,v in pairs(QuestGuru_StartTime) do
	    QuestGuru_QuestStart[k] = {};
	    QuestGuru_QuestStart[k].StartTime = v;
	end
end

function QuestGuru_UIInfoMessage(arg1)
	local questID=0;
	local sound, announceText;
	local numEntries, numQuests = GetNumQuestLogEntries();
	local i, ii, jj, itemName, numDone, numNeeded;
	local questLogTitleText, level, questTag, suggestedGroup, isHeader, isCollapsed, isComplete, isDaily;

	if (arg1 == nil) then return; end

	for questID=1, numEntries, 1 do
		questLogTitleText, level, questTag, suggestedGroup, isHeader, isCollapsed, isComplete, isDaily = GetQuestLogTitle(questID);
		local numObjectives = GetNumQuestLeaderBoards(questID);
		local currQuest = false;
		local questComplete = true;
		sound = nil;
		announceText = nil;

		if (numObjectives ~= nil) then
			for i=1, numObjectives, 1 do
				local text, type, finished = GetQuestLogLeaderBoard(i,questID);
				local qi, qj, qitemName, qnumDone, qnumNeeded = string.find(text, QG_ITEM_REQ_STR);
				if ((type == "item") or (type == "monster") or (type == "object")) then
					if (type == "object") then type = "item"; end
					ii, jj, itemName, numDone, numNeeded = string.find(arg1, QG_ITEM_REQ_STR);
					if ((itemName == qitemName) and (numNeeded == qnumNeeded)) then
						if (QuestGuru_WatchFlash == nil) then QuestGuru_WatchFlash = {}; end
						if (QuestGuru_WatchFlash[questID] == nil) then QuestGuru_WatchFlash[questID] = {}; end
						QuestGuru_WatchFlash[questID].fading = true;
						QuestGuru_WatchFlash[questID][i] = true;
						if (QuestGuru_Settings.Sounds.Progress.Enabled) then sound = QuestGuru_Settings.Sounds.Progress.Sound; end
						if (QuestGuru_Settings.Announce.item.Enabled and (type == "item")) then announceText = QuestGuru_Settings.Announce.item.Text; end
						if (QuestGuru_Settings.Announce.monster.Enabled and (type == "monster")) then announceText = QuestGuru_Settings.Announce.monster.Text; end
						if (numDone == numNeeded) then
							if (QuestGuru_Settings.Sounds.ObjComplete.Enabled) then sound = QuestGuru_Settings.Sounds.ObjComplete.Sound; end
							if (announceText) then announceText = announceText.." ($complete)"; end
							finished = true;
						end
      					currQuest = true;
					end
				elseif (type == "event") then
					itemName = text;
					numDone=1;
					numNeeded=1;
					if (arg1 == text.." ("..COMPLETE..")") then
						if (QuestGuru_WatchFlash == nil) then QuestGuru_WatchFlash = {}; end
						if (QuestGuru_WatchFlash[questID] == nil) then QuestGuru_WatchFlash[questID] = {}; end
						QuestGuru_WatchFlash[questID].fading = true;
						QuestGuru_WatchFlash[questID][i] = true;
						if (QuestGuru_Settings.Sounds.ObjComplete.Enabled) then sound = QuestGuru_Settings.Sounds.ObjComplete.Sound; end
						if (QuestGuru_Settings.Announce.event.Enabled) then announceText = QuestGuru_Settings.Announce.event.Text; end
						currQuest = true;
						finished = true;
					end
				end
				if (not finished) then questComplete = false; end
			end
		end
		if (currQuest) then
			if (questComplete) then
				if (QuestGuru_Settings.Sounds.QuestComplete.Enabled) then sound = QuestGuru_Settings.Sounds.QuestComplete.Sound; end
				if (QuestGuru_Settings.Tracker.AutoUnTrack) then
					QuestGuru_CommAddTimer(2, 1, RemoveQuestWatch, questID);
				end
				if (QuestGuru_Settings.Announce.Quest.Enabled) then announceText = QuestGuru_Settings.Announce.Quest.Text; end
				UIErrorsFrame:AddMessage(QG_QUEST_COMPLETE, 1, 1, 0, 1, 5);
			end
			QuestGuru_PlayExtraSound(sound);
			QuestGuru_DoAnnounce(announceText, numDone, numNeeded, itemName, questLogTitleText, arg1, questID);
			QuestGuru_CommAddTimer(1, 1, QuestGuru_SendQuestStatus, questID, false);
		end
	end
end

function QuestGuru_PlayExtraSound(sound)
	if (sound == nil) then return; end
	
	if (QuestGuru_Settings.Sounds.Enabled) then
	    if ((string.sub(sound, -4) == ".wav") or (string.sub(sound, -4) == ".mp3")) then
	        PlaySoundFile(sound);
		else
	    	PlaySound(sound);
		end
	end
end

function QuestGuru_QuestFrameGreetingPanel_OnShow()
	local numActiveQuests = GetNumActiveQuests();
	for i=1, numActiveQuests, 1 do
		local questTitleButton = getglobal("QuestTitleButton"..i);
		local questTitleButtonIcon = getglobal(questTitleButton:GetName() .. "QuestIcon");
		local level = GetActiveLevel(i);
		if (level == -1) then level = "*"; end
		local title = GetActiveTitle(i);
		if ( IsActiveQuestTrivial(i) ) then
			questTitleButton:SetFormattedText(TRIVIAL_QUEST_DISPLAY, "["..level.."] "..title);
		else
			questTitleButton:SetFormattedText(NORMAL_QUEST_DISPLAY, "["..level.."] "..title);
		end
	    if (QuestGuru_IsQuestComplete(title)) then
	    	SetDesaturation(questTitleButtonIcon, nil);
	    else
	    	SetDesaturation(questTitleButtonIcon, 1);
	    end
	end

	local numAvailableQuests = GetNumAvailableQuests();
	for i=(numActiveQuests + 1), (numActiveQuests + numAvailableQuests), 1 do
		local questTitleButton = getglobal("QuestTitleButton"..i);
		local questTitleButtonIcon = getglobal(questTitleButton:GetName() .. "QuestIcon");
		local level = GetAvailableLevel(i - numActiveQuests);
		if (level == -1) then level = "*"; end
		local title = GetAvailableTitle(i - numActiveQuests);
		if ( IsAvailableQuestTrivial(i - numActiveQuests) ) then
			questTitleButton:SetFormattedText(TRIVIAL_QUEST_DISPLAY, "["..level.."] "..title);
			questTitleButtonIcon:SetVertexColor(0.5,0.5,0.5);
		else
			questTitleButton:SetFormattedText(NORMAL_QUEST_DISPLAY, "["..level.."] "..title);
			questTitleButtonIcon:SetVertexColor(1,1,1);
		end
	end
end

function QuestGuru_QuestDetailShow()
	local questTitle = GetTitleText();
	local objText = GetObjectiveText();
	local descText = GetQuestText();
	local qID = QuestGuru_GetQuestID(questTitle, objText, descText);
	local questLevel;
	if (QuestGuru_Quests[QuestGuru_RealmName][qID] ~= nil) then
		questLevel = QuestGuru_Quests[QuestGuru_RealmName][qID].level;
		if (questLevel) then QuestTitleText:SetText("["..questLevel.."] "..GetTitleText()); end
	end
end

function QuestGuru_QuestProgressShow()
	local questTitle = GetTitleText();
	local objText = GetObjectiveText();
	local descText = GetQuestText();
	local qID = QuestGuru_GetQuestID(questTitle, objText, descText);
	local questLevel;
	if (QuestGuru_Quests[QuestGuru_RealmName][qID] ~= nil) then
		questLevel = QuestGuru_Quests[QuestGuru_RealmName][qID].level;
		if (questLevel) then QuestProgressTitleText:SetText("["..questLevel.."] "..GetTitleText()); end
	end

	local i;
	for i=1, GetNumQuestItems() do
		local name, texture, numItems, quality, isUsable = GetQuestItemInfo("required", i);
		local link = GetQuestItemLink("required", i);
		if (name and link) then
			QuestGuru_Items[QuestGuru_RealmName][name] = link;
		end
	end
end

function QuestGuru_GossipShow()
	QuestGuru_UpdateGossipFrame(1, true, GetGossipAvailableQuests());
	if (GetNumGossipAvailableQuests() > 0) then
		QuestGuru_UpdateGossipFrame(GetNumGossipAvailableQuests() + 2, false, GetGossipActiveQuests());
	else
		QuestGuru_UpdateGossipFrame(1, false, GetGossipActiveQuests());
	end
end

function QuestGuru_UpdateGossipFrame(currButton, availQuest, ...)
	local i;

	for i=1, select("#", ...), 3 do
	    local button = getglobal("GossipTitleButton"..currButton);
		local buttonIcon = getglobal(button:GetName() .. "GossipIcon");
		local level = select(i+1, ...);
		if (level == -1) then level = "*"; end
	    button:SetFormattedText("[%s] %s", level, select(i, ...));
	    if (QuestGuru_IsQuestComplete(select(i, ...)) or availQuest) then
	    	SetDesaturation(buttonIcon, nil);
	    else
	    	SetDesaturation(buttonIcon, 1);
	    end
	    currButton = currButton + 1;
	end
end

function QuestGuru_IsQuestComplete(questTitle)
	local numEntries, numQuests = GetNumQuestLogEntries();
	local i;
	
	for i=1, numEntries do
		local questLogTitleText, level, questTag, suggestedGroup, isHeader, isCollapsed, isComplete, isDaily = GetQuestLogTitle(i);
		local numObjectives = GetNumQuestLeaderBoards(i);

		if (questLogTitleText == questTitle) then return (isComplete or (numObjectives == 0)); end
	end
	return false;
end

function QuestGuru_GetQuestID(questTitle, questObj, questDesc)
	if ((QuestGuru_Player == nil) or (questTitle == nil) or (questObj == nil) or (questDesc == nil)) then return "Unknown000000"; end
	if (string.len(QuestGuru_Player) == 0) then return "Unknown000000"; end
	local qT = questTitle;
	qT = string.gsub(qT, "[ ',\.-:]", "");
	qT = string.gsub(qT, "\"", "");
	qT = string.sub(qT, 1, 10);
	
	local qO = string.gsub(questObj, QuestGuru_Player, "<name>");
	local objLen = string.len(qO);
	
	local qD = string.gsub(questDesc, QuestGuru_Player, "<name>");
	local descLen = string.len(qD);
	
	local qID = qT..string.format("%03x",objLen)..string.format("%03x",descLen);
	return qID;
end

function QuestGuru_UpdateQuestsDB()
	if (QuestGuru_Quests[QuestGuru_RealmName] == nil) then return; end
	local numEntries, numQuests = GetNumQuestLogEntries();
	local questID, i;
	local questSelected = GetQuestLogSelection();
	local k, v, z, ls, rs;

	for k,v in pairs(QuestGuru_QuestStart) do
		if (QuestGuru_QuestStart[k].NPCZone) then
			z = string.find(QuestGuru_QuestStart[k].NPCZone, " in ");
			if (z) then
				ls = strsub(QuestGuru_QuestStart[k].NPCZone, 1, z - 1);
				rs = strsub(QuestGuru_QuestStart[k].NPCZone, z + 4);
				QuestGuru_QuestStart[k].NPCZone = ls..", "..rs;
			end
		end
	end

	for questID=1, numEntries, 1 do
		local questLogTitleText, level, questTag, suggestedGroup, isHeader, isCollapsed, isComplete, isDaily = GetQuestLogTitle(questID);
		if (not isHeader) then
			SelectQuestLogEntry(questID);
			local questDescription, questObjectives = GetQuestLogQuestText();
			local qID = QuestGuru_GetQuestID(questLogTitleText, questObjectives, questDescription);
			if (QuestGuru_Quests[QuestGuru_RealmName][qID] == nil) then
				QuestGuru_Quests[QuestGuru_RealmName][qID] = {};
				QuestGuru_Quests[QuestGuru_RealmName][qID].level = level;
			end
			local qIDLink = GetQuestLink(questID);
			if (qIDLink) then
				QuestGuru_Quests[QuestGuru_RealmName][qID]["_link"] = qIDLink;
				local qIDi, qIDj, qNum = string.find(qIDLink, (":(%d+):"));
				if (qNum) then
				    if (QuestGuru_Quests[QuestGuru_RealmName][qNum] == nil) then
				        QuestGuru_Quests[QuestGuru_RealmName][qNum] = {};
					end
					QuestGuru_Quests[QuestGuru_RealmName][qNum][qID] = 1;
					if ((QuestGuru_Quests[QuestGuru_RealmName][qNum].StartInfo == nil) and (QuestGuru_QuestStart[questLogTitleText] ~= nil) and (QuestGuru_QuestStart[questLogTitleText].NPCName ~= QG_UNKNOWN) and (QuestGuru_QuestStart[questLogTitleText].NPCName ~= "Unknown") and (QuestGuru_QuestStart[questLogTitleText].NPCZone ~= QG_UNKNOWN) and (QuestGuru_QuestStart[questLogTitleText].NPCZone ~= "Unknown") and (QuestGuru_QuestStart[questLogTitleText].PosX ~= nil) and (QuestGuru_QuestStart[questLogTitleText].PosY ~= nil)) then
					    QuestGuru_Quests[QuestGuru_RealmName][qNum].StartInfo = QuestGuru_QuestStart[questLogTitleText].NPCName..";"..QuestGuru_QuestStart[questLogTitleText].NPCZone..";"..QuestGuru_QuestStart[questLogTitleText].PosX..";"..QuestGuru_QuestStart[questLogTitleText].PosY;
					end
				end
			end
			local currStatus = "Current;"
			local numObjectives = GetNumQuestLeaderBoards(questID);
			
			if (numObjectives ~= nil) then
				for i=1, numObjectives, 1 do
					local text, type, finished = GetQuestLogLeaderBoard(i,questID);
		
					if ((type == "item") or (type == "monster")) then
						local x, y, name, numItems, numNeeded = string.find(text, QG_ITEM_REQ_STR);
					    if (name ~= nil) then
					    	currStatus = currStatus..numItems..";";
						end
						if (type == "item") then
							local iiName, itemLink, itemRarity, itemLevel, itemMinLevel, itemType, itemSubType, itemStackCount, itemEquipLoc, texture = GetItemInfo(name);
							if (itemLink) then
								QuestGuru_Items[QuestGuru_RealmName][iiName] = itemLink;
							end
						end
					else
						if (finished) then
							currStatus = currStatus.."1;";
						else
							currStatus = currStatus.."0;";
						end
					end
				end
			end
			QuestGuru_Quests[QuestGuru_RealmName][qID][QuestGuru_Player] = currStatus;
		end
	end
	SelectQuestLogEntry(questSelected);
end

function QuestGuru_ShowMap(zoneName, x, y, npcName, questName)
	zoneName = gsub(zoneName, " in ", ", ");
	local z = string.find(zoneName, ", ");
	if (z) then
	    zoneName = string.sub(zoneName, z+2);
	end
	if (zoneName == "City of Ironforge") then
	    zoneName = "Ironforge";
	end
	local continentNames, key, val = { GetMapContinents() } ;
	for key, val in pairs(continentNames) do
		local ZoneNames = { GetMapZones(key) } ;
		local i, j;
		for i, j in pairs(ZoneNames) do
			if (zoneName == j) then
			    WorldMapFrame:Show();
			    SetMapZoom(key, i);
				local mapX = (x/100) * WorldMapDetailFrame:GetWidth()
				local mapY = -(y/100) * WorldMapDetailFrame:GetHeight()
				QuestGuru_WorldMapIconInfo.cont = key;
				QuestGuru_WorldMapIconInfo.zone = i;
				QuestGuru_WorldMapIconInfo.x = mapX;
				QuestGuru_WorldMapIconInfo.y = mapY;
				QuestGuru_WorldMapIconInfo.NPCName = npcName;
				QuestGuru_WorldMapIconInfo.QuestName = questName;
				QuestGuru_ShowWorldmapIcon();
			end
		end
	end
end

function QuestGuru_ShowWorldmapIcon()
	local cont = GetCurrentMapContinent();
	local zone = GetCurrentMapZone();
	
	if ((cont == QuestGuru_WorldMapIconInfo.cont) and (zone == QuestGuru_WorldMapIconInfo.zone)) then
		QuestGuru_WorldmapIcon:SetPoint("CENTER", "WorldMapDetailFrame", "TOPLEFT", QuestGuru_WorldMapIconInfo.x, QuestGuru_WorldMapIconInfo.y);
		QuestGuru_WorldmapIcon.NPCName = QuestGuru_WorldMapIconInfo.NPCName;
		QuestGuru_WorldmapIcon.QuestName = QuestGuru_WorldMapIconInfo.QuestName;
		QuestGuru_WorldmapIcon:Show();
	else
	    QuestGuru_WorldmapIcon:Hide();
	end
end

function QuestGuru_ShowWorldmapQuestIcons()
	local cont = GetCurrentMapContinent();
	local zone = GetCurrentMapZone();
	local i;

	for i=1, MAX_QUESTS do
		local currInfo = QuestGuru_WorldmapQuestIconInfo[i];
		local currIcon = getglobal("QuestGuru_WorldmapQuestIcon"..i);
		local currTex = getglobal("QuestGuru_WorldmapQuestIcon"..i.."Texture");
		SetDesaturation(currTex, nil);
		if ((cont == currInfo.cont) and (zone == currInfo.zone) and QuestGuru_Settings.ShowWorldMapIcons) then
			local mapX = (currInfo.x/100) * WorldMapDetailFrame:GetWidth();
			local mapY = -(currInfo.y/100) * WorldMapDetailFrame:GetHeight();
			currIcon:SetPoint("CENTER", "WorldMapDetailFrame", "TOPLEFT", mapX, mapY);
			currIcon.NPCName = currInfo.NPCName;
			currIcon.QuestName = currInfo.QuestName;
			if (currInfo.state == 8) then -- Quest complete
				currTex:SetTexCoord(0.25, 0.375, 0.5, 1);
			elseif (currInfo.state == 4) then -- Quest available
				currTex:SetTexCoord(0.125, 0.25, 0.5, 1);
			elseif (currInfo.state == 2) then -- Daily Quest available
				currTex:SetTexCoord(0.375, 0.5, 0.5, 1);
			elseif (currInfo.state == 1) then -- Quest in progress
				currTex:SetTexCoord(0.25, 0.375, 0.5, 1);
				SetDesaturation(currTex, 1);
			end
			currIcon:Show();
		else
			currIcon:Hide();
		end
	end
end

function QuestGuru_Echo(msg, always)
	if (always or ((QuestGuru_Settings) and (QuestGuru_Settings.DebugLevel) and (QuestGuru_Settings.DebugLevel > 0))) then
		DEFAULT_CHAT_FRAME:AddMessage(msg);
	end
end