--[[

    MonkeyQuest:
    Quest tracker.
    
    Website:	www.toctastic.net
	Author:		Trentin
	Email:		monkeymods@gmail.com

--]]

local MonkeyQuestLocal_resizing = false;
local MonkeyQuestLocal_needQuestLogEvent = false;
local MonkeyQuestLocal_gotQuestLogEvent = false;
local MonkeyQuestLocal_timeSinceRefresh = 0;
local MonkeyQuestLocal_numQuestLogEvents = 0;


function MonkeyQuest_OnLoad()

    -- register events
    this:RegisterEvent("VARIABLES_LOADED");
    this:RegisterEvent('QUEST_LOG_UPDATE');			-- used to know when to refresh the MonkeyQuest text
    this:RegisterEvent('PLAYER_LEVEL_UP');			-- when you level up the difficulty of some quests may change

	-- events when zone changes to update the zone highlighting quests
    this:RegisterEvent('ZONE_CHANGED');
	this:RegisterEvent('ZONE_CHANGED_INDOORS');
	this:RegisterEvent('ZONE_CHANGED_NEW_AREA');
	
	-- this will catch mobs needed for quests
	this:RegisterEvent('UPDATE_MOUSEOVER_UNIT');
    
end

function MonkeyQuest_OnEvent(event)
    
    if (event == "VARIABLES_LOADED") then

    	MonkeyQuest_Init();
    	--MonkeyQuest_BlizzRefresh();

    elseif (event == 'QUEST_LOG_UPDATE' or event == 'PLAYER_LEVEL_UP') then
    
        MonkeyAPI_DebugMsg("QUEST_LOG_UPDATE");
        
        MonkeyQuestLocal_numQuestLogEvents = MonkeyQuestLocal_numQuestLogEvents + 1;

        MonkeyQuestLocal_gotQuestLogEvent = true;
        
		if (MonkeyQuestLocal_needQuestLogEvent == true) then
			-- don't process, let the OnUpdate catch it, but reset the timer
			MonkeyQuestLocal_timeSinceRefresh = 0.0;
		else
			MonkeyQuestLocal_needQuestLogEvent = true;
			MonkeyQuestLocal_timeSinceRefresh = 0.0;
		end

    elseif (event == 'ZONE_CHANGED' or event == 'ZONE_CHANGED_INDOORS' or event == 'ZONE_CHANGED_NEW_AREA') then
        MonkeyQuest_BlizzRefresh();
		MonkeyQuest_Render();

	elseif (event == 'UPDATE_MOUSEOVER_UNIT') then
		        
        if (MonkeyQuestVars.showUnitTooltip.current == true) then
			-- check if this is a quest item
        	local strQuestTitle, strObjective;
        	
        	strQuestTitle, strObjective = MonkeyQuest_FindRelevantQuest(UnitName("mouseover"));
        	
        	MonkeyQuest_AddQuestInfoToTooltip(strQuestTitle, strObjective);
        end
	end
end

-- this event is used to have nice smooth resizing
function MonkeyQuest_OnUpdate(arg1)
	if (MonkeyQuestLocal_resizing == true) then
		--MonkeyQuest_UpdateSize();
		MonkeyQuest_Render();
	end
	
	-- need to make sure we don't read from the quest list before a QUEST_LOG_UPDATE or we'll get the previous character's data
	if (MonkeyQuestLocal_gotQuestLogEvent == false) then
		return;
	end
	
	-- update the timer
	MonkeyQuestLocal_timeSinceRefresh = MonkeyQuestLocal_timeSinceRefresh + arg1;
	
	--MonkeyAPI_DebugMsg("time: " .. MonkeyQuestLocal_timeSinceRefresh);

	-- if it's been more than MONKEYQUEST_DELAY seconds and we need to process a dropped QUEST_LOG_UPDATE
	if ((MonkeyQuestLocal_needQuestLogEvent == true) and (MonkeyQuestLocal_timeSinceRefresh > 0.15)) then
	    MonkeyAPI_DebugMsg("MonkeyQuest Refreshing.");
		MonkeyQuest_BlizzRefresh();
		MonkeyQuest_Render();
		MonkeyQuestLocal_needQuestLogEvent = false;
	end
	
	-- process pings
	MonkeyQuest_ProcessPings(arg1);
