local babble = BabbleLib:GetInstance("1.0")
local compost = CompostLib:GetInstance('compost-1')
local dewdrop = DewdropLib:GetInstance('1.0')
local tablet = TabletLib:GetInstance('1.0')
local metro = Metrognome:GetInstance('1')
local tourist = nil

QuestsFu = FuBarPlugin:GetInstance("1.2"):new({
	name          = QuestsFuLocals.NAME,
	description   = QuestsFuLocals.DESCRIPTION,
	version       = "1.2." .. string.sub("$Revision: 1755 $", 12, -3),
	releaseDate   = string.sub("$Date: 2006-05-13 02:04:35 -0700 (Sat, 13 May 2006) $", 8, 17),
	aceCompatible = 103,
	author        = "Kemayo",
	email         = "kemayo@gmail.com",
	website       = "http://kemayo.wowinterface.com/",
	category      = "quests",
	db            = AceDatabase:new("QuestsFuDB"),
	defaults      = {
		showLevels = true,
		showDifficulty = true,
		showImpossible = true,
		showArea = true,
		showCurrentAreaOnly = false,
		showClassAnyway = true,
		showCurrentAreaDescriptionOnly = false,
		showDescription = true,
		showCompletedObjectives = false,
		showInItemTooltip = true,
		colorObjectives = true,
		showText = {
			total = true,
			current = true,
			complete = false,
			lastmessage = true,
		},
	},
	charDefaults  = {
		hidden = {}
	},
	cmd           = AceChatCmd:new(QuestsFuLocals.COMMANDS, QuestsFuLocals.CMD_OPTIONS),
	loc           = QuestsFuLocals,
	hasIcon       = true,
	clickableTooltip = true,
	cannotDetachTooltip = false,
	cannotHideText= true,
	--profileCode   = true,
})

function QuestsFu:ToggleShowingText(setting, loud)
	self.data.showText[setting] = not self.data.showText[setting]
	self:UpdateText()
	return self.data.showText[setting]
end

function QuestsFu:IsShowingText(setting)
	return self.data.showText[setting]
end

function QuestsFu:IsShowingLevels()
	return self.data.showLevels
end

function QuestsFu:ToggleShowingLevels(silent)
	self.data.showLevels = not self.data.showLevels
	self:UpdateTooltip()
	return self.data.showLevels
end

function QuestsFu:IsShowingDifficulty()
	return self.data.showDifficulty
end

function QuestsFu:ToggleShowingDifficulty(silent)
	self.data.showDifficulty = not self.data.showDifficulty
	self:UpdateTooltip()
	return self.data.showDifficulty
end

function QuestsFu:IsShowingImpossible()
	return self.data.showImpossible
end

function QuestsFu:ToggleShowingImpossible(silent)
	self.data.showImpossible = not self.data.showImpossible
	self:UpdateTooltip()
	return self.data.showImpossible
end

function QuestsFu:IsShowingArea()
	return self.data.showArea
end

function QuestsFu:ToggleShowingArea(silent)
	self.data.showArea = not self.data.showArea
	self:UpdateTooltip()
	return self.data.showArea
end

function QuestsFu:IsShowingCurrentAreaOnly()
	return self.data.showCurrentAreaOnly
end

function QuestsFu:ToggleShowingCurrentAreaOnly(silent)
	self.data.showCurrentAreaOnly = not self.data.showCurrentAreaOnly
	self:UpdateTooltip()
	return self.data.showCurrentAreaOnly
end

function QuestsFu:IsShowingClassAnyway()
	return self.data.showClassAnyway
end

function QuestsFu:ToggleShowingClassAnyway(silent)
	self.data.showClassAnyway = not self.data.showClassAnyway
	self:UpdateTooltip()
	return self.data.showClassAnyway
end

function QuestsFu:IsShowingCurrentAreaDescriptionOnly()
	return self.data.showCurrentAreaDescriptionOnly
end

function QuestsFu:ToggleShowingCurrentAreaDescriptionOnly(silent)
	self.data.showCurrentAreaDescriptionOnly = not self.data.showCurrentAreaDescriptionOnly
	self:UpdateTooltip()
	return self.data.showCurrentAreaDescriptionOnly
