--[[
******************************************************************************************
AvgItemLvl 1.1.7
Description: Displays the equipped average item level on the tooltip and character sheet.

Author: Sindragosa
******************************************************************************************
]]--

AvgItemLvl = CreateFrame("Frame");

local UnitIsPlayer = UnitIsPlayer;
local UnitIsUnit = UnitIsUnit;
local UnitExists = UnitExists;
local UnitCanCooperate = UnitCanCooperate;
local UnitIsVisible = UnitIsVisible;
local UnitName = UnitName;
local UnitLevel = UnitLevel;
local UnitClass = UnitClass;
local UnitGUID = UnitGUID;
local GetItemInfo = GetItemData or GetItemInfo;
local CanInspect = CanInspect;
local CheckInteractDistance = CheckInteractDistance;
local GetMouseFocus = GetMouseFocus;
local GetTime = GetTime;
local GetRealmName = GetRealmName;
local InCombatLockdown = InCombatLockdown;
local format = format;
local floor = floor;
local strmatch = strmatch;
local strlower = strlower;

local RETRIEVING = RETRIEVING_DATA..CONTINUED;
local INSPECT_DELAY = 0.1;
local INSPECTS_PER_INTERVAL = 6;
local INSPECT_RESET_TIMER = 10;
local ITEM_LEVEL_PREFIX = STAT_AVERAGE_ITEM_LEVEL..":|cffffffff ";
local inspectsLeft = INSPECTS_PER_INTERVAL;
local inspectResetAt = 0;
local realmName = GetRealmName();

local cache = {};
local currentGuid;
local RESILIENCE = strlower(RESILIENCE or "resilience");
local SPELL_PENETRATION = strlower(SPELL_PENETRATION or "penetration");
local STAT_PVP_POWER = strlower(STAT_PVP_POWER or "pvp power");

local ShowAvgItemLevel;
local ScanGear;

AvgItemLvl.scanTooltip = CreateFrame("GameTooltip", "AvgItemLvl_ScanTip", nil, "GameTooltipTemplate");
AvgItemLvl.scanTooltip:SetOwner(UIParent, "ANCHOR_NONE");

AvgItemLvl.cache = cache;

local itemSlots = { "HeadSlot", "NeckSlot", "ShoulderSlot", "BackSlot", "ChestSlot", "WristSlot", "HandsSlot", "WaistSlot", "LegsSlot", "FeetSlot",
	"Finger0Slot", "Finger1Slot", "Trinket0Slot", "Trinket1Slot", "MainHandSlot", "SecondaryHandSlot" }; -- TabardSlot, ShirtSlot, RangedSlot

local pvpOnly = { Trinket0Slot = 1, Trinket1Slot = 1, MainHandSlot = 1, SecondaryHandSlot = 1 };
local upgradeTable = {
	[0]		=  0,
	[1]		=  8, -- 1/1
	[373]	=  4, -- 1/2
	[374]	=  8, -- 2/2
	[375]	=  4, -- 1/3
	[376]	=  4, -- 2/3
	[377]	=  4, -- 3/3
	[379]	=  4, -- 1/2
	[380]	=  4, -- 2/2
	[445]	=  0, -- 0/2
	[446]	=  4, -- 1/2
	[447]	=  8, -- 2/2
	[451]	=  0, -- 0/1
	[452]	=  8, -- 1/1
	[453]	=  0, -- 0/2
	[454]	=  4, -- 1/2
	[455]	=  8, -- 2/2
	[456]	=  0, -- 0/1
	[457]	=  8, -- 1/1
	[458]	=  0, -- 0/4
	[459]	=  4, -- 1/4
	[460]	=  8, -- 2/4
	[461]	= 12, -- 3/4
	[462]	= 16, -- 4/4
};

local AvgItemLvl_LDB = LibStub:GetLibrary("LibDataBroker-1.1"):NewDataObject("AvgItemLvl", {
	type = "launcher",
	icon = "Interface\\Icons\\INV_Sword_130",
	text = "0.0",
});

local function tnum(t)
	local n = 0;
	for k, v in pairs(t) do
		n = n + 1;
	end
	return n;
end

local function GetGlobalUnitName(unit)
	if (not unit) then
		return nil;
	end
	local name, server = UnitName(unit);
	return server and server ~= "" and name .. "-" .. server or name .. "-" .. realmName;
end

