local _G = getfenv(0);
local abs = abs;
local gtt = GameTooltip;
local UnitExists = UnitExists;
local modName = "TipTac";
local tt = CreateFrame("Frame",modName,UIParent);

-- Global Chat Message Function
function AzMsg(msg) DEFAULT_CHAT_FRAME:AddMessage(tostring(msg):gsub("|1","|cffffff80"):gsub("|2","|cffffffff"),0.5,0.75,1.0); end

-- Config Data Variables
local cfg;
local TT_DefaultConfig = {
	showUnitTip = true,
	showStatus = true,
	showGuildRank = false,
	nameType = "title",
	showRealm = "show",
	showTarget = "last",
	targetYouText = "<<YOU>>",
	showTargetedBy = true,

	gttScale = 1,
	updateFreq = 0.5,

	colSameGuild = "|cffff32ff",
	colRace = "|cffffffff",
	colLevel = "|cffc0c0c0",
	colorNameByClass = false,
	classColoredBorder = false,
	itemQualityBorder = true,

	reactText = false,
	colReactText1 = "|cffc0c0c0",
	colReactText2 = "|cffff0000",
	colReactText3 = "|cffff7f00",
	colReactText4 = "|cffffff00",
	colReactText5 = "|cff00ff00",
	colReactText6 = "|cff25c1eb",
	colReactText7 = "|cff808080",

	reactColoredBackdrop = false,
	reactColoredBorder = false,
	colReactBack1 = { 0.2, 0.2, 0.2 },
	colReactBack2 = { 0.3, 0, 0 },
	colReactBack3 = { 0.3, 0.15, 0 },
	colReactBack4 = { 0.3, 0.3, 0 },
	colReactBack5 = { 0, 0.3, 0.1 },
	colReactBack6 = { 0, 0, 0.5 },
	colReactBack7 = { 0.05, 0.05, 0.05 },

	tipBackdropBG = "Interface\\Buttons\\WHITE8X8",
	tipBackdropEdge = "Interface\\Tooltips\\UI-Tooltip-Border",
	backdropEdgeSize = 14,
	backdropInsets = 2.5,
	tipColor = { 0.1, 0.1, 0.2 },
	tipBorderColor = { 0.3, 0.3, 0.4 },
	gradientTip = true,
	gradientColor = { 0.8, 0.8, 0.8, 0.2 },

	modifyFonts = false,
	fontFace = "Fonts\\FRIZQT__.TTF",
	fontSize = 12,
	fontFlags = "",

	classification_normal = "%s ",
	classification_elite = "+%s ",
	classification_worldboss = "%s|r (Boss) ",
	classification_rare = "%s|r (Rare) ",
	classification_rareelite = "+%s|r (Rare) ",

	overrideFade = true,
	preFadeTime = 0.1,
	fadeTime = 0.1,
	hideWorldTips = true,

	hideDefaultBar = true,
	healthBar = true,
	healthBarClassColor = true,
	healthBarText = "value",
	healthBarColor = { 0.3, 0.9, 0.3 },
	manaBar = false,
	manaBarText = "value",
	manaBarColor = { 0.3, 0.55, 0.9 },
	powerBar = false,
	powerBarText = "value",

	barFontFace = "Fonts\\ARIALN.TTF",
	barFontSize = 12,
	barFontFlags = "OUTLINE",
	barHeight = 6,
	barTexture = "Interface\\TargetingFrame\\UI-StatusBar",

	aurasAtBottom = false,
	showBuffs = true,
	showDebuffs = true,
	selfAurasOnly = false,
	auraSize = 20,
	auraMaxRows = 2,
	showAuraCooldown = true,

	iconRaid = true,
	iconFaction = false,
	iconCombat = false,
	iconAnchor = "TOPLEFT",
	iconSize = 24,

	anchorWorldUnitType = "normal",
	anchorWorldUnitPoint = "BOTTOMRIGHT",
	anchorWorldTipType = "normal",
	anchorWorldTipPoint = "BOTTOMRIGHT",
	anchorFrameUnitType = "normal",
	anchorFrameUnitPoint = "BOTTOMRIGHT",
	anchorFrameTipType = "normal",
	anchorFrameTipPoint = "BOTTOMRIGHT",

	mouseOffsetX = 0,
	mouseOffsetY = 0,

	hideUFTipsInCombat = false,
	hideAllTipsInCombat = false,
	showHiddenTipsOnShift = false,

	showTalents = true,
	talentFormat = 1,
	talentCacheSize = 25,
};

-- Tips modified by TipTac in appearance and scale, you can add to this list if you want to modify more tips
local TT_TipsToModify = {
	"GameTooltip",
	"ShoppingTooltip1",
	"ShoppingTooltip2",
	"ShoppingTooltip3",
	"ItemRefTooltip",
	"WorldMapTooltip",
	"AtlasLootTooltip",
	"QuestHelperTooltip",
	"QuestGuru_QuestWatchTooltip",
};

local tipBackdrop = { tile = false, insets = {} };

-- Constants
local TT_LevelMatch = "^"..TOOLTIP_UNIT_LEVEL:gsub("%%s",".+"); -- Was changed to match other localizations properly, used to match: "^"..LEVEL.." .+" -- Az: doesn't actually match the level line on the russian client!
local TT_NotSpecified = "Not specified";
local TT_Reaction = {
	"Tapped",					-- No localized string of this
	FACTION_STANDING_LABEL2,	-- Hostile
	FACTION_STANDING_LABEL3,	-- Unfriendly (Caution)
	FACTION_STANDING_LABEL4,	-- Neutral
	FACTION_STANDING_LABEL5,	-- Friendly
	FACTION_STANDING_LABEL5,	-- Friendly (Exalted)
	DEAD,						-- Dead
};

-- Colors
local CLASS_COLORS = CUSTOM_CLASS_COLORS or RAID_CLASS_COLORS;
local COL_WHITE = "|cffffffff";
local COL_LIGHTGRAY = "|cffc0c0c0";
local TT_ClassColors = {};
for class, color in next, CLASS_COLORS do
	TT_ClassColors[class] = ("|cff%.2x%.2x%.2x"):format(color.r*255,color.g*255,color.b*255);
end

-- Mirror Anchors
local TT_MirrorAnchors = {
	TOP = "BOTTOM",
	TOPLEFT = "TOPRIGHT",
	TOPRIGHT = "TOPLEFT",
	BOTTOM = "TOP",
	BOTTOMLEFT = "BOTTOMRIGHT",
	BOTTOMRIGHT = "BOTTOMLEFT",
	LEFT = "RIGHT",
	RIGHT = "LEFT",
	CENTER = "CENTER",
};