end

function MonkeyQuest_OnMouseDown(arg1)

	if (arg1 == "LeftButton" and MonkeyQuestVars.frameLocked.current == false) then
		MonkeyQuestFrame:StartMoving();
	end

	-- right button on the title or frame opens up the MonkeyBuddy, if it's there
	if (arg1 == "RightButton") then
		if (MonkeyBuddyFrame ~= nil and MonkeyQuestVars.rightClickOpensConfig.current == true) then
			MonkeyBuddyFrame:Show();

			-- make MonkeyBuddy show the MonkeyQuest config
			MonkeyBuddySideBar_SelectAddOn(MONKEYQUEST_TITLE);
		end
	end
end


function MonkeyQuest_OnMouseUp(arg1)

	if (arg1 == "LeftButton") then
		MonkeyQuestFrame:StopMovingOrSizing();
	end
end

-- this function is called when the frame should be dragged around
function MonkeyQuestResizerBtn_OnMouseDown(arg1)

	MonkeyResizerBtn_OnMouseDown(arg1);

	-- left button moves the frame around
	if (arg1 == "LeftButton") then

		MonkeyQuestLocal_resizing = true;
	end
end

-- this function is called when the frame is stopped being dragged around
function MonkeyQuestResizerBtn_OnMouseUp(arg1)

	MonkeyResizerBtn_OnMouseUp(arg1);

	if (arg1 == "LeftButton") then
		
		MonkeyQuestLocal_resizing = false;
	end
end

