--## Author: Hizuro ## Version: 2.0.1-release ## SavedVariables: LFRotp_Options, LFRotp_Dev
local LFRofthepast = {};
--[[
LFRofthepast.L = setmetatable(L,{__index=function(t,k)
	local v = tostring(k);
	rawset(t,k,v);
	return v;
end});

local v = GetBuildInfo()
local n = tonumber((v:gsub("%.","")))
local s = "It is Patch X and the location of the Storyteller of Y remains unknown."
local t = "He was expected with Patch Z."
L["StillMissingNPC10"] = s:gsub("X",v):gsub("Y","The War Within")
L["StillMissingNPC11"] = s:gsub("X",v):gsub("Y","Midnight")..(n>1305 and t:gsub("Z","13.0.5") or "")

local L = LFRofthepast.L;

L["AddOnLoaded"] = "插件已加载..."
L["AddOnLoadedDesc"] = "登陆时显示 '插件已加载...' 信息"
L["Click"] = "点击"
L["Coordinates"] = "坐标"
L["LFR_of_the_past"] = "随机难度 [旧本]"
L["MinimapIcon"] = "小地图图标"
L["MinimapIconDesc"] = "在小地图上显示图标"
L["Open LFR [of the past] info panel"] = "打开随机难度[旧本]界面"
L["PlayerNeutral"] = "您是中立派系，你需要选定一下自己的派系."
L["TomTomAdd"] = "添加到TOMTOM"
L["TomTomMissing"] = "缺少插件TOMTOM"


L["NPC80675"] = "奥里多米"
L["NPC80633"] = "游学者韩恩"
L["NPC78709"] = "游学者福云"
L["NPC78777"] = "游学者辛恒"
L["NPC94870"] = "先知卡扎尔"
L["NPC94870"] = "先知卡扎尔"
L["NPC111246"] = "大法师提迈尔"
L["NPC31439"] = "大法师提迈尔"
L["NPC177193"] = "基库"
L["NPC177208"] = "埃浦"
L["NPC205959"] = "塔·艾尔法"
L["NPC262873"] = "路嘉·寻团"

--zhtw

L["NPC80675"] = "奧莉朵米"
L["NPC80633"] = "博學行者阿翰"
L["NPC78709"] = "博學行者阿傅"
L["NPC78777"] = "博學行者阿新"
L["NPC94870"] = "先知卡札爾"
L["NPC94870"] = "先知卡札爾"
L["NPC111246"] = "大法師泰彌亞"
L["NPC31439"] = "大法師泰彌亞"
L["NPC177193"] = "奇庫"
L["NPC177208"] = "艾普"
L["NPC205959"] = "塔葉法"
--L["NPC262873"] = "" -- missing on wowhead
--enus
-- Do you want to help localize this addon?
-- https://www.curseforge.com/wow/addons/@cf-project-name@/localization

L["AddOnLoaded"] = "AddOn loaded..."
L["AddOnLoadedDesc"] = "Show 'AddOn Loaded...' message on logins and UI reloads."
L["AddOnLoadedDescAlt"] = "Alternatively you can hold shift key on loading screen to display this message for this login only."
L["Click"] = "Click"
L["Coordinates"] = "Coordinates"
L["DarkBackground"] = "Dark background"
L["DarkBackgroundDesc"] = "With some add-ons you can remove the parchment background from the LFR NPC window. This option makes the text color lighter for better readability."
L["InfoMsg"] = "Blizzard added the LFR mode with Cataclysm. After Cataclysm, the NPCs that grant access to the older LFR wings were released. Therefore, this list starts with Cataclysm. There is no LFR mode for older raids like Icecrown Citadel or Molten Core."
L["InstanceEyeETT"] = "Instance eye"
L["InstanceEyeETTDesc"] = "Adds encounter tooltip to blizzards standard ui instance eye on minimap"
L["LFR NPCs"] = "LFR NPCs"
L["LFR_of_the_past"] = "LFR [of the past]"
L["MapPinDesc"] = "Add map pin link to your chat. You must click on it to add it to your world map."
L["MinimapETT"] = "Minimap button"
L["MinimapETTDesc"] = "Adds encounter tooltip to the addon own minimap button tooltip. Without a data broker panel addon like Titan Panel, you should enable \"Minimap icon\" to display the encounter tooltip."
L["MinimapIcon"] = "Minimap icon"
L["MinimapIconDesc"] = "Show icon on minimap"
L["Open LFR [of the past] info panel"] = "Open LFR [of the past] info panel"
L["PlayerNeutral"] = "You are faction neutral. This addon required a choosen faction to work."
L["TimearLegion"] = "Timear in the old Dalaran (WotLK) also grants access to the Legion LFR"
L["TomTomAdd"] = "Add to tomtom"
L["TomTomMissing"] = "Missing addon TomTom"


L["NPC80675"] = "Auridormi"
L["NPC80633"] = "Lorewalker Han"
L["NPC78709"] = "Lorewalker Fu"
L["NPC78777"] = "Lorewalker Shin"
L["NPC94870"] = "Seer Kazal"
L["NPC94870"] = "Seer Kazal"
L["NPC111246"] = "Archmage Timear"
L["NPC31439"] = "Archmage Timear"
L["NPC177193"] = "Kiku"
L["NPC177208"] = "Eppu"
L["NPC205959"] = "Ta'elfar"
L["NPC262873"] = "Luka Ferad"]]
LFRofthepast.npcID = {};
LFRofthepast.npcs = {};
LFRofthepast.instance2bosses = {} -- -GetInstanceDataByID
LFRofthepast.gossipIndexOffset = {} -- GossipFrame.OnShow
LFRofthepast.npc2instance = {} -- buttonHook_OnEnter, GossipFrame.OnShow, OnImmersionShow
LFRofthepast.idx2gossipOptionID = {} -- OnImmersionShow
LFRofthepast.instanceName2group = {} -- GetInstanceDataByID
LFRofthepast.noSubtitle = {}; -- buttonHook_OnEnter, GossipFrame.OnShow, OnImmersionShow