local function ShowTooltip(owner, unit, anchor)
	local avgItemLvl = "";
	local unitName = GetGlobalUnitName(unit);
	if (unitName and cache[unitName] and cache[unitName].avgItemLvl) then
		avgItemLvl = format("|cffffffff%.2f|r", cache[unitName].avgItemLvl);
	elseif (unit == "player") then
		local _, itemLevel = GetAverageItemLevel();
		avgItemLvl = format("|cffffffff%.2f|r", itemLevel);
	end
	GameTooltip:SetOwner(owner, anchor);
	GameTooltip:AddDoubleLine("Average Equipped Item Level", avgItemLvl);
	if (unit == "player") then
		GameTooltip:AddLine("|cffffffffThe average Item Level of your current equipment.|r");
	else
		GameTooltip:AddLine(format("|cffffffffThe average Item Level of %s's current equipment.|r", UnitName(unit)));
	end
	GameTooltip:Show();
end

AvgItemLvl_LDB.OnEnter = function(self) ShowTooltip(self, "player", "ANCHOR_BOTTOMLEFT"); end
AvgItemLvl_LDB.OnLeave = function() GameTooltip:Hide(); end

--------------------------------------------------------------------------------------------------------
--                                             Item Level                                             --
--------------------------------------------------------------------------------------------------------

AvgItemLvl.scanTooltip.itemTable = {};
function ScanGear(unit, guid)
	AvgItemLvl.scanTooltip.itemCount = 0;
	if (AvgItemLvl.scanTooltip.itemScan) then
		AvgItemLvl.scanTooltip.itemScan = nil;
		AvgItemLvl.scanTooltip.unit = nil;
		AvgItemLvl.scanTooltip.guid = nil;
		wipe(AvgItemLvl.scanTooltip.itemTable);
		AvgItemLvl.itemsLoaded = nil;
	end
	-- Check all item slots
	if (not AvgItemLvl.itemsLoaded) then
		for i = 1, #itemSlots do
			local textureName = GetInventoryItemTexture(unit, i);
			if textureName then
				if not (unit == "player") then
					AvgItemLvl.scanTooltip.itemCount = AvgItemLvl.scanTooltip.itemCount + 2;
				else
					AvgItemLvl.scanTooltip.itemCount = AvgItemLvl.scanTooltip.itemCount + 1;
				end
			end
		end
		if (AvgItemLvl.scanTooltip.itemCount == 0) and (unit and guid == currentGuid) then
			ShowAvgItemLevel(unit, true);
			return;
		end
		AvgItemLvl.scanTooltip.itemScan = true;
		AvgItemLvl.scanTooltip.unit = unit;
		AvgItemLvl.scanTooltip.guid = guid;

		AvgItemLvl:RegisterEvent("GET_ITEM_INFO_RECEIVED");
		for i = 1, #itemSlots do
			local textureName = GetInventoryItemTexture(unit, i);
			if textureName then
				AvgItemLvl.scanTooltip:SetInventoryItem(unit, i);
			end
		end
		if not (unit == "player") then
			for i = 1, #itemSlots do
				local itemId = GetInventoryItemID(unit, i);
				if (itemId) then
					AvgItemLvl.scanTooltip:SetItemByID(itemId);
				end
			end
		end
		return;
	end
	AvgItemLvl.scanTooltip.itemScan = nil;
	wipe(AvgItemLvl.scanTooltip.itemTable);
	AvgItemLvl.itemsLoaded = nil;

	if (unit and guid == currentGuid) then
		ShowAvgItemLevel(unit, true);
	end
end

local function ItemScanned(itemId)
	if (itemId) then
		AvgItemLvl.scanTooltip.itemTable[itemId] = nil;
		if (AvgItemLvl.scanTooltip.itemCount == 0 and tnum(AvgItemLvl.scanTooltip.itemTable) == 0 and AvgItemLvl.scanTooltip.unit and AvgItemLvl.scanTooltip.guid) then
			AvgItemLvl.scanTooltip.itemScan = nil;
			AvgItemLvl.itemsLoaded = true;
			AvgItemLvl:UnregisterEvent("GET_ITEM_INFO_RECEIVED");
			ScanGear(AvgItemLvl.scanTooltip.unit, AvgItemLvl.scanTooltip.guid);
		end
	end
end

local function ScanGear_OnTooltipSetItem(self, ...)
	if (not self.itemScan) then return end
	local itemName, itemLink = self:GetItem();
	self:ClearLines();
	if (itemLink) then
		self.itemCount = self.itemCount - 1;
		local itemId = strmatch(itemLink, "item:(%d+)");
		self.itemTable[itemId] = true;
		if (itemName == "") then
			local item = GetItemInfo(itemLink);
			if (not item) then return end
		end
		if (itemId) then
			ItemScanned(itemId);
		end
	end
end
AvgItemLvl.scanTooltip:HookScript("OnTooltipSetItem", ScanGear_OnTooltipSetItem)

