local DGV = DugisGuideViewer
if not DGV then return end

local Obj = DGV:RegisterModule("Objectives")
local L = DugisLocals

DGV.Objectives = Obj
Obj.essential = true
Obj.ReferenceFrame = CreateFrame("Frame", "DugisObjectiveReferenceFrame", UIParent) --Do not remove global name. It's required for saving the model viewer frame position even though it isn't referenced directly.

function Obj:Initialize()
	
	function Obj:Load()
		local autoTooltipFadeTime = math.huge
		local function ResetAutoTooltip()
			if SmallFrameTooltip then SmallFrameTooltip:SetAlpha(1) end
			autoTooltipFadeTime = math.huge
		end

		local function UpdateAutoTooltip()
			local toEnd = autoTooltipFadeTime-GetTime()
			if toEnd <= 0 then 
				SmallFrameTooltip:Hide()
				ResetAutoTooltip()
			elseif toEnd <= 3 then 
				SmallFrameTooltip:SetAlpha(toEnd/3) 
			end
		end

		local tooltip = CreateFrame( "GameTooltip", "SmallFrameTooltip", nil, "GameTooltipTemplate" ); 
		local function SetTooltipOnUpdate(self, event)
			if 
				DugisGuideViewer:isValidGuide(CurrentTitle) == true and 
				DugisGuideUser.CurrentQuestIndex and
				not DGV:UserSetting(DGV_EMBEDDEDTOOLTIP)
			then

				local statusFrameTooltipText = DGV.Modules.Objectives.GetDescriptionText(self.guideIndex)
				local filename, _, _ = SmallFrameTooltipTextLeft1:GetFont() -- needed so that it doesn't overwrite font style when using other addons. 
				
				tooltip:SetOwner(self)
				tooltip:SetFrameStrata("TOOLTIP") 
				tooltip:SetParent(UIParent)
				SmallFrameTooltipTextLeft1:SetFont(filename, 12)
				tooltip:SetPadding(5, 5)
				tooltip:AddLine(statusFrameTooltipText, 1, 1, 1, 1,true)
				tooltip:Show()

				local ttwidth, ttheight, fwidth, fheight, pad = DugisGuideViewer:GetToolTipSize(tooltip)

				tooltip:ClearAllPoints()
				local anchorPoint = strupper(DugisGuideViewer:GetDB(DGV_TOOLTIPANCHOR)):gsub("%s", "")
				if anchorPoint=="DEFAULT" and DGV:IsSmallFrameFloating() then
					anchorPoint = "LEFT"
				elseif anchorPoint=="DEFAULT" then
					anchorPoint = "LEFT"
				end
				
				local toolAnchorPoint 	= ""
				toolAnchorPoint = toolAnchorPoint..((anchorPoint:find("BOTTOM.*") and "TOP") or "")
				toolAnchorPoint	= toolAnchorPoint..((anchorPoint:find("TOP.*") and "BOTTOM") or "")
				toolAnchorPoint = toolAnchorPoint..((anchorPoint:find("^RIGHT") and "LEFT") or "")
				toolAnchorPoint = toolAnchorPoint..((anchorPoint:find("^LEFT") and "RIGHT") or "")
				toolAnchorPoint = toolAnchorPoint..((anchorPoint:find(".+LEFT") and "LEFT") or "")
				toolAnchorPoint = toolAnchorPoint..((anchorPoint:find(".+RIGHT") and "RIGHT") or "")
				
				
				ResetAutoTooltip()
			end
		end

		function DugisGuideViewer:ShowAutoTooltip(frame)
			frame = frame or DugisSmallFrameStatus1
			if not frame then return end
			--if 1 then return end
			if DugisGuideViewer:GetDB(DGV_SHOWTOOLTIP)==0 or (DGV.actions and DGV.actions[frame.guideIndex] and strmatch(DugisGuideViewer.actions[frame.guideIndex], "[CNK]")==nil) or DGV:UserSetting(DGV_EMBEDDEDTOOLTIP) then
				if tooltip then tooltip:Hide() end
				ResetAutoTooltip()
				return 
			end
			SetTooltipOnUpdate(frame)
			autoTooltipFadeTime = GetTime() + DugisGuideViewer:GetDB(DGV_SHOWTOOLTIP) + 3
			--SmallFrameTooltip:Show()
			tooltip:SetScript("OnUpdate", UpdateAutoTooltip)
		end

		local function OnClick(self, button)
			if button == "RightButton" then
				if DugisMainBorder:IsVisible() then
					DugisGuideViewer:HideLargeWindow()
				else
					--UIFrameFadeIn(DugisMainframe, 0.5, 0, 1)
					--UIFrameFadeIn(Dugis, 0.5, 0, 1)
					DugisGuideViewer:ShowLargeWindow()
				end
			elseif button == "LeftButton" and IsShiftKeyDown() then
				DugisGuideViewer.Modules.StickyFrame:AddRow(self.guideIndex) 
			elseif button == "LeftButton" and DGV.actions and DGV.actions[self.guideIndex] and strmatch(DGV.actions[self.guideIndex], "[CNKT]") then 
				local qid = DGV.qid[self.guideIndex]
				if qid then
					--local questIndex = C_QuestLog.GetLogIndexForQuestID(qid)
					--if questIndex and questIndex > 0 then 
						QuestMapFrame_OpenToQuestDetails( qid );
					--end
				end
			end
		end

		Obj.trackerModuleBlockTemplate = "DugisObjectiveBlockTemplate"
		Obj.trackerModuleName = "DugisObjectiveModule"
		Obj.trackerModuleContainer = ObjectiveTrackerFrame
		function Obj:CreateTrackerModule(template)
			local container = self.trackerModuleContainer
			local module = CreateFrame("Frame", self.trackerModuleName, container, template or "DugisObjectiveTrackerModuleTemplate")
			module.headerText = L["Guides"]
			module.events = { "QUEST_LOG_UPDATE", "QUEST_WATCH_LIST_CHANGED", "QUEST_AUTOCOMPLETE", "SUPER_TRACKING_CHANGED", "QUEST_TURNED_IN" }
			module.lineTemplate = "QuestObjectiveLineTemplate"
			module.blockTemplate = self.trackerModuleBlockTemplate
			module.rightEdgeFrameSpacing = 2
			module.questItemButtonSettings = {
				template = "DugisItemButtonTemplate",
				offsetX = 0,
				offsetY = 0,
			}
			module.uiOrder = 0
			module.hasDisplayPriority = true

			--Table to keep information about tabs. 
			-- { {guide = "", active = true, frame = {}, used = true, type = "P"}, {guide = "", active = false, frame = {}, used = true, type = "D"} }
			local tabs = {}
			local ticker = nil
			function module:FadeInFadeOutTabs(speed)
				if ticker then
					ticker:Cancel()
				end

				self.TabContainer:Show()

				ticker = C_Timer.NewTicker(speed or 0.02, function()
					local currentAlpha = self.TabContainer:GetAlpha()
					
					local isMouseOver = module:IsMouseOver() or self.TabContainer:IsMouseOver()
					if isMouseOver then
						currentAlpha = currentAlpha + 0.1
						if currentAlpha >= 1 then
							currentAlpha = 1
							ticker:Cancel()
							ticker = nil
							DGV.RegisterReaction():AfterWait(2):WithAction(self.FadeInFadeOutTabs, self)
						end
						self.TabContainer:SetAlpha(currentAlpha)
					else
						currentAlpha = currentAlpha - 0.1
						if currentAlpha <= 0 then
							currentAlpha = 0
							ticker:Cancel()
							ticker = nil
						end
						self.TabContainer:SetAlpha(currentAlpha)
					end
				end)
			end

			local function ShowTabMenu(tab)
				local someGuideLoaded = (tab.type ~= "Clear" and tab.type ~= "" and tab.type ~= nil)
				local menu = {
					{text = someGuideLoaded and  "Clear Guide" or "Select Guide"  , isNotRadio = true, notCheckable = true
					, func = function() 
						if someGuideLoaded then
							--SetGuideForTab(tab, "", "Clear")
							--if GetActiveTab() == tab then
							--    SmallFrame.ActivateTab(tab, true)
							--end
							DGV.ClearGuide()
						else
							DGV:ShowLargeWindow()
						end
					end},
					
					{text = "Close Menu", isNotRadio = true, notCheckable = true
					, func = function(itemInfo)   end}      
				}
				
				if not DugisTabMenu then
					CreateFrame("Frame", "DugisTabMenu", UIParent, "UIDropDownMenuTemplate, BackdropTemplate")
				end
				
				LuaUtils.DugisDropDown.LibDugi_EasyMenu(menu, DugisTabMenu, tab.frame, 30 , -3, "MENU", nil)
				LibDugi_DropDownList1:SetClampedToScreen(true)
				
			end

			local function GuideTypeIcon(type)
				if type == "Clear" or type == nil or DugisGuideViewer.chardb.EssentialsMode == 1 or not DugisGuideViewer:GuideOn() then
					return --"Interface\\AddOns\\DugisGuideViewerZ\\Artwork\\turnin_d"
				end

				local tabs = DGV.Modules.Guides.tabs
				for i=1, #tabs do
					local tab = tabs[i]
					if tab.guidetype == type then
						return tab.icon
					end
				end
				
				return "Interface\\Icons\\inv_level120"
			end

			local tabBorderShift = 
			{
				Default         = 0  
				,BlackGold       = 2
				,Bronze          = 0
				,DarkWood        = 0
				,ElvUI           = 3
				,Eternium        = 0
				,Gold            = 0
				,Metal           = 0
				,MetalRust       = 0
				,OnePixel        = 2
				,Stone           = 0
				,StonePattern    = 0
				,Thin            = 2
				,Wood            = 0 
			}
			local function LayoutTabs()

				local buttonsY = -8

				local border = DugisGuideViewer:UserSetting(DGV_LARGEFRAMEBORDER)
				
				buttonsY = buttonsY - tabBorderShift[border]
				
				local tabsSpace = 37
				local lastX = -25
				for i = 1, #tabs do
					local tab = tabs[i]
					
					tab.frame.tab = tab
					tab.tabIndex = i
					
					if tab.used and i <= (DugisGuideViewer:UserSetting(DGV_SMALL_FRAME_TABS_AMOUNT) or 3)+0.5 then
						tab.frame:ClearAllPoints()
						
						lastX = lastX + tabsSpace
						tab.frame:SetPoint("BOTTOMLEFT", module.TabContainer, "BOTTOMLEFT", lastX, buttonsY)
						
						tab.frame.Icon:ClearAllPoints()
						tab.frame.Icon:SetSize(27, 27)
						tab.frame.Icon:SetPoint("BOTTOM", tab.frame, "BOTTOM", 1, 2)
						tab.frame.Icon:SetTexture(GuideTypeIcon(tab.type))
						
						tab.frame:Show()
					else
						tab.frame:Hide()
					end
					
					if tab.active then
						tab.frame.TabBg:SetTexCoord(0.01562500, 0.79687500, 0.78906250, 0.95703125);
					else
						tab.frame.TabBg:SetTexCoord(0.01562500, 0.79687500, 0.61328125, 0.78125000);
					end
					local tabInfo = DugisGuideUser.smallFrameTabs[i] or {}
					DugisGuideUser.smallFrameTabs[i] = tabInfo
					tabInfo.guide = tab.guide
					tabInfo.type = tab.type
					tabInfo.active = tab.active
				end
				
			end

			local function ActivateTab(tab, setRelatedGuide)
				for i = 1, #tabs do
					tabs[i].active = false
				end
				tab.active = true
				LayoutTabs()
				
				if setRelatedGuide then
					DGV:DisplayViewTabInThread(tab.guide or "", nil, true)
				end
			end 

			local function AddTab(type_, guide_, active)

				if  #tabs >=6 then
					return 
				end
				
				local newTab = {guide = guide_ or "", used = true, active = active, type = type_}
				newTab.frame = CreateFrame("Frame", nil, module.TabContainer, "DugisObjectiveTabTemplate")

				newTab.frame:SetFrameStrata("BACKGROUND")
				newTab.frame:SetFrameLevel(2)
				
				newTab.frame:SetScript("OnMouseDown", function(self, button)
					if LuaUtils:ThreadInProgress("DisplayViewTab") then
						return
					end        
					if button == "LeftButton" then
						ActivateTab(newTab, true)
						if newTab.guide == "" or not newTab.guide then
							DGV.ClearGuide()
						end                    
					else
						ActivateTab(newTab, true)
						ShowTabMenu(newTab)
					end
				end)
			
				tabs[#tabs + 1] = newTab
				
			end 

			local function GetActiveTab()
				for i = 1, #tabs do
					if tabs[i].active then
						return tabs[i]
					end
				end
				tabs[1].active = true
				return tabs[1]
			end  

			local function SetGuideForTab(tab, guide, type_)
				tab.guide = guide
				tab.type = type_
				LayoutTabs()
			end     

			function module:SetGuideForActiveTab(guide, type_)
				local activeTab = GetActiveTab()
				SetGuideForTab(activeTab, guide, type_)
			end 

			local function InitializeTabs()
				if not DugisGuideUser.smallFrameTabs then
					DugisGuideUser.smallFrameTabs = {}
				end

				for i=1, #DugisGuideUser.smallFrameTabs do
					local savedTabInfo = DugisGuideUser.smallFrameTabs[i]
					AddTab(savedTabInfo.type, savedTabInfo.guide, savedTabInfo.active)
				end
				
				AddTab("Clear")
				AddTab("Clear")
				AddTab("Clear")
				AddTab("Clear")
			
				LayoutTabs()
			end

			function module:InitModule()
				if self.TabContainer then
					self.TabContainer:SetAlpha(0)
					if DugisGuideViewer:GuideOn() then 
						InitializeTabs()
					end
				end
				self:OnLoad() 
			end

			function module:OnEvent(event, ...)
				self:MarkDirty();
			end

			function module:OnBlockHeaderClick(block, mouseButton)
				OnClick(block, mouseButton)
			end

			local function SetDescColorStyle(block, baseColorStyle)
				local colorStyle = baseColorStyle
				if block.isHighlighted and colorStyle.reverse then
					colorStyle = colorStyle.reverse;
				end
				if block.Desc.colorStyle ~= colorStyle then
					block.Desc:SetTextColor("P", colorStyle.r, colorStyle.g, colorStyle.b);
					block.Desc.colorStyle = colorStyle;
				end
			end

			local function ShouldShowQuestPOI()
				return DGV.CurrentTitle == DGV.questAutoGuideName and DugisGuideUser.CurrentQuestIndex == 2
			end

			function module:OnBlockHeaderEnter(block)
				SetDescColorStyle(block, OBJECTIVE_TRACKER_COLOR["Normal"])
				if ShouldShowQuestPOI() then
					BonusObjectiveTracker_ShowRewardsTooltip(block)
				end
				SetTooltipOnUpdate(block, event)
				self:FadeInFadeOutTabs()
			end
			
			function module:OnBlockHeaderLeave(block)
				SetDescColorStyle(block, OBJECTIVE_TRACKER_COLOR["Normal"])
				DGV:ShowAutoTooltip(frame)
				tooltip:Hide()
				self:FadeInFadeOutTabs()
			end

			local function IsTooltipEmbedded()
				return DGV:UserSetting(DGV_EMBEDDEDTOOLTIP)
			end

			local function ShowObjectives()
				return DGV:UserSetting(DGV_OBJECTIVECOUNTER)
			end

			local function MultistepMode()
				return DGV:UserSetting(DGV_MULTISTEPMODE)
			end

			local function ShowHeader()
				return DGV:UserSetting(DGV_SHOW_SMALL_FRAME_HEADER)
			end

			local function ShowProgress()
				return DugisGuideViewer:UserSetting(DGV_DISPLAYGUIDESPROGRESS)
			end

			local function ShowProgressText()
				return DugisGuideViewer:UserSetting(DGV_DISPLAYGUIDESPROGRESSTEXT)
			end

			local function QuestIterator(stepIndex, control)
				if not control then 
					local qid = DGV.qid[stepIndex]
					return qid and 1, qid
				end
				local eqids = DGV.eqids[stepIndex]
				if not eqids then return end
				local id = select(control, strsplit(" ", eqids))
				id = id and tonumber(id)
				if not id then return end
				return control+1, id
			end

			local function DoQuestObjectives(block, questCompleted, questSequenced, isExistingBlock, useFullHeight)
				local firstLine
				local questID = block.qid;
				local objectiveCompleting = false;
				local questLogIndex = C_QuestLog.GetLogIndexForQuestID(questID);
				local numObjectives = GetNumQuestLeaderBoards(questLogIndex);
				local suppressProgressPercentageInObjectiveText = true;
			
				for objectiveIndex = 1, numObjectives do
					local text, objectiveType, finished = GetQuestLogLeaderBoard(objectiveIndex, questLogIndex, suppressProgressPercentageInObjectiveText);
					if text then
						local line = block:GetExistingLine(objectiveIndex);
						if questCompleted then
							-- only process existing lines that have not faded
							if line and line.state ~= ObjectiveTrackerAnimLineState.Faded then
								line = block:AddObjective(objectiveIndex, text, nil, useFullHeight, OBJECTIVE_DASH_STYLE_HIDE, OBJECTIVE_TRACKER_COLOR["Complete"]);
								-- don't do anything else if a line is either COMPLETING or FADING, the anims' OnFinished will continue the process
								if not line.state or line.state == ObjectiveTrackerAnimLineState.Present then
									-- this objective wasn't marked finished
									line:SetState(ObjectiveTrackerAnimLineState.Completing);
								end
							end
						else
							if finished then
								if line and line.state == ObjectiveTrackerAnimLineState.Faded then
									-- don't show this anymore
								elseif line then
									line = block:AddObjective(objectiveIndex, text, nil, useFullHeight, OBJECTIVE_DASH_STYLE_HIDE, OBJECTIVE_TRACKER_COLOR["Complete"]);
									if not line.state or line.state == ObjectiveTrackerAnimLineState.Present then
										-- complete this
										line:SetState(ObjectiveTrackerAnimLineState.Completing);
									end
								else
									-- didn't have a line, just show completed if not sequenced
									if not questSequenced then
										line = block:AddObjective(objectiveIndex, text, nil, useFullHeight, OBJECTIVE_DASH_STYLE_HIDE, OBJECTIVE_TRACKER_COLOR["Complete"]);
										line:SetState(ObjectiveTrackerAnimLineState.Completed);
									end
								end
							else
								if not questSequenced or not objectiveCompleting then
									-- new objectives need to animate in
									if questSequenced and isExistingBlock and not line then
										line = block:AddObjective(objectiveIndex, text, nil, useFullHeight);
										line:SetState(ObjectiveTrackerAnimLineState.Adding);
										PlaySound(SOUNDKIT.UI_QUEST_ROLLING_FORWARD_01);
										if objectiveType == "progressbar" then
											local progressBar = block:AddProgressBar(questID);
											progressBar:SetPercent(GetQuestProgressBarPercent(questID));
										end
									else
										line = block:AddObjective(objectiveIndex, text, nil, useFullHeight);
										-- some quest objectives can be undone
										if line.state == ObjectiveTrackerAnimLineState.Completed then
											line:SetState(ObjectiveTrackerAnimLineState.Present);
										end
										if objectiveType == "progressbar" then
											local progressBar = block:AddProgressBar(questID);
											progressBar:SetPercent(GetQuestProgressBarPercent(questID));
										end
									end
								end
							end
						end
						if line then
							if line.state == ObjectiveTrackerAnimLineState.Completing then
								objectiveCompleting = true;
							end
						end
						firstLine = firstLine or line
					end
				end
				if questCompleted and not objectiveCompleting then
					block:ForEachUsedLine(function(line, objectiveKey)
						if line.state == ObjectiveTrackerAnimLineState.Completed then
							line:SetState(ObjectiveTrackerAnimLineState.Fading);
						end
					end);
				end
				return firstLine;
			end

			local function UpdateObjectives(block, stepIndex, existingBlock)
				if ShowObjectives() 
					and strmatch(DGV.actions[stepIndex], "[CNK]")
					and not DGV:ReturnTag("V", stepIndex)
					and (DGV:getIcon(DGV.actions[stepIndex], stepIndex) ~= "Interface\\Minimap\\TRACKING\\Profession" or DGV:ReturnTag("AYG", stepIndex)) 
				then
					local firstLine
					for control, qid in QuestIterator, stepIndex do
						if control == 1 then
							--QuestObjective_SetupHeader(block, OBJECTIVE_TRACKER_LINE_WIDTH)
							--useItem[2] = -block.height --dynamic item button offset
							--QuestObjectiveSetupBlockButton_Item(block, C_QuestLog.GetLogIndexForQuestID(quest.questID))
							--[[local questLogIndex = C_QuestLog.GetLogIndexForQuestID(quest.questID)
							if QuestUtil.QuestShowsItemByIndex(questLogIndex, false) then
								block.ItemButton = block:AddRightEdgeFrame(module.questItemButtonSettings, questLogIndex);
							end]]
						end

						block.qid = qid
						block.id = qid
						local line = DoQuestObjectives(block, C_QuestLog.IsComplete(qid), IsQuestSequenced(qid), existingBlock, true)
						firstLine = firstLine or line
					end
					if firstLine then
						if module:IsDescriptionShown() then
							firstLine:SetPoint("TOPLEFT", block.Desc, "BOTTOMLEFT", 14, -module.lineSpacing)
						else
							firstLine:SetPoint("TOP", block.HeaderText, "BOTTOM", 14, -8)
							firstLine:SetPoint("RIGHT")
						end
					end
				end
			end

			local function GetQuestName(stepIndex)
				local qName = DGV.quests1L[stepIndex]
				qName = DGV.NPCJournalFrame:ReplaceSpecialTags(qName, true, stepIndex, true)
		
				qName = qName .. DGV.GetWaitIcon(DGV.CountRemainingPlayers(stepIndex));
				return qName
			end

			function module:IsDescriptionShown()
				return DGV:UserSetting(DGV_EMBEDDEDTOOLTIP)
			end

			function module:GetBlockIdentifier(stepIndex)
				return "DGV"..stepIndex
			end
			
			local function GetQuestLocation(questId)
				local templates = {"QuestPinTemplate", "WorldMap_WorldQuestPinTemplate"}
				for _, template in ipairs(templates) do
					for pin in WorldMapFrame:EnumeratePinsByTemplate(template) do
						if pin.questID == questId then
							return pin:GetPosition()
						end
					end
				end
			end			
			
			function module:LayoutSingle(stepIndex)
				local usedBlockId = self:GetBlockIdentifier(stepIndex)
				local existingBlock = self:GetExistingBlock(usedBlockId);
				local block = self:GetBlock(usedBlockId)
				block.dgvId = usedBlockId
				block.guideIndex = stepIndex
				block.guestStepIndex = stepIndex
				block.Chk:SetChecked(false)
				if stepIndex and DGV.actions[stepIndex] then
					local questId = DGV.qid[stepIndex]
					
					local level = DGV:GetQuestLevel(questId)
					local qName = DGV.quests1L[stepIndex]
					local questpart = DGV:ReturnTag("QIDP", stepIndex)
					
					if (level and level > 0 and strmatch(DGV.actions[stepIndex], "[ACT]") and DGV:UserSetting(DGV_QUESTLEVELON)) or (level and level > 0 and questpart and strmatch(DGV.actions[stepIndex], "[NK]") and DGV:UserSetting(DGV_QUESTLEVELON)) then qName = "["..level.."] "..qName end
		
					qName = GetQuestName(stepIndex)
		
					local icon = DGV:getIcon(DGV.actions[stepIndex], stepIndex)
					if icon then
						block.Icon:SetNormalTexture(icon)
					end
					block:SetHeader(qName);
					
					if DGV:ReturnTag("POI", stepIndex) and questId then 
						--local posX, posY = C_TaskQuest.GetQuestLocation(questId, C_TaskQuest.GetQuestZoneID(questId) or DGV:GetCurrentMapID())
						local posX, posY = GetQuestLocation(questId)
						if posX then 
							havePOIwaypoint = true
						end
					end
					
					if (DGV:HasCoord(stepIndex) or havePOIwaypoint) and DGV:UserSetting(DGV_SHOW_EXTRA_WAYPOINT_ICON) then 
						block.Waypoint:Enable()
						block.Waypoint:Show()
						block.Waypoint:SetNormalTexture(
							DGV.Modules.DugisArrow:GetFirstWaypointGuideIndex()==stepIndex and
							"Interface\\AddOns\\DugisGuideViewerZ\\Artwork\\waypoint_selected.tga" or
							"Interface\\AddOns\\DugisGuideViewerZ\\Artwork\\waypoint.tga")
						block.HeaderText:SetPoint("TOPLEFT", 28, 0)
						block.Chk:SetPoint("RIGHT", block.Icon, "LEFT", -14, 0)				
					else 
						block.Waypoint:Disable() 
						block.Waypoint:Hide()
						block.HeaderText:SetPoint("TOPLEFT", 14, 0)
						block.Chk:SetPoint("RIGHT", block.Icon, "LEFT", 0, 0)
					end
					if (stepIndex == DugisGuideUser.CurrentQuestIndex) and DGV:HasModel(stepIndex) then 
						block.ModelButton:Show() 
					else 
						block.ModelButton:Hide() 
					end
					if DGV:ReturnTag("NT", stepIndex)  then 
						block.Chk:Disable()
						block.Chk:Hide()
					else 
						block.Chk:Enable()
						block.Chk:Show()
					end

					if self:IsDescriptionShown() then
						block.Desc:Show()
						local text = Obj.GetDescriptionText(block.guideIndex)
						local fontFile, _, flags = block.Desc:GetFont("P")
						block.Desc:SetFont("P", fontFile, ObjectiveTrackerLineFont:GetFontHeight()-2, flags)
						block.Desc.text = text
						block.Desc:SetText(block.Desc.text)
						block.Desc:SetWidth(block.Desc:GetWidth())
						local descHeight = block.Desc:GetContentHeight() + self.lineSpacing
						block.Desc:SetHeight(descHeight)
						block.height = block.height + descHeight
					else
						block.Desc:Hide()
					end
					--block.lastRegion = block.Desc -- anchor first objective line
					UpdateObjectives(block, stepIndex, existingBlock)	
				end
				block.height = block.height + 0 + self.lineSpacing
				self:LayoutBlock(block)
				return block
			end

			function module:LayoutNoGuide()
				if DugisGuideViewer.chardb.EssentialsMode == 1 or not DugisGuideViewer:GuideOn() then
					local block = self:GetBlock("DGV_NO_GUIDE", "DugisNoGuideBlockTemplate")
					block:Hide();
					return
				end

				local block = self:GetBlock("DGV_NO_GUIDE", "DugisNoGuideBlockTemplate")
				block.HeaderText:SetText(L["No Guide Loaded"])
				local fontFile, _, flags = block.Desc:GetFont("P")
				block.Desc:SetFont("P", fontFile, ObjectiveTrackerLineFont:GetFontHeight()-2, flags)
				block.Desc:SetText(L["Right Click Here To Select One"])
				local descHeight = block.Desc:GetContentHeight() + self.lineSpacing
				block.Desc:SetHeight(descHeight)
				block.height = block.height + descHeight + 16
				self:LayoutBlock(block)
			end

			function module:LayoutContents()
				self.Header.ProgressBar:Hide()
				if DGV:isValidGuide(CurrentTitle) and DugisGuideViewer.chardb.EssentialsMode ~= 1 and DugisGuideViewer:GuideOn() then
					if ShowProgress() then
						local bar = self.Header.ProgressBar
							local left = container.isOnLeftSideOfScreen
							bar:SetPoint("RIGHT", 
								left and self.Header or self.Header.MinimizeButton, 
								left and "RIGHT" or "LEFT", 
								-14, 0)
						local percentComplete = DGV.Modules.Guides.percentComplete
						if percentComplete then
							bar:SetValue(percentComplete)
							bar:Show()
							if ShowProgressText() then
								bar.text:SetText(string.format("%.0f%%",percentComplete))
								bar.text:Show()
							else
								bar.text:Hide()
							end
						end
					else
						self.Header.ProgressBar:Hide()
					end
					local currentQuestIndex = DugisGuideUser.CurrentQuestIndex
					if currentQuestIndex then
						if MultistepMode() and not DGV:ReturnTag("NT", currentQuestIndex) then
							local maxstep = 0
							local total = math.ceil(DugisGuideViewer:GetDB(DGV_SMALLFRAME_STEPS) - 0.5) or 6
							
							if DGV:ReturnTag("SID", currentQuestIndex) or DGV:ReturnTag("SID", currentQuestIndex + 1 ) then 
								total = 2
							end
							
							for guideIndex in DGV.IterateRelevantSteps do				
								maxstep = maxstep + 1
								if maxstep <= total then 
									self:LayoutSingle(guideIndex)
								end
								if maxstep == 2 and not DGV:ReturnTag("AYG", guideIndex) then 
									DugisGuideUser.NextQuestIndex = guideIndex
								elseif DGV:ReturnTag("AYG", currentQuestIndex + 1) then 
									DugisGuideUser.NextQuestIndex = currentQuestIndex
								end
							end
						elseif DGV:ReturnTag("AYG", currentQuestIndex) and not DGV:ReturnTag("NT", currentQuestIndex) then -- AYG to make As you go step stick. 
							local maxstep = 0
							for guideIndex in DGV.IterateRelevantSteps do				
								maxstep = maxstep + 1
								if maxstep <= 2 then 
									self:LayoutSingle(guideIndex)
								end
								if maxstep == 2 and not DGV:ReturnTag("AYG", guideIndex) then 
									DugisGuideUser.NextQuestIndex = guideIndex
								elseif DGV:ReturnTag("AYG", currentQuestIndex + 1) then
									DugisGuideUser.NextQuestIndex = currentQuestIndex
								end
							end
						else
							self:LayoutSingle(currentQuestIndex)
						end
					end
				else
					self:LayoutNoGuide()
				end

				if not ShowHeader() or DugisGuideViewer.chardb.EssentialsMode == 1 or not DugisGuideViewer:GuideOn() then
					self.fromHeaderOffsetY = 4
					self.Header:Hide()
				else
					self.Header:Show()
					self.fromHeaderOffsetY = -10
				end
			end

			local originalFreeBlock = module.FreeBlock
			function module:FreeBlock(block)
				block.id = block.dgvId or block.id
				originalFreeBlock(self, block)
			end

			return module
		end

		--[[local function GetQuestPOI(questID, type)
			if ObjectiveTrackerFrame.BlocksFrame 
				and ObjectiveTrackerFrame.BlocksFrame.poiTable 
				and ObjectiveTrackerFrame.BlocksFrame.poiTable[type] then
				for index, buton in pairs(ObjectiveTrackerFrame.BlocksFrame.poiTable[type]) do
					if buton.questID == questID then
						return buton
					end
				end
			end
		end

		function module:UpdatePOIs(numPOINumeric)
			local stepIndex = DugisGuideUser.CurrentQuestIndex
			local block = stepIndex and self:GetExistingBlock("DGV"..stepIndex)
			local blocksFrame = block and block.module.BlocksFrame
			if blocksFrame and  blocksFrame.Init and blocksFrame.ResetUsage then
				local world = block.WorldQuestPOI
				block.module.ShowWorldQuests = false
	 			if not blocksFrame.poiTable then
					local onCreateFunc = nil;
					local useHighlightManager = true;
					blocksFrame:Init(onCreateFunc, useHighlightManager);
				end

				blocksFrame:ResetUsage();
				world:Hide()
				if ShouldShowQuestPOI() then
					local questId = DGV.qid[stepIndex]
					if questId then
						block.id = questId
						block.Icon:ClearNormalTexture()
						C_TaskQuest.RequestPreloadRewardData(questId)
						if QuestUtils_IsQuestWorldQuest(questId) then
							QuestUtil.SetupWorldQuestButton(world, 
								C_QuestLog.GetQuestTagInfo(questId), 
								true, 
								questId == C_SuperTrack.GetSuperTrackedQuestID())
							world.questID = questId
							block.module.ShowWorldQuests = true
							world:Show()
						else
							local mapBtn = GetQuestPOI(questId, "numeric")
							local poiButton = mapBtn and blocksFrame:GetButtonForQuest(questId, POIButtonUtil.Style.Numeric, mapBtn.index) or
								GetQuestPOI(questId, "completed") and blocksFrame:GetButtonForQuest(questId, POIButtonUtil.Style.QuestComplete, nil)
							if poiButton then
								poiButton:SetAllPoints(world)
								blocksFrame:SelectButton(poiButton);
							else
								blocksFrame:ClearSelection();
							end
						end
					end
				end
			end
		
			return numPOINumeric
		end]]

		--ObjectiveTracker_Update(OBJECTIVE_TRACKER_UPDATE_MODULE_DGV)

		local function DescriptionHyperlinkOnEnter(desc, linkData, link)
			if desc and desc.text and link and not link:find("|cffdddddd", 1, true) and not link:find("item", 1, true) then --exclude item for not, it breaks item hyperlink, to fix later
				local linkStart, linkEnd = desc.text:find(link, 1, true)
				if linkStart then
					local linkPrefix = (linkStart > 1 and desc.text:sub(1, linkStart - 1)) or ""
					local linkSuffix = (linkEnd < desc.text:len() and desc.text:sub(linkEnd + 1)) or ""
					local replacement = link:gsub("|c........", ""):gsub("|r", "") --strip color tags
						:gsub("(%[[^%]]*%])", "|cffdddddd%1|r") --new color tags
					desc:SetText(string.format("%s%s%s", linkPrefix, replacement, linkSuffix))
				end
			end
		end

		function DugiIcon_OnEnter(self)
			DugisGuideViewer:Button_OnEnter(self)
		end

		function DugiIcon_OnLeave()
			GameTooltip:Hide()
		end

		function DugiIcon_OnMouseUp(self)
			if DugisGuideViewer:UserSetting(DGV_SHOW_EXTRA_WAYPOINT_ICON) then return end
			local texture = self:GetNormalTexture()
			if texture then
				texture:SetPoint("TOPLEFT", self, "TOPLEFT", 0, 0)
				texture:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT", 0, 0)
			end
		end

		function DugiIcon_OnMouseDown(self)
			if DugisGuideViewer:UserSetting(DGV_SHOW_EXTRA_WAYPOINT_ICON) then return end
			local texture = self:GetNormalTexture()
			if texture then
				texture:SetPoint("TOPLEFT", self, "TOPLEFT", -1, -2)
				texture:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT", -1, -2)
			end
		end

		function DugiIcon_OnClick(self)
			if DugisGuideViewer:UserSetting(DGV_SHOW_EXTRA_WAYPOINT_ICON) then return end
			DugisGuideViewer:WayPoint_OnClick(self:GetParent().Waypoint)
		end

		function DugiDesc_OnHyperlinkClick(...)
			DGV.NPCJournalFrame.OnHyperlinkClick(...)
		end
		
		function DugiDesc_OnHyperlinkEnter(self, linkData, link, button)
			DGV.NPCJournalFrame.OnHyperlinkEnter(self, linkData, link, button, self)
			if LuaUtils:matchString(linkData, "waypoint") == "" then
				DGV.QueueInvocation(DescriptionHyperlinkOnEnter, self, linkData, link)
			end
		end 
		
		function DugiDesc_OnHyperlinkLeave(self, ...)
			DGV.NPCJournalFrame.OnHyperlinkLeave(self, ...)
			DGV.QueueInvocation(self.SetText, self, self.text)
		end

		function DugiDesc_OnMouseUp(self, mouseButton, ...)
			OnClick(self:GetParent(), mouseButton)
		end
	end

	function Obj.GetDescriptionText(guideIndex)
		local descriptionText = DGV:GetQuestStepText(guideIndex) 
		
		--Removed lua error
		if not descriptionText then
			return "", ""
		end
		
		local rawText = descriptionText
		
		if descriptionText and not string.match(descriptionText, "|Hitem") and string.match(descriptionText, "item:%d") then --ReplaceSpecialTags for items if it didn't get converted yet on load. 
			if DGV.NPCJournalFrame then 
				descriptionText = DGV.NPCJournalFrame:ReplaceSpecialTags(descriptionText, true)
			end
		end
		
		return descriptionText, rawText
	end

	local function ModuleCondition(self, module)
		return module.blockTemplate == self.trackerModuleBlockTemplate
	end

	function Obj.IterateModules(invariantCondition, module)
		module = next(ObjectiveTrackerManager.moduleToContainerMap, module)
		if not module then return
		elseif not invariantCondition then return module end

		local invariantType = type(invariantCondition)
		if invariantType == "table" and ModuleCondition(invariantCondition, module) then return module
		elseif invariantType == "function" and invariantCondition(module) then return module
		else return Obj.IterateModules(invariantCondition, module) end
	end

	local function HasSetGuideForActiveTab(module)
		return module.SetGuideForActiveTab
	end

	function Obj.SetGuideForActiveTab(guide, type_)
		for module in Obj.IterateModules,HasSetGuideForActiveTab do
			module:SetGuideForActiveTab(guide, type_)
		end
	end

	function Obj:GetTrackerModule()
		for module in Obj.IterateModules,self do
			return module
		end
	end

	function Obj:UpdateTrackerIntegration(remove)
		local module = self:GetTrackerModule()
		if remove then
			if not module then return end
			module:Hide()
			module:MarkBlocksUnused()
			module:FreeUnusedBlocks()
			ObjectiveTrackerManager:GetContainerForModule(module):RemoveModule(module);
			ObjectiveTrackerManager.moduleToContainerMap[module] = nil
		else
			if not module then
				module = self:CreateTrackerModule()
			end
			if not ObjectiveTrackerManager:GetContainerForModule(module) then
				ObjectiveTrackerManager:SetModuleContainer(module, self.trackerModuleContainer)
			end

		end
	end

	local function RelateFramePointsOnce(frame, reference, leftOffset, topOffset, rightOffset, bottomOffset)
		if frame and reference and reference:GetLeft() then --prevents error when adjusting the game screensize in windows mode
			frame:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", reference:GetLeft()+leftOffset, reference:GetTop()+topOffset)
			frame:SetPoint("BOTTOMRIGHT", UIParent, "BOTTOMLEFT", reference:GetRight()+rightOffset, reference:GetBottom()+bottomOffset)
		end
	end

	local function LayoutObjectivesBackground(forced)
		local bg = DugisObjectiveBackground
		if DGV:GuideOn() 
			and DugisGuideViewer:UserSetting(DGV_WATCHFRAMEBORDER)
			and ObjectiveTrackerFrame.Header:IsVisible() 
			and not ObjectiveTrackerFrame.isCollapsed
			and not DGV:IncompatibleAddonLoaded()
		then
			if not bg:IsShown() or forced then
				bg:Show()
				RelateFramePointsOnce(bg, ObjectiveTrackerFrame.NineSlice, -10, 10, 3, -10)
				DGV:SetFrameBackdrop(bg, DGV.BACKGRND_PATH, DGV:GetBorderPath(), 10, 4, 12, 5)
			end
		elseif bg:IsShown() then
			bg:Hide()
			bg:ClearAllPoints()
		end
	end

	function Obj:Update()
		if InCombatLockdown() then
			DGV.DoOutOfCombat(self.Update, self)
			return
		end
		LayoutObjectivesBackground(true)
		self:UpdateTrackerIntegration(not DGV:UserSetting(DGV_ANCHOREDSMALLFRAME) or not Obj.loaded)
		local module = Obj:GetTrackerModule()
		if module then
			module:MarkDirty()
		end
		if DGV.Modules and DGV.Modules.SmallFrame and DGV.Modules.SmallFrame.Update then DGV.Modules.SmallFrame:Update() end --sometimes get "attempt to call method 'Update' (a nil value)" error on login with ElvUI addon
		local anchored = DGV:UserSetting(DGV_ANCHOREDSMALLFRAME)
		Obj.ReferenceFrame:SetAllPoints(anchored and DugisObjectiveBackground or (not anchored) and DugisSmallFrameContainer.Background)
	end

	local bgReaction = DGV.RegisterFunctionPathReaction("ObjectiveTrackerFrame", "Update"):WithAction(LayoutObjectivesBackground):OutOfCombat()

	function Obj:Unload()
		self:UpdateTrackerIntegration(true)
		if bgReaction then bgReaction:Dispose() end
	end

	local function SanitizeObjectiveTracker()
		if not DGV:UserSetting(DGV_ANCHOREDSMALLFRAME) or InCombatLockdown() then return end
		local origObjectiveTrackerFrameDirtyCallback
		local function FrameDirtyOutOfCombat()
			DGV.DoOutOfCombatCancelOld("FrameDirtyOutOfCombat", origObjectiveTrackerFrameDirtyCallback)
		end

		local function WrapDirtyMethod()
			origObjectiveTrackerFrameDirtyCallback = ObjectiveTrackerFrame.dirtyCallback
			ObjectiveTrackerFrame.dirtyCallback = FrameDirtyOutOfCombat
		end

		DGV.RegisterFunctionPathReaction("ObjectiveTrackerFrame", "SetDirtyMethod"):WithAction(WrapDirtyMethod):Once()

		local function UpdateHeightOutOfCombat()
			DGV.DoOutOfCombatCancelOld("UpdateHeightOutOfCombat",  ObjectiveTrackerContainerMixin.UpdateHeight, ObjectiveTrackerFrame)
		end

		ObjectiveTrackerFrame.UpdateHeight = UpdateHeightOutOfCombat

		BonusObjectiveTracker.questItemButtonSettings.template = "DugisItemButtonTemplate"
		QuestObjectiveTracker.questItemButtonSettings.template = "DugisItemButtonTemplate"
		CampaignQuestObjectiveTracker.questItemButtonSettings.template = "DugisItemButtonTemplate"
	end
	--SanitizeObjectiveTracker() --get taint error sometimes and seems to work fine without it. 

end


DGV.RegisterFunctionPathReaction("ObjectiveTrackerFrame", "Update"):Dispose()