-------------------------------------------------------------------------------
function MonkeyQuest_Render()

	local key, value, questKey, questValue, objectiveKey, objectiveValue;
	local headerIndex = 1;
	local itemIndex = 1;
	local prevFrameType;
	local height = 0;
	local itemHeight = 0;
	local strQuestLvl = "";
	local strQuestTag = "";
	local strObjectives = "";
	local zoneColour = MonkeyQuestVars.zoneColour.current;
	local pingColour = MonkeyQuestVars.pingColour.current;
	
	local tempColour;

	local headerFrame, headerTitleFrame, headerTitleText;
	

	-- just make sure everything is loaded before rendering
	if (getglobal("MonkeyQuestListHeader" .. headerIndex) == nil) then
		return;
	end
	
	MonkeyAPI_DebugMsg("MonkeyQuest Rendering.");

	MonkeyQuest_UpdateTitle();
	
	
	for key, value in pairs(MonkeyQuestTable) do

		-- make it easier
		headerFrame = getglobal("MonkeyQuestListHeader" .. headerIndex);
		headerTitleFrame = getglobal("MonkeyQuestListHeader" .. headerIndex .. "_Title");
		headerTitleText = getglobal("MonkeyQuestListHeader" .. headerIndex .. "_Title_Txt");
		
		
		headerTitleText:SetText(value.headerTitle);
		headerFrame.headerTitle = value.headerTitle;
		headerFrame.headerKey = key;
		
		headerTitleFrame:UnlockHighlight();

		-- current zone
		if (MonkeyQuestVars.showCurrentZone.current == true and value.currentZone == true) then
			headerTitleFrame:GetHighlightTexture():SetVertexColor(zoneColour.r, zoneColour.g, zoneColour.b, zoneColour.a);
			headerTitleFrame:LockHighlight();
		else
			headerTitleFrame:GetHighlightTexture():SetVertexColor(pingColour.r, pingColour.g, pingColour.b, 1);
		end

		if (prevFrameType ~= nil) then

			if (prevFrameType == "header") then
				headerFrame:SetPoint("TOPLEFT", getglobal("MonkeyQuestListHeader" .. (headerIndex - 1)), "BOTTOMLEFT", 0, -1);

			elseif (prevFrameType == "item") then
				headerFrame:SetPoint("TOPLEFT", getglobal("MonkeyQuestListItem" .. (itemIndex - 1)), "BOTTOMLEFT", -16, -1);
			end
		end

		getglobal("MonkeyQuestListHeader" .. headerIndex .. "_Cross"):SetChecked(not value.expanded);
		headerFrame:Show();
		
		headerFrame:SetHeight(headerTitleText:GetHeight());
		
		height = height + headerFrame:GetHeight() + 1;

		headerIndex = headerIndex + 1;

		prevFrameType = "header";

		-- go through the quests table and render each quest
		if (value.expanded == true and value.quests ~= nil and table.maxn(value.quests) > 0) then

			for questKey, questValue in pairs(value.quests) do

				-- render the quest or not
				if (questValue.visible == true or MonkeyQuestVars.showAllQuests.current == true) then
				    
					if (MonkeyQuestVars.showQuestLevels.current == true) then

						if (MonkeyQuestVars.showQuestDifficultyColour.current == true) then
							-- quest difficulty colour
							tempColour = GetDifficultyColor(questValue.level);
							strQuestLvl = MonkeyAPI_RGBAToColourStr(tempColour.r, tempColour.g, tempColour.b);
						else
							strQuestLvl = "";
						end

						strQuestLvl = strQuestLvl .. "[" .. questValue.level;
						if (questValue.suggestedGroup > 0) then
							strQuestLvl = strQuestLvl .. "g" .. questValue.suggestedGroup;
						end
						strQuestLvl = strQuestLvl .. "] ";
					else
						strQuestLvl = "";
					end

					tempColour = MonkeyQuestVars.questTitleColour.current;
					strQuestLvl = strQuestLvl .. MonkeyAPI_RGBAToColourStr(tempColour.r, tempColour.g, tempColour.b);

					if (questValue.questTag ~= nil) then
						strQuestTag = " (" .. questValue.questTag .. ")";
					elseif (questValue.isComplete and questValue.isComplete > 0) then
						strQuestTag = " (" .. COMPLETE .. ")";
					elseif (questValue.isComplete and questValue.isComplete < 0) then
						strQuestTag = " (" .. FAILED .. ")";
					else
						strQuestTag = "";
					end


					-- keep track of which frame this quest is in
					questValue.frameIndex = itemIndex;

					-- set the blizzard quest index
					getglobal("MonkeyQuestListItem" .. itemIndex).blizzIndex = questValue.blizzIndex;

					-- info to link to the MonkeyQuestTable
					getglobal("MonkeyQuestListItem" .. itemIndex).headerKey = key;
					getglobal("MonkeyQuestListItem" .. itemIndex).questKey = questKey;
					getglobal("MonkeyQuestListItem" .. itemIndex).questTitle = questValue.questTitle;

					-- quest tag and title
	                getglobal("MonkeyQuestListItem" .. itemIndex .. "_TagTxt"):SetText(strQuestTag);
					getglobal("MonkeyQuestListItem" .. itemIndex .. "_Txt"):SetText(strQuestLvl .. questValue.questTitle);

	                itemHeight = getglobal("MonkeyQuestListItem" .. itemIndex .. "_Txt"):GetHeight();



                    -- render the checkbox
					getglobal("MonkeyQuestListItem" .. itemIndex .. "_Check"):SetChecked(questValue.visible);
                    if (MonkeyQuestVars.showAllQuests.current == true) then
                        getglobal("MonkeyQuestListItem" .. itemIndex .. "_Check"):Show();
				    else
				        getglobal("MonkeyQuestListItem" .. itemIndex .. "_Check"):Hide();
				    end
				    
				    
					-- render the quest objectives
	                strObjectives = "";

	                if (questValue.objectives ~= nil) then
						for objectiveKey, objectiveValue in pairs(questValue.objectives) do

							if (objectiveValue.numNeeded ~= nil) then
								strObjectives = strObjectives .. MonkeyQuest_GetObjectiveColourStr(tonumber(objectiveValue.numItems), tonumber(objectiveValue.numNeeded)) ..
									objectiveKey .. ": " .. objectiveValue.numItems .. "/" .. objectiveValue.numNeeded;
							else
							    strObjectives = strObjectives .. objectiveKey;
							end
							strObjectives = strObjectives .. "\n";
	                    end
	                end

	                getglobal("MonkeyQuestListItem" .. itemIndex .. "_ObjectivesTxt"):SetText(strObjectives);
	                if (questValue.numLeaderBoards == nil or questValue.numLeaderBoards < 1) then
	                    getglobal("MonkeyQuestListItem" .. itemIndex .. "_ObjectivesTxt"):SetWidth(MonkeyQuestListFrame:GetWidth()-70);
	                else
	                end


	                itemHeight = itemHeight + getglobal("MonkeyQuestListItem" .. itemIndex .. "_ObjectivesTxt"):GetHeight();

	                getglobal("MonkeyQuestListItem" .. itemIndex):SetHeight(itemHeight);

	                -- re-anchor
					if (prevFrameType ~= nil) then

						--getglobal("MonkeyQuestListItem" .. itemIndex):ClearAllPoints();
						getglobal("MonkeyQuestListItem" .. itemIndex):SetParent(getglobal("MonkeyQuestListHeader" .. (headerIndex - 1) .. "_Children"));
						--getglobal("MonkeyQuestListItem" .. itemIndex):SetPoint("RIGHT", MonkeyQuestListScrollFrame_ScrollChild, "RIGHT", 0, 0);

						if (prevFrameType == "header") then
							getglobal("MonkeyQuestListItem" .. itemIndex):SetPoint("TOPLEFT", getglobal("MonkeyQuestListHeader" .. (headerIndex - 1) .. "_Children"), "BOTTOMLEFT", 16, 0);

						elseif (prevFrameType == "item") then
							getglobal("MonkeyQuestListItem" .. itemIndex):SetPoint("TOPLEFT", getglobal("MonkeyQuestListItem" .. (itemIndex - 1)), "BOTTOMLEFT", 0, 0);
						end
					end

					if (getglobal("MonkeyQuestListItem" .. itemIndex).ping == nil) then
						getglobal("MonkeyQuestListItem" .. itemIndex):UnlockHighlight();
					end

					-- current zone
					if (MonkeyQuestVars.showCurrentZone.current == true and questValue.currentZone == true) then
						getglobal("MonkeyQuestListItem" .. itemIndex):GetHighlightTexture():SetVertexColor(zoneColour.r, zoneColour.g, zoneColour.b, zoneColour.a);
					    getglobal("MonkeyQuestListItem" .. itemIndex):LockHighlight();
					else
						getglobal("MonkeyQuestListItem" .. itemIndex):GetHighlightTexture():SetVertexColor(pingColour.r, pingColour.g, pingColour.b, 1);
					end

					getglobal("MonkeyQuestListItem" .. itemIndex):Show();

					height = height + getglobal("MonkeyQuestListItem" .. itemIndex):GetHeight() + 1;

					itemIndex = itemIndex + 1;

					prevFrameType = "item";
				
				end
			end
		end

	end
	
	-- hide all the other frames
	for i = headerIndex, MAX_QUESTLOG_QUESTS, 1 do
		getglobal("MonkeyQuestListHeader" .. i):Hide();
	end
	
	for i = itemIndex, MAX_QUESTLOG_QUESTS, 1 do
		getglobal("MonkeyQuestListItem" .. i):Hide();
	end
	

	MonkeyQuestListScrollFrame_ScrollChild:SetHeight(height - 8);
	MonkeyQuestListScrollFrame_ScrollChild:SetWidth(MonkeyQuestListFrame:GetWidth()-38);
	MonkeyQuestListScrollFrame:UpdateScrollChildRect();
	--MonkeyQuest_UpdateSize();