local function UpdateNpcData(entry)
	if not entry then
		wipe(LFRofthepast.npcID);
		for i=1, #LFRofthepast.npcs do
			UpdateNpcData(LFRofthepast.npcs[i])
		end
		return
	end
	LFRofthepast.npcID[entry[1]]=1;
	local mapInfo = C_Map.GetMapInfo(entry[2]);
	if mapInfo then
		if  mapInfo.name == DUNGEON_FLOOR_DALARANCITY1 then
			local spell = C_Spell.GetSpellInfo((entry[2]==627 and 224869) or (entry[2]==125 and 53140));
			local _,target = strsplit(HEADER_COLON,spell.name,2);
			if target then
				mapInfo.name = target:trim(); -- replace "Dalaran" by "Dalaran - Broken Isles"
			end
		end
		entry.zoneName = mapInfo.name;
	end

	if type(entry.alt)=="table" then
		UpdateNpcData(entry.alt)
	end
end

function LFRofthepast.load_data()
	local faction = UnitFactionGroup("player");
	local Alliance = faction=="Alliance";
	local function _(a,h)
		return Alliance and a or h;
	end

	-- {<npcid>, <zoneid>, <posX>, <posY>, <expansionNumber>, <instanceType>, <instances[...]>}
	-- expansionNumber is for _G["EXPANSION_NAME"..<expansionNumber>]
	local data = {
		-- cata (patch 6.0.1)
		{80675,74,63.1,27.3,3,"LFR",imgs={"cata%d",4},indexOffset=1,patch="6.0.1",
			{416,42612,1,2,3,4,alt={843}},{417,42613,5,6,7,8,alt={844}}, -- dragon soul
		},

		-- mop (patch 6.0.1)
		{80633,390,83.16,30.56,4,"LFR",imgs={"mop%d",3},noSubtitle={[526]=true},patch="6.0.1",
			{527,42620,1,2,3,alt={830,2598}},{528,42621,4,5,6,alt={831,2597}},
			{529,42622,1,2,3,alt={832,2596}},{530,42623,4,5,6,alt={833,2595}},
			{526,42624,1,2,3,4,alt={834,2599}},
			{610,42625,1,2,3,alt={835,2594}},{611,42626,4,5,6,alt={836,2593}},{612,42627,7,8,9,alt={837,2592}},{613,42628,10,11,12,alt={838,2591}},
			{716,42629,1,2,4,alt={839,2590}},{717,42630,5,6,7,8,alt={840,2589}},{724,42631,9,10,11,alt={841,2588}},{725,42632,12,13,14,alt={842,2587}}
		},
		{78709,390,82.95,30.38,4,"SZN",addTo=2,order=2,noSubtitle=true,patch="6.0.1",
			{492,42511},{499,42512},{504,42513},{511,42514},{517,42515},{539,42516},{_(543,542),42517},{586,42519},{588,42523},{589,42520},{590,42522},{593,42518},{595,42521},{624,42524},{625,42525},{637,42526}
		},
		{78777,390,83.05,30.48,4,"SZHC",addTo=2,order=3,noSubtitle=true,patch="6.0.1",
			{639,42577},{646,42576},{647,42574},{648,42578},{649,42575},{652,42573}
		},

		-- WoD (patch 6.2.0) (same npc id and different location for alliance and horde)
		{_(94870,94870),_(582,590),_(33.2,41.5),_(37.2,47.0),5,"LFR",imgs={"wod%d_%s",3},indexOffset=1,patch="6.2.0",
			{849,44390,1,2,3,alt={1363}},{850,44391,4,5,6,alt={1364}},{851,44392,7,alt={1365}},
			{847,44393,1,2,7,alt={1359}},{846,44394,3,8,5,alt={1360}},{848,44395,4,6,9,alt={1361}},{823,44396,10,alt={1362}},
			{982,44397,1,2,3,alt={1366}},{983,44398,4,5,6,alt={1367}},{984,44399,7,8,11,alt={1368}},{985,44400,9,10,12,alt={1369}},{986,44401,13,alt={1370}},
		},

		-- legion (patch 7.0.3)
		{111246,627,63.6,55.6,6,"LFR",imgs={"legion%d",3},indexOffset=1,patch="7.0.3",
			{1287,37110,1,5,3,alt={1912,2844}},{1288,37111,2,4,6,alt={1927,2845}},{1289,37112,7,alt={1926,2846}},
			{1290,37113,1,2,3,alt={1925,2847}},{1291,37114,4,8,6,alt={1924,2848}},{1292,37115,5,7,9,alt={1923,2849}},{1293,37116,10,alt={1922,2850}},
			{1411,37117,1,2,3,alt={1921,2851}},
			{1494,37118,1,3,5,alt={1920,2835}},{1495,37119,2,4,6,alt={1919,2836}},{1496,37120,7,8,alt={1918,2848}},{1497,37121,9,alt={1917,2838}},
			{1610,37122,1,2,4,alt={1916,2821}},{1611,37123,5,3,6,alt={1915,2822}},{1612,37124,7,8,9,alt={1914,2823}},{1613,37125,10,11,alt={1913,2824}}
		},
		{31439,125,63.6,55.6,6,"LFR",addTo=6,order=2,imgs={"legion%d",3},info="旧达拉然（WotLK）中的时间也允许访问军团的LFR",indexOffset=1,patch="?",
			copyFrom = 111246
		},

		-- bfa (patch 9.0.5)
		{_(177193,177208),_(1161,1165),_(74.21,13.53),_(68.62,30.27),7,"LFR",imgs={"bfa%d_%s",3},indexOffset=false,patch="9.0.5",
			{1731,52303,1,2,3},{1732,52304,4,5,6},{1733,52305,7,8}, -- Uldir
			{_(1945,1948),_(52309,52306),1,2,3,name2group=true},{_(1946,1949),_(52310,52307),4,5,6},{_(1947,1950),_(52311,52308),7,8,9}, -- dazar'alor
			{1951,52312,1,2}, -- Crucible of Storms
			{2009,52313,1,3,2},{2010,52314,4,5,6},{2011,52315,7,8}, -- eternal palace
			{2036,52316,1,3,2},{2037,52317,4,6,5,7},{2038,52318,8,9,10},{2039,0,11,12}, -- ny'alotha (TODO: 2039 need check)
		},

		-- shadowlands (patch 10.1.5)
		{205959,1670,41.4,71.41,8,"LFR",imgs={"sl%d",2},patch="10.1.5",
			{2411,110020,2,4,6, alt={2090} },{2412,110037,3,5,7, alt={2091} },{2413,110036,1,8,9, alt={2092} },{2414,110035,10, alt={2096} }, -- castle nathria
			{2221,110034,1,2,3,alt={2341,2415}},{2222,110033,4,5,6,alt={2342,2416}},{2223,110032,7,8,9,alt={2343,2417}},{2224,110031,10,alt={2344,2418}}, -- Sanctum of Domination 9.1.0
			{2291,110030,2,4,7,alt={2345,2419}},{2292,110029,1,3,5,6,alt={2346,2420}},{2293,110028,8,9,10,alt={2347,2421}},{2294,110027,11,alt={2348,2422}}, -- Sepulcher of the First Ones 9.2.0
		},

		-- dragonflight (patch 12.0.5); why it was not added at 11.0.5 or 11.1.5?
		{262873, 2112, 58.48, 35.37, 9, "LFR",imgs={"df%d",3},patch="12.0.5",
			{2703,0,1,2,3,alt={2370}},{2705,1,4,5,6,alt={2371}},{2706,2,7,8,alt={2372}},
			{2704,3,1,2,3,alt={2399}},{2707,4,4,5,6,alt={2400}},{2708,5,7,8,alt={2401}},{2709,6,9, alt={2402}},
			{2710,7,1,2,3,alt={2466}},{2468,8,4,5,6,alt={2711}},{2712,9,7,8,alt={2467}},{2713,10,9,alt={2469}},
		},

		-- the war within (patch ??.??.??)
		-- still missing...
		{0, 0, 0, 0, 10, "LFR",imgs={"tww%d",3},patch="missing",
		 	{2649,0,1,2,3}, {2650,1,1,2,3}, {2651,2,1,2},
		 	{2780,3,1,2}, {2781,4,1,2}, {2782,5,1,2,3}, {2783,6,1},
		 	{2799,7,1,2,3}, {2800,8,1,2,3}, {2801,9,1,2,3},
		},

		-- midnight (patch ??.??.??)
		--{0, 0, 0, 0, 11, "LFR",imgs={"mn%d",3},patch="missing",
		-- 	{3126,0,1}, -- dream cut?
		-- 	{3156,1,1,2,3}, {3159,2,4,5,6}, {3160,3,7}, -- void spike
		-- 	{3155,4,1,2,3},
		--},

		-- last titan (patch ??.??.??)
		--{0, 0, 0, 0, 12, "LFR",imgs={"tlt%d",3},
		--},
	};

	local npcID2Index = {}

	for i=1, #data do
		local npcID,npcID2 = data[i][1];
		if data[i].altNPC then
			npcID2 = data[i].altNPC[1];
		end
		tinsert(LFRofthepast.npcs,data[i])
		local npcIndex = #LFRofthepast.npcs;
		npcID2Index[npcID] = npcIndex;
		for j=7, #data[i] do
			local e = data[i][j];
			--
			if not LFRofthepast.idx2gossipOptionID[npcID] then
				LFRofthepast.idx2gossipOptionID[npcID]={};
			end
			tinsert(LFRofthepast.idx2gossipOptionID[npcID],e[2]);
			if npcID2 then
				LFRofthepast.idx2gossipOptionID[npcID2] = LFRofthepast.idx2gossipOptionID[npcID];
			end
			--
			if not LFRofthepast.npc2instance[npcID] then
				LFRofthepast.npc2instance[npcID] = {}
			end
			LFRofthepast.npc2instance[npcID][e[2]] = e[1];
			if npcID2 then
				LFRofthepast.npc2instance[npcID2] = LFRofthepast.npc2instance[npcID];
			end
			--
			if e.name2group then
				LFRofthepast.instanceName2group[e[1]] = e.name2group;
			end
			--
			if e[3] then
				LFRofthepast.instance2bosses[e[1]] = {}
				for k=3, #e do
					tinsert(LFRofthepast.instance2bosses[e[1]],e[k]);
				end
				if e.alt then
					-- This part catching a problem with GetInstanceInfo() that could return a different instanceID than expected.
					local N = GetLFGDungeonNumEncounters(e[1])
					for a=1, #e.alt do
						local nAlt = GetLFGDungeonNumEncounters(e.alt[a])
						if nAlt<N then
							-- some lfr wings have multiple ids with different GetLFGDungeonNumEncounters() results.
							local b = {}
							for n=0, nAlt do
								tinsert(b,n)
							end
							LFRofthepast.instance2bosses[e.alt] = b;
						else
							LFRofthepast.instance2bosses[e.alt] = LFRofthepast.instance2bosses[e[1]]
						end
					end
				end
			end
			--
			LFRofthepast.gossipIndexOffset[npcID] = data[i].indexOffset==nil and 0 or data[i].indexOffset;
			--
			if data[i].noSubtitle then
				LFRofthepast.noSubtitle[npcID] = data[i].noSubtitle;
			end
		end

		if data[i].copyFrom and npcID2Index[data[i].copyFrom] then
			local d = LFRofthepast.npcs[npcID2Index[data[i].copyFrom]];
			for j=7, #d do
				tinsert(data,d[j]);
			end
		end
	end

	UpdateNpcData()