local TT_MirrorAnchorsSmart = {
	TOPLEFT = "BOTTOMRIGHT",
	TOPRIGHT = "BOTTOMLEFT",
	BOTTOMLEFT = "TOPRIGHT",
	BOTTOMRIGHT = "TOPLEFT",
};

-- Data Variables
local isColorBlind;
local pLevel;
local u = {};
local lineOne = {};
local lineInfo = {};
local targetedList = {};
local auras = {};
local bars = {};
local tipIcon;

--------------------------------------------------------------------------------------------------------
--                                       TipTac Anchor Creation                                       --
--------------------------------------------------------------------------------------------------------

tt:SetWidth(114);
tt:SetHeight(24);
tt:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 8, edgeSize = 12, insets = { left = 2, right = 2, top = 2, bottom = 2 } });
tt:SetBackdropColor(0.1,0.1,0.2,1);
tt:SetBackdropBorderColor(0.1,0.1,0.1,1);
tt:SetMovable(1);
tt:EnableMouse(1);
tt:SetToplevel(1);
tt:SetClampedToScreen(1);
tt:SetPoint("CENTER");
tt:Hide();

tt.text = tt:CreateFontString(nil,"ARTWORK","GameFontHighlight");
tt.text:SetText("TipTacAnchor");
tt.text:SetPoint("LEFT",6,0);

tt.close = CreateFrame("Button",nil,tt,"UIPanelCloseButton");
tt.close:SetWidth(24);
tt.close:SetHeight(24);
tt.close:SetPoint("RIGHT");

-- Cursor Update -- This is a workaround so that gatherer addons can get the name of nodes
function tt:CURSOR_UPDATE(event)
	if (gtt:IsShown()) and (gtt:IsOwned(UIParent)) and (not u.token) then
		local backup = GameTooltipTextLeft1:GetText();
		gtt:Hide();
		GameTooltipTextLeft1:SetText(backup);
	end
end

-- Login -- Set Level
function tt:PLAYER_LOGIN(event)
	pLevel = UnitLevel("player");
	self[event] = nil;
end

-- Level Up -- Update Level
function tt:PLAYER_LEVEL_UP(event,newLevel)
	pLevel = newLevel;
end

-- Variables Loaded
function tt:VARIABLES_LOADED(event)
	isColorBlind = (GetCVar("colorblindMode") == "1");
	-- Init Config
	if (not TipTac_Config) then
		TipTac_Config = {};
	end
	cfg = setmetatable(TipTac_Config,{ __index = TT_DefaultConfig });
	-- Default the bar texture if it no longer exists
	bars[1]:SetStatusBarTexture(cfg.barTexture);
	if (not bars[1]:GetStatusBarTexture()) then
		cfg.barTexture = nil;
	end
	-- Hook Tips & Apply Settings
	self:HookTips();
	self:ApplySettings();
	-- Position
	if (cfg.left and cfg.top) then
		self:ClearAllPoints();
		self:SetPoint("TOPLEFT",UIParent,"BOTTOMLEFT",cfg.left,cfg.top);
	else
		self:Show();
		-- Just set left and top here, in case the player just closes the anchor without moving, so it doesn't keep showing up when they log in
		cfg.left, cfg.top = self:GetLeft(), self:GetTop();
	end
	-- Cleanup
	self:UnregisterEvent(event);
	self[event] = nil;
end

-- Console Var Change
function tt:CVAR_UPDATE(event,var,value)
	if (var == "USE_COLORBLIND_MODE") then
		isColorBlind = (value == "1");
	end
end

tt:SetScript("OnMouseDown",tt.StartMoving);
tt:SetScript("OnMouseUp",function(self) self:StopMovingOrSizing(); cfg.left, cfg.top = self:GetLeft(), self:GetTop(); end);
tt:SetScript("OnEvent",function(self,event,...) self[event](self,event,...); end);

tt:RegisterEvent("PLAYER_LOGIN");
tt:RegisterEvent("PLAYER_LEVEL_UP");
tt:RegisterEvent("VARIABLES_LOADED");
tt:RegisterEvent("CVAR_UPDATE");

--------------------------------------------------------------------------------------------------------
--                                           Slash Handling                                           --
--------------------------------------------------------------------------------------------------------
_G["SLASH_"..modName.."1"] = "/tip";
_G["SLASH_"..modName.."2"] = "/tiptac";
SlashCmdList[modName] = function(cmd)
	-- Extract Parameters
	local param1, param2 = cmd:match("^([^%s]+)%s*(.*)$");
	param1 = (param1 and param1:lower() or cmd:lower());
	-- Options
	if (param1 == "") then
		local loaded, reason = LoadAddOn("TipTacOptions");
		if (loaded) then
			if (TipTacOptions:IsShown()) then
				TipTacOptions:Hide();
			else
				TipTacOptions:Show();
			end
		else
			AzMsg("Could not open TicTac Options: |1"..tostring(reason).."|r. Please make sure the addon is enabled from the character selection screen.");
		end
	-- Show Anchor
	elseif (param1 == "anchor") then
		tt:Show();
	-- Invalid or No Command
	else
		UpdateAddOnMemoryUsage();
		AzMsg(format("----- |2%s|r |1%s|r ----- |1%.2f |2kb|r -----",modName,GetAddOnMetadata(modName,"Version"),GetAddOnMemoryUsage(modName)));
		AzMsg("The following |2parameters|r are valid for this addon:");
		AzMsg(" |2anchor|r = Shows the anchor where the tooltip appears");
	end
end
--------------------------------------------------------------------------------------------------------
--                                         Modify Unit Tooltip                                        --
--------------------------------------------------------------------------------------------------------

-- Get Reaction Index
local function GetUnitReactionIndex(unit)
	-- Deadies
	if (UnitIsDead(unit)) then
		return 7;
	-- Players (Can't rely on UnitPlayerControlled() alone, since it always returns nil on units out of range)
	elseif (UnitIsPlayer(unit) or UnitPlayerControlled(unit)) then
		if (UnitCanAttack(unit,"player")) then
			return (UnitCanAttack("player",unit) and 2 or 3);
		elseif (UnitCanAttack("player",unit)) then
			return 4;
		elseif (UnitIsPVP(unit) and not UnitIsPVPSanctuary(unit) and not UnitIsPVPSanctuary("player")) then
			return 5;
		else
			return 6;
		end
	-- Tapped
	elseif (UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit)) then
		return 1;
	-- Others
	else
		local reaction = (UnitReaction(unit,"player") or 3);
		return (reaction > 5 and 5) or (reaction < 2 and 2) or reaction;
	end