end
-------------------------------------------------------------------------------

function MonkeyQuest_BlizzRefresh()

	if (MonkeyQuestLocal_numQuestLogEvents < 2) then
		return;
	end
	
	MonkeyAPI_DebugMsg("MonkeyQuest BlizzRefresh.");
	
	local numEntries, numQuests = GetNumQuestLogEntries();
	local questIndex, questLogTitle, questTitleTag, questNumGroupMates, questNormalText, questHighlight, questCheck;
	local questLogTitleText, level, questTag, suggestedGroup, isHeader, isCollapsed, isComplete, color;
	local numPartyMembers, partyMembersOnQuest, tempWidth, textWidth;

	local headerIndex = 1;
	local itemIndex = 1;
	
	local headerTable = {};
	local questTable = {};
	local objectiveTable = {};
	
	local strQuestDesc, strQuestShortDesc;
	local numQuestLeaderBoards;
	local objectiveDesc, objectiveType, objectiveComplete;
	local j, k, objectiveName, objectiveNumItems, objectiveNumNeeded;
	
	local questLogEntry = GetQuestLogSelection();
	
	local strSubZoneText = string.lower(GetSubZoneText());
	local strZoneText = string.lower(GetZoneText());
	
	for i = 1, numEntries, 1 do
	
	    SelectQuestLogEntry(i);

		questLogTitleText, level, questTag, suggestedGroup, isHeader, isCollapsed, isComplete = GetQuestLogTitle(i);

		if (isHeader) then
		
			headerTable = MonkeyQuest_GetQuestTable(questLogTitleText);

			if (headerTable == nil) then
				headerTable = MonkeyQuest_AddNewHeader(questLogTitleText, false);
			end
			
			headerTable.active = true;
			
			headerTable.currentZone = false;

			if (strSubZoneText ~= "") then
				if (string.find(string.lower(questLogTitleText), strSubZoneText)) then
					headerTable.currentZone = true;
				end
			end
			if (strZoneText ~= "") then
				if (string.find(string.lower(questLogTitleText), strZoneText)) then
					headerTable.currentZone = true;
				end
			end

		else
		    strQuestDesc, strQuestShortDesc = GetQuestLogQuestText();
		    
			questTable = MonkeyQuest_GetQuestTable(questLogTitleText);
			
			if (questTable == nil) then
			
				questTable = {};

				questTable.questTitle = questLogTitleText;
				questTable.originalHeader = headerTable.headerTitle;
				questTable.shortDesc = strQuestShortDesc;
				questTable.longDesc = strQuestDesc;
				questTable.visible = true;
				questTable.suggestedGroup = suggestedGroup;
				questTable.questTag = questTag;
				questTable.level = level;
				questTable.isComplete = isComplete;
				questTable.active = true;
				questTable.blizzIndex = i;

				if (headerTable.quests == nil) then
					headerTable.quests = {};
				end

				table.insert(headerTable.quests, questTable);
			else
				questTable.suggestedGroup = suggestedGroup;
				questTable.questTag = questTag;
				questTable.level = level;
				questTable.isComplete = isComplete;
				questTable.active = true;
				questTable.blizzIndex = i;
			end

			questTable = MonkeyQuest_GetQuestTable(questLogTitleText);

			if (questTable.objectives == nil) then
				questTable.objectives = {};
			end
			
			
			numQuestLeaderBoards = GetNumQuestLeaderBoards(i);
			questTable.numLeaderBoards = numQuestLeaderBoards;

			if (numQuestLeaderBoards > 0) then
				for ii = 1, numQuestLeaderBoards, 1 do

					objectiveDesc, objectiveType, objectiveComplete = GetQuestLogLeaderBoard(ii, i);

					if (objectiveType == "item" or objectiveType == "monster" or objectiveType == "object") then

						j, k, objectiveName, objectiveNumItems, objectiveNumNeeded = string.find(objectiveDesc, "(.*):%s*([-%d]+)%s*/%s*([-%d]+)%s*$");

						if (objectiveName ~= nil and objectiveName ~= "  slain" and objectiveName ~= " ") then
							if (questTable.objectives[objectiveName] == nil) then
								questTable.objectives[objectiveName] = {};
							end

							if (objectiveComplete == 1 and questTable.objectives[objectiveName].complete == nil) then
								PlaySoundFile(MONKEYQUEST_SOUND_COMPLETE);
								MonkeyAPI_DebugMsg("work complete!");
							end
							
							if (questTable.objectives[objectiveName].numItems ~= objectiveNumItems) then
							    -- ping the quest in the list
								if (questTable.frameIndex ~= nil and MonkeyQuestVars.showObjectivePings.current == true) then
									MonkeyQuest_PingQuest(questTable.questTitle, getglobal("MonkeyQuestListItem" .. questTable.frameIndex));
								end
							end

							questTable.objectives[objectiveName].complete = objectiveComplete;
							questTable.objectives[objectiveName].numItems = objectiveNumItems;
							questTable.objectives[objectiveName].numNeeded = objectiveNumNeeded;
						end
					elseif (objectiveType == "event") then
					    if (objectiveDesc ~= nil) then
						    if (questTable.objectives[objectiveDesc] == nil) then
								questTable.objectives[objectiveDesc] = {};
							end
							if (objectiveComplete == 1 and questTable.objectives[objectiveDesc].complete == nil) then
								PlaySoundFile(MONKEYQUEST_SOUND_COMPLETE);
								MonkeyAPI_DebugMsg("work complete!");
								
								-- ping the quest in the list
								if (questTable.frameIndex ~= nil and MonkeyQuestVars.showObjectivePings.current == true) then
									MonkeyQuest_PingQuest(questTable.questTitle, getglobal("MonkeyQuestListItem" .. questTable.frameIndex));
								end
							end
							questTable.objectives[objectiveDesc].complete = objectiveComplete;
						end
					end
				end
			else
				questTable.objectives[strQuestShortDesc] = {};
			end
			
			-- is the quest relative to the current zone?
			questTable.currentZone = false;

			if (strSubZoneText ~= "") then
				if (string.find(string.lower(questLogTitleText), strSubZoneText) or
					string.find(string.lower(strQuestDesc), strSubZoneText) or
					string.find(string.lower(strQuestShortDesc), strSubZoneText)) then

					questTable.currentZone = true;
				end
			elseif (strZoneText ~= "") then
				if (string.find(string.lower(questLogTitleText), strZoneText) or
					string.find(string.lower(strQuestDesc), strZoneText) or
					string.find(string.lower(strQuestShortDesc), strZoneText)) then
					
					questTable.currentZone = true;
				end
			end
		end
	end
	
	SelectQuestLogEntry(questLogEntry);
	
	MonkeyQuest_CleanQuestTable();
	
	MonkeyQuest_SortQuestTable();
	