local function GetAdjustedItemLevel(quality, iLevel, unitLevel)
	unitLevel = unitLevel or 80;
	if not quality or not iLevel then
		return 0;
	elseif quality == 3 and unitLevel >= 60 then
		if iLevel >= 300 and unitLevel >= 85 then
			return iLevel;
		else
			return iLevel - 13;
		end
	elseif quality == 2 and unitLevel >= 60 then
		if iLevel >= 300 and unitLevel >= 85 then
			return iLevel;
		else
			return iLevel - 26;
		end
	elseif quality < 2 then
		return 0;
	elseif quality == 7 then
		if unitLevel == 90 then return 450;
		elseif unitLevel == 89 then return 442;
		elseif unitLevel > 85 and unitLevel <= 88 then return 434 - (88 - unitLevel) * 17;
		elseif unitLevel == 85 then return 333;
		elseif unitLevel == 84 then return 325;
		elseif unitLevel > 80 and unitLevel <= 83 then return 317 - (83 - unitLevel) * 17;
		elseif unitLevel == 80 then return 187 - (80 - unitLevel) * 4;
		elseif unitLevel >= 68 then return 187 - (80 - unitLevel) * 4;
		elseif unitLevel >= 58 then return 109 - (68 - unitLevel) * 3;
		elseif unitLevel < 58 then return unitLevel + 5;
		end
	else
		return iLevel;
	end
end

local function GetCurrentItemLevel(unit, adjusted, pve)
	if (not unit) or (not UnitIsPlayer(unit)) then return; end
	--if (not GetTalentTabInfo(1, not UnitIsUnit(unit, "player"), nil, 1)) then return; end

	local itemLvlSum, itemCount = 0, 0;
	local slot, link, itemName, itemLink, itemQuality, itemLevel, itemLevel2, equipSlot, _, twoHanderEquipped;

	local itemLvlSum2, pvpItems = 0, 0;
	local level = UnitLevel(unit);
	local _, class = UnitClass(unit);
	for i = 1, #itemSlots do
		itemLevel = 0;
		itemLevel2 = 0;
		slot = GetInventorySlotInfo(itemSlots[i]);
		link = GetInventoryItemLink(unit, slot);
		if link then
			itemName, itemLink, itemQuality, itemLevel, _, _, _, _, equipSlot = GetItemInfo(link);
			if itemLevel then
				if AvgItemLvlDB.includeUpgrades and itemLevel >= 458 then
					local upgradeId = tonumber(strmatch(link, "item:%d+:%d+:%d+:%d+:%d+:%d+:%-?%d+:%-?%d+:%d+:%d+:(%d+)"));
					if (upgradeId and upgradeTable[upgradeId]) then
						itemLevel = itemLevel + upgradeTable[upgradeId];
					end
				end
				itemLevel2 = itemLevel;
				if itemSlots[i] == "MainHandSlot" and (equipSlot == "INVTYPE_2HWEAPON" or class == "HUNTER") then twoHanderEquipped = true; end
				if itemSlots[i] == "SecondaryHandSlot" then twoHanderEquipped = nil; end
				if adjusted then
					itemLevel2 = GetAdjustedItemLevel(itemQuality, itemLevel2, level);
				end
				if pve then
					AvgItemLvl.scanTooltip:ClearLines();
					AvgItemLvl.scanTooltip:SetOwner(UIParent, "ANCHOR_NONE");
					local hasItem = AvgItemLvl.scanTooltip:SetInventoryItem(unit, slot);
					if hasItem then
						local numLines = AvgItemLvl.scanTooltip:NumLines();
						for l = 1, numLines do
							local text = _G["AvgItemLvl_ScanTipTextLeft" .. l]:GetText() or "";
							text = strlower(text);
							if strmatch(text, RESILIENCE) or strmatch(text, STAT_PVP_POWER) or strmatch(text, SPELL_PENETRATION) then
								if itemLevel < 450 or pvpOnly[itemSlots[i]] then itemLevel2 = itemLevel2 * 0.85; end
								pvpItems = pvpItems + 1;
								break;
							end
						end
					end
				end
			else
				itemLevel = 0;
				itemLevel2 = 0;
			end
		end
		if not (twoHanderEquipped and itemSlots[i] == "SecondaryHandSlot") then
			itemLvlSum = itemLvlSum + itemLevel;
			itemLvlSum2 = itemLvlSum2 + itemLevel2;
			itemCount = itemCount + 1;
		end
	end
	if (itemCount == 0) then
		return 0, 0, 0;
	end
	return floor(itemLvlSum / itemCount * 100) / 100, floor(itemLvlSum2 / itemCount * 100) / 100, pvpItems;
end