end

-- Returns the correct difficulty color compared to the player
local function GetDifficultyLevelColor(level)
	level = (level - pLevel);
	if (level > 4) then
		return "|cffff2020"; -- red
	elseif (level > 2) then
		return "|cffff8040"; -- orange
	elseif (level >= -2) then
		return "|cffffff00"; -- yellow
	elseif (level >= -GetQuestGreenRange()) then
		return "|cff40c040"; -- green
	else
		return "|cff808080"; -- gray
	end
end

-- Add target
local function AddTarget(lineList,target)
	local targetUnit = u.token.."target";
	if (UnitIsUnit("player",targetUnit)) then
		lineList[#lineList + 1] = COL_WHITE;
		lineList[#lineList + 1] = cfg.targetYouText;
	else
		local targetReaction = cfg["colReactText"..GetUnitReactionIndex(targetUnit)];
		lineList[#lineList + 1] = targetReaction;
		lineList[#lineList + 1] = "[";
		if (UnitIsPlayer(targetUnit)) then
			local _, targetClass = UnitClass(targetUnit);
			lineList[#lineList + 1] = (TT_ClassColors[targetClass] or COL_LIGHTGRAY);
			lineList[#lineList + 1] = target;
			lineList[#lineList + 1] = targetReaction;
		else
			lineList[#lineList + 1] = target;
		end
		lineList[#lineList + 1] = "]";
	end
end

-- Gather Unit Details
local function ModifyUnitTooltip()
	wipe(lineOne);
	wipe(lineInfo);
	local unit = u.token;
	local reaction = cfg["colReactText"..u.reactionIndex];
	local name, realm = UnitName(unit);
	local hasGuildTitle;
	-- Level + Classification
	local level = UnitLevel(unit);
	local tttData = (TipTacTalents and TipTacTalents.current);
	if (tttData) and (level == -1) and (u.isPlayer) and (tttData.name == name) and (tttData[3]) then -- Using TipTacTalents, determine level of ?? players by adding talent points together
		level = (tttData[1] + tttData[2] + tttData[3] + 9);
	end
	local classification = UnitClassification(unit);
	lineInfo[#lineInfo + 1] = (UnitCanAttack(unit,"player") or UnitCanAttack("player",unit)) and GetDifficultyLevelColor(level ~= -1 and level or 500) or cfg.colLevel;
	lineInfo[#lineInfo + 1] = (cfg["classification_"..classification] or "%d "):format(level == -1 and "??" or level);
	-- Players
	if (u.isPlayer) then
		-- race
		lineInfo[#lineInfo + 1] = " ";
		lineInfo[#lineInfo + 1] = cfg.colRace;
		lineInfo[#lineInfo + 1] = UnitRace(unit);
		-- class
		local class, classEng = UnitClass(unit);
		lineInfo[#lineInfo + 1] = " ";
		lineInfo[#lineInfo + 1] = (TT_ClassColors[classEng] or COL_WHITE);
		lineInfo[#lineInfo + 1] = class;
		u.classEng = classEng;
		-- name
		lineOne[#lineOne + 1] = (cfg.colorNameByClass and (TT_ClassColors[classEng] or COL_WHITE) or reaction);
		lineOne[#lineOne + 1] = (cfg.nameType == "original" and u.originalName) or (cfg.nameType == "title" and UnitPVPName(unit)) or name;
		if (realm) and (realm ~= "") and (cfg.showRealm ~= "none") then
			if (cfg.showRealm == "show") then
				lineOne[#lineOne + 1] = " - ";
				lineOne[#lineOne + 1] = realm;
			else
				lineOne[#lineOne + 1] = " (*)";
			end
		end
		-- dc, afk or dnd
		if (cfg.showStatus) then
			local status = (not UnitIsConnected(unit) and " <DC>") or (UnitIsAFK(unit) and " <AFK>") or (UnitIsDND(unit) and " <DND>");
			if (status) then
				lineOne[#lineOne + 1] = COL_WHITE;
				lineOne[#lineOne + 1] = status;
			end
		end
		-- guild
		local guild, guildRank = GetGuildInfo(unit);
		if (guild) then
			local pGuild = GetGuildInfo("player");
			local guildColor = (guild ~= pGuild and reaction or cfg.colSameGuild);
			GameTooltipTextLeft2:SetFormattedText(cfg.showGuildRank and guildRank and "%s<%s> %s%s" or "%s<%s>",guildColor,guild,COL_LIGHTGRAY,guildRank);
			hasGuildTitle = true;
		end
	-- NPCs
	else
		-- name
		lineOne[#lineOne + 1] = reaction;
		lineOne[#lineOne + 1] = name;
		-- guild/title
		if (u.title) then
			-- Az: this doesn't work with mini diablo, which has the format: 1) Mini Diablo 2) Lord of Terror 3) Player's Pet 4) Level 1 Non-combat Pet
			(isColorBlind and GameTooltipTextLeft3 or GameTooltipTextLeft2):SetFormattedText("%s<%s>",reaction,u.title);
			hasGuildTitle = true;
		end
		-- class
		local class = UnitCreatureFamily(unit) or UnitCreatureType(unit);
		if (not class or class == TT_NotSpecified) then
			class = UNKNOWN;
		end
		lineInfo[#lineInfo + 1] = " ";
		lineInfo[#lineInfo + 1] = cfg.colRace;
		lineInfo[#lineInfo + 1] = class;
	end
	-- Target
	if (cfg.showTarget ~= "none") then
		local targetUnit = unit.."target";
		local target = UnitName(targetUnit);
		if (target) and (target ~= UNKNOWN and target ~= "" or UnitExists(targetUnit)) then
			if (cfg.showTarget == "first") then
				lineOne[#lineOne + 1] = COL_WHITE;
				lineOne[#lineOne + 1] = " : |r";
				AddTarget(lineOne,target);
			elseif (cfg.showTarget == "second") then
				lineOne[#lineOne + 1] = "\n  ";
				AddTarget(lineOne,target);
			elseif (cfg.showTarget == "last") then
				lineInfo[#lineInfo + 1] = "\n|cffffd100Targeting: ";
				AddTarget(lineInfo,target);
			end
		end
	end
	-- Reaction Text
	if (cfg.reactText) then
		lineInfo[#lineInfo + 1] = "\n";
		lineInfo[#lineInfo + 1] = cfg["colReactText"..u.reactionIndex];
		lineInfo[#lineInfo + 1] = TT_Reaction[u.reactionIndex];
	end
	-- Line One + Guild
	GameTooltipTextLeft1:SetFormattedText(("%s"):rep(#lineOne),unpack(lineOne));
	-- Info Line
	local lineIndex = 2 + (isColorBlind and UnitIsVisible(unit) and 1 or 0) + (hasGuildTitle and 1 or 0);
	local gttLine = _G["GameTooltipTextLeft"..lineIndex];
	gttLine:SetFormattedText(("%s"):rep(#lineInfo),unpack(lineInfo));
	gttLine:SetTextColor(1,1,1);
end

-- Add "Targeted By" line
local function AddTargetedBy()
	local numParty, numRaid = GetNumPartyMembers(), GetNumRaidMembers();
	if (numParty > 0 or numRaid > 0) then
		for i = 1, (numRaid > 0 and numRaid or numParty) do
			local unit = (numRaid > 0 and "raid"..i or "party"..i);
			if (UnitIsUnit(unit.."target",u.token)) and (not UnitIsUnit(unit,"player")) then
				local _, class = UnitClass(unit);
				targetedList[#targetedList + 1] = TT_ClassColors[class];
				targetedList[#targetedList + 1] = UnitName(unit);
				targetedList[#targetedList + 1] = "|r, ";
			end
		end
		if (#targetedList > 0) then
			targetedList[#targetedList] = nil;
			gtt:AddLine(" ",nil,nil,nil,1);
			local line = _G["GameTooltipTextLeft"..gtt:NumLines()];
			line:SetFormattedText("Targeted By (|cffffffff%d|r): %s",(#targetedList + 1) / 3,table.concat(targetedList));
			wipe(targetedList);
		end
	end
end

--------------------------------------------------------------------------------------------------------
--                                        Health & Power Bars                                         --
--------------------------------------------------------------------------------------------------------

-- Make Two StatusBars
for i = 1, 2 do
	local bar = CreateFrame("StatusBar",nil,gtt);
	bar:SetWidth(0);	-- Az: As of patch 3.3.3, setting the initial size will somehow mess up the texture. Previously this initilization was needed to fix an anchoring issue.
	bar:SetHeight(0);

	bar.bg = bar:CreateTexture(nil,"BACKGROUND");
	bar.bg:SetTexture(0.3,0.3,0.3,0.6);
	bar.bg:SetAllPoints();

	bar.text = bar:CreateFontString(nil,"ARTWORK");
	bar.text:SetPoint("CENTER");
	bar.text:SetTextColor(1,1,1);

	bars[#bars + 1] = bar;
end

-- Configures the Health and Power Bars
local function SetupHealthAndPowerBar()
	u.powerType = UnitPowerType(u.token);
	-- Visibility
	if (cfg.healthBar) then
		bars[1]:Show();
		if (u.isPlayer) and (cfg.healthBarClassColor) then
			local color = CLASS_COLORS[u.classEng];
			bars[1]:SetStatusBarColor(color.r,color.g,color.b);
		else
			bars[1]:SetStatusBarColor(unpack(cfg.healthBarColor));
		end
	else
		bars[1]:Hide();
	end
	if (UnitPowerMax(u.token) ~= 0) and (cfg.manaBar and u.powerType == 0 or cfg.powerBar and u.powerType ~= 0) then
		if (u.powerType == 0) then
			bars[2]:SetStatusBarColor(unpack(cfg.manaBarColor));
		else
			u.powerColor = PowerBarColor[u.powerType or 5];
			bars[2]:SetStatusBarColor(u.powerColor.r,u.powerColor.g,u.powerColor.b);
		end
		bars[2]:Show();
	else
		bars[2]:Hide();
	end
	-- Anchor Frames
	bars[2]:ClearAllPoints();
	bars[1]:ClearAllPoints();
	if (bars[2]:IsShown()) then
		bars[2]:SetPoint("BOTTOMLEFT",8,9);
		bars[2]:SetPoint("BOTTOMRIGHT",-8,9);
		if (bars[1]:IsShown()) then
			bars[1]:SetPoint("BOTTOMLEFT",bars[2],"TOPLEFT",0,4);
			bars[1]:SetPoint("BOTTOMRIGHT",bars[2],"TOPRIGHT",0,4);
		end
	elseif (bars[1]:IsShown()) then
		bars[1]:SetPoint("BOTTOMLEFT",8,9);
		bars[1]:SetPoint("BOTTOMRIGHT",-8,9);
	end
	-- Calculate the space needed for the shown bars
	bars.offset = 0;
	for _, bar in ipairs(bars) do
		if (bar:IsShown()) then
			bars.offset = (bars.offset + cfg.barHeight + 5);
		end
	end
	if (bars.offset == 0) then
		bars.offset = nil;
	end
	-- Hide GTT Status bar, we have our own, which is prettier!
	if (cfg.hideDefaultBar) then
		GameTooltipStatusBar:Hide();
	end
end

-- Format Number Value
local function FormatValue(val)
	if (val < 10000) then
		return val;
	elseif (val < 1000000) then
		return ("%.1fk"):format(val / 1000);
	else
		return ("%.2fm"):format(val / 1000000);
	end
end

-- Format Bar Text
local function FormatBarValues(fs,val,max,type)
	if (type == "none") then
		fs:SetText("");
	elseif (type == "auto") then
		fs:SetFormattedText("%s / %s",FormatValue(val),FormatValue(max));
	elseif (type == "deficit") then
		fs:SetFormattedText("%s%d",(val == max and "" or "-"),max - val);
	elseif (type == "value") or (max == 0) then -- max should never be zero, but if it is, dont let it pass through to the "percent" type, or there will be an error
		fs:SetFormattedText("%d / %d",val,max);
	elseif (type == "percent") then
		fs:SetFormattedText("%.0f%%",val / max * 100);
	end
end

-- Update Health & Power
local function UpdateHealthAndPowerBar()
	-- Health
	if (bars[1]:IsShown()) then
		local val, max = UnitHealth(u.token), UnitHealthMax(u.token);
		bars[1]:SetMinMaxValues(0,max);
		bars[1]:SetValue(val);
		FormatBarValues(bars[1].text,val,max,cfg.healthBarText);
	end
	-- Power
	if (bars[2]:IsShown()) then
		local val, max = UnitPower(u.token), UnitPowerMax(u.token);
		bars[2]:SetMinMaxValues(0,max);
		bars[2]:SetValue(val);
		local barText = (u.powerType == 0 and cfg.manaBarText or cfg.powerBarText);
		FormatBarValues(bars[2].text,val,max,barText);
	end
end

--------------------------------------------------------------------------------------------------------
--                                       Auras - Buffs & Debuffs                                      --
--------------------------------------------------------------------------------------------------------

local function CreateAura()
	local aura = CreateFrame("Frame",nil,gtt);
	aura:SetWidth(cfg.auraSize);
	aura:SetHeight(cfg.auraSize);
	aura.count = aura:CreateFontString(nil,"OVERLAY");
	aura.count:SetPoint("BOTTOMRIGHT",1,0);
	aura.count:SetFont(GameFontNormal:GetFont(),(cfg.auraSize / 2),"OUTLINE");
	aura.icon = aura:CreateTexture(nil,"BACKGROUND");
	aura.icon:SetAllPoints();
	aura.icon:SetTexCoord(0.07,0.93,0.07,0.93);
	aura.cooldown = CreateFrame("Cooldown",nil,aura,"CooldownFrameTemplate");
	aura.cooldown:SetReverse(1);
	aura.cooldown:SetAllPoints();
	aura.cooldown:SetFrameLevel(aura:GetFrameLevel());
	aura.border = aura:CreateTexture(nil,"OVERLAY");
	aura.border:SetPoint("TOPLEFT",-1,1);
	aura.border:SetPoint("BOTTOMRIGHT",1,-1);
	aura.border:SetTexture("Interface\\Buttons\\UI-Debuff-Overlays");
	aura.border:SetTexCoord(0.296875,0.5703125,0,0.515625);
	auras[#auras + 1] = aura;
	return aura;
end

-- The outer variable "pos" is the actual index of the shown auras we are actually going to use, in case certain auras are filtered. The "index" variable is for querying the auras.
local function SetupAuras()
	-- Init
	local pos = 1;
	local maxAuras = floor(gtt:GetWidth() / (cfg.auraSize + 1));
	-- Get Buffs
	if (cfg.showBuffs) then
		local index = 1;
		while (true) do
			local _, _, iconTexture, count, debuffType, duration, endTime, casterUnit = UnitAura(u.token,index,"HELPFUL");
			if (not iconTexture) or (pos / maxAuras > cfg.auraMaxRows) then
				break;
			end
			if (not cfg.selfAurasOnly or casterUnit == "player" or casterUnit == "pet" or casterUnit == "vehicle") then
				local aura = auras[pos] or CreateAura();
				-- Anchor It
				aura:ClearAllPoints();
				if (pos == 1) then
					if (cfg.aurasAtBottom) then
						aura:SetPoint("TOPLEFT",gtt,"BOTTOMLEFT");
					else
						aura:SetPoint("BOTTOMLEFT",gtt,"TOPLEFT");
					end
				elseif (maxAuras == 1) or (pos % maxAuras == 1) then
					if (cfg.aurasAtBottom) then
						aura:SetPoint("TOP",auras[pos - maxAuras],"BOTTOM",0,1);
					else
						aura:SetPoint("BOTTOM",auras[pos - maxAuras],"TOP",0,1);
					end
				else
					aura:SetPoint("LEFT",auras[pos - 1],"RIGHT",1,0);
				end
				-- Cooldown
				if (cfg.showAuraCooldown) and (duration and duration > 0 and endTime and endTime > 0) then
					aura.cooldown:SetCooldown(endTime - duration,duration);
				else
					aura.cooldown:Hide();
				end
				-- Set Texture + Count
				aura.icon:SetTexture(iconTexture);
				aura.count:SetText(count and count > 1 and count or "");
				-- Border
				aura.border:Hide();
				-- Show + Next, Break if exceed max desired rows of auras
				aura:Show();
				pos = (pos + 1);
			end
			index = (index + 1);
		end
	end
	-- Get Debuffs
	if (cfg.showDebuffs) and (pos / maxAuras <= cfg.auraMaxRows) then
		local index = 1;
		local buffCount = (pos - 1);
		local lineOffset = floor(buffCount / maxAuras);
		local buffsOnFirstLine = (maxAuras - buffCount % maxAuras);
		while (true) do
			local _, _, iconTexture, count, debuffType, duration, endTime, casterUnit = UnitAura(u.token,index,"HARMFUL");
			if (not iconTexture) or (pos / maxAuras > cfg.auraMaxRows) then
				break;
			end
			if (not cfg.selfAurasOnly or casterUnit == "player" or casterUnit == "pet" or casterUnit == "vehicle") then
				local aura = auras[pos] or CreateAura();
				-- Anchor It
				aura:ClearAllPoints();
				if (pos == buffCount + 1) then
					if (cfg.aurasAtBottom) then
						aura:SetPoint("TOPRIGHT",gtt,"BOTTOMRIGHT",-1,(cfg.auraSize + 1) * lineOffset * -1);
					else
						aura:SetPoint("BOTTOMRIGHT",gtt,"TOPRIGHT",-1,(cfg.auraSize + 1) * lineOffset);
					end
				elseif ((pos - 1) % maxAuras == 0) then
					if (cfg.aurasAtBottom) then
						aura:SetPoint("TOPRIGHT",gtt,"BOTTOMRIGHT",0,(cfg.auraSize + 1) * floor(pos / maxAuras) * -1);
					else
						aura:SetPoint("BOTTOMRIGHT",gtt,"TOPRIGHT",0,(cfg.auraSize + 1) * floor(pos / maxAuras));
					end
				else
					aura:SetPoint("RIGHT",auras[pos - 1],"LEFT",-1,0);
				end
				-- Cooldown
				if (cfg.showAuraCooldown) and (duration and duration > 0 and endTime and endTime > 0) then
					aura.cooldown:SetCooldown(endTime - duration,duration);
				else
					aura.cooldown:Hide();
				end
				-- Set Texture + Count
				aura.icon:SetTexture(iconTexture);
				aura.count:SetText(count and count > 1 and count or "");
				-- Border
				local color = DebuffTypeColor[debuffType] or DebuffTypeColor["none"];
				aura.border:SetVertexColor(color.r,color.g,color.b);
				aura.border:Show();
				-- Show + Next, Break if exceed max desired rows of aura
				aura:Show();
				pos = (pos + 1);
			end
			index = (index + 1);
		end
	end
	-- Hide the Unused
	for i = pos, #auras do
		auras[i]:Hide();
	end
end

--------------------------------------------------------------------------------------------------------
--                                          GameTooltip Hooks                                         --
--------------------------------------------------------------------------------------------------------

--[[
	USEFUL NOTES :: This is apparently the order at which the GTT construsts the tip
	- GameTooltip_SetDefaultAnchor()
	- Internal_Function_Which_Fills_Tip()		-- GTT:GetUnit() becomes valid after this!
	- GTT:Show()								-- Will Resize the tip
	- GTT.OnTooltipSetUnit()
	- Something that resizes the tip, Show() already does this, but it's also done after OnTooltipSetUnit() again. Or maybe it's just another addon's hook doing it. Tested without any addons loaded, and it still resizes after.
--]]

-- GTT Control Variables
local gtt_lastUpdate = 0;
local gtt_newHeight;
local gtt_anchorType;
local gtt_anchorPoint;

-- Get The Anchor Position Depending on the Tip Content and Parent Frame -- Do not depend on "u.token" here, as it might not have been cleared yet!
-- Checking "mouseover" here isn't ideal due to actionbars, it will sometimes return true because of selfcast.
local function GetAnchorPosition()
	local mouseFocus = GetMouseFocus();
	local isUnit = UnitExists("mouseover") or (mouseFocus and mouseFocus:GetAttribute("unit"));
	local var = "anchor"..(mouseFocus == WorldFrame and "World" or "Frame")..(isUnit and "Unit" or "Tip");
	return cfg[var.."Type"], cfg[var.."Point"];
end

-- HOOK: GTT:Show -- If there are any bar offsets, resize the tip
local gttShow = gtt.Show;
gtt.Show = function(self,...)
	gttShow(self,...);
	if (bars.offset) then
		gtt_newHeight = (self:GetHeight() + bars.offset);
		self:SetHeight(gtt_newHeight);
	end
end

-- HOOK: GTT:FadeOut -- This allows us to check when the tip is fading out.
local gttFadeOut = gtt.FadeOut;
gtt.FadeOut = function(self,...)
	if (not u.token) or (not cfg.overrideFade) then
		self.fadeOut = 2; -- Don't allow the OnUpdate handler to run the fadeout/update code
		gttFadeOut(self,...);
	elseif (cfg.preFadeTime == 0 and cfg.fadeTime == 0) then
		self:Hide();
	else
		self.fadeOut = 1;
		gtt_lastUpdate = 0;
	end
end

-- HOOK: GTT OnShow -- This ensures that default anchored world frame tips have the proper color, their internal function seems to set them to a dark blue color
local function GTTHook_OnShow(self,...)
	gtt_anchorType, gtt_anchorPoint = GetAnchorPosition();
	if (gtt_anchorType == "mouse") and (self:GetAnchorType() ~= "ANCHOR_CURSOR") then
		tt:AnchorFrameToMouse(self);
	end
	if (self:IsOwned(UIParent)) and (not self:GetUnit()) then
		self:SetBackdropColor(unpack(cfg.tipColor));
	end
end

-- HOOK: GTT OnUpdate
local function GTTHook_OnUpdate(self,elapsed)
	-- This ensures that mouse anchored world frame tips have the proper color, their internal function seems to set them to a dark blue color
	if (self:GetAnchorType() == "ANCHOR_CURSOR") then
		self:SetBackdropColor(unpack(cfg.tipColor));
		self:SetBackdropBorderColor(unpack(cfg.tipBorderColor));
		return;
	-- Anchor GTT to Mouse
	elseif (gtt_anchorType == "mouse") then
		tt:AnchorFrameToMouse(self);
	end

	-- Fadeout / Update Tip if Showing a Unit
	-- Do not allow (fadeOut == 2), as that is only for non overridden fadeouts, but we still need to keep resizing the tip
	if (u.token) and (self.fadeOut ~= 2) then
		gtt_lastUpdate = (gtt_lastUpdate + elapsed);
		if (self.fadeOut) then
			self:Show(); -- Overrides self:FadeOut()
			if (gtt_lastUpdate > cfg.fadeTime + cfg.preFadeTime) then
				self.fadeOut = nil;
				self:Hide();
			elseif (gtt_lastUpdate > cfg.preFadeTime) then
				self:SetAlpha(1 - (gtt_lastUpdate - cfg.preFadeTime) / cfg.fadeTime);
			end
		-- This is only really useful for worldframe unit tips, when u.token == "mouseover", they do not call the GTT:FadeOut()
		elseif (not UnitExists(u.token)) then
			self:FadeOut();
		elseif (cfg.updateFreq > 0) and (gtt_lastUpdate > cfg.updateFreq) then
			gtt_lastUpdate = 0;
			tt:ApplyGeneralAppearance();
		end
	end

	-- Resize the Tooltip if it's size has changed more than 0.1 units
	if (gtt_newHeight) and (abs(self:GetHeight() - gtt_newHeight) > 0.1) then
		self:SetHeight(gtt_newHeight);
	end
end

-- HOOK: GTT OnTooltipSetUnit
local function GTTHook_OnTooltipSetUnit(self,...)
	-- Hides the tip in combat if one of those options are set. Also checks if the Shift key is pressed, and cancels hiding of the tip (if that option is set, that is)
	if (cfg.hideAllTipsInCombat or cfg.hideUFTipsInCombat and self:GetOwner() ~= UIParent) and (not cfg.showHiddenTipsOnShift or not IsShiftKeyDown()) and (UnitAffectingCombat("player")) then
		self:Hide();
		return;
	end
	local _, unit = self:GetUnit();
	-- Concated unit tokens such as "targettarget" cannot be returned as the unit by GTT:GetUnit() and it will return as "mouseover", but the "mouseover" unit is still invalid at this point for those unitframes!
	-- To overcome this problem, we look if the mouse is over a unitframe, and if that unitframe has a unit attribute set?
	if (not unit) then
		local mFocus = GetMouseFocus();
		unit = mFocus and mFocus:GetAttribute("unit");
	end
	-- A mage's mirror images sometimes doesn't return a unit, this would fix it
	if (not unit) and (UnitExists("mouseover")) then
		unit = "mouseover";
	end
	-- Sometimes when you move your mouse quicky over units in the worldframe, we can get here without a unit
	if (not unit) then
		self:Hide();
		return;
	end
	-- A "mouseover" unit is better to have as we can then safely say the tip should no longer show when it becomes invalid. Harder to say with a "party2" unit.
	-- This also helps fix the problem that "mouseover" units aren't valid for group members out of range, a bug that has been in WoW since 3.0.2 I think.
	if (UnitIsUnit(unit,"mouseover")) then
		unit = "mouseover";
	end
	-- We're done, apply appearance
	u.token = unit;
	self.fadeOut = nil; -- Az: Sometimes this wasn't getting reset, the fact a cleanup isn't performed at this point, now that it was moved to "OnTooltipCleared" is very bad, so this is a fix
	tt:ApplyGeneralAppearance(true);
end

-- HOOK: GTT OnTooltipCleared -- This will clean up auras, bars, raid icon and vars for the gtt when we aren't showing a unit
local function GTTHook_OnTooltipCleared(self,...)
	wipe(u);
	gtt_lastUpdate = 0;
	gtt_newHeight = nil;
	self.fadeOut = nil;
	bars.offset = nil;
	for i = 1, #bars do
		bars[i]:Hide();
	end
	for i = 1, #auras do
		auras[i]:Hide();
	end
	if (tipIcon) then
		tipIcon:Hide();
	end
end

-- OnHide Script -- Used to default the background and border color
local function TipHook_OnHide(self,...)
	self:SetBackdropColor(unpack(cfg.tipColor));				-- Default: For most: (0.1,0.1,0.2), World Objects?: (0,0.2,0.35)
	self:SetBackdropBorderColor(unpack(cfg.tipBorderColor));	-- Default: (1,1,1,1)
end

-- OnTooltipSetItem Script -- For item colored border
local function TipHook_OnTooltipSetItem(self,...)
	if (cfg.itemQualityBorder) then
		local _, link = self:GetItem();
		if (link) then
			local _, _, rarity = GetItemInfo(link);
			self:SetBackdropBorderColor(GetItemQualityColor(rarity or 0));
		end
	end
end

-- Function to loop through tips to modify and hook
function tt:HookTips()
	-- Need to be called as late as possible during load, as we want to try and be the last addon to hook "OnTooltipSetUnit" so we always have a "completed" tip to work on
	gtt:HookScript("OnShow",GTTHook_OnShow);
	gtt:HookScript("OnUpdate",GTTHook_OnUpdate);
	gtt:HookScript("OnTooltipSetUnit",GTTHook_OnTooltipSetUnit);
	gtt:HookScript("OnTooltipCleared",GTTHook_OnTooltipCleared);
	-- HOOK: OnHide & OnTooltipSetItem Scripts
	for index, tip in ipairs(TT_TipsToModify) do
		tip = (_G[tip] or false);	-- don't want to nil out an entry
		TT_TipsToModify[index] = tip;
		if (type(tip) == "table") and (type(tip.GetObjectType) == "function") then
			tip:HookScript("OnHide",TipHook_OnHide);
			if (tip:HasScript("OnTooltipSetItem")) then
				tip:HookScript("OnTooltipSetItem",TipHook_OnTooltipSetItem);
			end
		end
	end
	-- Replace GameTooltip_SetDefaultAnchor (For Re-Anchoring) -- Patch 3.2 made this function secure for some reason
	hooksecurefunc("GameTooltip_SetDefaultAnchor",function(tooltip,parent)
		-- Return if no tooltip or parent
		if (not tooltip or not parent) then
			return;
		end
		-- Position Tip to Normal, Mouse or Parent anchor
		gtt_anchorType, gtt_anchorPoint = GetAnchorPosition();
		tooltip:SetOwner(parent,"ANCHOR_NONE");
		if (gtt_anchorType == "mouse") then
			tt:AnchorFrameToMouse(tooltip);
		elseif (gtt_anchorType == "parent") then
			tooltip:SetPoint(TT_MirrorAnchorsSmart[gtt_anchorPoint] or TT_MirrorAnchors[gtt_anchorPoint],parent,gtt_anchorPoint);
		else
			tooltip:SetPoint(gtt_anchorPoint,tt);
		end
		tooltip.default = 1;
	end);
	-- Clear this function as it's not needed anymore
	self.HookTips = nil;
end

--------------------------------------------------------------------------------------------------------
--                                              Settings                                              --
--------------------------------------------------------------------------------------------------------

-- Setup Gradient Tip
local function SetupGradientTip(tip)
	local g = tip.tipTacGradient;
	if (not cfg.gradientTip) then
		if (g) then
			g:Hide();
		end
		return;
	elseif (not g) then
		g = tip:CreateTexture();
		g:SetTexture(1,1,1,1);
		tip.tipTacGradient = g;
	end
	g:SetGradientAlpha("VERTICAL",0,0,0,0,unpack(cfg.gradientColor));
	g:SetPoint("TOPLEFT",cfg.backdropInsets,cfg.backdropInsets * -1);
	g:SetPoint("BOTTOMRIGHT",tip,"TOPRIGHT",cfg.backdropInsets * -1,-36);
	g:Show();
end

-- Apply Settings
function tt:ApplySettings()
	-- Hide World Tips Instantly
	if (cfg.hideWorldTips) then
		self:RegisterEvent("CURSOR_UPDATE");
	else
		self:UnregisterEvent("CURSOR_UPDATE");
	end
	-- Set Backdrop
	tipBackdrop.bgFile = cfg.tipBackdropBG;
	tipBackdrop.edgeFile = cfg.tipBackdropEdge;
	tipBackdrop.edgeSize = cfg.backdropEdgeSize;
	tipBackdrop.insets.left = cfg.backdropInsets;
	tipBackdrop.insets.right = cfg.backdropInsets;
	tipBackdrop.insets.top = cfg.backdropInsets;
	tipBackdrop.insets.bottom = cfg.backdropInsets;
	-- Set Scale, Backdrop, Gradient
	for _, tip in ipairs(TT_TipsToModify) do
		if (type(tip) == "table") and (type(tip.GetObjectType) == "function") then
			SetupGradientTip(tip);
			tip:SetScale(cfg.gttScale);
			tip:SetBackdrop(tipBackdrop);
			tip:SetBackdropColor(unpack(cfg.tipColor));
			tip:SetBackdropBorderColor(unpack(cfg.tipBorderColor));
		end
	end
	-- Bar Appearances
	GameTooltipStatusBar:SetStatusBarTexture(cfg.barTexture);
	GameTooltipStatusBar:GetStatusBarTexture():SetHorizTile(false);	-- Az: 3.3.3 fix
	GameTooltipStatusBar:GetStatusBarTexture():SetVertTile(false);	-- Az: 3.3.3 fix
	GameTooltipStatusBar:SetHeight(cfg.barHeight);
	for _, bar in ipairs(bars) do
		bar:SetStatusBarTexture(cfg.barTexture);
		bar:GetStatusBarTexture():SetHorizTile(false);	-- Az: 3.3.3 fix
		bar:GetStatusBarTexture():SetVertTile(false);	-- Az: 3.3.3 fix
		bar:SetHeight(cfg.barHeight);
		bar.text:SetFont(cfg.barFontFace,cfg.barFontSize,cfg.barFontFlags);
	end
	-- If disabled, hide auras, else set their size
	for _, aura in ipairs(auras) do
		if (cfg.showBuffs or cfg.showDebuffs) then
			aura:SetWidth(cfg.auraSize);
			aura:SetHeight(cfg.auraSize);
			aura.count:SetFont("Fonts\\FRIZQT__.TTF",(cfg.auraSize / 2),"OUTLINE");
		else
			aura:Hide();
		end
	end
	-- GameTooltip Font Templates
	if (cfg.modifyFonts) then
		GameTooltipHeaderText:SetFont(cfg.fontFace,cfg.fontSize + 2,cfg.fontFlags);
		GameTooltipText:SetFont(cfg.fontFace,cfg.fontSize,cfg.fontFlags);
		GameTooltipTextSmall:SetFont(cfg.fontFace,cfg.fontSize - 2,cfg.fontFlags);
	end
	-- Raid Icon
	if (cfg.iconRaid or cfg.iconFaction or cfg.iconCombat) and (not tipIcon) then
		tipIcon = gtt:CreateTexture(nil,"BACKGROUND");
	end
	if (tipIcon) then
		if (cfg.iconRaid or cfg.iconFaction or cfg.iconCombat) then
			tipIcon:SetWidth(cfg.iconSize);
			tipIcon:SetHeight(cfg.iconSize);
			tipIcon:ClearAllPoints();
			tipIcon:SetPoint(TT_MirrorAnchors[cfg.iconAnchor],gtt,cfg.iconAnchor);
		else
			tipIcon:Hide();
		end
	end
end

--------------------------------------------------------------------------------------------------------
--                                          TipTac Functions                                          --
--------------------------------------------------------------------------------------------------------

-- Allows other mods to "register" tooltips or frames to be modified by TipTac
function tt:AddModifiedTip(tip,noHooks)
	if (type(tip) == "string") then
		tip = _G[tip];
	end
	if (type(tip) == "table") and (type(tip.GetObjectType) == "function") then
		TT_TipsToModify[#TT_TipsToModify + 1] = tip;
		if (not noHooks) then
			tip:HookScript("OnHide",TipHook_OnHide);
			if (tip:HasScript("OnTooltipSetItem")) then
				tip:HookScript("OnTooltipSetItem",TipHook_OnTooltipSetItem);
			end
		end
		self:ApplySettings();
	end
end

-- Anchor any given frame to mouse position
function tt:AnchorFrameToMouse(frame)
	local x, y = GetCursorPosition();
	local effScale = frame:GetEffectiveScale();
	frame:ClearAllPoints();
	frame:SetPoint(gtt_anchorPoint,UIParent,"BOTTOMLEFT",(x / effScale + cfg.mouseOffsetX),(y / effScale + cfg.mouseOffsetY));
end

-- Apply TipTac Appearance
local function ApplyTipTacAppearance(first)
	-- Store Original Name
	if (first) and (cfg.nameType == "original") then
		u.originalName = GameTooltipTextLeft1:GetText();
	end
	-- Find NPC Title -- Az: 09.08.22: Should work with colorblind mode now
	if (first) and (not u.isPlayer) then
		u.title = (isColorBlind and GameTooltipTextLeft3 or GameTooltipTextLeft2):GetText();
		if (u.title) and (u.title:find(TT_LevelMatch)) then
			u.title = nil;
		end
	end
	-- Modify the Tip
	ModifyUnitTooltip();
	if (first) and (cfg.showTargetedBy) then
		AddTargetedBy();
	end
	-- Bars
	if (first) or (UnitPowerType(u.token) ~= u.powerType) then
		SetupHealthAndPowerBar();
	end
	UpdateHealthAndPowerBar();
	-- Remove PVP Line, which makes the tip look a bit bad
	for i = 2, gtt:NumLines() do
		local line = _G["GameTooltipTextLeft"..i];
		if (line:GetText() == PVP_ENABLED) then
			line:SetText(nil);
			break;
		end
	end
	-- Show & Adjust Height
	gtt:Show();
end

-- Apply General Appearance
function tt:ApplyGeneralAppearance(first)
	u.isPlayer = UnitIsPlayer(u.token);
	u.reactionIndex = GetUnitReactionIndex(u.token);
	-- Reaction Backdrop/Border Color
	if (cfg.reactColoredBackdrop) then
		gtt:SetBackdropColor(unpack(cfg["colReactBack"..u.reactionIndex]));
	end
	if (cfg.reactColoredBorder) then
		gtt:SetBackdropBorderColor(unpack(cfg["colReactBack"..u.reactionIndex]));
	-- Class Colored Border
	elseif (first) and (cfg.classColoredBorder) and (u.isPlayer) then
		local _, classEng = UnitClass(u.token);
		local color = CLASS_COLORS[classEng];
		gtt:SetBackdropBorderColor(color.r,color.g,color.b);
	end
	-- Raid Icon
	if (cfg.iconRaid or cfg.iconFaction or cfg.iconCombat) then
		local raidIconIndex = GetRaidTargetIndex(u.token);
		if (cfg.iconRaid) and (raidIconIndex) then
			tipIcon:SetTexture("Interface\\TargetingFrame\\UI-RaidTargetingIcons");
			SetRaidTargetIconTexture(tipIcon,raidIconIndex);
			tipIcon:Show();
		elseif (cfg.iconFaction) and (UnitIsPVPFreeForAll(u.token)) then
			tipIcon:SetTexture("Interface\\TargetingFrame\\UI-PVP-FFA");
			tipIcon:SetTexCoord(0,0.62,0,0.62);
			tipIcon:Show();
		elseif (cfg.iconFaction) and (UnitIsPVP(u.token)) and (UnitFactionGroup(u.token)) then
			tipIcon:SetTexture("Interface\\TargetingFrame\\UI-PVP-"..UnitFactionGroup(u.token));
			tipIcon:SetTexCoord(0,0.62,0,0.62);
			tipIcon:Show();
		elseif (cfg.iconCombat) and (UnitAffectingCombat(u.token)) then
			tipIcon:SetTexture("Interface\\CharacterFrame\\UI-StateIcon");
			tipIcon:SetTexCoord(0.5,1,0,0.5);
			tipIcon:Show();
		else
			tipIcon:Hide();
		end
	end
	-- TipTac Appearance
	if (cfg.showUnitTip) then
		ApplyTipTacAppearance(first);
	end
	-- Auras - Has to be updated last because it depends on the tips new dimention
	if (cfg.showBuffs or cfg.showDebuffs) then
		SetupAuras();
	end
end