end


local HST = LibStub("HizurosSharedTools")
HST.RegisterPrint(LFRofthepast,addon,"LFRotp");

local ACD = LibStub("AceConfigDialog-3.0");
local LDB = LibStub("LibDataBroker-1.1");
local LDBIcon = LibStub("LibDBIcon-1.0", true);

local buttons,hookedButton,NPC_ID,db = {},{};
local iconTexCoords,killedEncounter,BossKillQueryUpdate,UpdateInstanceInfoLock = {},{},false,false;
local imgSize,imgPath = 168,"Interface\\AddOns\\LFR_of_the_past\\media\\";
local ImmersionFrame = _G["ImmersionFrame"];
local TomTom = _G["TomTom"];
local LC = LibStub("LibColors-1.0");
local C = LC.color;
LC.colorset({
	["ltyellow"]	= "fff569",
	["dkyellow"]	= "ffcc00",
	["ltorange"]	= "ff9d6a",
	["dkorange"]	= "905d0a",
	["ltred"]		= "ff8080",
	["ltred2"]		= "ff4040",
	["dkred"]		= "800000",
	["violet"]		= "f000f0",
	["ltviolet"]	= "f060f0",
	["dkviolet"]	= "800080",
	["ltblue"]		= "69ccf0",
	["dkblue"]		= "000088",
	["dailyblue"]	= "00b3ff",
	["ltcyan"]		= "80ffff",
	["dkcyan"]		= "008080",
	["ltgreen"]		= "80ff80",
	["dkgreen"]		= "00aa00",
	["dkgray"]		= "404040",
	["gray2"]		= "A0A0A0",
	["ltgray"]		= "b0b0b0",
	["gold"]		= "ffd700",
	["silver"]		= "eeeeef",
	["copper"]		= "f0a55f",
	["unknown"]		= "ee0000",
});
local skull = "|T337496:12:12:0:0:32:32:0:16:0:16|t ";
local GossipTextPattern = {};
do
	local colors = {enemy="dkred",enemyClear="dkgreen",enemyDarkBG="ltred2",enemyClearDarkBG="green"}
	for k,v in pairs(colors)do
		GossipTextPattern[k] = "%s\n"..skull..C(v,"%d/%d");
	end