end

function QuestsFu:IsShowingDescription()
	return self.data.showDescription
end

function QuestsFu:ToggleShowingDescription(silent)
	self.data.showDescription = not self.data.showDescription
	self:UpdateTooltip()
	return self.data.showDescription
end

function QuestsFu:IsColoringObjectives()
	return self.data.colorObjectives
end

function QuestsFu:ToggleColoringObjectives(silent)
	self.data.colorObjectives = not self.data.colorObjectives
	self:UpdateTooltip()
	return self.data.colorObjectives
end

function QuestsFu:IsShowingCompletedObjectives()
	return self.data.showCompletedObjectives
end

function QuestsFu:ToggleShowingCompletedObjectives(silent)
	self.data.showCompletedObjectives = not self.data.showCompletedObjectives
	self:UpdateTooltip()
	return self.data.showCompletedObjectives
end

function QuestsFu:IsShowingInItemTooltip()
	return self.data.showInItemTooltip
end

function QuestsFu:ToggleShowingInItemTooltip(silent)
	self.data.showInItemTooltip = not self.data.showInItemTooltip
	self:UpdateTooltip()
	return self.data.showInItemTooltip
end

function QuestsFu:Initialize()
	--In case of upgrade, handle anything where the type has changed.
	--if self.data.version ~= self.versionNumber then
	--
	--end
	if TouristLib then
		tourist = TouristLib:GetInstance("1.0")
	end
	
	self.numQuests = 0
	self.numEntries = 0
	self.zones = {}
	self.zone_quests = {}
	self.quests = {}
	self.items = {}
	self.mobs = {}
	self.lastuimessage = ""
	self.lastquestmessage = ""
	
	self.timeSince = 0
	self.allowedToUpdate = true
end

function QuestsFu:Enable()
	self:RegisterEvent("QUEST_LOG_UPDATE", "OnQuestLogUpdate")
	self:RegisterEvent("PLAYER_LEVEL_UP", "UpdateTooltip") -- Quest difficulty colors can change on level; just redraw the tooltip.
	self:RegisterEvent("UPDATE_MOUSEOVER_UNIT", "OnMouseOverUnit")
	self:RegisterEvent("UI_INFO_MESSAGE","OnUIInfoMessage")
	self:Hook("ContainerFrameItemButton_OnEnter", "OnItemTooltip")
	metro:Register(self.name, self.ThrottleUpdate, 1, self)
	metro:Register(self.name .. "ClearMessage", self.ClearUIInfoMessage, 0.5, self)
end

function QuestsFu:Disable()
	metro:Unregister(self.name)
	metro:Unregister(self.name .. "ClearMessage")
end

function QuestsFu:ThrottleUpdate(timeSinceLast)
	self.timeSince = self.timeSince + timeSinceLast
	if self.timeSince > 1 then
		metro:Stop(self.name)
		self.allowedToUpdate = true
		self:Update()
	end
end

function QuestsFu:OnUIInfoMessage()
	self.lastuimessage = arg1
	metro:Start(self.name .. "ClearMessage")
end

function QuestsFu:ClearUIInfoMessage()
	self.lastuimessage = ""
	metro:Stop(self.name .. "ClearMessage")
end

function QuestsFu:OnQuestLogUpdate()
	--print(arg1, arg2, arg3, arg4)
	if self.allowedToUpdate then self.lastquestmessage = self.lastuimessage end
	self.allowedToUpdate = false
	self.timeSince = 0
	metro:Start(self.name)
end

function QuestsFu:OnMouseOverUnit()
	-- Make sure that this is wanted, and that the tooltip is actually read/writeable.
	if self:IsShowingInItemTooltip() and self:CanMessWithGameTooltip() then
		--Comes with color codes.  Strip 'em out.
		local thisMob = string.gsub(getglobal('GameTooltipTextLeft1'):GetText(),"|c........(.*)|?r?","%1")
		if self.mobs[thisMob] then
			self:AddToGameTooltipAndFixHeight(self.mobs[thisMob].quest..": "..self.mobs[thisMob].needed, self.mobs[thisMob].colorr, self.mobs[thisMob].colorg, self.mobs[thisMob].colorb)
		end
	end