local function GetAvgItemLevel(unit)
	if (not unit) or (not UnitIsPlayer(unit)) then return; end

	local name = GetGlobalUnitName(unit);
	if (not name) then return; end

	local itemLevel, avgItemLvl, pvpItems = GetCurrentItemLevel(unit, AvgItemLvlDB.adjustedMode, AvgItemLvlDB.pveMode);

	-- Cache the new entry
	if (not cache[name]) then
		cache[name] = {};
	end
	if (itemLevel and avgItemLvl) then
		cache[name].itemLevel, cache[name].avgItemLvl = itemLevel, avgItemLvl;
		cache[name].pvpItems = pvpItems;
	elseif (cache[name] and cache[name].itemLevel and cache[name].avgItemLvl) then
		itemLevel, avgItemLvl, pvpItems = cache[name].itemLevel, cache[name].avgItemLvl, cache[name].pvpItems;
	end
	return avgItemLvl, itemLevel, pvpItems;
end

function ShowAvgItemLevel(unit, itemsScanned)
	if (not unit) or (not UnitIsPlayer(unit)) or (not AvgItemLvlDB.iLevelTip) or (TipTacTalents and TipTac_Config and TipTac_Config.showItemLevel) then
		return;
	end
	if not itemsScanned then
		ScanGear(unit, currentGuid);
		return;
	end
	local avgItemLvl, itemLevel, pvpItems = GetAvgItemLevel(unit);
	itemLevel = avgItemLvl and format("%.2f", avgItemLvl) or "??";

	if (unit == "player") then
		GameTooltip:AddLine(ITEM_LEVEL_PREFIX..itemLevel);
		if (AvgItemLvlDB.showPVP and pvpItems and pvpItems > 0) then
			GameTooltip:AddLine(format("|cffff0000%d PvP |4item:items; detected", pvpItems));
		end
		GameTooltip:Show();
	elseif (unit) then
		local pvpFound;
		local numLines = GameTooltip:NumLines();
		for i = 2, numLines do
			if (strmatch(_G["GameTooltipTextLeft"..i]:GetText() or "", "^"..ITEM_LEVEL_PREFIX)) then
				_G["GameTooltipTextLeft"..i]:SetFormattedText("%s%s", ITEM_LEVEL_PREFIX, itemLevel);
				if (AvgItemLvlDB.showPVP and pvpItems and pvpItems > 0) then
					for l = i, numLines do
						if (strmatch(_G["GameTooltipTextLeft"..l]:GetText() or "", "PvP items detected") or strmatch(_G["GameTooltipTextLeft"..l]:GetText() or "", "PvP item detected")) then
							_G["GameTooltipTextLeft"..l]:SetFormattedText("|cffff0000%d PvP |4item:items; detected", pvpItems);
							pvpFound = true;
							break;
						end
					end
					if (not pvpFound) then
						GameTooltip:AddLine(format("|cffff0000%d PvP |4item:items; detected", pvpItems));
					end
				end
				GameTooltip:Show();
				break;
			end
		end
	end
	currentGuid = nil;
end


-- Inspect Players
local function InspectPlayerUnit(unit)
	if (not unit) or (not UnitIsPlayer(unit)) or (UnitIsUnit(unit, "player")) then
		return;
	end
	AvgItemLvl.queueTimer = 0;
	AvgItemLvl.allowInspect = true;
	AvgItemLvl:Show();
end


-- CanInspectUnit
local function CanInspectUnit(unit)
	if (not unit) or (UnitIsDead("player")) then
		return;
	end
	local unitType = (not UnitIsPlayer(unit) and 1) or (UnitCanCooperate("player", unit) and 3) or 2;
	return CanInspect(unit) or (unitType ~= 1 and UnitIsVisible(unit) and CheckInteractDistance(unit, 1));
end


-- NotifyInspect
do
	if (not NOTIFY_INSPECT_HOOKED) then
		AvgItemLvl.unit = nil;
		AvgItemLvl.guid = nil;
		AvgItemLvl.inspectTime = 0;
		NOTIFY_INSPECT_HOOKED = true;
		local oldNotifyInspect = NotifyInspect;
		function NotifyInspect(...)
			local unit = ...;
			local guid = UnitGUID(unit);
			local currentTime = GetTime();
			if guid and (not Examiner or not Examiner:IsShown() or not Examiner.scanIsActive or Examiner.scanIsActive == guid) then
				if (currentTime - 0.5 > AvgItemLvl.inspectTime or guid == AvgItemLvl.guid) then
					AvgItemLvl.unit = unit;
					AvgItemLvl.guid = guid;
					AvgItemLvl.inspectTime = currentTime;
					oldNotifyInspect(...);
					return true;
				end
			end
		end
	end
end