end


function MonkeyQuest_UpdateTitle()
	
	local numEntries, numQuests = GetNumQuestLogEntries();

	-- set the title, with or without the number of quests
	if (MonkeyQuestVars.showTitleNumQuests.current == true) then

		if (MonkeyQuestVars.showTitleName.current == true) then

			MonkeyQuestTitleBtn_Txt:SetText(MONKEYQUEST_TITLE .. " " .. numQuests .. "/" .. MAX_QUESTLOG_QUESTS);
		else
			MonkeyQuestTitleBtn_Txt:SetText(numQuests .. "/" .. MAX_QUESTLOG_QUESTS);
		end

	elseif (MonkeyQuestVars.showTitleName.current == true) then

		MonkeyQuestTitleBtn_Txt:SetText(MONKEYQUEST_TITLE);
	else
		MonkeyQuestTitleBtn_Txt:SetText("");
	end
end


function MonkeyQuest_UpdateSize()

	local iWidth = MonkeyQuestListFrame:GetWidth()-38;
	
	--MonkeyQuest_Render();


	MonkeyQuestListScrollFrame_ScrollChild:SetWidth(iWidth);

	--MonkeyQuestListScrollFrame_ScrollChild:SetHeight(iHeight);

	MonkeyQuestListScrollFrame:UpdateScrollChildRect();
end


function MonkeyQuestListHeader_Cross_OnClick()

	local headerTable = MonkeyQuest_GetQuestTable(getglobal(this:GetParent():GetName()).headerTitle);
	
	headerTable.expanded = not this:GetChecked();
	
	MonkeyQuest_Render();

end

function MonkeyQuestListHeader_Title_OnClick()

	local headerTable = MonkeyQuest_GetQuestTable(getglobal(this:GetParent():GetName()).headerTitle);

	getglobal(this:GetParent():GetName() .. "_Cross"):SetChecked(headerTable.expanded);
	headerTable.expanded = not headerTable.expanded;

	MonkeyQuest_Render();

end