end
GossipTextPattern.raidWing = " "..C("dkgray","|| %s");
GossipTextPattern.raidWingDarkBG = " "..C("gray","|| %s");
GossipTextPattern.raidWingImmersion = "%1$s\n"..C("gray","%4$s").."\n"..skull..C("ltred2","%2$d/%3$d");
GossipTextPattern.raidWingImmersionClear = "%1$s\n"..C("gray","%4$s").."\n"..skull..C("green","%2$d/%3$d");

function LFRofthepast.faction(isNeutral)
	local faction = (UnitFactionGroup("player") or "neutral"):lower();
	if isNeutral then
		return faction=="neutral";
	end
	return faction;
end

local function ScanSavedInstances()
	for index=1, (GetNumSavedInstances()) do
		local instanceName, _, instanceReset, instanceDifficulty, _, _, _, _, _, _, _, encounterProgress = GetSavedInstanceInfo(index);
		if (instanceDifficulty==7 or instanceDifficulty==17) and encounterProgress>0 and instanceReset>0 then
			local encounters,ttInfo = {}, C_TooltipInfo.GetInstanceLockEncountersComplete(index)
			if ttInfo and ttInfo.lines then
				for i=2, #ttInfo.lines, 2 do
					encounters[ttInfo.lines[i]] = ttInfo.lines[i+1]==BOSS_DEAD;
				end
				killedEncounter[instanceName.."-"..instanceDifficulty] = encounters;
			end
		end
	end
	UpdateInstanceInfoLock = false;
end

local function GetInstanceDataByID(instanceID)
	local data = {
		groupName = false,
		instanceID = instanceID,
		instanceInfo = {},
		encounters = {},
		numEncountersKilled=0,
	};
	local info = {};
	info.name, info.typeID, info.subtypeID, info.minLevel, info.maxLevel, info.recLevel, info.minRecLevel, info.maxRecLevel, info.expansionLevel,
	info.groupID, info.textureFilename, info.difficulty, info.maxPlayers, info.description, info.isHoliday, info.bonusRepAmount, info.minPlayers,
	info.isTimeWalker, info.name2, info.minGearLevel, info.isScalingDungeon, info.lfgMapID = GetLFGDungeonInfo(instanceID);
	data.instanceInfo = info;
	if info.name~=info.name2 or LFRofthepast.instanceName2group[instanceID] then
		data.groupName = info.name2;
	end

	local encounters,list,killed = {},{},0
	if LFRofthepast.instance2bosses[instanceID] then
		list = LFRofthepast.instance2bosses[instanceID];
	else
		local num = GetLFGDungeonNumEncounters(instanceID) or 0;
		for i=1, num do
			tinsert(list,i);
		end
	end

	for _, index in ipairs(list)do
		local boss, _, isKilled = GetLFGDungeonEncounterInfo(instanceID,index);
		local n = (info.name2 or info.name).."-"..info.difficulty;
		if not isKilled and killedEncounter[n] and killedEncounter[n][boss] then -- from saved instances
			isKilled = true;
		end
		tinsert(encounters,{index=index,name=boss,isKilled=isKilled})
		if isKilled then
			killed=killed+1;
		end
	end

	data.encounters, data.numEncountersKilled = encounters, killed;

	return data;
end

local function RequestRaidInfoUpdate()
	if BossKillQueryUpdate then
		RequestRaidInfo();
	end
end

local function UpdateNpcID(dataTable)
	-- get npcID from creature guid string
	-- https://warcraft.wiki.gg/wiki/API_UnitGUID
	local npcGUID = UnitGUID("npc");
	if issecretvalue(npcGUID) and not canaccessvalue(npcGUID) then
		-- secret value is the biggest bullshit on earth. breaking 99.9% of the time non combat/non raid addons.
		NPC_ID = nil;
		return;
	end
	local _,_,_,_,_,npdId = strsplit('-',npcGUID);
	NPC_ID = tonumber(npdId);
	return (NPC_ID and LFRofthepast.npcID[NPC_ID] and dataTable and not IsControlKeyDown());  -- and db.profile.replaceOptions
