local _G = getfenv(0);

-- Saved Data Tables
Examiner_Config = {};
Examiner_Cache = {};

-- Working Vars
local u = {};
local ExStats = {};
local ExSets = {};
local ExCacheList = {};
local ExStatList = {};
local ExCompare;

-- Misc Constants
local EX_MagicSchools = { "ARCANE", "FIRE", "NATURE", "FROST", "SHADOW", "HOLY" };

local EX_Frames = { "Config", "Cache", "Stat", "PVP" };

local EX_Checks = {
	{ var = "EnableCache", label = "살펴본 대상 정보 저장", tip = "체크시, 매번 대상을 살펴보기 할 때 마다, 대상의 아이템 정보가 저장되어 추 후에 다시 확인 할 수 있습니다." },
	{ var = "CachePvP", label = "명예/투기장 정보 저장", tip = "체크시, 대상의 명예/투기장 정보를 함께 저장합니다. (메모리 점유율 증가)" },
	{ var = "SpellDmgToSchools", label = "원소 공격력을 주문 공격력에 합산", tip = "체크시, 기본 주문 공격력을 특정 계열 주문 공격력에 합산 하여 보여줍니다." },
	{ var = "RatingsInPercent", label = "적중도 퍼센트 표시", tip = "체크시, 각종 적중도는 대상의 레벨에 준하여 퍼센트로 표시됩니다." },
	{ var = "ActAsUIFrame", label = "프레임 고정", tip = "체크시, Examiner 창은 다른 일반 UI 프레임 (특성창, 퀘스트창, 우편함 프레임) 처럼 고정된 형태로 표시됩니다, 체크하지 않으면 자유롭게 이동이 가능합니다." },
	{ var = "AutoInspect", label = "대상 변경시 자동 살펴보기", tip = "체크시, 대상을 살펴보기 중 대상이 변경되면 변경된 대상을 자동으로 살펴보기를 실행합니다." },
	{ var = "AcceptAddonMsg", label = "정보 공유", tip = "체크시, Examiner는 다른 Examiner 사용자가 보내오는 살펴보기 정보를 공유 합니다." },
	{ var = "ScanUnknownItems", label = "알려지지 않은 캐쉬 아이템 검색", tip = "저장된 정보를 불러올시, 일반적으로 Examiner는 강제 종료를 피하기 위해 로컬 아이템 캐쉬에 포함되지 않은 아이템은 무시합니다. 강제 종료의 위험 부담을 감수 하고 사용하고자 한다면 체크하세요." },
};

local EX_DefaultConfig = {
	EnableCache = true,
	CachePvP = false,
	SpellDmgToSchools = true,
	RatingsInPercent = false,
	ActAsUIFrame = true,
	AutoInspect = true,
	AcceptAddonMsg = false,
	ScanUnknownItems = false,
	cacheSort = "class",
	scale = 1,
};

-- Texture Mapping
local EX_Backgrounds = {
	"DruidBalance",
	"DruidFeralCombat",
	"DruidRestoration",
	"HunterBeastMastery",
	"HunterMarksmanship",
	"HunterSurvival",
	"MageArcane",
	"MageFire",
	"MageFrost",
	"PaladinCombat",
	"PaladinHoly",
	"PaladinProtection",
	"PriestDiscipline",
	"PriestHoly",
	"PriestShadow",
	"RogueAssassination",
	"RogueCombat",
	"RogueSubtlety",
	"ShamanElementalCombat",
	"ShamanEnhancement",
	"ShamanRestoration",
	"WarlockCurses",
	"WarlockDestruction",
	"WarlockSummoning",
	"WarriorArms",
	"WarriorFury",
	"WarriorProtection",
};

-- RaceCoords. For females, add 0.5 to "top" and "bottom".
-- Interface\\Glues\\CharacterCreate\\UI-CharacterCreate-Races
local EX_RaceCoord = {
	["Human"]		= { left = 0/8, right = 1/8, top = 0/4, bottom = 1/4 },
	["Dwarf"]		= { left = 1/8, right = 2/8, top = 0/4, bottom = 1/4 },
	["Gnome"]		= { left = 2/8, right = 3/8, top = 0/4, bottom = 1/4 },
	["NightElf"]	= { left = 3/8, right = 4/8, top = 0/4, bottom = 1/4 },
	["Draenei"]		= { left = 4/8, right = 5/8, top = 0/4, bottom = 1/4 },
	["Tauren"]		= { left = 0/8, right = 1/8, top = 1/4, bottom = 2/4 },
	["Scourge"]		= { left = 1/8, right = 2/8, top = 1/4, bottom = 2/4 },
	["Troll"]		= { left = 2/8, right = 3/8, top = 1/4, bottom = 2/4 },
	["Orc"]			= { left = 3/8, right = 4/8, top = 1/4, bottom = 2/4 },
	["BloodElf"]	= { left = 4/8, right = 5/8, top = 1/4, bottom = 2/4 },
};

--------------------------------------------------------------------------------------------------------
--                                         OnLoad & OnUpdate                                          --
--------------------------------------------------------------------------------------------------------
function Examiner_OnLoad(self)
	-- Init Specific Mod Vars
	self.modName = "Examiner";
	self.modVers = GetAddOnMetadata(self.modName,"Version");
	-- Events
	self:RegisterEvent("VARIABLES_LOADED");
	self:RegisterEvent("PLAYER_TARGET_CHANGED");
	self:RegisterEvent("UNIT_MODEL_CHANGED");
	self:RegisterEvent("UNIT_PORTRAIT_UPDATE");
	self:RegisterEvent("UNIT_INVENTORY_CHANGED");
	self:RegisterEvent("INSPECT_HONOR_UPDATE");
	self:RegisterEvent("INSPECT_TALENT_READY");
	self:RegisterEvent("CHAT_MSG_ADDON");
	-- Add Slash Command
	SlashCmdList["EXAMINER"] = Examiner_OnSlash;
	SLASH_EXAMINER1 = "/examiner";
	SLASH_EXAMINER2 = "/ex";
	-- Set Misc Stuff
	self.showItems = true;
	self.activePage = 3;
	Examiner_ConfigFrameFooter:SetText("Examiner |cffffff80"..self.modVers);
	-- UI Panel Entry
	UIPanelWindows[self.modName] = { area = "left", pushable = 1, whileDead = 1 };
	-- Hook Blizz Inspect
	InspectUnit = Examiner_InspectUnit;
	UnitPopupButtons["INSPECT"].dist = 0;
	-- Talent Init
	Examiner.inspect = true;
	TalentFrame_Load(Examiner);
	-- Talent Tabs
	self.selectedTab = 1;
	self.currentSelectedTab = 1;
	PanelTemplates_SetNumTabs(self,5);
	PanelTemplates_UpdateTabs(self);
end

-- OnUpdate
function Examiner_OnUpdate(self,elapsed)
	if (self.markForUpdate) and (Examiner_CheckLastUnit()) and (CheckInteractDistance(u.token,1)) then
		Examiner_InspectUnit(u.token);
	end
end