hooksecurefunc("PaperDollFrame_SetItemLevel", function(statFrame, unit)
	if (unit ~= "player") or (not AvgItemLvlDB.iLevelCharSheet) then
		return;
	end
	local name = GetGlobalUnitName("player");
	local text = _G[statFrame:GetName().."StatText"];
	if (strmatch(text:GetText() or "", "^.+ %(.+%)")) then
		return;
	end
	local itemLevel = format("%.2f", floor(GetAverageItemLevel() * 100) / 100);
	local avgItemLvl = cache[name] and cache[name].avgItemLvl and format("%.2f", cache[name].avgItemLvl) or "??";

	text:SetText(avgItemLvl.." ("..itemLevel..")");
	statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..STAT_AVERAGE_ITEM_LEVEL.." "..avgItemLvl.." ("..itemLevel..")"..FONT_COLOR_CODE_CLOSE;
end)

--------------------------------------------------------------------------------------------------------
--                                           Event Handling                                           --
--------------------------------------------------------------------------------------------------------

-- OnUpdate
AvgItemLvl:SetScript("OnUpdate", function(self, elapsed)
	if (not self.allowInspect) then
		return;
	end
	self.queueTimer = self.queueTimer + elapsed;
	if (self.queueTimer >= INSPECT_DELAY) then
		self.queueTimer = 0;
		local currentTime = GetTime();
		if (currentTime > inspectResetAt) then
			inspectsLeft = INSPECTS_PER_INTERVAL;
		end
		if (inspectsLeft == INSPECTS_PER_INTERVAL) then
			inspectResetAt = currentTime + INSPECT_RESET_TIMER;
		end

		if (inspectsLeft > 0) and (not Examiner or not Examiner:IsShown()) then
			self:Hide();
			self.allowInspect = nil;
			if (InCombatLockdown() and not AvgItemLvlDB.scanInCombat) then
				currentGuid = nil;
				return;
			end
			local name, unit = GameTooltip:GetUnit();
			if unit and UnitExists(unit) and (UnitGUID(unit) == currentGuid) and CanInspectUnit(unit) then
				self:RegisterEvent("INSPECT_READY");
				--if (InspectFrame) then
				--	InspectFrame.unit = unit;
				--end
				NotifyInspect(unit);
			end
		end
	end
end)

-- OnTooltipSetUnit
GameTooltip:HookScript("OnTooltipSetUnit", function(self, ...)
	if (not AvgItemLvlDB.iLevelTip) or (TipTacTalents and TipTac_Config and TipTac_Config.showItemLevel) then
		return;
	end
	if (InCombatLockdown() and not AvgItemLvlDB.scanInCombat) then
		local name = GetGlobalUnitName(unit);
		if (cache[name] and cache[name].itemLevel and cache[name].avgItemLvl) then
			self:AddLine(ITEM_LEVEL_PREFIX..format("%.2f", cache[name].avgItemLvl));
			if (AvgItemLvlDB.showPVP and cache[name].pvpItems and cache[name].pvpItems > 0) then
				self:AddLine(format("|cffff0000%d PvP |4item:items; detected", cache[name].pvpItems));
			end
			GameTooltip:Show();
		end
		return;
	end
	-- Abort any delayed inspect in progress
	AvgItemLvl.allowInspect = nil;
	AvgItemLvl:Hide();
	-- Get the unit
	local _, unit = self:GetUnit();
	if (not unit) then
		local mFocus = GetMouseFocus();
		if (mFocus) and (mFocus.unit) then
			unit = mFocus.unit;
		end
	end
	-- No Unit or not a Player
	if (not unit) or (not UnitIsPlayer(unit)) then
		return;
	end
	-- Only for players
	if (UnitIsPlayer(unit)) then
		local name = GetGlobalUnitName(unit);
		currentGuid = UnitGUID(unit);
		-- Clear
		--ClearInspectPlayer();
		-- Player
		if (UnitIsUnit(unit, "player")) then
			ShowAvgItemLevel("player", true);
		-- Others
		else
			local requestInspectData = (not InspectFrame or not InspectFrame:IsShown()) and (not Examiner or not Examiner:IsShown()) and CanInspectUnit(unit);
			if (requestInspectData) then
				InspectPlayerUnit(unit);
			end
			if (cache[name] and cache[name].itemLevel and cache[name].avgItemLvl) then
				self:AddLine(ITEM_LEVEL_PREFIX..format("%.2f", cache[name].avgItemLvl));
				if (AvgItemLvlDB.showPVP and cache[name].pvpItems and cache[name].pvpItems > 0) then
					self:AddLine(format("|cffff0000%d PvP |4item:items; detected", cache[name].pvpItems));
				end
			elseif (requestInspectData) then
				self:AddLine(ITEM_LEVEL_PREFIX..RETRIEVING);
			end
			GameTooltip:Show();
		end
	end
end);