end

----------------------------------------------------
--- GossipFrame entries

local function buttonHook_OnEnter(self)
	if not (NPC_ID and LFRofthepast.npcID[NPC_ID]) then return end  -- and db.profile.replaceOptions
	local instanceID
	if ImmersionFrame then
		instanceID = self.data.instanceID;
	elseif self.GetElementData then
		local option = self.GetElementData()
		if option.info and option.info.instanceID then
			instanceID = option.info.instanceID;
		elseif LFRofthepast.npc2instance[NPC_ID] and LFRofthepast.npc2instance[NPC_ID][option.info.gossipOptionID] then
			instanceID = LFRofthepast.npc2instance[NPC_ID][option.info.gossipOptionID];
		else
			instanceID = option.index; --really? maybe deprecated
		end
	end

	ScanSavedInstances()
	local data = GetInstanceDataByID(instanceID);
	if not data then
		return
	end

	-- prepare instance encounter list
	--local bosses = GetInstanceBosses(data.instanceID); -- remove

	if data.instanceInfo.description=="" and #data.encounters==0 then
		return; -- don't display tooltip without more than the title (instance name)
	end

	-- set anchoring and ownership of the tooltip
	GameTooltip:SetOwner(self,"ANCHOR_NONE");
	if ImmersionFrame then
		GameTooltip:SetPoint("RIGHT",self,"LEFT",-4,0)
	else
		GameTooltip:SetPoint("LEFT",GossipFrame,"RIGHT");
	end

	local showID = "";
	if false then -- TODO: Add db option to show instance id
		showID = " " .. C("ltblue","("..data.instanceID..")");
	end

	-- instance name
	GameTooltip:AddLine(data.instanceInfo.name.. showID);

	-- instance group name (for raids splitted into multible lfr instances)
	local noSubtitle = (type(LFRofthepast.noSubtitle[NPC_ID])=="table" and LFRofthepast.noSubtitle[NPC_ID][data.instanceID]==true) or LFRofthepast.noSubtitle[NPC_ID]==true;
	if (not noSubtitle) and data.instanceInfo.name~=data.instanceInfo.name2 then
		GameTooltip:AddLine(C("gray",data.instanceInfo.name2));
	end

	-- instance description
	if data.instanceInfo.description and data.instanceInfo.description~="" then
		GameTooltip:AddLine(" ");
		GameTooltip:AddLine(data.instanceInfo.description,1,1,1,1);
	end

	-- instance encounter list
	if #data.encounters>0 then
		GameTooltip:AddLine(" ");
		for i, encounter in ipairs(data.encounters)do
			local info = C("ltgray"," (insId: ".. data.instanceID .." / lfrBoss: "..i.." / raidBoss: "..encounter.index..")");
			if encounter.name then
				GameTooltip:AddDoubleLine(C("ltblue",encounter.name)..(IsShiftKeyDown() and info or ""),encounter.isKilled and C("red",BOSS_DEAD) or C("green",BOSS_ALIVE));
			else
				GameTooltip:AddDoubleLine(C("ltred",_G["ERR_INTERNAL_ERROR"]),info);
			end
		end
	end

	if IsShiftKeyDown() then
		GameTooltip:AddLine(" ")
		GameTooltip:AddDoubleLine(C("ltgray","DebugMode"),C("ltgray","2.0.1-release / "..GetLocale()))
	end

	GameTooltip:Show();
end

local function buttonHook_OnLeave()
	GameTooltip:Hide();
end

hooksecurefunc(GossipOptionButtonMixin, "Setup", function(self, optionInfo)
	if not hookedButton[self] then
		hookedButton[self] = true;
		self:HookScript("OnEnter",buttonHook_OnEnter);
		self:HookScript("OnLeave",buttonHook_OnLeave);
	end
	if optionInfo.name:match("T337496:12:12:0:0:32:32:0:16:0:16") and optionInfo.icon==1502548 then
		self.Icon:SetTexCoord(0.15,0.85,0.15,0.85); -- make raid icon a little bit bigger
	else
		self.Icon:SetTexCoord(0,1,0,1);
	end
end);

GossipFrame:HookScript("OnShow",function(self)
	if not UpdateNpcID(type(GossipFrame.gossipOptions)=="table") then
		return
	end

	wipe(buttons);
	wipe(iconTexCoords);
	ScanSavedInstances();

	-- update options before layout gossip buttons; very smart. ;-) Thanks at fuba82.
	for i,option in ipairs(GossipFrame.gossipOptions) do
		local instanceID,data;
		if LFRofthepast.npc2instance[NPC_ID] and LFRofthepast.npc2instance[NPC_ID][option.gossipOptionID] then
			instanceID = LFRofthepast.npc2instance[NPC_ID][option.gossipOptionID];
		else
			instanceID = LFRofthepast.npc2instance[NPC_ID][option.orderIndex + (LFRofthepast.gossipIndexOffset[NPC_ID] or 0)];
		end
		data = GetInstanceDataByID(instanceID);
		if data then
			option.nameOrig = option.name;
			option.instanceID = instanceID;

			local noSubtitle = (type(LFRofthepast.noSubtitle[NPC_ID])=="table" and LFRofthepast.noSubtitle[NPC_ID][option.instanceID]==true) or LFRofthepast.noSubtitle[NPC_ID]==true;

			-- replace gossip icon (interface/minimap/raid)
			option.icon = 1502548;

			-- replcae gossip text
			if #data.encounters==0 then
				option.name = data.instanceInfo.name; -- mostly for szenarios
			else
				local dark = ""; --db.profile.darkBackground and "DarkBG" or ""
				local clear = #data.encounters==data.numEncountersKilled and "Clear" or "";
				local pattern = GossipTextPattern["enemy"..clear..dark];
				if (not noSubtitle) and data.instanceInfo.name~=data.instanceInfo.name2 then
					pattern = pattern .. GossipTextPattern["raidWing"..dark];
				end
				option.name = pattern:format(
					data.instanceInfo.name, -- instance wing name
					data.numEncountersKilled, -- encounters killed this week
					#data.encounters, -- number of encounters of the wing
					data.instanceInfo.name2
				);
			end
		end
	end