end

function QuestsFu:OnItemTooltip()
	self.Hooks["ContainerFrameItemButton_OnEnter"].orig()
	if self:IsShowingInItemTooltip() and self:CanMessWithGameTooltip() then
		--Comes with color codes.  Strip 'em out.
		local thisItem = string.gsub(getglobal('GameTooltipTextLeft1'):GetText(),"|c........(.*)|?r?","%1")
		if self.items[thisItem] then
			self:AddToGameTooltipAndFixHeight(self.items[thisItem].quest..": "..self.items[thisItem].needed, self.items[thisItem].colorr, self.items[thisItem].colorg, self.items[thisItem].colorb)
		end
	end
end

function QuestsFu:CanMessWithGameTooltip()
	if GameTooltip and getglobal('GameTooltipTextLeft1'):IsVisible() and getglobal('GameTooltipTextLeft1'):GetText() ~= nil then
		return true
	else
		return false
	end
end

function QuestsFu:AddToGameTooltipAndFixHeight(text, r, g, b)
	GameTooltip:AddLine(text, r, g, b)
	
	-- Fix up the width of the tooltip
	length = getglobal(GameTooltip:GetName() .. "TextLeft" .. GameTooltip:NumLines()):GetStringWidth()
	-- Space for right-border:
	length = length + 22
	
	GameTooltip:SetHeight(GameTooltip:GetHeight() + 14)
	if length > GameTooltip:GetWidth() then
		GameTooltip:SetWidth(length)
	end
end

function QuestsFu:MenuSettings(level, value)
	if level == 1 then
		dewdrop:AddLine(
			'text', self.loc.MENU_SHOW_LEVELS,
			'func', 'ToggleShowingLevels',
			'arg1', self,
			'checked', self:IsShowingLevels()
		)
		
		dewdrop:AddLine(
			'text', self.loc.MENU_SHOW_DIFFICULTY,
			'func', 'ToggleShowingDifficulty',
			'arg1', self,
			'checked', self:IsShowingDifficulty()
		)
		
		dewdrop:AddLine(
			'text', self.loc.MENU_SHOW_IMPOSSIBLE,
			'func', 'ToggleShowingImpossible',
			'arg1', self,
			'checked', self:IsShowingImpossible()
		)
		
		dewdrop:AddLine(
			'text', self.loc.MENU_SHOW_AREA,
			'func', 'ToggleShowingArea',
			'arg1', self,
			'checked', self:IsShowingArea()
		)
		
		dewdrop:AddLine(
			'text', self.loc.MENU_SHOW_CURRENT_AREA_ONLY,
			'func', 'ToggleShowingCurrentAreaOnly',
			'arg1', self,
			'checked', self:IsShowingCurrentAreaOnly()
		)
		
		dewdrop:AddLine(
			'text', self.loc.MENU_SHOW_CLASS_ANYWAY,
			'func', 'ToggleShowingClassAnyway',
			'arg1', self,
			'checked', self:IsShowingClassAnyway()
		)
		
		dewdrop:AddLine(
			'text', self.loc.MENU_SHOW_DESCRIPTION,
			'func', 'ToggleShowingDescription',
			'arg1', self,
			'checked', self:IsShowingDescription()
		)
		
		dewdrop:AddLine(
			'text', self.loc.MENU_COLOR_OBJECTIVES,
			'func', 'ToggleColoringObjectives',
			'arg1', self,
			'checked', self:IsColoringObjectives()
		)
		
		dewdrop:AddLine(
			'text', self.loc.MENU_SHOW_COMPLETED_OBJECTIVES,
			'func', 'ToggleShowingCompletedObjectives',
			'arg1', self,
			'checked', self:IsShowingCompletedObjectives()
		)
		
		dewdrop:AddLine(
			'text', self.loc.MENU_SHOW_CURRENT_AREA_DESCRIPTION_ONLY,
			'func', 'ToggleShowingCurrentAreaDescriptionOnly',
			'arg1', self,
			'checked', self:IsShowingCurrentAreaDescriptionOnly()
		)
		
		dewdrop:AddLine(
			'text', self.loc.MENU_SHOW_IN_ITEM_TOOLTIP,
			'func', 'ToggleShowingInItemTooltip',
			'arg1', self,
			'checked', self:IsShowingInItemTooltip()
		)
		
		dewdrop:AddLine(
			'text', self.loc.MENU_SHOW_TEXT,
			'notClickable', true,
			'checked', self:IsShowingText("total") or self:IsShowingText("complete") or self:IsShowingText("current") or self:IsShowingText("lastmessage"),
			'hasArrow', self:IsShowingText("total") or self:IsShowingText("complete") or self:IsShowingText("current") or self:IsShowingText("lastmessage"),
			'value', 'total'
		)
	elseif level == 2 then
		if value == "total" then
			dewdrop:AddLine(
				'text', self.loc.MENU_SHOW_TEXT_COMPLETE,
				'func', 'ToggleShowingText',
				'arg1', self,
				'arg2', 'complete',
				'checked', self:IsShowingText("complete")
			)
			
			dewdrop:AddLine(
				'text', self.loc.MENU_SHOW_TEXT_CURRENT,
				'func', 'ToggleShowingText',
				'arg1', self,
				'arg2', 'current',
				'checked', self:IsShowingText("current")
			)
			
			dewdrop:AddLine(
				'text', self.loc.MENU_SHOW_TEXT_TOTAL,
				'func', 'ToggleShowingText',
				'arg1', self,
				'arg2', 'total',
				'checked', self:IsShowingText("total")
			)
			
			dewdrop:AddLine(
				'text', self.loc.MENU_SHOW_TEXT_LASTMESSAGE,
				'func', 'ToggleShowingText',
				'arg1', self,
				'arg2', 'lastmessage',
				'checked', self:IsShowingText("lastmessage")
			)
		end
	end