--------------------------------------------------------------------------------------------------------
--                                          Fix InspectFrame                                          --
--------------------------------------------------------------------------------------------------------

local InspectPaperDollFrame_SetLevel;
local InspectPaperDollFrame_OnShow;
local InspectGuildFrame_Update;
AvgItemLvl.hooks = {};

local function InspectPaperDollFrame_SetLevel_Hook()
	if InspectFrame and InspectFrame.unit and CanInspect(InspectFrame.unit) then
		return InspectPaperDollFrame_SetLevel();
	end
end

local function InspectGuildFrame_Update_Hook()
	if InspectFrame and InspectFrame.unit and CanInspect(InspectFrame.unit) then
		return InspectGuildFrame_Update();
	end
	--print("InspectGuildFrame_Update filtered!")
end

local function InspectPaperDollFrame_OnShow_Hook()
	if InspectFrame and InspectFrame.unit and CanInspect(InspectFrame.unit) then
		return InspectPaperDollFrame_OnShow();
	end
end

local function CreateHooks()
	if _G.InspectPaperDollFrame_SetLevel and _G.InspectPaperDollFrame_SetLevel ~= InspectPaperDollFrame_SetLevel_Hook and not InspectFix then
		InspectPaperDollFrame_SetLevel = _G.InspectPaperDollFrame_SetLevel;
		_G.InspectPaperDollFrame_SetLevel = InspectPaperDollFrame_SetLevel_Hook;
		--print("InspectPaperDollFrame_SetLevel hook created.")
		if not AvgItemLvl.hooks["InspectPaperDollFrame_SetLevel_Hook"] then
			AvgItemLvl.hooks["InspectPaperDollFrame_SetLevel_Hook"] = true;
		end
	end
	if _G.InspectGuildFrame_Update and _G.InspectGuildFrame_Update ~= InspectGuildFrame_Update_Hook and not InspectFix then
		InspectGuildFrame_Update = _G.InspectGuildFrame_Update;
		_G.InspectGuildFrame_Update = InspectGuildFrame_Update_Hook;
		--print("InspectGuildFrame_Update hook created.")
		if not AvgItemLvl.hooks["InspectGuildFrame_Update_Hook"] then
			AvgItemLvl.hooks["InspectGuildFrame_Update_Hook"] = true;
		end
	end
	if _G.InspectPaperDollFrame_OnShow and _G.InspectPaperDollFrame_OnShow ~= InspectPaperDollFrame_OnShow_Hook and not InspectFix then
		InspectPaperDollFrame_OnShow = _G.InspectPaperDollFrame_OnShow;
		_G.InspectPaperDollFrame_OnShow = InspectPaperDollFrame_OnShow_Hook;
		--print("InspectPaperDollFrame_OnShow hook created.")
		if not AvgItemLvl.hooks["InspectPaperDollFrame_OnShow_Hook"] then
			AvgItemLvl.hooks["InspectPaperDollFrame_OnShow_Hook"] = true;
		end
	end
	--print("Hooks created.")
end

local function AvgItemLvl_SetLevel(textFrame, level)
	if (not level) then
		textFrame:SetText("Avg iLvl\n|cffffffff??|r");
	else
		textFrame:SetFormattedText("Avg iLvl\n|cffffffff%.2f|r", level);
	end
	textFrame:Show();
end