end);

GossipFrame:HookScript("OnHide",function()
	for icon, texCoord in pairs(iconTexCoords)do
		icon:SetTexCoord(unpack(texCoord));
		iconTexCoords[icon]=nil;
	end
end);

local function OnImmersionShow()
	if not UpdateNpcID(type(ImmersionFrame.TitleButtons.Buttons)=="table") then
		return;
	end

	wipe(buttons);
	wipe(iconTexCoords);
	ScanSavedInstances();

	local updated,instanceID,buttonID,gossipOptionID = false;
	for i,button in ipairs(ImmersionFrame.TitleButtons.Buttons)do
		updated,instanceID,buttonID,gossipOptionID = false;
		if button:IsShown() and button.type=="Gossip" then
			buttonID = button.idx
			if button.gossipOptionID then
				gossipOptionID = button.gossipOptionID
			elseif LFRofthepast.idx2gossipOptionID[NPC_ID] and #LFRofthepast.idx2gossipOptionID[NPC_ID]>0 then
				gossipOptionID = LFRofthepast.idx2gossipOptionID[NPC_ID][buttonID]
			end
			if gossipOptionID then
				instanceID = LFRofthepast.npc2instance[NPC_ID][gossipOptionID];
			end
			if instanceID then
				local data = GetInstanceDataByID(instanceID)
				button.data = data;
				local noSubtitle = (type(LFRofthepast.noSubtitle[NPC_ID])=="table" and LFRofthepast.noSubtitle[NPC_ID][instanceID]==true) or LFRofthepast.noSubtitle[NPC_ID]==true;
				-- gossip text replacement
				if #data.encounters==0 then
					button:SetText(data.instanceInfo.name)
				else
					local clear = #data.encounters==data.numEncountersKilled and "Clear" or "";
					local pattern = GossipTextPattern["enemy"..clear.."DarkBG"];
					if (not noSubtitle) and (data.instanceInfo.name~=data.instanceInfo.name2 or LFRofthepast.instanceName2group[instanceID]) then
						pattern = GossipTextPattern["raidWingImmersion"..clear];
					end
					button:SetFormattedText(
						pattern,
						data.instanceInfo.name, -- name of instance wing
						data.numEncountersKilled, -- killed  encounters
						#data.encounters, -- number of encounters in this wing
						data.instanceInfo.name2 -- raid name
					)
				end

				-- gossip icon replacement
				iconTexCoords[button.Icon] = {button.Icon:GetTexCoord()};
				button.Icon:SetTexture(1502548); -- interface\\minimap\\raid
				button.Icon:SetTexCoord(0.20,0.80,0.20,0.80);

				if not hookedButton["button"..buttonID] then
					local fnc = (button:GetScript("OnEnter")==nil and "Set" or "Hook") .. "Script";
					button[fnc](button,"OnEnter",buttonHook_OnEnter);
					button[fnc](button,"OnLeave",buttonHook_OnLeave);
					hookedButton["button"..buttonID] = true;
				end
				buttons[buttonID] = data;
			end
		end
	end
end

local function ImmersionFrame_GossipShow()
	C_Timer.After(0.1,OnImmersionShow);
end

local function ImmersionFrame_OnHide()
	for icon, texCoord in pairs(iconTexCoords)do
		icon:SetTexCoord(unpack(texCoord));
		iconTexCoords[icon]=nil;
	end
end

----------------------------------------------------
-- create info tooltip for raids

local function CreateEncounterTooltip(parent, append)
	if not IsInRaid() then
		return
	end
	ScanSavedInstances()
	local instanceName, _, difficultyID, difficultyName, _, _, _, instanceMapID, _, instanceID = GetInstanceInfo()
	local data
	if difficultyID==7 or difficultyID==17 then
		data = GetInstanceDataByID(instanceID)
	end
	if data then
		if not append then
			GameTooltip:SetOwner(parent,"ANCHOR_NONE");
			local point,relPoint,y,rectLeft,rectBottom = "TOP","BOTTOM",-5,parent:GetRect();
			if GetScreenHeight()/2>rectBottom then
				point,relPoint,y = "BOTTOM","TOP",5
			end
			GameTooltip:SetPoint(point,parent,relPoint,0,y);
		end

		GameTooltip:SetText(instanceName);
		GameTooltip:AddLine(difficultyName,1,1,1);

		GameTooltip:AddLine(" ");

		GameTooltip:AddLine(C("ltblue",data.instanceInfo.name));
		for _, encounter in ipairs(data.encounters)do
			GameTooltip:AddDoubleLine("|Tinterface/questtypeicons:14:14:0:0:128:64:0:18:36:54|t "..encounter.name,encounter.isKilled and C("red",BOSS_DEAD) or C("green",BOSS_ALIVE));
		end

		GameTooltip:Show();
		if append then
			return true;
		end
	end
end

-- QueueStatusFrame hook to add tooltip to the QueueStatusFrame tooltip
QueueStatusFrame:HookScript("OnShow",function(parent)
	--if db.profile.queueStatusFrameETT then
		CreateEncounterTooltip(parent);
	--end
end);

QueueStatusFrame:HookScript("OnHide",function(parent)
	GameTooltip:Hide();
end);