end

function QuestsFu:Report()
	local report = compost:Acquire(
		compost:AcquireHash('text', self.loc.ARGUMENT_SHOWLEVELS, 'val', (self:IsShowingLevels() and 1 or 0), 'map', FuBarLocals.MAP_ONOFF),
		compost:AcquireHash('text', self.loc.ARGUMENT_SHOWDIFFICULTY, 'val', (self:IsShowingDifficulty() and 1 or 0), 'map', FuBarLocals.MAP_ONOFF),
		compost:AcquireHash('text', self.loc.ARGUMENT_SHOWAREA, 'val', (self:IsShowingArea() and 1 or 0), 'map', FuBarLocals.MAP_ONOFF),
		compost:AcquireHash('text', self.loc.ARGUMENT_SHOWCURRENTAREAONLY, 'val', (self:IsShowingCurrentAreaOnly() and 1 or 0), 'map', FuBarLocals.MAP_ONOFF),
		compost:AcquireHash('text', self.loc.ARGUMENT_SHOWDESCRIPTION, 'val', (self:IsShowingDescription() and 1 or 0), 'map', FuBarLocals.MAP_ONOFF),
		compost:AcquireHash('text', self.loc.ARGUMENT_COLOROBJECTIVES, 'val', (self:IsColoringObjectives() and 1 or 0), 'map', FuBarLocals.MAP_ONOFF),
		compost:AcquireHash('text', self.loc.ARGUMENT_COMPLETEDOBJECTIVES, 'val', (self:IsShowingCompletedObjectives() and 1 or 0), 'map', FuBarLocals.MAP_ONOFF),
		compost:AcquireHash('text', self.loc.ARGUMENT_CURRENTAREADESCRIPTIONONLY, 'val', (self:IsShowingCurrentAreaDescriptionOnly() and 1 or 0), 'map', FuBarLocals.MAP_ONOFF),
		compost:AcquireHash('text', self.loc.ARGUMENT_SHOWINITEMTOOLTIP, 'val', (self:IsShowingInItemTooltip() and 1 or 0), 'map', FuBarLocals.MAP_ONOFF)
	)
	self.cmd:report(report)
	compost.Reclaim(report, 1)
end