local function CreateButton(frame)
	if frame == "PaperDollFrame" and not PaperDollFrameAvgItemLvl then
		--[[local button = CreateFrame("Button", "PaperDollFrameAvgItemLvl", PaperDollFrame);
		--button:SetNormalTexture(AvgItemLvl_LDB.icon);
		button:SetPoint("BOTTOMLEFT", 240, 8);
		button:SetWidth(45); button:SetHeight(25);
		AvgItemLvl.paperDollText = button:CreateFontString("PaperDollFrameAvgItemLvlText", "OVERLAY", "GameFontNormalSmall");
		AvgItemLvl.paperDollText:SetAllPoints();
		AvgItemLvl.paperDollText:SetJustifyH("RIGHT");
		AvgItemLvl.paperDollText:Hide();
		button:SetScript("OnEnter", function(self) ShowTooltip(self, "player", "ANCHOR_RIGHT") end);
		button:SetScript("OnLeave", function() GameTooltip:Hide() end);
		PaperDollFrame:HookScript("OnShow", function(self) AvgItemLvl_SetLevel(AvgItemLvl.paperDollText, GetAvgItemLevel("player")); end);
		PaperDollFrame:HookScript("OnHide", function(self) AvgItemLvl.paperDollText:Hide(); end);
		AvgItemLvl_SetLevel(AvgItemLvl.paperDollText, GetAvgItemLevel("player"));
		local avgItemLvl = GetAvgItemLevel("player");
		if (avgItemLvl) then
			AvgItemLvl_LDB.text = format("|cffffffff%.2f|r", avgItemLvl);
		else
			AvgItemLvl_LDB.text = "|cffffffff??|r";
		end]]--
	elseif frame == "InspectFrame" and not InspectFrameAvgItemLvl then
		local button = CreateFrame("Button", "InspectFrameAvgItemLvl", InspectFrame);
		--button:SetNormalTexture(AvgItemLvl_LDB.icon);
		button:SetPoint("BOTTOMLEFT", 240, 8);
		button:SetWidth(45); button:SetHeight(25);
		AvgItemLvl.inspectText = button:CreateFontString("InspectFrameAvgItemLvlText", "OVERLAY", "GameFontNormalSmall");
		AvgItemLvl.inspectText:SetAllPoints();
		AvgItemLvl.inspectText:SetJustifyH("RIGHT");
		AvgItemLvl.inspectText:Hide();
		button:SetScript("OnEnter", function(self) ShowTooltip(self, "target", "ANCHOR_RIGHT") end);
		button:SetScript("OnLeave", function() GameTooltip:Hide() end);
		InspectPaperDollFrame:HookScript("OnShow", function(self) AvgItemLvl_SetLevel(AvgItemLvl.inspectText, GetAvgItemLevel("target")); end);
		InspectPaperDollFrame:HookScript("OnHide", function(self) AvgItemLvl.inspectText:Hide(); end);
	end
end

--------------------------------------------------------------------------------------------------------
--                                              OnEvent                                               --
--------------------------------------------------------------------------------------------------------

local function CheckDB()
	if (not AvgItemLvlDB) then
		AvgItemLvlDB = {};
	end
	local defaults = {
		iLevelTip = true,
		pveMode = true,
		showPVP = true,
		adjustedMode = nil,
		iLevelCharSheet = true,
		includeUpgrades = true,
	};
	for k, v in pairs(defaults) do
		if (not AvgItemLvlDB[k]) then
			AvgItemLvlDB[k] = v;
		end
	end
end

local selfLoaded, inspectLoaded;
AvgItemLvl:SetScript("OnEvent", function(self, event, ...)
	if (event == "ADDON_LOADED") then
		local addon = ...;
		if (addon == "AvgItemLvl") then
			CheckDB();
			if (not AvgItemLvlCache) then
				AvgItemLvlCache = {};
			end
			cache = AvgItemLvlCache;

			self:RegisterEvent("PLAYER_ENTERING_WORLD");
			self:RegisterEvent("PLAYER_EQUIPMENT_CHANGED");
			self:RegisterEvent("ITEM_UPGRADE_MASTER_UPDATE");
			selfLoaded = true;
		elseif (addon == "Blizzard_InspectUI") then
			CreateButton("InspectFrame");
			CreateHooks();
			inspectLoaded = true;
		end
		if (selfLoaded and inspectLoaded) then
			self:UnregisterEvent("ADDON_LOADED");
			selfLoaded = nil; inspectLoaded = nil;
		end
	elseif (event == "PLAYER_ENTERING_WORLD") then
		self:UnregisterEvent("PLAYER_ENTERING_WORLD");
		self.playerGUID = UnitGUID("player");
		realmName = GetRealmName();
		--CreateButton("PaperDollFrame");
		local avgItemLvl = GetAvgItemLevel("player");
		if (avgItemLvl) then
			AvgItemLvl_LDB.text = format("|cffffffff%.2f|r", avgItemLvl);
		else
			AvgItemLvl_LDB.text = "|cffffffff??|r";
		end
	elseif (event == "GET_ITEM_INFO_RECEIVED") then
		if (not self.scanTooltip.itemScan) then
			self:UnregisterEvent("GET_ITEM_INFO_RECEIVED");
			return;
		end
		for itemId in pairs(self.scanTooltip.itemTable) do
			if (GetItemInfo(itemId)) then
				ItemScanned(itemId);
			end
		end
	elseif (event == "INSPECT_READY") then
		self:UnregisterEvent("INSPECT_READY");
		local guid = ...;
		local name, unit = GameTooltip:GetUnit();
		if (unit and guid == UnitGUID(unit)) then
			ShowAvgItemLevel(unit);
		end
		--[[if (not InspectFrame or not InspectFrame:IsShown()) and (not Examiner or not Examiner:IsShown()) then
			ClearInspectPlayer();
		end]]--
	elseif (event == "PLAYER_EQUIPMENT_CHANGED" or event == "ITEM_UPGRADE_MASTER_UPDATE") then
		local avgItemLvl = GetAvgItemLevel("player");
		if (avgItemLvl) then
			AvgItemLvl_LDB.text = format("|cffffffff%.2f|r", avgItemLvl);
		else
			AvgItemLvl_LDB.text = "|cffffffff??|r";
		end
		--AvgItemLvl_SetLevel(AvgItemLvl.paperDollText, avgItemLvl);
	end
end);