--------------------------------------------------------------------------------------------------------
--                                           Event Handling                                           --
--------------------------------------------------------------------------------------------------------
function Examiner_OnEvent(self,event)
	-- Variables Loaded
	if (event == "VARIABLES_LOADED") then
		-- Default Config
		for option, defValue in pairs(EX_DefaultConfig) do
			if (Examiner_Config[option] == nil) then
				Examiner_Config[option] = defValue;
			end
		end
		-- Set Scale & Frame Movability
		self:SetScale(Examiner_Config.scale);
		self:SetMovable(not Examiner_Config.ActAsUIFrame);
	-- AddOn Message
	elseif (event == "CHAT_MSG_ADDON") and (Examiner_Config.AcceptAddonMsg) then
		if (arg3 == "WHISPER") and (arg2 ~= "") and (arg1:sub(1,8) == "EXAMINER") then
			-- Split
			local entryName, data = arg1:match("^EXAMINER#(.-)#(.+)$");
			data = { entryName, ("\\"):split(data) };
			-- Special Commands
			if (data[2] and data[2] == "CMD") then
				if (arg2 == "CLEAR") then
					Examiner_Cache[data[1]] = { Items = {}, Sets = {} };
				elseif (arg2 == "DONE") then
					AzMsg("|2Examiner|r |1"..Examiner_PlayerChatLink(data[1]).."|r 에 대한 살펴보기 정보가 |1"..Examiner_PlayerChatLink(arg4).."|r 로 부터 도착하였습니다.");
					SendAddonMessage("EXAMINER#"..data[1].."#CMD","RECIEVED","WHISPER",arg4);
					if (Examiner.activePage == 2) then
						Examiner_BuildCacheList();
					end
				elseif (arg2 == "RECIEVED") then
					AzMsg("|2Examiner|r 당신은 |1"..Examiner_PlayerChatLink(data[1]).."|r 에 대한 살펴보기 정보를 |1"..Examiner_PlayerChatLink(arg4).."|r 로 부터 받았습니다.");
				end
				return;
			end
			-- Fill out table
			local cache = Examiner_Cache;
			for i = 1, #data - 1 do
				if (not cache[data[i]]) then
					cache[data[i]] = {};
				end
				cache = cache[data[i]];
			end
			-- Set Value
			cache[data[#data]] = (tonumber(arg2) and tonumber(arg2) or arg2);
		end
	------------------------------------
	-- End Here if Examiner is Closed --
	------------------------------------
	elseif (not Examiner:IsVisible()) then
		return;
	-- Target Unit Changed
	elseif (event == "PLAYER_TARGET_CHANGED") then
		if (Examiner_Config.AutoInspect) and (UnitExists("target")) then
			Examiner_InspectUnit("target");
		elseif (u.token == "target") then
			u.token = nil;
			self.markForUpdate = nil;
		end
	-- Mouseover Unit Changed
	elseif (event == "UPDATE_MOUSEOVER_UNIT") then
		u.token = nil;
		self.markForUpdate = nil;
		self:UnregisterEvent("UPDATE_MOUSEOVER_UNIT");
	-- Model or Portrait Change
	elseif (event == "UNIT_MODEL_CHANGED" or event == "UNIT_PORTRAIT_UPDATE") then
		if (Examiner_CheckLastUnit() and UnitIsUnit(arg1,u.token)) then
			ExaminerModel:ClearModel();
			ExaminerModel:SetUnit(u.token);
			SetPortraitTexture(ExaminerPortrait,u.token);
		end
	-- Refresh on Item Change
	elseif (event == "UNIT_INVENTORY_CHANGED") then
		if (Examiner_CheckLastUnit() and UnitIsUnit(arg1,u.token) and CheckInteractDistance(u.token,1)) then
			Examiner_InspectUnit(u.token);
		end
	-- Honor Update
	elseif (event == "INSPECT_HONOR_UPDATE") then
		Examiner_PVPUpdate();
	-- Talent Update
	elseif (event == "INSPECT_TALENT_READY") then
		if (ExaminerTalents:IsShown()) then
			Examiner_TalentsUpdateTabs();
			TalentFrame_Update(Examiner);
		end
		u.talents = select(3,GetTalentTabInfo(1,true)).."/"..select(3,GetTalentTabInfo(2,true)).."/"..select(3,GetTalentTabInfo(3,true));
		Examiner_BuildStatList();
		if (Examiner_Config.EnableCache) then
			local cacheEntry = Examiner_Cache[Examiner_GetEntryName()];
			if (cacheEntry) then
				cacheEntry.talents = u.talents;
			end
		end
	end
end

--------------------------------------------------------------------------------------------------------
--                                           Slash Handling                                           --
--------------------------------------------------------------------------------------------------------
function Examiner_OnSlash(cmd)
	-- Extract Parameters
	local param1, param2 = cmd:match("^([^%s]+)%s*(.*)$");
	param1 = (param1 and param1:lower() or cmd:lower());
	-- Inspect!
	if (param1 == "inspect" or param1 == "i") then
		Examiner_InspectUnit(param2 == "" and "target" or param2);
	-- Scan a Single Item
	elseif (param1 == "si") then
		if (param2 ~= "") then
			local itemStats = {};
			ExScanner:ScanItemLink(param2,itemStats);
			AzMsg("--- |2검색 결과 : "..param2.."|r ---");
			for stat in pairs(itemStats) do
				AzMsg((ExScanner.StatNames[stat] or stat).." = |1"..Examiner_GetStatValue(stat,itemStats).."|r.");
			end
		else
			AzMsg("아이템링크가 없습니다.");
		end
	-- Compares two Items
	elseif (param1 == "compare") then
		if (param2 ~= "") then
			local item1, item2 = param2:match("(|c.+|r)%s+(|c.+|r)");
			if (item1 and item2) then
				local itemStats1, itemStats2 = {}, {};
				local value;
				ExScanner:ScanItemLink(item1,itemStats1);
				ExScanner:ScanItemLink(item2,itemStats2);
				AzMsg("--- |2검색 결과 : "..item1.."|2 와(과) "..item2.."|2 의 비교정보|r ---");
				for stat, name in pairs(ExScanner.StatNames) do
					if (itemStats1[stat] or itemStats2[stat]) then
						value = Examiner_GetStatValue(stat,itemStats1) - Examiner_GetStatValue(stat,itemStats2);
						if (value > 0) then
							value = "|cff80ff80+"..value;
						elseif (value < 0) then
							value = "|cffff8080"..value;
						end
						AzMsg(name.." = |1"..value.."|r.");
					end
				end
			else
				AzMsg("아이템 링크를 찾을 수 없습니다.");
			end
		else
			AzMsg("아이템 링크 정보가 없습니다.");
		end
	-- Arena Calculator
	elseif (param1 == "arena") then
		param2 = tonumber(param2);
		if (type(param2) == "number") then
			AzMsg(format("|2Arena Point Calculation|r |1%d|r Rating |2=|r 2v2: |1%.1f|r, 3v3: |1%.1f|r, 5v5: |1%.1f|r.",param2,Examiner_CalculateArenaPoints(param2,2),Examiner_CalculateArenaPoints(param2,3),Examiner_CalculateArenaPoints(param2,5)));
		end
	-- Send Inspection Data
	elseif (param1 == "send") then
		Examiner_SendPlayer(param2);
	-- Scale
	elseif (param1 == "scale") then
		param2 = tonumber(param2);
		if (type(param2) == "number") then
			Examiner_Config.scale = param2;
			Examiner:SetScale(param2);
		end
	-- Invalid or No Command
	else
		UpdateAddOnMemoryUsage();
		AzMsg("----- |2"..Examiner.modName.."|r |1"..Examiner.modVers.."|r ----- |1"..format("%.2f",GetAddOnMemoryUsage(Examiner.modName)).." |2kb|r -----");
		AzMsg("다음 |2명령어|r들을 사용하실 수 있습니다. |2/examiner|r 또는 |2/ex|r:");
		AzMsg(" |2inspect '대상이름'|r = 대상이름을 살펴보기 합니다.(이름이 주어지지 않았을 시엔 대상을 살펴봅니다.");
		AzMsg(" |2si '아이템링크'|r = 아이템을 검색하여 해당 아이템의 능력치 총계량을 보여줍니다.");
		AzMsg(" |2compare '아이템링크1' '아이템링크2'|r = 주어진 두 아이템의 능력치를 비교합니다.");
		AzMsg(" |2send '보낼사람'|r = 현재 자신의 살펴보기 정보를 Examiner를 사용하는 다른 유저에게 보냅니다.");
		AzMsg(" |2scale '변수'|r = Examiner 창의 크기를 설정합니다. (기본값 1)");
		AzMsg(" |2arena '점수'|r = 투기장 평점 계산기");
	end
end

--------------------------------------------------------------------------------------------------------
--                                Global Chat Message Function (Rev 2)                                --
--------------------------------------------------------------------------------------------------------
if (not AZMSG_REV or AZMSG_REV < 2) then
	AZMSG_REV = 2;
	function AzMsg(text)
		text = tostring(text):gsub("|1","|cffffff80"):gsub("|2","|cffffffff");
		DEFAULT_CHAT_FRAME:AddMessage(text,128/255,192/255,255/255);
	end
end
--------------------------------------------------------------------------------------------------------
--                                            Model Frame                                             --
--------------------------------------------------------------------------------------------------------

function Examiner_Model_OnUpdate(self,elapsed)
	if (self.isRotating) then
		local endx, endy = GetCursorPosition();
		self.rotation = (endx - self.startx) / 34 + self:GetFacing();
		self:SetFacing(self.rotation);
		self.startx, self.starty = GetCursorPosition();
	elseif (self.isPanning) then
		local endx, endy = GetCursorPosition();
		local z, x, y = self:GetPosition(z,x,y);
		x = (endx - self.startx) / 45 + x;
		y = (endy - self.starty) / 45 + y;
		self:SetPosition(z,x,y);
		self.startx, self.starty = GetCursorPosition();
	end
end

function Examiner_Model_OnMouseWheel(self)
	local z, x, y = self:GetPosition();
	local scale = (IsControlKeyDown() and 2 or 0.7);
	z = (arg1 > 0 and z + scale or z - scale);
	self:SetPosition(z,x,y);
end

function Examiner_Model_OnMouseDown(self)
	self.startx, self.starty = GetCursorPosition();
	if (arg1 == "LeftButton") then
		self.isRotating = 1;
		if (IsControlKeyDown()) then
			Examiner_SetBackgroundTexture(nil);
		end
	elseif (arg1 == "RightButton") then
		self.isPanning = 1;
		if (IsControlKeyDown()) then
			Examiner_ToggleBackground();
		end
	end
end

function Examiner_Model_OnMouseUp(self)
	if (arg1 == "LeftButton") then
		self.isRotating = nil;
	elseif (arg1 == "RightButton") then
		self.isPanning = nil;
	end
end

--------------------------------------------------------------------------------------------------------
--                                            Config Stuff                                            --
--------------------------------------------------------------------------------------------------------

-- CheckBoxes: OnLoad
function Examiner_ConfigCheckBox_OnLoad(self)
	self.tooltipText = EX_Checks[self:GetID()].tip;
	_G[self:GetName().."Text"]:SetText(EX_Checks[self:GetID()].label);
end

-- Config Frame OnShow
function Examiner_Config_OnShow()
	for index, table in ipairs(EX_Checks) do
		_G["Examiner_ConfigFrameCheck"..index]:SetChecked(Examiner_Config[EX_Checks[index].var]);
	end
end

-- CheckBoxes: OnClick
function Examiner_ConfigCheckBox_OnClick(self,button)
	local id = self:GetID();
	Examiner_Config[EX_Checks[id].var] = not Examiner_Config[EX_Checks[id].var];
	if (EX_Checks[id].var == "SpellDmgToSchools" or EX_Checks[id].var == "RatingsInPercent") then
		Examiner_BuildStatList();
	elseif (EX_Checks[id].var == "ActAsUIFrame") then
		Examiner:SetMovable(not Examiner_Config.ActAsUIFrame);
		if (Examiner_Config.ActAsUIFrame) then
			Examiner:Hide();
			ShowUIPanel(Examiner);
		else
			HideUIPanel(Examiner);
			Examiner:Show();
		end
	end
end

--------------------------------------------------------------------------------------------------------
--                                             Item Slots                                             --
--------------------------------------------------------------------------------------------------------

-- OnLoad
function Examiner_ItemSlots_OnLoad(self)
	local buttonName = self:GetName();
	local slotId;
	self.slotName = buttonName:sub(20);
	slotId, self.backgroundTextureName = GetInventorySlotInfo(self.slotName);
	_G[buttonName.."IconTexture"]:SetTexture(self.backgroundTextureName);
	self:RegisterForDrag("LeftButton");
	self:SetID(slotId);
end

-- OnClick
function Examiner_ItemSlots_OnClick(self,button)
	if (self.link) then
		if (IsControlKeyDown()) then
			DressUpItemLink(self.link);
			return;
		elseif (IsShiftKeyDown()) and (ChatFrameEditBox:IsVisible()) then
			ChatFrameEditBox:Insert(select(2,GetItemInfo(self.link)));
			return;
		end
	elseif (self.realLink) then
		ExScanner.Tooltip:ClearLines();
		ExScanner.Tooltip:SetHyperlink(self.realLink);
		Examiner_LoadPlayerFromCache(Examiner_Cache[Examiner_GetEntryName()],0);
		Examiner_ItemSlots_OnEnter(self);
	end
	Examiner_ItemSlots_OnDrag(self);
end

-- OnDrag
function Examiner_ItemSlots_OnDrag(self)
	if (Examiner_CheckLastUnit() and UnitIsUnit(u.token,"player")) then
		PickupInventoryItem(self:GetID());
	end
end

-- OnEnter
function Examiner_ItemSlots_OnEnter(self)
	GameTooltip:SetOwner(self,"ANCHOR_RIGHT");
	if (Examiner_CheckLastUnit() and CheckInteractDistance(u.token,1) and GameTooltip:SetInventoryItem(u.token,self:GetID())) then
	elseif (self.link) then
		GameTooltip:SetHyperlink(self.link);
	elseif (self.realLink) then
		GameTooltip:SetText(_G[self.slotName:upper()]);
		GameTooltip:AddLine("ItemID: "..self.realLink:match("item:(%d+)"),0,0.44,0.86);
		GameTooltip:AddLine("This item is unsafe, you can click to query\nthe server, but it may result in a disconnect.",1,1,1);
		GameTooltip:Show();
	else
		GameTooltip:SetText(_G[self.slotName:upper()]);
	end
end

-- OnLeave
function Examiner_ItemSlots_OnLeave(self)
	ResetCursor();
	GameTooltip:Hide();
	Examiner.statTooltip = nil;
end

-- OnUpdate
function Examiner_ItemSlots_OnUpdate(self,elapsed)
	if (GameTooltip:IsOwned(self)) and (self.link) then
		-- Inspect Cursor
		if (IsControlKeyDown()) then
			ShowInspectCursor();
		else
			ResetCursor();
		end
		-- Stat Tip Hide
		if (not IsAltKeyDown()) and (Examiner.statTooltip) then
			Examiner.statTooltip = nil;
			Examiner_ItemSlots_OnEnter(self);
		-- Stat Tip Show (Az: Does not support compare yet)
		elseif (IsAltKeyDown()) and (not Examiner.statTooltip) then
			Examiner.statTooltip = 1;
			GameTooltip:SetOwner(self,"ANCHOR_RIGHT");
			local itemStats = {};
			local itemName, _, itemRarity = GetItemInfo(self.link);
			GameTooltip:AddLine(itemName,GetItemQualityColor(itemRarity));
			ExScanner:ScanItemLink(self.link,itemStats);
			for stat in pairs(itemStats) do
				GameTooltip:AddDoubleLine(ExScanner.StatNames[stat] or stat,Examiner_GetStatValue(stat,itemStats),1,1,1);
			end
			GameTooltip:Show();
		end
		-- Equip Compare Tip
		if (not Examiner.statTooltip) then
			if (IsShiftKeyDown()) and (not ShoppingTooltip1:IsVisible()) then
				GameTooltip_ShowCompareItem();
			elseif (not IsShiftKeyDown()) and (ShoppingTooltip1:IsVisible()) then
				ShoppingTooltip1:Hide();
				ShoppingTooltip2:Hide();
			end
		end
	end
end

-- UpdateSlot: Updates slot from "button.link"
function Examiner_ItemSlots_UpdateItemSlot(button)
	local border = _G[button:GetName().."BorderTexture"];
	if (button.link) then
		local _, _, itemRarity, _, _, _, _, _, _, itemTexture = GetItemInfo(button.link);
		-- Set Texture
		SetItemButtonTexture(button,itemTexture or button.backgroundTextureName);
		-- Set Rarity Border Color
		--[[local r,g,b = GetItemQualityColor(itemRarity and itemRarity ~= 1 and itemRarity or 0);
		border:SetVertexColor(r,g,b);
		border:Show();]]
		if (itemRarity) and (itemRarity ~= -1) then
			local r,g,b = GetItemQualityColor(itemRarity);
			border:SetVertexColor(r,g,b,1);

			border:SetBlendMode"ADD" -- 두꺼운 테두리
			border:SetAlpha(.8)      -- 두꺼운 테두리
			border:SetWidth(70)	 --border:SetWidth(41) 기본
			border:SetHeight(70)	 --border:SetHeight(41) 기본
		else
			border:SetVertexColor(0.5,0.5,0.5,1);
		end
		border:Show();
	elseif (button.realLink) then
		SetItemButtonTexture(button,"Interface\\Icons\\INV_Misc_QuestionMark");
		border:Hide();
	else
		SetItemButtonTexture(button,button.backgroundTextureName);
		border:Hide();
	end
end

--------------------------------------------------------------------------------------------------------
--                                            Unit Details                                            --
--------------------------------------------------------------------------------------------------------

-- Unit Detail String
function Examiner_UnitDetailString()
	local info, color = {};
	-- Level
	color = GetDifficultyColor(u.level ~= -1 and u.level or 500);
	tinsert(info,LEVEL..(" |cff%.2x%.2x%.2x"):format(color.r*255,color.g*255,color.b*255)..(u.level ~= -1 and u.level or "??").."|r");
	-- Classification (non players only, so ok to use u.token)
	if (not u.raceFixed) then
		local classification = UnitClassification(u.token);
		if (Examiner.Classification[classification]) then
			tinsert(info,"("..Examiner.Classification[classification]..")");
		end
	end
	-- Race for Players / Family or Type for NPC's
	if (u.race) then
		tinsert(info,u.race ~= "Not specified" and u.race or "Unknown");
	end
	-- Players Only: Class (+ Realm)
	if (u.raceFixed) then
		if (u.class) then
			color = RAID_CLASS_COLORS[u.classFixed];
			tinsert(info,("|cff%.2x%.2x%.2x"):format(color.r*255,color.g*255,color.b*255)..u.class.."|r");
		end
		if (u.realm) then
			tinsert(info,"of "..u.realm);
		end
	end
	-- Return
	return table.concat(info," ");
end

-- Unit Guild String (Faction for NPC's)
function Examiner_UnitGuildString()
	-- Players
	if (u.raceFixed) then
		if (u.guild and u.guildRank and u.guildIndex) then
			return "<"..u.guild..">의 " ..u.guildRank.."";
		end
	-- NPC's only, so ok to use 'u.token' here
	else
		ExScanner.Tooltip:ClearLines();
		ExScanner.Tooltip:SetUnit(u.token);
		local line;
		for i = 2, ExScanner.Tooltip:NumLines()-1 do
			line = _G["ExScannerTipTextLeft"..i]:GetText();
			if (line:find("^"..LEVEL.." .+")) then
				line = _G["ExScannerTipTextLeft"..i+1]:GetText();
				if (line ~= PVP_ENABLED) then
					return line;
				end
			end
		end
	end
	-- Else return empty
	return "";
end

-- Return name used for entires
function Examiner_GetEntryName()
	return (u.realm and u.name.."-"..u.realm or u.name);
end

--------------------------------------------------------------------------------------------------------
--                                            Cache Stuff                                             --
--------------------------------------------------------------------------------------------------------

-- Format Time (sec)
function Examiner_FormatTime(time)
	local color = "|cffffff80";
	-- bugged?
	if (time < 0) then
		return "n/a";
	-- under a min
	elseif (time < 60) then
		return color..time.."|rs";
	-- less than 1 hour
	elseif (time < 60*60) then
		return format(color.."%d|rm"..color.."%.2d|rs",time/60,mod(time,60));
	-- less than 1 day
	elseif (time < 60*60*24) then
		time = (time/60);
		return format(color.."%d|rh"..color.."%.2d|rm",time/60,mod(time,60));
	-- above 1 day
	else
		time = (time/60/60);
		return format(color.."%d|rd"..color.."%.2d|rh",time/24,mod(time,24));
	end
end

-- Cache Player
function Examiner_CachePlayer(override)
	if (not override) and (not Examiner_Config.EnableCache or UnitIsUnit(u.token,"player")) then
		return;
	end
	-- New Entry
	local entryName = Examiner_GetEntryName();
	Examiner_Cache[entryName] = {};
	local entry = Examiner_Cache[entryName];
	for name, value in pairs(u) do
		if (name ~= "token") then
			entry[name] = value;
		end
	end
	-- Cache Items
	entry["Items"] = {};
	for _, slotName in ipairs(ExScanner.Slots) do
		entry["Items"][slotName] = _G["Examiner_ItemButton"..slotName].link;
	end
	-- Cache Sets
	entry["Sets"] = {};
	local idx;
	for setName, setEntry in pairs(ExSets) do
		entry["Sets"][setName] = { count = setEntry.count, max = setEntry.max };
		idx = 1;
		while (setEntry["setBonus"..idx]) do
			entry["Sets"][setName]["setBonus"..idx] = setEntry["setBonus"..idx];
			idx = (idx + 1);
		end
	end
	-- Cache Complete
	return 1;
end

-- Load player from cache
function Examiner_LoadPlayerFromCache(entry,loadLevel)
	-- loadLevel Information --
	-- 2 = Load no extra info from cache besides items/sets/pvp (Use when unit is in loading range but outside inspect range)
	-- 1 = Load just what we cannot get from being outside inspect range (Use when unit is outside loading and inspect range)
	-- 0 = Load everything (Use when you have no unit to get info from)
	if (loadLevel <= 2) then
		u.time = entry.time;
		u.zone = entry.zone;
		if (loadLevel <= 1) then
			u.pvpName = entry.pvpName;
			u.guild, u.guildRank, u.guildIndex = entry.guild, entry.guildRank, entry.guildIndex;
			if (loadLevel <= 0) then
				-- Clear last unit, as we don't have one for a cached player at level 0
				ClearInspectPlayer();
				u.token = nil;
				-- General Info
				u.name, u.realm = entry.name, entry.realm;
				u.level = entry.level;
				u.class, u.classFixed = entry.class, entry.classFixed;
				u.race, u.raceFixed = entry.race, entry.raceFixed;
				u.sex = entry.sex;
				u.talents = entry.talents;
				-- Textures & Model
				local gender = (u.sex == 3 and "Female" or "Male");
				ExaminerPortrait:SetTexture("Interface\\CharacterFrame\\TemporaryPortrait-"..gender.."-"..u.raceFixed);
				ExaminerModel:ClearModel();
				Examiner_SetBackgroundTexture(u.raceFixed);
			end
		end
	end
	-- Title, Detail & Guild Text
	ExaminerTitle:SetText(u.pvpName);
	ExaminerDetails:SetText(Examiner_UnitDetailString());
	ExaminerGuild:SetText(Examiner_UnitGuildString());
	-- Reset
	ExStats = {};
	ExSets = {};
	-- Item Slots
	local button;
	for _, slotName in ipairs(ExScanner.Slots) do
		button = _G["Examiner_ItemButton"..slotName];
		button.link = entry["Items"][slotName];
		button.realLink = nil;
		-- Only scan the item if it's in the users local cache, to avoid DC's
		if (button.link) then
			if (Examiner_Config.ScanUnknownItems or GetItemInfo(button.link)) then
				ExScanner:ScanItemLink(button.link,ExStats);
			else
				button.realLink = button.link;
				button.link = nil;
			end
		end
		Examiner_ItemSlots_UpdateItemSlot(button);
	end
	-- Sets + Set Bonuses
	local idx;
	for setName, setEntry in pairs(entry["Sets"]) do
		ExSets[setName] = { count = setEntry.count, max = setEntry.max };
		idx = 1;
		while (setEntry["setBonus"..idx]) do
			ExSets[setName]["setBonus"..idx] = setEntry["setBonus"..idx];
			ExScanner:ScanLineForPatterns(setEntry["setBonus"..idx],ExStats);
			idx = (idx + 1);
		end
	end
	-- Honor + Arena
	Examiner_PVPClear();
	Examiner_LoadHonorFromCache(entry["Honor"]);
	Examiner_LoadArenaTeamsFromCache(entry);
	-- Update Stats
	Examiner_BuildStatList();
	Examiner_UpdateResistances();
	-- Finalize
	Examiner_StatFrameCached:Show();
	Examiner.statsLoaded = 1;
	Examiner.unitType = 3; -- Force unitType to 3 to make things simple by having Examiner believe it's a same faction unit?
	Examiner_Button_Stats:Enable();
	Examiner_Button_PvP:Enable();
	Examiner_Button_Talents:Disable();
	-- Fix UI: Force page to Stats (but only if we are loading a person from the cache page)
	if (loadLevel == 0) then
		Examiner.activePage = 3;
		Examiner_StatFrame:Show();
		Examiner_CacheFrame:Hide();
		Examiner_ShowItemSlotButtons(Examiner.showItems);
	end
end

-- Cache List Sorting
function Examiner_SortCacheList(a,b)
	if (Examiner_Cache[a][Examiner_Config.cacheSort] == Examiner_Cache[b][Examiner_Config.cacheSort]) then
		return Examiner_Cache[a].name < Examiner_Cache[b].name;
	else
		return (Examiner_Cache[a][Examiner_Config.cacheSort] or "") < (Examiner_Cache[b][Examiner_Config.cacheSort] or "");
	end
end

-- Build the table used to display the cache (display table)
function Examiner_BuildCacheList()
	-- Create display table
	ExCacheList = {};
	for entryName in pairs(Examiner_Cache) do
		tinsert(ExCacheList,entryName);
	end
	sort(ExCacheList,Examiner_SortCacheList);
	-- Update
	Examiner_CacheFrameHeader:SetText("저장된 유저 ("..#ExCacheList..")");
	Examiner_CacheList_Update();
end

-- ScrollBar: Cache list update
function Examiner_CacheList_Update()
	FauxScrollFrame_Update(Examiner_CacheFrameScroll,#ExCacheList,8,30);
	local button, playerRace, playerName;
	local index, entryName, entry, color, coords, iconOffset;
	for i = 1, 8 do
		index = (FauxScrollFrame_GetOffset(Examiner_CacheFrameScroll) + i);
		button = _G["Examiner_CacheFrameEntry"..i];
		if (ExCacheList[index]) then
			playerRace = _G["Examiner_CacheFrameEntry"..i.."Race"];
			playerName = _G["Examiner_CacheFrameEntry"..i.."Name"];

			entryName = ExCacheList[index];
			entry = Examiner_Cache[entryName];
			color = RAID_CLASS_COLORS[entry.classFixed];

			button.entryName = entryName;
			playerName:SetText("|cffffffff"..entry.level.."|r "..entryName);
			playerName:SetTextColor(color.r,color.g,color.b);

			coords = EX_RaceCoord[entry.raceFixed];
			iconOffset = (entry.sex == 3 and 0.5 or 0);
			playerRace:SetTexCoord(coords.left,coords.right,coords.top+iconOffset,coords.bottom+iconOffset);

			button:SetWidth(#ExCacheList > 8 and 200 or 214);
			button:Show();
		else
			button:Hide();
		end
	end
	-- Update Tooltip if we Scroll
	local mouseFocus = GetMouseFocus();
	if (mouseFocus) and (Examiner_Cache[mouseFocus.entryName]) and (GameTooltip:IsOwned(mouseFocus)) then
		Examiner_CacheEntry_OnEnter(mouseFocus);
	end
end

-- CacheEntry: OnClick
function Examiner_CacheEntry_OnClick(self,button)
	if (button == "LeftButton") then
		PlaySound("igMainMenuOptionCheckBoxOn");
		Examiner_LoadPlayerFromCache(Examiner_Cache[self.entryName],0);
	elseif (button == "RightButton") and (IsShiftKeyDown()) then
		Examiner_Cache[self.entryName] = nil;
		Examiner_BuildCacheList();
	end
end

-- CacheEntry: OnEnter
function Examiner_CacheEntry_OnEnter(self)
	local entry = Examiner_Cache[self.entryName];
	GameTooltip:SetOwner(self,"ANCHOR_RIGHT");
	-- Init Text & Colors
	local color = RAID_CLASS_COLORS[entry.classFixed];
	local classText = ("|cff%.2x%.2x%.2x%s|r"):format(color.r*255,color.g*255,color.b*255,entry.class);
	color = GetDifficultyColor(entry.level);
	local level = ("|cff%.2x%.2x%.2x%d|r"):format(color.r*255,color.g*255,color.b*255,entry.level);
	-- Add Lines & Show
	GameTooltip:AddLine(entry.pvpName..(entry.realm and " - "..entry.realm or ""),0.5,0.75,1.0);
	if (entry.guild) then
		GameTooltip:AddLine("<"..entry.guild..">",0.0,0.5,0.8);
	end
	GameTooltip:AddLine(level.." "..entry.race.." "..classText,1,1,1);
	GameTooltip:AddLine(entry.zone,1,1,1);
	GameTooltip:AddLine(" ");
	GameTooltip:AddDoubleLine("저장 번호:",FauxScrollFrame_GetOffset(Examiner_CacheFrameScroll) + self:GetID());
	GameTooltip:AddDoubleLine("마지막 검색:",Examiner_FormatTime(time()-entry.time));
	GameTooltip:AddLine("Shift + 우-클릭: 삭제",0.75,0.75,0.75);
	GameTooltip:Show();
end

--------------------------------------------------------------------------------------------------------
--                                            Stats Stuff                                             --
--------------------------------------------------------------------------------------------------------

-- Returns a modified Token Value from the given statTable (value might be modified by certain options)
function Examiner_GetStatValue(statToken,statTable)
	local value = (statTable[statToken] or 0);
	-- OPTION: Give Rating Values in Percent
	if (Examiner_Config.RatingsInPercent) and (ExScanner:GetRatingInPercent(statToken,value,u.level)) then
		value = format("%.2f",ExScanner:GetRatingInPercent(statToken,value,u.level));
	end
	-- OPTION: Add spell damage to each spell school
	if (Examiner_Config.SpellDmgToSchools) and (statTable["SPELLDMG"]) then
		for _, schoolToken in ipairs(EX_MagicSchools) do
			if (statToken == schoolToken.."DMG") then
				value = (value + statTable["SPELLDMG"]);
				break;
			end
		end
	end
	-- Return the value
	return value;
end

-- Show Resistances (Must support comparing)
function Examiner_UpdateResistances()
	local label, stat, value;
	for i = 1, 5 do
		label = _G["Examiner_StatFrameResistBox"..i.."Text"];
		stat = (EX_MagicSchools[i].."RESIST");
		if (ExCompare) and (ExStats[stat] or ExCompare[stat]) then
			value = (Examiner_GetStatValue(stat,ExStats) - Examiner_GetStatValue(stat,ExCompare));
			if (value > 0) then
				value = "|cff80ff80+"..value;
			elseif (value < 0) then
				value = "|cffff8080"..value;
			end
			label:SetText(value);
		elseif (ExStats[stat]) then
			label:SetText(Examiner_GetStatValue(stat,ExStats));
		else
			label:SetText("");
		end
	end
end

-- Build Stat List (Must support comparing)
function Examiner_BuildStatList()
	local lastHeader, value;
	ExStatList = {};
	-- Build display table
	for _, statCat in ipairs(Examiner.StatEntryOrder) do
		lastHeader = (#ExStatList + 1);
		for _, statToken in ipairs(statCat.stats) do
			if (ExCompare) and (ExStats[statToken] or ExCompare[statToken]) then
				value = (Examiner_GetStatValue(statToken,ExStats) - Examiner_GetStatValue(statToken,ExCompare));
				if (value > 0) then
					value = "|cff80ff80+"..value;
				elseif (value < 0) then
					value = "|cffff8080"..value;
				end
				tinsert(ExStatList,{ name = (ExScanner.StatNames[statToken] or statToken), value = value });
			elseif (ExStats[statToken]) then
				tinsert(ExStatList,{ name = (ExScanner.StatNames[statToken] or statToken), value = Examiner_GetStatValue(statToken,ExStats) });
			end
		end
		if (lastHeader <= #ExStatList) then
			tinsert(ExStatList,lastHeader,{ name = statCat.name });
		end
	end
	-- Add Sets + One Line of Padding
	lastHeader = (#ExStatList + 1);
	for setName, setEntry in pairs(ExSets) do
		tinsert(ExStatList,{ name = setName, value = setEntry.count.."/"..setEntry.max });
	end
	if (lastHeader <= #ExStatList) then
		tinsert(ExStatList,lastHeader,{});
		tinsert(ExStatList,lastHeader+1,{ name = "세트 아이템" });
	end
	-- Other Details
	local iLvlTotal, iLvl, link = 0;
	for _, slotName in ipairs(ExScanner.Slots) do
		if (slotName ~= "TabardSlot") and (slotName ~= "ShirtSlot") then
			if (slotName == "SecondaryHandSlot") and (not _G["Examiner_ItemButton"..slotName].link) then
				slotName = "MainHandSlot";
			end
			link = _G["Examiner_ItemButton"..slotName].link;
			if (link) then
				iLvl = select(4,GetItemInfo(link));
				if (iLvl) then
					iLvlTotal = (iLvlTotal + iLvl);
				end
			end
		end
	end
	tinsert(ExStatList,{});
	tinsert(ExStatList,{ name = "기타 정보" });
	tinsert(ExStatList,{ name = "대상 출처", value = tostring(u.token) });
	if (u.talents) then
		tinsert(ExStatList,{ name = "특성 세분화", value = u.talents });
	end
	tinsert(ExStatList,{ name = "아이템 레벨 총합", value = iLvlTotal });
	tinsert(ExStatList,{ name = "평균 아이템 레벨", value = format("%.2f",iLvlTotal / (#ExScanner.Slots - 2)) });
	-- Update
	tinsert(ExStatList,{});
	Examiner_StatList_Update();
end

-- ScrollBar: Update Stat List
function Examiner_StatList_Update()
	FauxScrollFrame_Update(Examiner_StatFrameScroll,#ExStatList,20,12);
	local index, entry, entryName, entryValue;
	for i = 1, 20 do
		index = (FauxScrollFrame_GetOffset(Examiner_StatFrameScroll) + i);
		entry = _G["Examiner_StatFrameEntry"..i];
		if (ExStatList[index]) then
			entryName = _G["Examiner_StatFrameEntry"..i.."Name"];
			entryValue = _G["Examiner_StatFrameEntry"..i.."Value"];
			if (ExStatList[index].value) then
				entryName:SetTextColor(1,1,1);
				entryName:SetText("  "..ExStatList[index].name);
				entryValue:SetText(ExStatList[index].value);
			elseif (ExStatList[index].name) then
				entryName:SetTextColor(0.5,0.75,1.0);
				entryName:SetText(ExStatList[index].name..":");
				entryValue:SetText("");
			else
				entryName:SetText("");
				entryValue:SetText("");
			end
			entry:SetWidth(#ExStatList > 20 and 200 or 214);
			entry:Show();
		else
			entry:Hide();
		end
	end
end

--------------------------------------------------------------------------------------------------------
--                                             PvP Stuff                                              --
--------------------------------------------------------------------------------------------------------

-- Arena Team Detail Frame OnLoad
function Examiner_ArenaTeamDetail_OnLoad(self)
	local labels = { "경기", "참여", "승리", "패배", "예상 투기장 점수" };
	_G[self:GetName().."Label"]:SetText(labels[self:GetID()]..":");
end

-- Update PvP Info
function Examiner_PVPUpdate()
	if (HasInspectHonorData()) then
		Examiner_LoadHonorNormal();
		Examiner_LoadArenaTeamsNormal();
	else
		RequestInspectHonorData();
	end
end

-- Load Honor Normal
function Examiner_LoadHonorNormal()
	local unit = (u.token or "");
	local faction = UnitFactionGroup(unit);
	local todayHK, todayHonor, yesterdayHK, yesterdayHonor, lifetimeHK, lifetimeRank = GetInspectHonorData();
	-- Update
	Examiner_UpdateHonor(todayHK, todayHonor, yesterdayHK, yesterdayHonor, lifetimeHK, lifetimeRank, faction);
	-- Cache
	if (Examiner_Config.EnableCache) and (Examiner_Config.CachePvP) then
		local cacheEntry = Examiner_Cache[Examiner_GetEntryName()];
		if (cacheEntry) then
			cacheEntry["Honor"] = { todayHK = todayHK, todayHonor = todayHonor, yesterdayHK = yesterdayHK, yesterdayHonor = yesterdayHonor, lifetimeHK = lifetimeHK, lifetimeRank = lifetimeRank };
		end
	end
	-- Show Honor Points for Player only
	if (UnitIsUnit(unit,"player")) then
		Examiner_PVPFrameLifetimeHonor:SetText(GetHonorCurrency());
		Examiner_PVPFrameLifetimeHonor:SetTextColor(0,1,0);
		--Examiner_PVPFrameHonorPointsValue:SetText("|cffffff80"..GetHonorCurrency());
		--Examiner_PVPFrameArenaPointsValue:SetText("|cffffff80"..GetArenaCurrency());
	end
end

-- Load Honor From Cache (Az: faction is always given as the player's which is a bit wrong)
function Examiner_LoadHonorFromCache(honorEntry)
	if (honorEntry) then
		Examiner_UpdateHonor(honorEntry.todayHK, honorEntry.todayHonor, honorEntry.yesterdayHK, honorEntry.yesterdayHonor, honorEntry.lifetimeHK, honorEntry.lifetimeRank, UnitFactionGroup("player"));
	end
end

-- Honor Update
function Examiner_UpdateHonor(todayHK, todayHonor, yesterdayHK, yesterdayHonor, lifetimeHK, lifetimeRank, faction)
	-- Show Rank
	if (lifetimeRank ~= 0) then
		Examiner_PVPFrameRank:SetTexture("Interface\\PvPRankBadges\\PvPRank"..format("%.2d",lifetimeRank-4));
		Examiner_PVPFrameRank:SetTexCoord(0,1,0,1);
		Examiner_PVPFrameHeader:SetText(GetPVPRankInfo(lifetimeRank,u.token).." (등급 "..(lifetimeRank-4)..")");
	-- Az: This needs a little rework
	else
		if (faction) then
			Examiner_PVPFrameRank:SetTexture("Interface\\TargetingFrame\\UI-PVP-"..faction);
			Examiner_PVPFrameRank:SetTexCoord(0,0.59375,0,0.59375);
		else
			Examiner_PVPFrameRank:SetTexture(nil);
		end
		Examiner_PVPFrameHeader:SetText("명예 계급 없음");
	end
	-- Show Kills/Honor
	Examiner_PVPFrameTodayKills:SetText(todayHK);
	Examiner_PVPFrameTodayHonor:SetText(todayHonor);
	Examiner_PVPFrameYesterdayKills:SetText(yesterdayHK);
	Examiner_PVPFrameYesterdayHonor:SetText(yesterdayHonor);
	Examiner_PVPFrameLifetimeKills:SetText(lifetimeHK);
	Examiner_PVPFrameLifetimeHonor:SetText("---");
	Examiner_PVPFrameLifetimeHonor:SetTextColor(1,1,0);

	-- New Show Kills/Honor (Not Used Yet)
--[[	Examiner_PVPFrameKillsTodayValue:SetText("|cffffff80"..todayHK);
	Examiner_PVPFrameKillsYesterdayValue:SetText("|cffffff80"..yesterdayHK);
	Examiner_PVPFrameKillsLifetimeValue:SetText("|cffffff80"..lifetimeHK);
	Examiner_PVPFrameHonorTodayValue:SetText("|cffffff80"..todayHonor);
	Examiner_PVPFrameHonorYesterdayValue:SetText("|cffffff80"..yesterdayHonor);]]
end

-- Load Arena Teams Normal
function Examiner_LoadArenaTeamsNormal()
	local teamName, teamSize, teamRating, teamPlayed, teamWins, playerPlayed, emblem, border;
	local seasonTeamPlayed, seasonTeamWins, seasonPlayerPlayed, teamRank;
	local backR, backG, backB, emblemR, emblemG, emblemB, borderR, borderG, borderB;
	local arenaFrame;
	local cacheEntry = Examiner_Cache[Examiner_GetEntryName()];
	-- Loop
	for i = 1, MAX_ARENA_TEAMS do
		if (Examiner_CheckLastUnit() and UnitIsUnit(u.token,"player")) then
			teamName, teamSize, teamRating, teamPlayed, teamWins, seasonTeamPlayed, seasonTeamWins, playerPlayed, seasonPlayerPlayed, teamRank, backR, backG, backB, emblem, emblemR, emblemG, emblemB, border, borderR, borderG, borderB = GetArenaTeam(i);
			teamPlayed, teamWins, playerPlayed = seasonTeamPlayed, seasonTeamWins, seasonPlayerPlayed;
		else
			teamName, teamSize, teamRating, teamPlayed, teamWins, playerPlayed, backR, backG, backB, emblem, emblemR, emblemG, emblemB, border, borderR, borderG, borderB = GetInspectArenaTeamData(i);
		end
		-- Update
		if (teamName) then
			Examiner_ArenaTeamUpdate(teamName, teamSize, teamRating, teamPlayed, teamWins, playerPlayed, backR, backG, backB, emblem, emblemR, emblemG, emblemB, border, borderR, borderG, borderB);
			-- Cache
			if (Examiner_Config.EnableCache) and (Examiner_Config.CachePvP) and (cacheEntry) then
				cacheEntry["Arena"..i] = { teamName = teamName, teamSize = teamSize, teamRating = teamRating, teamPlayed = teamPlayed, teamWins = teamWins, playerPlayed = playerPlayed, backR = backR, backG = backG, backB = backB, emblem = emblem, emblemR = emblemR, emblemG = emblemG, emblemB = emblemB, border = border, borderR = borderR, borderG = borderG, borderB = borderB };
			end
		end
	end
end

-- Load Arena Team From Cache
function Examiner_LoadArenaTeamsFromCache(cacheEntry)
	local arenaTeam;
	for i = 1, MAX_ARENA_TEAMS do
		if (cacheEntry["Arena"..i]) then
			arenaTeam = cacheEntry["Arena"..i];
			Examiner_ArenaTeamUpdate(arenaTeam.teamName, arenaTeam.teamSize, arenaTeam.teamRating, arenaTeam.teamPlayed, arenaTeam.teamWins, arenaTeam.playerPlayed, arenaTeam.backR, arenaTeam.backG, arenaTeam.backB, arenaTeam.emblem, arenaTeam.emblemR, arenaTeam.emblemG, arenaTeam.emblemB, arenaTeam.border, arenaTeam.borderR, arenaTeam.borderG, arenaTeam.borderB);
		end
	end
end

-- Arena Team Update
function Examiner_ArenaTeamUpdate(teamName, teamSize, teamRating, teamPlayed, teamWins, playerPlayed, backR, backG, backB, emblem, emblemR, emblemG, emblemB, border, borderR, borderG, borderB)
	local arenaFrame = "Examiner_PVPFrameArenaTeam"..teamSize;
	-- General
	_G[arenaFrame.."Name"]:SetText(teamName);
	_G[arenaFrame.."Rating"]:SetText(teamRating);
	-- Games/Played
	_G[arenaFrame.."GamesValue"]:SetText("|cffffff80"..teamPlayed);
	_G[arenaFrame.."PlayedValue"]:SetText(Examiner_PVPFormatNumbers(playerPlayed,teamPlayed));
	-- Wins/Loss
	_G[arenaFrame.."WinsValue"]:SetText(Examiner_PVPFormatNumbers(teamWins,teamPlayed));
	_G[arenaFrame.."LossValue"]:SetText(Examiner_PVPFormatNumbers(teamPlayed-teamWins,teamPlayed));
	-- Estimated Points
	_G[arenaFrame.."PointsValue"]:SetFormattedText("|cffffff80%.1f",Examiner_CalculateArenaPoints(teamRating,teamSize));
	-- Banner
	_G[arenaFrame.."Banner"]:SetTexture("Interface\\PVPFrame\\PVP-Banner-"..teamSize);
	_G[arenaFrame.."Banner"]:SetVertexColor(backR,backG,backB);
	_G[arenaFrame.."Emblem"]:SetVertexColor(emblemR,emblemG,emblemB);
	_G[arenaFrame.."Border"]:SetVertexColor(borderR,borderG,borderB);
	_G[arenaFrame.."Border"]:SetTexture(border ~= -1 and "Interface\\PVPFrame\\PVP-Banner-"..teamSize.."-Border-"..border or nil);
	_G[arenaFrame.."Emblem"]:SetTexture(emblem ~= -1 and "Interface\\PVPFrame\\Icons\\PVP-Banner-Emblem-"..emblem or nil);
	-- Show Frame
	_G[arenaFrame]:Show();
end

-- Clear the PvP info
function Examiner_PVPClear()
	-- Header
	Examiner_PVPFrameRank:SetTexture(nil);
	Examiner_PVPFrameHeader:SetText("명예 정보 없음");
	-- Clear Honor
	Examiner_PVPFrameTodayKills:SetText("---");
	Examiner_PVPFrameTodayHonor:SetText("---");
	Examiner_PVPFrameYesterdayKills:SetText("---");
	Examiner_PVPFrameYesterdayHonor:SetText("---");
	Examiner_PVPFrameLifetimeKills:SetText("---");
	Examiner_PVPFrameLifetimeHonor:SetText("---");
	Examiner_PVPFrameLifetimeHonor:SetTextColor(1,1,0);
	-- Hide Arena Teams
	Examiner_PVPFrameArenaTeam2:Hide();
	Examiner_PVPFrameArenaTeam3:Hide();
	Examiner_PVPFrameArenaTeam5:Hide();
end

-- Format Numbers
function Examiner_PVPFormatNumbers(value,max)
	local color = (value == 0 and "|cffff8080" or "|cffffff80");
	if (max == 0) then
 		return color.."0|r ("..color.."0%|r)";
	else
		return color..value.."|r  ("..color..format("%.1f",value / max * 100).."%|r)";
	end
end

-- Calculate Arena Points (Updated Formula for 2.2)
function Examiner_CalculateArenaPoints(teamRating,teamSize)
	local points;
	if (teamRating <= 1500) then
		points = (0.22 * teamRating + 14);
	else
		points = (1511.26 / (1 + 1639.28 * 2.71828 ^ (-0.00412 * teamRating)));
	end
	return (teamSize == 5 and points) or (teamSize == 3 and points * 0.88) or (teamSize == 2 and points * 0.76);
end

-- Calculate Arena Points (Old Formula, Pre 2.2)
--[[function Examiner_CalculateArenaPointsOld(teamRating,teamSize)
	local points;
	if (teamRating <= 1500) then
		points = (0.38 * teamRating - 194);
	else
		points = (1426.79 / (1 + 918.836 * 2.71828 ^ (-0.00386405 * teamRating)));
	end
	return (teamSize == 5 and points) or (teamSize == 3 and points * 0.8) or (teamSize == 2 and points * 0.7);
end]]

--------------------------------------------------------------------------------------------------------
--                                           Inspect Stuff                                            --
--------------------------------------------------------------------------------------------------------

-- Normal Open
function Examiner_Open(unit)
	if (not u.name) then
		Examiner_InspectUnit("player");
	elseif (Examiner:IsVisible()) then
		HideUIPanel(Examiner);
	elseif (Examiner_Config.ActAsUIFrame) then
		ShowUIPanel(Examiner);
	else
		Examiner:Show();
	end
end

-- Inspect Unit
function Examiner_InspectUnit(unit)
	ClearInspectPlayer();
	-- Check Unit
	if (not unit or not UnitExists(unit)) then
		unit = "player";
	elseif (unit == "mouseover") then
		Examiner:RegisterEvent("UPDATE_MOUSEOVER_UNIT");
	end
	-- Get Unit Info
	u.token = unit;
	u.name, u.realm = UnitName(unit);
	if (u.realm == "") then
		u.realm = nil;
	end
	u.pvpName = UnitPVPName(unit);
	u.level = UnitLevel(unit);
	u.sex = UnitSex(unit);
	u.class, u.classFixed = UnitClass(unit);
	u.race, u.raceFixed = UnitRace(unit);
	if (not u.race) then
		u.race = UnitCreatureFamily(unit) or UnitCreatureType(unit);
	end
	u.guild, u.guildRank, u.guildIndex = GetGuildInfo(unit);
	u.time = time();
	u.zone = GetMinimapZoneText();
	if (GetRealZoneText() ~= u.zone) then
		u.zone = GetRealZoneText()..", "..u.zone;
	end
	u.talents = nil;
	-- Textures & Model
	ExaminerModel:ClearModel();
	ExaminerModel:SetUnit(unit);
	SetPortraitTexture(ExaminerPortrait,unit);
	Examiner_SetBackgroundTexture(u.raceFixed);
	-- Title, Detail & Guild Text
	ExaminerTitle:SetText(u.pvpName or u.name);
	ExaminerDetails:SetText(Examiner_UnitDetailString());
	ExaminerGuild:SetText(Examiner_UnitGuildString());
	-- Reset
	ExStats = {};
	ExSets = {};
	Examiner.markForUpdate = nil;
	Examiner.statsLoaded = nil;
	Examiner_PVPClear();
	-- Unit Type (1 = npc, 2 = opposing faction, 3 = same faction)
	Examiner.unitType = (not UnitIsPlayer(unit) and 1) or (UnitCanCooperate("player",unit) and 3) or 2;
	-- Inspect & Cache (If 'markForUpdate' gets set to true, it will reinspect once when getting into inspect range)
	local inInspectRange = CheckInteractDistance(unit,1);
	-- NPC's
	if (Examiner.unitType == 1) then
		Examiner_PVPFrame:Hide();
		Examiner_Button_PvP:Disable();
		Examiner_Button_Talents:Disable();
	-- Players
	else
		Examiner_Button_PvP:Enable();
		-- In Inspect Range Depending Stuff
		if (inInspectRange) then
			NotifyInspect(unit);
			Examiner_PVPUpdate();
			-- Talent Stuff added in 2.3 - Can request talents even from opposing faction!
			Examiner.unit = u.token;
			if (ExaminerTalents:IsShown()) then
				Examiner_TalentsUpdateTabs();
				TalentFrame_Update(Examiner);
			end
			Examiner_Button_Talents:Enable();
		else
			Examiner.markForUpdate = 1;
			Examiner_Button_Talents:Disable();
		end
		-- Out of Range or Opposing Faction - Try and load from Cache
		if (not inInspectRange or Examiner.unitType == 2) then
			local entryName = Examiner_GetEntryName();
			if (Examiner_Cache[entryName]) then
				Examiner_LoadPlayerFromCache(Examiner_Cache[entryName],UnitPlayerControlled(unit) and 2 or 1); -- Note: UnitPlayerControlled() returns nil for units out of loading range
			end
		-- In Range
		elseif (inInspectRange) and (Examiner.unitType == 3) then
			Examiner_StatFrameCached:Hide();
			Examiner.statsLoaded = 1;
			ExScanner:ScanUnitItems(unit,ExStats,ExSets);
			Examiner_GetUnitItems(unit);
			Examiner_UpdateResistances();
			Examiner_BuildStatList();
			if (Examiner_CachePlayer()) and (Examiner.activePage == 2) then
				Examiner_BuildCacheList();
			end
		end
	end
	-- If Talents are Showing
	if (ExaminerTalents:IsShown()) and (not inInspectRange or Examiner.unitType == 1) then
		Examiner_TalentsVisible(false);
	end
	-- Fix UI Depending on Stats Being Loaded
	if (Examiner.statsLoaded) then
		if (Examiner.activePage) then
			_G["Examiner_"..EX_Frames[Examiner.activePage].."Frame"]:Show();
		end
		Examiner_Button_Stats:Enable();
	else
		if (Examiner.activePage ~= 4) then
			Examiner_UIToggleExclusive(nil);
		end
		Examiner_Button_Stats:Disable();
	end
	-- Item Buttons
	Examiner_ShowItemSlotButtons(Examiner.activePage ~= 4 and not ExaminerTalents:IsShown() and Examiner.showItems and Examiner.unitType == 3 and Examiner.statsLoaded);
	-- Show Examiner
	if (not Examiner:IsShown()) then
		if (Examiner_Config.ActAsUIFrame) then
			ShowUIPanel(Examiner);
		else
			Examiner:Show();
		end
	end
end

-- Get Unit Items
function Examiner_GetUnitItems(unit)
	local button;
	for _, slotName in ipairs(ExScanner.Slots) do
		button = _G["Examiner_ItemButton"..slotName];
		button.link = GetInventoryItemLink(unit,button:GetID());
		if (button.link) then
			button.link = button.link:match(ExScanner.ItemLinkPattern);
		end
		Examiner_ItemSlots_UpdateItemSlot(button);
	end
end

-- Hover over the CachedIcon
function Examiner_CacheIcon_OnEnter(self)
	GameTooltip:SetOwner(self,"ANCHOR_RIGHT");
	GameTooltip:AddLine("Cached Entry");
	GameTooltip:AddDoubleLine("Last Inspected:",Examiner_FormatTime(time()-u.time),1,1,1);
	GameTooltip:AddDoubleLine("Zone:",u.zone,1,1,1);
	GameTooltip:Show();
end

--------------------------------------------------------------------------------------------------------
--                                             UI Buttons                                             --
--------------------------------------------------------------------------------------------------------

-- Main UI Buttons: OnEnter
function Examiner_Buttons_OnEnter(self)
	local id = self:GetID();
	local headers = { "설정", "저장된 유저", "방어구 능력치", "명예 정보", "특성보기" };
	local hints = { "Examiner 설정", "우클릭-확장 메뉴", "우클릭-확장 메뉴", "명예&투기장 현황", "Examiner 인터페이스 숨김" };
	GameTooltip_SetDefaultAnchor(GameTooltip,self);
	GameTooltip:AddLine(headers[id]);
	GameTooltip:AddLine(hints[id],1,1,1);
	GameTooltip:Show();
end

-- Main UI Buttons: OnClick
function Examiner_Buttons_OnClick(self,button)
	local id = self:GetID();
	CloseDropDownMenus();
	-- Button = Left --
	if (button == "LeftButton") then
		-- Hide Talents if they are shown
		if (ExaminerTalents:IsShown()) then
			Examiner_TalentsVisible(false);
			Examiner_SetBackgroundTexture(u.raceFixed);
			if (id == 5) then
				id = nil;
				Examiner_UIToggleExclusive(nil);
				if (Examiner.activePage) and (Examiner.activePage ~= 3 or Examiner.statsLoaded) then
					_G["Examiner_"..EX_Frames[Examiner.activePage].."Frame"]:Show();
				end
			end
		end
		-- Do stuff depending on button pressed
		if (id == 5) then
			Examiner_TalentsVisible(true);
			Examiner_TalentsUpdateTabs();
			TalentFrame_Update(Examiner);
		elseif (id == 2) and (IsShiftKeyDown()) then
			Examiner_Cache = {};
		elseif (id == 3) and (IsShiftKeyDown()) and (Examiner.statsLoaded) then
			Examiner_CacheStatsForCompare();
		elseif (id) then
			Examiner_UIToggleExclusive(id);
		end
		-- Update Cache List if Visible
		if (id == 2) and (Examiner_CacheFrame:IsShown()) then
			Examiner_BuildCacheList();
		end
		-- Set Item Buttons Visible State
		if (ExaminerModel:IsShown()) then
			Examiner_ShowItemSlotButtons(Examiner.activePage ~= 4 and not ExaminerTalents:IsShown() and Examiner.showItems and Examiner.unitType == 3 and Examiner.statsLoaded);
		end
	-- Button = Right --
	elseif (button == "RightButton") then
		if (id == 2 or id == 3) then
			ToggleDropDownMenu(1,nil,ExaminerDropDown,self:GetName(),0,0);
		end
	end
end

-- DropDown: OnLoad
function Examiner_DropDown_OnLoad(self)
	UIDropDownMenu_Initialize(self,Examiner_DropDown_Initialize,"MENU");
end

-- StaticPopupDialogs Entry
StaticPopupDialogs["EXAMINER_SENDTO"] = {
	text = "살펴보기 정보를 보낼 대상의 이름을 입력하세요.",
	button1 = ACCEPT,
	button2 = CANCEL,
	hasEditBox = 1,
	maxLetters = 12,
	OnAccept = function()
		Examiner_SendPlayer(_G[this:GetParent():GetName().."EditBox"]:GetText());
	end,
	OnShow = function()
		_G[this:GetName().."EditBox"]:SetFocus();
	end,
	OnHide = function()
		if (ChatFrameEditBox:IsShown()) then
			ChatFrameEditBox:SetFocus();
		end
		_G[this:GetName().."EditBox"]:SetText("");
	end,
	EditBoxOnEnterPressed = function()
		Examiner_SendPlayer(_G[this:GetParent():GetName().."EditBox"]:GetText());
		this:GetParent():Hide();
	end,
	EditBoxOnEscapePressed = function()
		this:GetParent():Hide();
	end,
	timeout = 0,
	exclusive = 1,
	whileDead = 1,
	hideOnEscape = 1
};

-- DropDown: OnClick
function Examiner_DropDown_OnClick()
	-- Sort
	if (type(this.value) == "string") then
		Examiner_Config.cacheSort = this.value;
	-- Clear Cache
	elseif (this.value == 1) then
		Examiner_Cache = {};
	-- Cache Player
	elseif (this.value == 2) then
		Examiner_CachePlayer(1);
	-- Mark for Compare & Clear Compare
	elseif (this.value == 3 or this.value == 4) then
		Examiner_CacheStatsForCompare(this.value == 4);
	-- Send To...
	elseif (this.value == 5) then
		StaticPopup_Show("EXAMINER_SENDTO");
	end

	-- Rebuild Cache List
	if (Examiner.activePage == 2) and (type(this.value) == "string" or this.value == 1 or this.value == 2) then
		Examiner_BuildCacheList();
	end
end

-- DropDown: Init
local info = { func = Examiner_DropDown_OnClick };
local EX_SortMethods = { "name", "realm", "level", "guild", "race", "class", "time" };
function Examiner_DropDown_Initialize()
	-- Cache
	if (this:GetID() == 2) then
		-- title: sort
		info.isTitle = 1;
		info.text = "정렬 방식";
		UIDropDownMenu_AddButton(info);
		info.isTitle, info.disabled = nil, nil;
		-- method
		for _, method in ipairs(EX_SortMethods) do
			info.text = method.." 순으로 정렬";
			info.value = method;
			info.checked = (Examiner_Config.cacheSort == method);
			UIDropDownMenu_AddButton(info);
		end
		info.checked = nil;
		info.isTitle, info.disabled = nil, nil;
		-- title: clear
		info.isTitle = 1;
		info.text = "";
		UIDropDownMenu_AddButton(info);
		info.text = "저장 공간";
		UIDropDownMenu_AddButton(info);
		info.isTitle, info.disabled = nil, nil;
		-- clear
		info.text = "저장 정보 초기화";
		info.value = 1;
		UIDropDownMenu_AddButton(info);
	-- Stats
	elseif (this:GetID() == 3) then
		-- title: stats (unit)
		info.isTitle = 1;
		info.text = "능력치"..(u.token and " ("..u.token..")" or "");
		UIDropDownMenu_AddButton(info);
		info.isTitle, info.disabled = nil, nil;
		-- items
		if (Examiner.statsLoaded) then
			info.text = "정보 저장";
			info.value = 2;
			info.checked = (Examiner_Cache[Examiner_GetEntryName()] ~= nil);
			UIDropDownMenu_AddButton(info);
			info.text = "비교";
			info.value = 3;
			info.checked = (Examiner.compEntry == Examiner_GetEntryName());
			UIDropDownMenu_AddButton(info);
			info.checked = nil;
		end
		if (Examiner.compEntry) then
			info.text = "비교 해제";
			info.value = 4;
			UIDropDownMenu_AddButton(info);
		end
		if (Examiner.statsLoaded) then
			info.text = "보내기...";
			info.value = 5;
			UIDropDownMenu_AddButton(info);
		end
	end
end

--------------------------------------------------------------------------------------------------------
--                                            Talent Stuff                                            --
--------------------------------------------------------------------------------------------------------

-- Select Tab
function Examiner_TalentsSelectTab()
	local id = this:GetID();
	PanelTemplates_SetTab(Examiner,id);
	Examiner.currentSelectedTab = id;
	Examiner.pointsSpent = select(3,GetTalentTabInfo(id,true));
	TalentFrame_Update(Examiner);
end

-- Update Tabs
function Examiner_TalentsUpdateTabs()
	local numTabs = GetNumTalentTabs(true);
	local tab, tabName, pointsSpent;
	for i = 1, MAX_TALENT_TABS do
		tab = _G["ExaminerTab"..i];
		if (i <= numTabs) then
			tabName, _, pointsSpent = GetTalentTabInfo(i,true);
			if (i == Examiner.selectedTab) then
				Examiner.pointsSpent = pointsSpent;
			end
			tab:SetText(tabName.." |cff00ff00"..pointsSpent);
			tab:Show();
			PanelTemplates_TabResize(-16,tab);
		else
			tab:Hide();
		end
	end
end

-- Talents visible or not
function Examiner_TalentsVisible(show)
	-- Show Talents
	if (show) then
		ExaminerModel:Hide();
		ExaminerTalents:Show();
		ExaminerDetails:Hide();
		ExaminerGuild:Hide();

		Examiner_UIToggleExclusive(nil);

		ExaminerBackgroundTopLeft:SetHeight(270);
		ExaminerBackgroundTopRight:SetHeight(270);
		ExaminerBackgroundBottomLeft:SetHeight(141);
		ExaminerBackgroundBottomRight:SetHeight(141);
		ExaminerBackgroundTopLeft:SetWidth(267);
		ExaminerBackgroundTopRight:SetWidth(74);
		ExaminerBackgroundBottomLeft:SetWidth(267);
		ExaminerBackgroundBottomRight:SetWidth(74);
	-- Hide Talents
	else
		ExaminerModel:Show();
		ExaminerTalents:Hide();
		ExaminerDetails:Show();
		ExaminerGuild:Show();
		for i = 1, MAX_TALENT_TABS do
			_G["ExaminerTab"..i]:Hide();
		end
		Examiner_SetBackgroundTexture(u.raceFixed);
	end
end

--------------------------------------------------------------------------------------------------------
--                                 Send Player (AddOn Whisper Message)                                --
--------------------------------------------------------------------------------------------------------

-- Returns a clickable chat link for a player
function Examiner_PlayerChatLink(name)
	return "|Hplayer:"..name.."|h["..name.."]|h";
end

-- Sends Table Recursive
function Examiner_SendStatRecursive(to,root,table)
	for name, value in pairs(table) do
		if (type(value) == "table") then
			Examiner_SendStatRecursive(to,root..name.."\\",value);
		elseif (name ~= "token") then
			SendAddonMessage(root..name,value,"WHISPER",to);
		end
	end
end

-- Sends the current inspected player to another person through SendAddonMessage()
function Examiner_SendPlayer(to)
	-- Check if we can actually send data
	if (not Examiner.statsLoaded) then
		AzMsg("|2Examiner|r 보낼 살펴보기 정보가 없습니다!");
		return;
	end
	-- Check if we have someone to send to, if not, default to target
	if (not to or to == "") then
		if (UnitIsPlayer("target")) then
			local realm;
			to, realm = UnitName("target");
			if (realm) and (realm ~= "") then
				to = name.."-"..realm:gsub(" ","");
			end
		end
		if (not to or to == "") then
			AzMsg("|2Examiner|r 상대방 이름을 입력하세요.");
			return;
		end
	end
	-- Send Data
	local entryName = Examiner_GetEntryName();
	-- Clear Old Record
	SendAddonMessage("EXAMINER#"..entryName.."#CMD","CLEAR","WHISPER",to);
	-- Root Values
	Examiner_SendStatRecursive(to,"EXAMINER#"..entryName.."#",u);
	-- Items
	for _, slotName in ipairs(ExScanner.Slots) do
		SendAddonMessage("EXAMINER#"..entryName.."#Items\\"..slotName,_G["Examiner_ItemButton"..slotName].link,"WHISPER",to);
	end
	-- Sets
	Examiner_SendStatRecursive(to,"EXAMINER#"..entryName.."#Sets\\",ExSets);
	-- Honor + Arena
		-- Az: bla bla bla, not yet!
	-- Done
	SendAddonMessage("EXAMINER#"..entryName.."#CMD","DONE","WHISPER",to);
	AzMsg("|2Examiner|r 대상 |1"..Examiner_PlayerChatLink(entryName).."|r 에 대한 살펴보기 정보를 |1"..Examiner_PlayerChatLink(to).."|r 에게 보냅니다.");
end

--------------------------------------------------------------------------------------------------------
--                                          UI Helper Stuff                                           --
--------------------------------------------------------------------------------------------------------

-- Cache current stats for compare or clear previous marked one
function Examiner_CacheStatsForCompare(unmark)
	if (unmark) then
		ExCompare = nil;
		Examiner.compEntry = nil
	else
		ExCompare = Examiner_CopyTable(ExStats);
		Examiner.compEntry = Examiner_GetEntryName();
	end
	Examiner_BuildStatList();
	Examiner_UpdateResistances();
end

-- Toggle given frame, hide all others (give nil to hide all)
function Examiner_UIToggleExclusive(id)
	local frame;
	for frameId, frameName in ipairs(EX_Frames) do
		frame = _G["Examiner_"..frameName.."Frame"];
		if (frameId == id) and (not frame:IsShown()) then
			frame:Show();
		else
			frame:Hide();
		end
		if (frameId == id) then
			Examiner.activePage = (frame:IsShown() and id or nil);
		end
	end
end

-- Show/Hide Item Slot Buttons
function Examiner_ShowItemSlotButtons(visible)
	for _, slotName in ipairs(ExScanner.Slots) do
		if (visible) then
			_G["Examiner_ItemButton"..slotName]:Show();
		else
			_G["Examiner_ItemButton"..slotName]:Hide();
		end
	end
end

-- Toggle the Background
function Examiner_ToggleBackground()
	if (ExaminerBackgroundTopLeft:IsShown()) then
		ExaminerBackgroundTopLeft:Hide();
		ExaminerBackgroundTopRight:Hide();
		ExaminerBackgroundBottomLeft:Hide();
		ExaminerBackgroundBottomRight:Hide();
	else
		ExaminerBackgroundTopLeft:Show();
		ExaminerBackgroundTopRight:Show();
		ExaminerBackgroundBottomLeft:Show();
		ExaminerBackgroundBottomRight:Show();
	end
end

-- Background Texture
function Examiner_SetBackgroundTexture(race)
	-- If watching talents, ignore this call
	if (ExaminerTalents:IsShown()) then
		return;
	end
	-- Find Texture
	local texture;
	if (not race) then
		texture = "Interface\\TalentFrame\\"..EX_Backgrounds[random(1,#EX_Backgrounds)].."-";
	else
		if (race == "Gnome") then
			race = "Dwarf";
		elseif (race == "Troll") then
			race = "Orc";
		end
		texture = "Interface\\DressUpFrame\\DressUpBackground-"..race;
	end
	-- Set Texture Height
	ExaminerBackgroundTopLeft:SetHeight(270);
	ExaminerBackgroundTopRight:SetHeight(270);
	ExaminerBackgroundBottomLeft:SetHeight(141);
	ExaminerBackgroundBottomRight:SetHeight(141);
	-- Set Texture
	if (texture:find("DressUpFrame")) then
		ExaminerBackgroundTopLeft:SetTexture(texture.."1");
		ExaminerBackgroundTopRight:SetTexture(texture.."2");
		ExaminerBackgroundBottomLeft:SetTexture(texture.."3");
		ExaminerBackgroundBottomRight:SetTexture(texture.."4");
		ExaminerBackgroundTopLeft:SetWidth(256);
		ExaminerBackgroundTopRight:SetWidth(64);
		ExaminerBackgroundBottomLeft:SetWidth(256);
		ExaminerBackgroundBottomRight:SetWidth(64);
	else
		ExaminerBackgroundTopLeft:SetTexture(texture.."TopLeft");
		ExaminerBackgroundTopRight:SetTexture(texture.."TopRight");
		ExaminerBackgroundBottomLeft:SetTexture(texture.."BottomLeft");
		ExaminerBackgroundBottomRight:SetTexture(texture.."BottomRight");
		ExaminerBackgroundTopLeft:SetWidth(267);
		ExaminerBackgroundTopRight:SetWidth(74);
		ExaminerBackgroundBottomLeft:SetWidth(267);
		ExaminerBackgroundBottomRight:SetWidth(74);
	end
end

-- Copy Table
function Examiner_CopyTable(source)
	local dest = {};
	for k, v in pairs(source) do
		if (type(v) == "table") then
			dest[k] = Examiner_CopyTable(v);
		else
			dest[k] = v;
		end
	end
	return dest;
end

-- Check Last Unit
function Examiner_CheckLastUnit()
	if (u.token) and (UnitExists(u.token)) and (UnitName(u.token) == u.name) then
		return 1;
	else
		u.token = nil;
		Examiner.markForUpdate = nil;
		return;
	end
end