function QuestsFu:UpdateData()
	--UpdateText and UpdateTooltip both need to know things about the questlog.  Better to do this once.
	compost:Reclaim(self.quests, 3)
	compost:Reclaim(self.zone_quests, 1)
	
	local startingQuestLogSelection = GetQuestLogSelection()
	local numEntries, numQuests = GetNumQuestLogEntries()
	local numQuestsDone = 0
	local quests = compost:Acquire()
	local zones = compost:Erase(self.zones)
	--LEVELS--local level_quests = {}
	local zone_quests = compost:Acquire()
	local items = compost:Erase(self.items)
	local mobs = compost:Erase(self.mobs)
	local zoneIndex = "OMG NONE" --The first item in the quest log should always be a header, so this should always be replaced.  But just in case.
	
	if numEntries > 0 and self.allowedToUpdate then
		local questid
		for questid = 1, numEntries do
			local strQuestLogTitleText, strQuestLevel, strQuestTag, isHeader, isCollapsed, isComplete = GetQuestLogTitle(questid)
			local q = compost:Acquire()
			
			if isHeader then
				zoneIndex = strQuestLogTitleText
				table.insert(zones, zoneIndex)
				zone_quests[zoneIndex] = compost:Acquire()
			else
				SelectQuestLogEntry(questid)
				
				if strQuestTag == self.loc.ELITE then
					q.tag = "+"
				elseif strQuestTag == self.loc.DUNGEON then
					q.tag = "D"
				elseif strQuestTag == self.loc.PVP then
					q.tag = "P"
				elseif strQuestTag == self.loc.RAID then
					q.tag = "R"
				end
				
				--LEVELS--if strQuestLevel and not level_quests[tonumber(strQuestLevel)] then
				--LEVELS--	level_quests[tonumber(strQuestLevel)] = {}
				--LEVELS--end
				
				if isComplete == 1 then
					isComplete = self.loc.QUEST_DONE
					numQuestsDone = numQuestsDone + 1
				elseif isComplete == -1 then
					isComplete = self.loc.QUEST_FAILED
				else
					isComplete = nil
				end
				
				q.title = strQuestLogTitleText
				q.level = strQuestLevel
				q.complete = isComplete
				
				local lb = compost:Acquire()
				if GetNumQuestLeaderBoards() > 0 then
					local ii
					for ii=1, GetNumQuestLeaderBoards() do
						local desc, qtype, done = GetQuestLogLeaderBoard(ii)
						local itemName,mobName,numNeeded,numItems,factionName,factionCurrent,factionNeeded
						
						if qtype == 'item' then
							itemName,numItems,numNeeded = babble.Deformat(desc, QUEST_OBJECTS_FOUND)
							desc = itemName
						elseif qtype == 'monster' then
							mobName,numItems,numNeeded = babble.Deformat(desc, QUEST_MONSTERS_KILLED)
							if mobName == nil or numItems == nil or numNeeded == nil then
								--Sometimes we get objectives like "Find Mankrik's Wife: 0/1", which are listed as "monster".
								mobName, numItems, numNeeded = babble.Deformat(desc, QUEST_OBJECTS_FOUND)
							end
							desc = mobName
						elseif qtype == 'reputation' then
							factionName,factionCurrent,factionNeeded = babble.Deformat(desc, QUEST_FACTION_NEEDED)
							numItems = self:GetReactionLevel(factionCurrent)
							numNeeded = self:GetReactionLevel(factionNeeded)
							desc = factionName
						end
						
						local r,g,b
						if numItems ~= nil then
							-- This quest involves items!
							r, g, b = FuBarUtils.GetThresholdColor(numItems / numNeeded)
						end
						
						if qtype == 'item' then
							items[itemName] = compost:AcquireHash('quest', strQuestLogTitleText, 'item', itemName, 'needed', string.format("%s/%s",numItems,numNeeded), 'colorr', r, 'colorg', g, 'colorb', b)
						elseif qtype == 'monster' then
							mobs[mobName] = compost:AcquireHash('quest', strQuestLogTitleText, 'mob', mobName, 'needed', string.format("%s/%s",numItems,numNeeded), 'colorr', r, 'colorg', g, 'colorb', b)
						end
						
						if done then
							done = self.loc.QUEST_DONE
						elseif numItems and numNeeded then
							if qtype == 'reputation' then
								done = string.format("%s/%s",factionCurrent,factionNeeded)
							else
								done = string.format("%s/%s",numItems,numNeeded)
							end
						else
							--I think this shouldn't happen.  ...but I haven't seen every quest out there.
							done = ""
						end
						
						table.insert(lb, compost:AcquireHash('description', desc, 'done', done, 'colorr', r, 'colorg', g, 'colorb', b))
					end
				else
					local strQuestDescription, strQuestObjectives = GetQuestLogQuestText(questid)
					--q.objective = self.superwrap(strQuestObjectives, 50, 0, 2)
					q.objective = strQuestObjectives
				end
				q.leaderboard = lb
				q.id = questid
				
				quests[questid] = q
				table.insert(zone_quests[zoneIndex], questid)
				--LEVELS--table.insert(level_quests[tonumber(strQuestLevel)], questid)
			end
		end
	end
	
	self.quests = quests
	self.zones = zones
	--LEVELS--self.level_quests = level_quests
	self.zone_quests = zone_quests
	self.items = items
	self.mobs = mobs
	self.numQuests = numQuests
	self.numEntries = numEntries
	self.numQuestsDone = numQuestsDone
	
	SelectQuestLogEntry(startingQuestLogSelection)