----------------------------------------------------
--[[ addon option panel

local dbDefaults = {
	profile = {
		AddOnLoaded = true,
		minimap = {hide=false},
		minimapButtonETT = false,
		queueStatusFrameETT = true,
		darkBackground = false,
		replaceOptions = true,
	}
};

local function getset(info,value)
	local key = info[#info];
	if value~=nil then
		if key=="minimap" then
			db.profile[key].hide = not value;
			LDBIcon:Refresh(addon);
			return;
		end
		db.profile[key] = value;
		return;
	end
	if key=="minimap" then
		return not db.profile[key].hide;
	end
	return db.profile[key];
end

local options = {
	type = "group",
	name = L[addon],
	get = getset,
	set = getset,
	childGroups = "tab",
	args = {
		AddOnLoaded = {
			type = "toggle", order = 1,
			name = L["AddOnLoaded"], desc = L["AddOnLoadedDesc"].."|n|n|cff44ff44"..L["AddOnLoadedDescAlt"].."|r"
		},
		minimap = {
			type = "toggle", order = 2,
			name = L["MinimapIcon"], desc = L["MinimapIconDesc"]
		},
		npcOptions = {
			type = "group", order = 3, inline = true,
			name = L["LFR NPCs"],
			args = {
				replaceOptions = {
					type = "toggle", order = 1,
					name = L["Replace options"], desc = L["Replace text of option entries on lfr npcs"]
				},
				darkBackground = {
					type = "toggle", order = 2,
					name = L["DarkBackground"], desc = L["DarkBackgroundDesc"],
					disabled = function()
						return not db.profile.replaceOptions
					end
				},
			},
		},
		encounterTooltips = {
			type = "group", order = 4, inline = true,
			name = L["EncounterTooltip"],
			args = {
				minimapButtonETT = {
					type = "toggle", order = 3,
					name = L["MinimapETT"], desc = L["MinimapETTDesc"],
				},
				queueStatusFrameETT = {
					type = "toggle", order = 4,
					name = L["InstanceEyeETT"], desc = L["InstanceEyeETTDesc"],
				},
			}
		},
		neutral = {
			type = "description", order = 5, fontSize = "large",
			name = L["PlayerNeutral"],
		},
		info = {
			type = "description", order = 6, fontSize = "medium",
			name = L["InfoMsg"]
		},
		-- npcs added by function updateOptions
	}
};

local function RegisterOptions()
	db = LibStub("AceDB-3.0"):New("LFRotp_Options",dbDefaults,true);
	LibStub("AceConfig-3.0"):RegisterOptionsTable(L[addon], options);
	local opts = LibStub("AceConfigDialog-3.0"):AddToBlizOptions(L[addon]);
	HST.BlizzOptions_ExpandOnShow(opts);
	HST.AddCredit(L[addon]); -- options.args.credits.args
	ACD:SetDefaultSize(L[addon],700,700)
end

local function createDescription(npc)
	if npc[1]==0 then
		return {
			type = "description", fontSize="large",]]
			--name = L["StillMissingNPC"..npc[5]]
		--[[};
	end
	local colon = CHAT_HEADER_SUFFIX:trim()
	local npcName = L["Currently unknown"];
	if rawget(L,"NPC"..npc[1]) then]]
		--npcName = L["NPC"..npc[1]];
	--[[end
	local lines = {
		C("dkyellow",NAME..colon) .." ".. npcName,
		C("dkyellow",ZONE..colon) .." ".. (npc[3]==false and L["Somewhere in"].." "..npc.zoneName.."?" or npc.zoneName),
	};
	if npc[3] and npc[4] then
		tinsert(lines,C("dkyellow",L["Coordinates"]..colon) .." ".. npc[3]..", "..npc[4]);
	end
	if type(npc.info)=="string" then
		tinsert(lines,C("dkyellow",INFO..colon).." "..C("ltgreen",npc.info))
	end
	return {
		type = "description", order = 1, fontSize = "medium", width="double",
		name = table.concat(lines,"|n")
	}
end

local function addWaypointToOpt(opt,npc)
	opt.args.TomTom = {
		type = "execute", order = 2, width="half",
		name = L["TomTom"],
		func = function()]]
			--HST.AddWaypoint(npc[2],npc[3],npc[4],L["NPC"..npc[1]],addon,true,false)
		--[[end,
		hidden =function() return TomTom and TomTom.AddWaypoint end
	}
	opt.args.MapPin = {
		type = "execute", order = 4, width="half",
		name = MAP_PIN, desc = L["MapPinDesc"],
		func = function()]]
			--HST.AddWaypoint(npc[2],npc[3],npc[4],L["NPC"..npc[1]],addon,false,false)
		--[[end
	}
end

local function updateOptions()
	local faction = LFRofthepast.faction();

	options.args.neutral.hidden=true;
	ScanSavedInstances()

	for i=1, #LFRofthepast.npcs do
		local npc = LFRofthepast.npcs[i];
		if npc.addTo then
			local opt = {
				type="group", order=npc.order+1, inline=true,
				name="",
				args = {
					desc = createDescription(npc)
				}
			}
			if npc[3] and npc[4] then
				addWaypointToOpt(opt,npc);
			end
			options.args["entry"..npc.addTo].args.location.args["npc"..npc.order] = opt;
		else
			local opt = {
				type = "group",order = 10+i,]]
				--name = _G["EXPANSION_NAME"..npc[5]],
				--[[childGroups="tab",
				args = {
					location = {
						type="group", order=1,
						name=LOCATION_COLON:gsub(HEADER_COLON,""),
						args= {
							npc1 = {
								type="group", order=2, inline=true,]]
								--name="", --L["NPC"..npc[1]],
								--[[args = {
									desc = createDescription(npc)
								}
							}
						}
					},
					info = {
						type ="group", order = 2, hidden=true,
						name = INFO,
						args = {
						}
					}
				}
			}
			if npc[1]>0 and npc[3] and npc[4] then
				addWaypointToOpt(opt.args.location.args.npc1,npc);
			end
			if npc.imgs then
				opt.args["pics_spacer"] = {
					type="description", order = 10, name= " "
				}
				for I=1, npc.imgs[2] do
					opt.args.location.args["pic"..I] = {
						type = "description", order = 10+I, width = "normal", name = "",
						image = imgPath..npc.imgs[1]:format(I,faction), imageWidth = imgSize, imageHeight = imgSize
					}
				end
			end
			local order = 1;
			for j=7, #npc do
				local instanceID = npc[j][1];
				local instanceData = GetInstanceDataByID(instanceID);
				if instanceData then
					local entry = {
						type = "group", order = order, inline=true,
						name = instanceData.instanceInfo.name
							.. (instanceData.groupName and " "..C("ltgray","("..instanceData.groupName..")") or "")
							--.. C("ltgray"," ("..instanceID..")")
							,
						args = {
						}
					}
					entry.args.desc = {
						type = "description", order=2, fontSize="medium",
						name = instanceData.instanceInfo.description
					}
					if instanceData.encounters then
						local encounterEntries = {}
						for _,encounter in ipairs(instanceData.encounters)do
							local color = "yellow";
							local name = UNKNOWN
							if encounter.name then
								color = encounter.isKilled and "red" or "green";
								name = "   |Tinterface\\lfgframe\\lfg:14:14:0:0:64:32:0:32:0:32|t"..encounter.name
							else
								LFRofthepast:debug(instanceID)
							end
							tinsert(encounterEntries,C(color,name));
						end
						entry.args.encounters = {
							type = "description", order=2, fontSize="medium",
							name = table.concat(encounterEntries,"|n")
						}
					end

					opt.args.info.args["instance-"..instanceID] = entry;
					opt.args.info.hidden=false;
					order=order+1;
				end
			end
			options.args["entry"..i] = opt;
		end
	end
end

----------------------------------------------------
-- LibDataBroker

--local function LDBObject_OnEnter(self)end
--local function LDBObject_OnLeave(self)end

local function LDBObject_OnClick(self,button)
	--if button=="LeftButton" then
	--else]]
		--if ACD.OpenFrames[L[addon]]~=nil then
			--[[ACD:Close(L[addon]);
		else
			ACD:Open(L[addon]);]]
			--ACD.OpenFrames[L[addon]]:SetStatusText(GAME_VERSION_LABEL..CHAT_HEADER_SUFFIX.."2.0.1-release");
		--[[end
	--end
end

local function RegisterDataBroker()
	if not LDB then return end

	local LDBObject = LDB:NewDataObject(addon,{
		type		= "data source",
		icon		= "interface\\lfgframe\\ui-lfg-icon-heroic",
		iconCoords	= {0,0.55,0,0.55},
		label		= L[addon],
		text		= L[addon],
		OnTooltipShow = function(tt)
			if db.profile.minimapButtonETT and CreateEncounterTooltip(tt,true) then
				return;
			end

			tt:AddLine(L[addon]);
			for _,npc in ipairs(LFRofthepast.npcs) do
				if rawget(L,"NPC"..npc[1]) then
					tt:AddLine(" ");
					if npc[3] then]]
						--tt:AddLine(L["NPC"..npc[1]].." "..C("mage","(".. _G["EXPANSION_NAME"..npc[5]]..")"),.3,1,.3);
						--[[tt:AddLine(npc.zoneName..", "..npc[3]..", "..npc[4],.7,.7,.7);
						if type(npc.info)=="string" then
							tt:AddLine(npc.info,.7,.9,.9,true)
						end
					else]]
						--tt:AddLine(L["Currently unknown"].." "..C("mage","(".. _G["EXPANSION_NAME"..npc[5]]..")"),.3,1,.3);
						--[[tt:AddLine(L["Somewhere in"].." "..npc.zoneName.."?",.7,.7,.7)
					end
				end
			end
			tt:AddLine(" ");
			tt:AddLine(C("copper",L["Click"]).." || "..C("green",L["Open LFR [of the past] info panel"]));
		end,
		--OnEnter = LDBObject_OnEnter,
		--OnLeave = LDBObject_OnLeave,
		OnClick = LDBObject_OnClick
	});

	if LDBIcon then
		LDBIcon:Register(addon, LDBObject, db.profile.minimap);
	end
end]]

----------------------------------------------------
-- event frame
local LFRofthepastFrame = CreateFrame("frame");
LFRofthepastFrame:SetScript("OnEvent",function(self,event,...)
	--[[if event=="ADDON_LOADED" then
		if addon==... then
			if LFRotp_Options==nil then
				LFRotp_Options = {};
			end

			RegisterOptions();

			RegisterDataBroker();

			if db.profile.AddOnLoaded or IsShiftKeyDown() then
				LFRofthepast:print(L["AddOnLoaded"]);
			end
		elseif (...=="Immersion" or ImmersionFrame) and not immersionHook then
			immersionHook = true;
			hooksecurefunc(ImmersionFrame,"GOSSIP_SHOW",ImmersionFrame_GossipShow);
			ImmersionFrame:HookScript("OnHide",ImmersionFrame_OnHide);
		end
	elseif not LFRofthepast.faction(true) and (event=="PLAYER_LOGIN" or event=="NEUTRAL_FACTION_SELECT_RESULT") then]]
	if not LFRofthepast.faction(true) and (event=="PLAYER_LOGIN" or event=="NEUTRAL_FACTION_SELECT_RESULT") then
		RequestRaidInfo();
		LFRofthepast.load_data();
		--updateOptions();
	elseif event=="BOSS_KILL" then
		BossKillQueryUpdate=true;
		C_Timer.After(0.16,RequestRaidInfoUpdate);
	elseif event=="UPDATE_INSTANCE_INFO" then
		BossKillQueryUpdate=false;
		if not UpdateInstanceInfoLock then
			UpdateInstanceInfoLock = true;
			C_Timer.After(0.3,ScanSavedInstances);
		end
	end
end);
LFRofthepastFrame:RegisterEvent("ADDON_LOADED");
LFRofthepastFrame:RegisterEvent("PLAYER_LOGIN");
LFRofthepastFrame:RegisterEvent("NEUTRAL_FACTION_SELECT_RESULT");
LFRofthepastFrame:RegisterEvent("BOSS_KILL");
LFRofthepastFrame:RegisterEvent("UPDATE_INSTANCE_INFO");
LFRofthepastFrame:RegisterEvent("RAID_INSTANCE_WELCOME");