AvgItemLvl:RegisterEvent("ADDON_LOADED");


function AvgItemLvl:Print(...)
	if not (...) then return; end
	print("|cff4fcfffAvgItemLvl:|r "..(...));
end

SLASH_AVGITEMLVL1 = "/avgilvl";
SLASH_AVGITEMLVL2 = "/avgitemlvl";
SLASH_AVGITEMLVL3 = "/ail";
local options = {};
SlashCmdList.AVGITEMLVL = function(msg)
	if not msg then return; end
	wipe(options);
	for v in gmatch(strlower(msg), "[^ ]+") do
		options[#options + 1] = v;
	end
	if options[1] == "mode" then
		if options[2] == "pve" then
			AvgItemLvlDB.pveMode = not AvgItemLvlDB.pveMode;
			AvgItemLvl:Print("PVE mode is now "..(AvgItemLvlDB.pveMode and "|cff00ff00on|r" or "|cffff0000off|r"))
		elseif options[2] == "adjusted" then
			AvgItemLvlDB.adjustedMode = not AvgItemLvlDB.adjustedMode;
			AvgItemLvl:Print("Adjusted mode is now "..(AvgItemLvlDB.adjustedMode and "|cff00ff00on|r" or "|cffff0000off|r"))
		end
	elseif options[1] == "tip" then
		AvgItemLvlDB.iLevelTip = not AvgItemLvlDB.iLevelTip;
		AvgItemLvl:Print("Item Level on tooltips is now "..(AvgItemLvlDB.iLevelTip and "|cff00ff00on|r" or "|cffff0000off|r"))
	elseif options[1] == "charsheet" then
		AvgItemLvlDB.iLevelCharSheet = not AvgItemLvlDB.iLevelCharSheet;
		AvgItemLvl:Print("Item Level on character sheet is now "..(AvgItemLvlDB.iLevelCharSheet and "|cff00ff00on|r" or "|cffff0000off|r"))
	elseif options[1] == "combat" then
		AvgItemLvlDB.scanInCombat = not AvgItemLvlDB.scanInCombat;
		AvgItemLvl:Print("Item Level scanning while in combat is now "..(AvgItemLvlDB.scanInCombat and "|cff00ff00on|r" or "|cffff0000off|r"))
	elseif options[1] == "showpvp" then
		AvgItemLvlDB.showPVP = not AvgItemLvlDB.showPVP;
		AvgItemLvl:Print("PVP Item Count is now "..(AvgItemLvlDB.showPVP and "|cff00ff00on|r" or "|cffff0000off|r"))
	elseif options[1] == "upgrades" then
		AvgItemLvlDB.includeUpgrades = not AvgItemLvlDB.includeUpgrades;
		AvgItemLvl:Print("Item Level Upgrade Detection is now "..(AvgItemLvlDB.includeUpgrades and "|cff00ff00on|r" or "|cffff0000off|r"))
	elseif options[1] == "list" then
		AvgItemLvl:Print("PVE mode is "..(AvgItemLvlDB.pveMode and "|cff00ff00on|r" or "|cffff0000off|r"))
		AvgItemLvl:Print("Adjusted mode is "..(AvgItemLvlDB.adjustedMode and "|cff00ff00on|r" or "|cffff0000off|r"))
		AvgItemLvl:Print("Item Level on tooltips is "..(AvgItemLvlDB.iLevelTip and "|cff00ff00on|r" or "|cffff0000off|r"))
		AvgItemLvl:Print("Item Level on character sheet is "..(AvgItemLvlDB.iLevelCharSheet and "|cff00ff00on|r" or "|cffff0000off|r"))
		AvgItemLvl:Print("Item Level scanning while in combat is "..(AvgItemLvlDB.scanInCombat and "|cff00ff00on|r" or "|cffff0000off|r"))
		AvgItemLvl:Print("PVP Item Count is "..(AvgItemLvlDB.showPVP and "|cff00ff00on|r" or "|cffff0000off|r"))
		AvgItemLvl:Print("Item Level Upgrade Detection is "..(AvgItemLvlDB.includeUpgrades and "|cff00ff00on|r" or "|cffff0000off|r"))
	end
end