end

function QuestsFu:UpdateText()
	local text = ""
	local maxQuests = 20
	if self.allowedToUpdate then
		local r,g,b = GameFontNormal:GetTextColor()
		local color = string.format("%02X%02X%02X", r * 255, g * 255, b * 255)
		if self:IsShowingText("complete") then
			color = FuBarUtils.GetThresholdHexColor(self.numQuestsDone / self.numQuests)
			text = text .. FuBarUtils.Colorize(color,self.numQuestsDone)
		end
		if self:IsShowingText("complete") and (self:IsShowingText("current") or self:IsShowingText("total")) then
			text = text .. FuBarUtils.Colorize(color,"/")
		end
		if self:IsShowingText("current") then
			color = FuBarUtils.GetThresholdHexColor((maxQuests - self.numQuests) / maxQuests)
			text = text .. FuBarUtils.Colorize(color,self.numQuests)
		end
		if self:IsShowingText("current") and self:IsShowingText("total") then
			text = text .. FuBarUtils.Colorize(color,"/")
		end
		if self:IsShowingText("total") then
			text = text .. FuBarUtils.Colorize(color,maxQuests)
		end
		if (self:IsShowingText("total") or self:IsShowingText("complete") or self:IsShowingText("current")) and self:IsShowingText("lastmessage") and self.lastquestmessage ~= "" then
			text = text .. " m: "
		end
		if self:IsShowingText("lastmessage") and self.lastquestmessage ~= "" then
			text = text .. self.lastquestmessage
		end
	else
		text = self.loc.TEXT_LOADING
	end
	self:SetText(text)
end

function QuestsFu:UpdateTooltip()
	if self.numQuests > 0 and self.allowedToUpdate then
		if table.getn(self.zones) then
			local currentZone = GetZoneText()
			local zonename, zone
			local cat
			if not self:IsShowingArea() then
				cat = tablet:AddCategory()
			end
			
			for _,zone in self.zones do
				-- If showing area headers and either not showing only the current area's quests or this is the current area.
				if self:IsShowingArea() and ((currentZone == zone) or not self:IsShowingCurrentAreaOnly() or (self:IsShowingClassAnyway() and ace.char.class == zone)) then
					local r,g,b = 0.749,1,0.749
					zonename = zone
					if zone == ace.char.class then r, g, b = babble.GetClassColor(zone) 
					elseif tourist then
						if self:IsShowingLevels() and tourist:IsZoneOrInstance(zone) then 
							local high, low = tourist:GetLevel(zone)
							if high > 0 and low > 0 then
								zonename = string.format("%s (%d-%d)", zone, high, low)
							end
						end
						if self:IsShowingDifficulty() and tourist:IsZoneOrInstance(zone) then
							r, g, b = tourist:GetLevelColor(zone)
						end
					end
					cat = tablet:AddCategory(
						'id', zone,
						'text', zonename,
						'columns', 2,
						'hideBlankLine', true,
						'showWithoutChildren', true,
						'checked', true, 'hasCheck', true, 'checkIcon', self.charData.hidden[zone] and "Interface\\Buttons\\UI-PlusButton-Up" or "Interface\\Buttons\\UI-MinusButton-Up",
						'func', 'ToggleCategory', 'arg1', self, 'arg2', zone,
						'textR', r,
						'textG', g,
						'textB', b,
						'child_func', 'QuestClick',
						'child_arg1', self
					)
				end
				-- If we're not hiding the zone and it's either the current zone or we're not showing only the current zone.
				if (not self.charData.hidden[zone]) and ((not self:IsShowingCurrentAreaOnly()) or (currentZone == zone) or (self:IsShowingClassAnyway() and ace.char.class == zone)) and (table.getn(self.zone_quests[zone]) > 0) then
					local questid
					for _,questid in self.zone_quests[zone] do
						local quest = self.quests[questid]
						
						--Are we hiding impossible quests, and is this quest impossibe?
						local questImpossible = (GetDifficultyColor(quest.level) == QuestDifficultyColor.impossible)
						if not questImpossible or (questImpossible and self:IsShowingImpossible()) then
							local thisQuest, thisQuestColor
							local questLevel = ""
							
							if self:IsShowingLevels() then
								questLevel = format("[%s%s] ", quest.level, quest.tag or "")
							end
							
							thisQuest = questLevel..quest.title
							
							if self:IsShowingDifficulty() then
								thisQuestColor = GetDifficultyColor(quest.level)
							end
							
							cat:AddLine(
								'text', thisQuest,
								'text2', quest.complete,
								'textR', (thisQuestColor and thisQuestColor.r) or 1, 'textG', (thisQuestColor and thisQuestColor.g) or 1, 'textB', (thisQuestColor and thisQuestColor.b) or 1,
								'text2R', (quest.complete == self.loc.QUEST_FAILED) and 1 or 0, 'text2G', (quest.complete == self.loc.QUEST_DONE) and 1 or 0, 'text2B', 0,
								'arg2', quest.id,
								'indentation', 6
							)
							
							-- If we're showing descriptions/objectives and it's either the current zone or we're not showing descriptions only for the current zone.
							if self:IsShowingDescription() and ((currentZone == zone) or not self:IsShowingCurrentAreaDescriptionOnly()) then
								-- If we know of leaderboard objectives:
								if table.getn(quest.leaderboard) > 0 then
									local i, goal
									for i,goal in quest.leaderboard do
										if not (goal.done == self.loc.QUEST_DONE and not self:IsShowingCompletedObjectives()) then
											local r,g,b
											if self:IsColoringObjectives() then
												r,g,b = goal.colorr, goal.colorg, goal.colorb
											end
											cat:AddLine(
												'text', '  '..goal.description,
												'text2', goal.done,
												'textR', r or ((thisQuestColor and thisQuestColor.r) or 1), 'textG', g or ((thisQuestColor and thisQuestColor.g) or 1), 'textB', b or ((thisQuestColor and thisQuestColor.b) or 1),
												'text2R', r or ((thisQuestColor and thisQuestColor.r) or 1), 'text2G', g or ((thisQuestColor and thisQuestColor.g) or 1), 'text2B', b or ((thisQuestColor and thisQuestColor.b) or 1),
												'size', tablet:GetNormalFontSize()-2, 'size2', tablet:GetNormalFontSize()-2,
												'arg2', quest.id,
												'indentation', 12
											)
										end
									end
								-- Otherwise, if the quest is incomplete (or complete and we're showing completed objectives), add the generic objective.
								elseif not (quest.complete and not self:IsShowingCompletedObjectives()) then
									cat:AddLine(
										'text', quest.objective,
										'wrap', true,
										'textR', (thisQuestColor and thisQuestColor.r) or 1,
										'textG', (thisQuestColor and thisQuestColor.g) or 1,
										'textB', (thisQuestColor and thisQuestColor.b) or 1,
										'size', tablet:GetNormalFontSize()-2,
										'arg2', quest.id,
										'indentation', 12
									)
								end
							end
						end
					end
				end
			end
		end
	end
	tablet:SetHint(self.loc.TOOLTIP_HINT)
end

function QuestsFu:ToggleCategory(id, button)
	if self.charData.hidden[id] then
		self.charData.hidden[id] = false
	else
		self.charData.hidden[id] = true
	end
	-- Refresh in place
	self:UpdateTooltip()
end

--TheFly contributed the base of this, and it's still using much of the logic he provided
function QuestsFu:QuestClick(questid, button)
	if IsShiftKeyDown() then
		-- Shift-click toggles quest-watch on this quest.
		if IsQuestWatched(questid) then
			RemoveQuestWatch(questid)
			QuestWatch_Update()
		else
			-- Set error if no objectives
			if GetNumQuestLeaderBoards(questid) == 0 then
				UIErrorsFrame:AddMessage(QUEST_WATCH_NO_OBJECTIVES, 1.0, 0.1, 0.1, 1.0, UIERRORS_HOLD_TIME)
				return
			end
			-- Set an error message if trying to show too many quests
			if GetNumQuestWatches() >= MAX_WATCHABLE_QUESTS then
				UIErrorsFrame:AddMessage(format(QUEST_WATCH_TOO_MANY, MAX_WATCHABLE_QUESTS), 1.0, 0.1, 0.1, 1.0, UIERRORS_HOLD_TIME)
				return
			end
			AddQuestWatch(questid)
			QuestWatch_Update()
		end
	elseif IsAltKeyDown() and ChatFrameEditBox:IsVisible() then
		-- Add [level:quest title] to the chat editbox if it's open.
		ChatFrameEditBox:Insert(string.format("[%s%s:%s]",self.quests[questid].level,self.quests[questid].tag or "",self.quests[questid].title))
	elseif IsControlKeyDown() then
		-- Share the quest with party members.
		local wasSelected = GetQuestLogSelection()
		SelectQuestLogEntry(questid)
		if (GetQuestLogPushable() and GetNumPartyMembers() > 0) then
			QuestLogPushQuest()
		end
		SelectQuestLogEntry(questid)
	else
		if QuestLogFrame:IsVisible() then
			if self.lastIndex == questid then
				HideUIPanel(QuestLogFrame)
			end
		else
			ShowUIPanel(QuestLogFrame)
		end
		if (self.numEntries > QUESTS_DISPLAYED) then
			if (questid < self.numEntries - QUESTS_DISPLAYED) then
				FauxScrollFrame_SetOffset(QuestLogListScrollFrame, questid - 1)
				QuestLogListScrollFrameScrollBar:SetValue((questid - 1) * QUESTLOG_QUEST_HEIGHT)
			else
				FauxScrollFrame_SetOffset(QuestLogListScrollFrame, self.numEntries - QUESTS_DISPLAYED)
				QuestLogListScrollFrameScrollBar:SetValue((self.numEntries - QUESTS_DISPLAYED) * QUESTLOG_QUEST_HEIGHT)
			end
		end
		
		SelectQuestLogEntry(questid)
		QuestLog_SetSelection(questid)
		self.lastIndex = questid
	end
end

function QuestsFu:OnClick()
	ToggleQuestLog()
end

function QuestsFu:GetReactionLevel(leveltext)
	if leveltext == FACTION_STANDING_LABEL1 then --Hated
		return 1
	elseif leveltext == FACTION_STANDING_LABEL2 then --Hostile
		return 2
	elseif leveltext == FACTION_STANDING_LABEL3 then --Unfriendly
		return 3
	elseif leveltext == FACTION_STANDING_LABEL4 then --Neutral
		return 4
	elseif leveltext == FACTION_STANDING_LABEL5 then --Friendly
		return 5
	elseif leveltext == FACTION_STANDING_LABEL6 then --Honored
		return 6
	elseif leveltext == FACTION_STANDING_LABEL7 then --Revered
		return 7
	elseif leveltext == FACTION_STANDING_LABEL8 then --Exalted
		return 8
	end
end

QuestsFu:RegisterForLoad()
