--[[
Equipment Display System

The slot class handles items in slots on a player. 

It is a class which is provided with information about what to display:
	-	unit (player, target, partyX etc)
	-	slot info  (refID, x,y,z,icon,size,amount)
	- 	tooltip function
	-	on click (picup / place) functions

Build in functions makes it possible to rotate the figure (only in one plane).
It is nessecary for this function to determine when the icon shall be shown in front of the figure and when it shall be shown behind it.


--]] 

local calibrate = false;

-- data
local CamPos = {};
local CamDir = {};

--	Alliance Male
CamPos["Human-Male"] = {2.845844923,0,-0.177884383};	-- ok
CamDir["Human-Male"] = {-1,0,0.017852564};
CamPos["Night Elf-Male"] = {4.057864672,0,-0.34};		-- ok
CamDir["Night Elf-Male"] = {-1,0,0};
CamPos["Dwarf-Male"]={2.53132841556727,0,0.159508060838374}  -- ok
CamDir["Dwarf-Male"]={-1,0,-0.114500036602475}
CamPos["Draenei-Male"]={4.33142824614634,0,0.111236309981817} -- ok
CamDir["Draenei-Male"]={-1,0,-0.100664874109562}
CamPos["Gnome-Male"]={2.1627564057806,0,0.0122689528924064}
CamDir["Gnome-Male"]={-1,0,-0.0506036745303314}


-- Alliance Female
CamPos["Gnome-Female"] = {1.703185572,0,0.156207708};
CamDir["Gnome-Female"] = {-1,0,-0.063621795};
CamPos["Human-Female"]={2.49707379233109,0,-0.0106598778621643}
CamDir["Human-Female"]={-1,0,-0.0163051664108343}
CamPos["Dwarf-Female"]={2.19992199838378,0,0.0245148495664771}
CamDir["Dwarf-Female"]={-1,0,-0.049393554608541}
CamPos["Night Elf-Female"]={4.23034501440184,0,-0.0379146954580338}
CamDir["Night Elf-Female"]={-1,0,-0.0152025854692188}
CamPos["Draenei-Female"]={3.99051376275215,0,-0.000259100939754398}
CamDir["Draenei-Female"]={-1,0,0.0210278220327247}


-- Horde Male
CamPos["Orc-Male"]={3.89031316240057,0,-0.197486}
CamDir["Orc-Male"]={-1,0,0}
CamPos["Undead-Male"]={3.42844067121756,0,-0.287250890539236}
CamDir["Undead-Male"]={-1,0,0.0282036159719208}
CamPos["Tauren-Male"]={3.90229589455977,0,-0.00189262571556618}
CamDir["Tauren-Male"]={-1,0,-0.0194820654784481}
CamPos["Troll-Male"]={4.57453194649561,0,-0.00375368402110371}
CamDir["Troll-Male"]={-1,0,-0.0586627436900888}
CamPos["Blood Elf-Male"]={3.86825416179682,0,0.0417639353605309}
CamDir["Blood Elf-Male"]={-1,0,0.030287199332928}

-- Horde Female
CamPos["Orc-Female"]={3.17238708536657,0,0.00148408508847812}
CamDir["Orc-Female"]={-1,0,-0.0278394306049981}
CamPos["Undead-Female"]={3.28345231815537,0,-0.0345984158985607}
CamDir["Undead-Female"]={-1,0,0.0174701738937148}
CamPos["Tauren-Female"]={3.33901313926797,0,0.0818068482704375}
CamDir["Tauren-Female"]={-1,0,-0.146335987006906}
CamPos["Troll-Female"]={3.97114719685901,0,-0.0400682948069166}
CamDir["Troll-Female"]={-1,0,-0.0575599297066138}
CamPos["Blood Elf-Male"]={3.2892542673688,0,0.0118071713949199}
CamDir["Blood Elf-Male"]={-1,0,-0.017794584841872}






local StdSlots = {};
StdSlots["Human-Male"] = {belt={0.11,-0.02,-0.03,1.5} };

GH_Display_BG_List = {
	{p="Interface\\AddOns\\GHI\\texture\\Alliance.tga",x=128,y=256},
	{p="Interface\\AddOns\\GHI\\texture\\HordeBgs.tga",x=128,y=256},
	{p="Interface\\AddOns\\GHI\\texture\\Scarlet.tga",x=128,y=256},
	{p="Interface\\AddOns\\GHI\\texture\\Forsaken.tga",x=128,y=256},
	
	
	{p="Interface\\GLUES\\MODELS\\UI_BLOODELF\\bloodelf_matte.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_BLOODELF\\bloodelf_mountains.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_BLOODELF\\rg_jlo_BloodElf_DoorTrim_01.blp",x=128,y=256},
	
	
	
	{p="Interface\\GLUES\\MODELS\\UI_BLOODELF\\RG_MM_CLOUDS_03.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_CharacterSelect\\UI_CharactersClouds.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_DeathKnight\\IceCrown_Clouds_Unholy01.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_DRAENEI\\draenei_platform_crystal.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_Dwarf\\dwarfsky.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_Dwarf\\snow.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_Dwarf\\dwarfsky.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_Human\\caustic02.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_Human\\MM_clouds_03.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_Human\\MM_sky_02.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_MAINMENU\\DarkPortal_platform_01.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_MAINMENU\\DarkPortal_stone_01.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_MAINMENU\\DarkPortal_trim_01.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_MAINMENU\\DurotarRock03.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_MAINMENU\\MM_clouds_01.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_MAINMENU\\MM_sky_01.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_MAINMENU\\mm_thorns_01.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_MAINMENU\\swordgradient.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_MAINMENU\\SWORDGRADIENT2.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_MainMenu_BurningCrusade\\dp_Lightning2.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_MainMenu_BurningCrusade\\dp_Lightning2b.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_NightElf\\aa_moonwell_glow.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_NightElf\\aa_NE_clouds.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_NightElf\\aa_NE_ground.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_NightElf\\aa_NE_sky.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_NightElf\\caustic01.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_NightElf\\causticblend.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_NightElf\\KalidarMidTree_purple01.blp",x=128,y=256},
	{p="Interface\\GLUES\\MODELS\\UI_Tauren\\sky1.blp",x=128,y=256},
}



function New_GH_Display(parent)
	local i = 1000;
	while( getglobal("GH_D"..i) ) do
		i = i + 1;
	end
	return GH_Display:Create("GH_D"..i,parent);
end

GH_Display = {}
GH_Display.__index = GH_Display;
GH_Display.hooked ={};

-- 	standard
function GH_Display:Create(varName,parent)
		
	setglobal(varName,GH_Display); 
	
	local obj = {}             -- our new object
	setmetatable(obj, getglobal(varName))  -- make GHU_Talent handle lookup
	
	-- obj.data = 1
	obj.display = CreateFrame("DressUpModel",varName.."Display",parent or UIParent,"GHDisplayTemplate");
	obj.display.type = "GH_DisplayDressUpModel";
	obj.display:SetFrameStrata("MEDIUM");
	obj.display.main = obj;
	local n = obj.display:GetName();
	_G[n.."RotateRightButton"]:SetFrameStrata("MEDIUM");
	_G[n.."RotateLeftButton"]:SetFrameStrata("MEDIUM");
	_G[n.."ZoomInButton"]:SetFrameStrata("MEDIUM");
	_G[n.."ZoomOutButton"]:SetFrameStrata("MEDIUM");
	
	obj.display:SetScript("OnShow",function()
		this.rotation = 0;
		this.x = 0;
		this.y = 0;
		this.z = 0;
		--print("OnShow");
		this:SetRotation(0);
		this:SetPosition(0,0,0);
		--if not(this.orig_SetPos) then this.orig_SetPos = this.SetPosition end
		--this.SetPosition = function(t,...) print(...); t.orig_SetPos(t,...); end;
		this.main:Update(true);
		
		--this.main:SetPosition(this.main.x,this.main.y,this.main.z);
		this.type = "GH_Display";
	end);
	
	--bgFile = "Interface/Tooltips/UI-Tooltip-Background"
		
	obj.objects = {};
	
	-- insert calibration lines
	if calibrate then
	obj.display.texture1 = obj.display:CreateTexture()
	obj.display.texture1:SetPoint("LEFT", obj.display, "LEFT", 0, 0);
	obj.display.texture1:SetPoint("RIGHT", obj.display, "RIGHT", 0, 0);
	obj.display.texture1:SetHeight(1);
	obj.display.texture1:SetTexture(1.0,0.0,0.0,0.5);
	
	obj.display.texture2 = obj.display:CreateTexture()
	obj.display.texture2:SetPoint("LEFT", obj.display, "LEFT", 0, 60);
	obj.display.texture2:SetPoint("RIGHT", obj.display, "RIGHT", 0, 60);
	obj.display.texture2:SetHeight(1);
	obj.display.texture2:SetTexture(0.0,1.0,0.0,0.5);
	
	obj.display.texture3 = obj.display:CreateTexture()
	obj.display.texture3:SetPoint("LEFT", obj.display, "LEFT", 0, -80);
	obj.display.texture3:SetPoint("RIGHT", obj.display, "RIGHT", 0, -80);
	obj.display.texture3:SetHeight(1);
	obj.display.texture3:SetTexture(0.0,0.0,1.0,0.5); --]]
	end
	
	setglobal(varName,obj); 
	return obj;
end

function GH_Display:CreateStandaloneFrame()
	if not(self.parent) then
		local f = CreateFrame("Frame",self.display:GetParent());
		f:SetPoint("CENTER",UIParent);
		f:SetFrameStrata("LOW");
		
		f:SetWidth(128);
		f:SetHeight(256); --self.display:GetHeight()
		
		local bg = ""--"Interface/GLUES/MODELS/UI_MAINMENU/MM_sky_01";
		f:SetBackdrop({edgeFile = "Interface/Tooltips/UI-Tooltip-Border", bgFile =  bg, edgeSize = 16, insets = { left = 4, right = 4, top = 4, bottom = 4 }});
		f:SetFrameLevel(2);
		--print(f:GetFrameStrata())
		
		-- create extra backdrop frame
		local f2 = CreateFrame("Frame",f);
		f2:SetPoint("CENTER",f);
		f2:SetWidth(128);
		f2:SetHeight(256);
		f2:SetBackdrop({edgeFile = "", bgFile = "Interface/DialogFrame/UI-DialogBox-Background-Dark", edgeSize = 16, insets = { left = 4, right = 4, top = 4, bottom = 4 }});
		f2:SetFrameLevel(1);
		f2:SetFrameStrata("BACKGROUND");
		f.black = f2;
		
		self.display:SetPoint("CENTER",f);
		f:Show();
		self.parent = f;
	end
end

function GH_Display:SetUnit(unit)
	if not( UnitExists(unit) and UnitRace(unit)) then 
		self.CamPos = {0,0,0};
		self.CamDir = {1,0,0};
		return 
	end
	
	self.display:SetUnit(unit);
	-- self.display:
	--self.display:SetModel("World\\ArtTest\\Boxtest\\xyz.m2");
	-- 
	self.name = UnitName(unit);
	if self.nameString then
		self.nameString:SetText(self.name);	
	end
	
	local race = UnitRace(unit);
	local gender = UnitSex(unit);
	if gender == 2 then gender = "Male"; else gender = "Female" end
	
	local s = race.."-"..gender;
	if not(type(CamPos[s])=="table") then
		GHI_Message(format("No camera position data found for %s %s.",race,gender));
		self.CamPos = {0,0,0}
	else
		self.CamPos = CamPos[s];
	end
	
	if not(type(CamDir[s])=="table") then
		GHI_Message(format("No camera direction data found for %s %s.",race,gender));
		self.CamDir = {-1,0,0}
	else
		self.CamDir = CamDir[s];
	end
	
	
end

function GH_Display:Update(forceChange)
	local change = forceChange;
	if not((self.lastRotation or 0) == self.display:GetFacing())  then 
		change = true;
	end
	
	
	local r = {self.display:GetPosition()};
	self.lastPosition = self.lastPosition or {};
	
	if self.dragged then
		local now = {GetCursorPosition()};
		local last = self.lastDragPos;
		if not(now[1] == last[1]) or not(now[2] == last[2]) then
			r[2] = r[2] + (now[1]-last[1])/100;
			r[3] = r[3] + (now[2]-last[2])/100;
			
			if (abs(atan(r[2],r[1])) < 45 and abs(atan(r[3],r[1])) < 65 ) or  calibrate  then
				self.lastDragPos = now;
				self.display:SetPosition(unpack(r));
				self.display.x = r[1];
				self.display.y = r[2];
				self.display.z = r[3];
				
				
				change = true;
			end
		end
	elseif not(self.lastPosition[1] == r[1] and self.lastPosition[2] == r[2] and self.lastPosition[3] == r[3]) then
		change = true;
	end
	
	if change then
		self.lastRotation = self.display:GetFacing();
		self.lastPosition = r;
		
		for i,o in pairs(self.objects) do
			
			o.object:Update(self,o.frame);
		end
		
		
		
		--[[
		local x,y,z = unpack(self.lastPosition);
		local a = deg(self.lastRotation);
		objX,objY,objZ = 0.1, 0.2, 0.1 -- relative to center of model
		rx,ry = (cos(a)*objX - objY*sin(a)),(sin(a)*objX + objY*cos(a));
		local behind;
		if rx < 0 then
			behind = true;
		end --]]
		--self:TestAt(x + rx,y + ry,z + objZ,behind);
		
		
	end
end

function GH_Display:AddObject(o) -- o is a GH_DO
	local new = {};
		
	new.object = o;
	
	
	-- create the frame
	local f = CreateFrame("Button",nil,self.display)
	if self.strata then
		f:SetFrameStrata(self.strata);
	else
		f:SetFrameStrata("MEDIUM")
	end
	f:SetWidth(32);
	f:SetHeight(32);
	local t = f:CreateTexture(nil,"BACKGROUND");
	 
	t:SetAllPoints(f);
	f.texture = t;
	f.object = o;
	
	-- setup clicks etc
	f:RegisterForClicks("AnyUp");
	f:SetScript("OnClick",o.OnClick);
	f:SetScript("OnEnter",o.OnEnter);
	f:SetScript("OnLeave",o.OnLeave);
	
	
	new.frame = f;
	
	
	
	table.insert(self.objects,new);
	self.version = time()
end


function GH_Display:SetObjects(objs) -- objs being a table of GH_DO
	assert(type(objs)=="table" and type(objs[1])=="table","Usage objs (table of GH_DO)");
	self:ClearAllObjects();
	self.objects = {};
	
	for _,o in pairs(objs) do
		self:AddObject(o);
	end
	self:Update(true);
	
end

function GH_Display:SetFrameStrata(strata)
	self.display:SetFrameStrata(strata);
	self.strata = strata;
	
end

function GH_Display:SetFrameLevel(lvl)
	self.display:SetFrameLevel(lvl);
	self.frameLevel = lvl;
end

function GH_Display:SetBackground(path)
	if self.parent then
		self.parent:SetBackdrop({edgeFile = "Interface/Tooltips/UI-Tooltip-Border", bgFile = path, edgeSize = 16, insets = { left = 4, right = 4, top = 4, bottom = 4 }});	
	end
end

function GH_Display:ClearAllObjects()
	-- go trough all objects, hide them and dispose their frames
	if type(self.objects) == "table" then
		for i=1,#(self.objects) do
			if type(self.objects[i]) == "table" then
				self.objects[i].frame:Hide();
			end
		end
		wipe(self.objects);
	end
end

function GH_Display:GetOverlayPos(objX,objY,objZ) -- x,y,z are relative to center of model. Returns ox,oy,scale,isBehind
	
	local fx,fy,fz = unpack(self.lastPosition);
	local a = deg(self.lastRotation);
	local rx,ry,rz = (cos(a)*objX - objY*sin(a)),(sin(a)*objX + objY*cos(a)),objZ;
	local x,y,z = fx + rx, fy + ry, fz + rz;
	local isBehind;
	if rx < 0 then
		isBehind = true;
	end
	
	local cpX,cpY,cpZ = unpack(self.CamPos);
	local cdX,cdY,cdZ = unpack(self.CamDir);
	local coX,coY,coZ = x-cpX,y-cpY,z-cpZ;
	local ay = GetVectorAngle(coX,coY,cdX,cdY);
	local az = GetVectorAngle(coX,coZ,cdX,cdZ);
	local dist = sqrt(coX*coX,coY*coY,coZ*coZ);
	local k = 337;
	
	local overlay_x = tan(ay)*k;
	local overlay_y = tan(az)*k;
	
	if coY/coX > -cdY then
		overlay_x = -overlay_x;
	end
	
	if coZ/coX > -cdZ then
		overlay_y = -overlay_y;
	end
	local scale = 1/dist; 
	
	return overlay_x,overlay_y,scale,isBehind;	
end

function GH_Display:Show()
	if self.parent then
		self.parent:Show();
		if self.parent.black then
			self.parent.black:Show();
		end
	end
	self.display:Hide();
	self.display:Show();
end
function GH_Display:Hide() --print("hide");
	if self.parent then
		self.parent:Hide();
		self.display:Hide(); --print("hiding parent",self.parent.black)
		if self.parent.black then
			self.parent.black:Hide();
		end
	else
		self.display:Hide();
	end
end
function GH_Display:IsShown()
	if self.parent then
		return self.parent:IsShown();
	else
		return self.display:IsShown();
	end
end

function GH_Display:ShowEmpty(show)
	self.showEmpty = show;
	self:Update(true);
end

function GH_Display:GetStdSlotList()
	local race = UnitRace("player");
	local gender = UnitSex("player");
	if gender == 2 then gender = "Male"; else gender = "Female" end
	local s = race.."-"..gender;
	
	local t = {};
	for i,_ in pairs(StdSlots[s] or {}) do
		table.insert(t,i);
	end
	return t;
end

function GH_Display:GetStdSlotCoor(val) 
	local race = UnitRace("player");
	local gender = UnitSex("player");
	if gender == 2 then gender = "Male"; else gender = "Female" end
	local s = race.."-"..gender;
	
	return (StdSlots[s] or {})[val];
end


function GH_Display:TestAt(x,y,z,behind)
	--x,y,z,behind = -10,0,1.2,nil;
	if not(self.TestFrame) then
		local f = CreateFrame("Frame",nil,this.display)
		f:SetFrameStrata("MEDIUM")
		f:SetWidth(16);
		f:SetHeight(16);
		local t = f:CreateTexture(nil,"BACKGROUND")
		t:SetTexture("Interface\\QuestFrame\\UI-Quest-BulletPoint.blp")
		t:SetAllPoints(f)
		f.texture = t
		f:Show();
		self.TestFrame = f;
	end
	
	if behind then
		self.TestFrame:SetFrameStrata("LOW")
	else
		self.TestFrame:SetFrameStrata("MEDIUM")
	end
	
	local width = 0.16;
	
	--[[ 	Faction checked:
	Night elf male: 528.66 and 4.0436;
	Tauren male: 528.66 and 4.0436; (acceptable but not perfect)
	Dwarf male and gnome female: (being off when zooming far in)
	--]]
	--[[
	k1 = k1 or 528.66; --259.7138030;
	k2 = k2 or 4.0436; --3.1--2.9;
	--K3 values:
	--	0.0978  good for dwarves when z = 0.5 and y = 0.5
	--
	k3 = k3 or 1; 
	local overlay_y = ((k1*y)/(k2-x));
	local overlay_z = ((k1*z)/(k2-x))*k3;
	local scale = (k1*(y+width)/(k2-x))-overlay_y;--]]
	
	local cpX,cpY,cpZ = unpack(self.CamPos);
	local cdX,cdY,cdZ = unpack(self.CamDir);
	
	local coX,coY,coZ = x-cpX,y-cpY,z-cpZ;
	--coX,coY,coZ = -1,0,0.0891;
	--print(format("co(%s,%s,%s)",coX,coY,coZ));
	local ay = GetVectorAngle(coX,coY,cdX,cdY);
	local az = GetVectorAngle(coX,coZ,cdX,cdZ);
	
	local dist = sqrt(coX*coX,coY*coY,coZ*coZ);
	--print(format("ys %s %s",coY,cdY));
	--print(format("Az = %s deg",az));
	
	k = k or 337;
	
	local overlay_y = tan(ay)*k;
	local overlay_z = tan(az)*k;
	
	if coY < cdY then
		overlay_y = -overlay_y;
	end
	
	if coZ < cdZ then
		overlay_Z = -overlay_Z;
	end
	
	--print(format("tan(%s)*%s = %s",az,k,tan(az)*k));
	--overlay_z = 51;
	
	local scale = 1/dist; -- todo calculate this
	--print(scale);
	
	self.TestFrame:SetHeight(scale*20);
	self.TestFrame:SetWidth(scale*20);
	self.TestFrame:SetPoint("CENTER",overlay_y,overlay_z);
end

function Model_OnUpdate2(self, elapsedTime, rotationsPerSecond)
	if ( not rotationsPerSecond ) then
		rotationsPerSecond = ROTATIONS_PER_SECOND;
	end
	if ( _G[self:GetName().."RotateLeftButton"]:GetButtonState() == "PUSHED" ) then
		self.rotation = self.rotation + (elapsedTime * 2 * PI * rotationsPerSecond);
		if ( self.rotation < 0 ) then
			self.rotation = self.rotation + (2 * PI);
		end
		self:SetRotation(self.rotation);
	end
	if ( _G[self:GetName().."RotateRightButton"]:GetButtonState() == "PUSHED" ) then
		self.rotation = self.rotation - (elapsedTime * 2 * PI * rotationsPerSecond);
		if ( self.rotation > (2 * PI) ) then
			self.rotation = self.rotation - (2 * PI);
		end
		self:SetRotation(self.rotation);
	end
	if ( _G[self:GetName().."ZoomInButton"]:GetButtonState() == "PUSHED" ) then
		self.x = min(self.x + elapsedTime,1.4);
		self:SetPosition(self.x,self.y,self.z);
	end
	if ( _G[self:GetName().."ZoomOutButton"]:GetButtonState() == "PUSHED" ) then
		self.x = max(self.x - elapsedTime,(calibrate and -29) or -1.5);
		self:SetPosition(self.x,self.y,self.z);
	end
end


function GetVectorAngle(ax, ay, bx, by) -- from http://www.allegro.cc/forums/thread/591460/673459
	
	local dotproduct, lengtha, lengthb, result;

	dotproduct = (ax * bx) + (ay * by);
	lengtha = sqrt(ax * ax + ay * ay);
	lengthb = sqrt(bx * bx + by * by);

	result = acos( dotproduct / (lengtha * lengthb) );
	
	--GHI_Message(format("dot %s, lenA %s, lenB %s, res %s",dotproduct,lengtha,lengthb,result or "nil"));
	
	if(dotproduct < 0) then
		if(result > 0) then
			result = result + math.pi;
		else
			result = result - math.pi;
		end
	end
	return result;
end

--[[	GH Display Object
--]]
GH_DO = {}
GH_DO.__index = GH_DO;

-- 	standard
function GH_DO:Create(x,y,z,scale,name,icon,clickFunc,tooltipType,refID,codeReq)
	assert((type(x) == "number"  and type(y) == "number" and type(z) == "number" and type(icon) == "string") or type(x)=="table","Usage num,num,num,num,string,[func]");

	local i = 1000;
	while( getglobal("GH_DO"..i) ) do
		i = i + 1;
	end
	varName = "GH_DO"..i;
	
	setglobal(varName,GH_DO); 
	
	local obj = {}             -- our new object
	setmetatable(obj, getglobal(varName))  
	if type(x) == "table" then
		obj:Deserialize(x);
	else
		obj.x = x;
		obj.y = y;
		obj.z = z;
		obj.scale = scale;
		obj.icon = icon;
		obj.clickFunc = clickFunc;
		obj.tooltipType = tooltipType;
		obj.refID = refID;
		obj.name = name;
	end
	obj.type = "GH_DO";
	setglobal(varName,obj); 
	return obj;
end

function GH_DO:SetInfo(ref,icon)
	self.refID = ref;
	self.icon = icon;
end


function GH_DO:Update(display,frame) -- show or update
	
	
	local ox,oy,scale,isBehind = display:GetOverlayPos(self.x,self.y,self.z);
	
	--print((abs(oy) + scale*16)," > ",(display.display:GetHeight() / 2));
	
	if (abs(oy) + scale*16) > (display.display:GetHeight() / 2) then
		--print("Too high");
		frame:Hide();
		return;
	end
	
	if (abs(ox) + scale*16) > (display.display:GetWidth() / 2) then
		frame:Hide();
		return;
	end
	
	if self.refID == 0 and not(display.showEmpty) then
		frame:Hide();
		return;
	end
	
	
	frame.texture:SetTexture(self.icon);
	
	if isBehind then
		if display.strata then
			frame:SetFrameStrata(display.strata);
			frame:SetFrameLevel((display.frameLevel or 1)-1);
		else
			frame:SetFrameStrata("LOW");
		end
	else
		if display.strata then
			frame:SetFrameLevel((display.frameLevel or 1)+1);
		else
			frame:SetFrameStrata("MEDIUM")
		end
	end
	
	frame:SetHeight(scale*32*(self.scale or 1));
	frame:SetWidth(scale*32*(self.scale or 1));
	frame:SetPoint("CENTER",ox,oy);
	--print(format("%s , %s",ox,oy));
	
	
	
	frame:Show();
end

function GH_DO:OnClick(...)
	if self.object.clickFunc then
		self.object.clickFunc(...);
	end
end

function GH_DO:OnEnter(...)
	if self.object.tooltipType then
		GHI_EqDisplayOnEnter(self.object.tooltipType);
		--self.object.tooltipFunc(...);
	end
end

function GH_DO:OnLeave(...)
	if self.object.tooltipType then
		GameTooltip:Hide();
	end
end

function GH_DO:Serialize()
	local t = {
		x = self.x,
		y = self.y,
		z = self.z,
		scale = self.scale,
		icon = self.icon,
		refID = self.refID,
		name = self.name,
		tooltipType = self.tooltipType
	};
	--print(sending)
	--GHI_PrintArray(t);
	return t;	
end

function GH_DO:Deserialize(t)
	if not(type(t)=="table") then return end;
	self.x = t.x;
	self.y = t.y;
	self.z = t.z;
	self.scale = t.scale;
	self.icon = t.icon;
	self.refID = t.refID;
	self.name = t.name;
	self.tooltipType = t.tooltipType;
	--GHI_PrintArray(self)
	
end

function GHDT()
	local d = New_GH_Display();
	d:SetUnit("Player");
	
	local objs = {};
	table.insert(objs,GH_DO:Create(0.15,0.0,0.45,"Interface\\Icons\\INV_Jewelry_Necklace_02",print,print,"R1"));
	table.insert(objs,GH_DO:Create(0.0,-0.25,-0.1,"Interface\\Icons\\INV_Jewelry_Ring_04",print,print,"R2"));
	
	d:SetObjects(objs);
	d:CreateStandaloneFrame();
	
end


-- =========================================
--				GHI Display USE
-- =========================================

local PD; -- player display
local Displays = {}; -- target display and other displays
local EnabledAsStd = {"neck"}
GHI_EquipmentDisplayData = GHI_EquipmentDisplayData or {};

local function SetPositionInfo(slot,id) 
	local pos = GHI_EquipmentDisplayData.pos or {};
	pos[slot] = {ItemID = id};
	GHI_EquipmentDisplayData.pos = pos;
	GHI_UpdatePlayerEquipmentDisplay()
end

function GHI_SetCustomSlotInfo(slotRef,info)
	local customSlots = GHI_EquipmentDisplayData.customSlots or {};
	customSlots[slotRef] = info
	GHI_EquipmentDisplayData.customSlots = customSlots;
	
	-- update the display frame
	local ref = 0;
	local icon = "Interface\\PaperDoll\\UI-Backpack-EmptySlot.blp";
		
	local o = GH_DO:Create(info.x,info.y,info.z,info.scale,info.name,icon,GHI_EqDisplayOnClick,GHI_EqDisplayOnEnter,ref);
	o.SetPositionInfo = SetPositionInfo;
	o.slotRef = slotRef; -- ref for position data
	PD:AddObject(o);
	PD:Update(true);
end

function GHI_GetPlayerEquipmentDisplay()
	if not(PD) then
		--GHI_ShowPlayerEquipmentDisplay();  -- would give loop
		--PD:Hide();
		return;
	end
	return PD
end

function GHI_ShowPlayerEquipmentDisplay()
	if PD and PD.display and PD.display:IsShown() then
		PD:Hide();
		return;
	end
	if PD then
		PD:Show();
		PD.display:SetUnit("player"); -- update the 3d itself
	else
		-- show the menu for new slot and hide it (fixes it being i the wrong layer)
		local f = GHM_NewFrame(GHI_NCS_Menu);
		f:Hide();
	
		PD = New_GH_Display();
		PD:SetUnit("player");
		PD:CreateStandaloneFrame();
		PD:Show();
		
		-- Create buttons (std slot, custom slot, background, settings)
		local btns = {	
			{ref="DisplayedSlots",short=GHI_SELECT_DISPLAYED_SLOTS_SHORT,name=GHI_SELECT_DISPLAYED_SLOTS},
			{ref="NewSlot",short=GHI_NEW_CUSTOM_SLOT_SHORT,name=GHI_NEW_CUSTOM_SLOT},
			{ref="background",short=GHI_BACKGROUND_SHORT,name=GHI_BACKGROUND},
			--{ref="options",short="Op",name="Equipment Display Options?"}, -- needed at all?  Used for: Show Weapons?
		}
		if calibrate then
			table.insert(btns,{ref="calPrt",short="prt",name="Save position (for calibration)"});
			table.insert(btns,{ref="showCal",short="show",name="Show saved positions (for calibration)"});
		end
		local margin = 5;
		local width = ((PD.display:GetWidth()-margin) / #(btns));
		for i=1,#(btns) do
			local b = CreateFrame("Button","GHI_PDBtn_"..btns[i].ref,PD.display,"UIPanelButtonTemplate");
			b.ref = btns[i].ref;
			b:SetText(btns[i].short);
			b.tttext = btns[i].name;
			b:SetWidth(width-margin);
			b:SetHeight(20);
			b:SetPoint("BOTTOMLEFT",margin+ ((i-1)*width),margin);
			
			b:SetScript("OnEnter",function() GameTooltip:SetOwner(this, "ANCHOR_LEFT");
				GameTooltip:ClearLines()
				GameTooltip:AddLine(this.tttext,1,0.8196079,0);
				GameTooltip:Show()
				this.UpdateTooltip = nil;
			end);
			b:SetScript("OnLeave",function() GameTooltip:Hide(); end);
			b:SetScript("OnClick",function() GHI_PlayerEDBtnClick(this.ref); end);
		end
		
		-- close button
		local b = CreateFrame("Button","GHI_PDB_Close",PD.display,"UIPanelCloseButton");
		b:SetPoint("TOPRIGHT",17,17);
		b.main = PD;
		b:SetScript("OnClick",function() this.main:Hide(); end);
		
		-- initialize data first time 
		if GHI_EquipmentDisplayData == nil then
			GHI_EquipmentDisplayData = {};
			GHI_EquipmentDisplayData.stdEnabled = PD:GetStdSlotList();
		end
		
		
		GHI_UpdatePlayerEquipmentDisplay()
		PD:ShowEmpty(not(GHI_MiscData["hide_empty_slots"]));
	end
	GHI_updateContainerFrameAnchors() 
end

function GHI_UpdatePlayerEquipmentDisplay()
	if not(PD) then return end;
	PD:ClearAllObjects();
	local data = GHI_EquipmentDisplayData or {};
	local pos = data.pos or {};
	local stdEnabled = data.stdEnabled or {};
	local customSlots = data.customSlots or {};
	local bg = data.background or "";
	
	local objs = {};
	
	--background
	PD:SetBackground(bg)
	
	-- insert all standard slots
	for _,slot in pairs(stdEnabled) do
		local coor = PD:GetStdSlotCoor(slot);
		--print(type(coor));
		if type(coor) == "table" then
			local icon = "Interface\\PaperDoll\\UI-Backpack-EmptySlot.blp";
			local ref = 0; -- empty
			if type(pos[slot]) == "table" then
				local id = pos[slot].ItemID;
				if id then
					_,icon = GHI_GetItemInfo(id);
					ref = id;
				end
			end
			
			local name = GHI_SLOT_NAMES[slot] or "";
			
			--print("insert");
			local o = GH_DO:Create(coor[1],coor[2],coor[3],coor[4],name,icon,GHI_EqDisplayOnClick,"GHI",ref);
			o.SetPositionInfo = SetPositionInfo;
			o.slotRef = slot; -- ref for position data
			table.insert(objs,o);
		end
	end
	
	-- insert custom slots
	for id,slot in pairs(customSlots) do
		if slot.enabled == true then
			local ref = 0;
			local icon = "Interface\\PaperDoll\\UI-Backpack-EmptySlot.blp";
			if type(pos[id]) == "table" then
				local id = pos[id].ItemID;
				if id then
					_,icon = GHI_GetItemInfo(id);
					ref = id;
				end
			end
			
			local o = GH_DO:Create(slot.x,slot.y,slot.z,slot.scale,slot.name,icon,GHI_EqDisplayOnClick,"GHI",ref,slot.code);
			o.SetPositionInfo = SetPositionInfo;
			o.slotRef = id; -- ref for position data
			table.insert(objs,o);
		end
	end
	
	-- todo: go trough all slots, looks at their items RC actions and insert eventual armor?
	
	-- set slots
	if #(objs) > 0 then
		PD:SetObjects(objs);
	end
	
	GHI_EqDisplayUpdated()
end

function GHI_PlayerEDBtnClick(btnRef) 
	if btnRef == "NewSlot" then
		GHI_ShowNewSlotMenu();
	elseif btnRef == "calPrt" then
		local x,y,z = PD.display:GetPosition();
		
		local f = GHM_NewFrame(GHI_Calb_Menu);
		local c = f.GetLabel("code") or "";		
		
		c = format("%s%f	%f\n",c,x,z);
		c = gsub(c,"%.",",");
		print("Coordinates saved");
		f.ForceLabel("code",c);
	elseif btnRef == "showCal" then
		local f = GHM_NewFrame(GHI_Calb_Menu);
		f:Show();
	elseif btnRef == "background" then
		local f = GHM_NewFrame(GHI_BackgroundMenu);
		--local t = GHM_StockIcons[ "Spell" ] local l={}; for i =1,20 do table.insert(l,{p="Interface\\Interface\\Icons\\"..t[random(#(t))]}); end 
		GHI_ED_BackgroundMenu_P1_L1_O1.SetImages(GH_Display_BG_List)
		f.ForceLabel("img",GHI_EquipmentDisplayData.background)   -- force current showed BG
		f:Show();
	elseif btnRef == "DisplayedSlots" then
		local f = GHM_NewFrame(GHI_DisplayedSlotMenu);
		local list = f.GetLabelFrame("list");
		local slots = PD:GetStdSlotList();
		local edit = f.GetLabelFrame("edit");
		edit:Disable();
		
		list.Clear()
		for i=1,#(slots) do
			local enabled = false;
			for _,enabled_slot in pairs(GHI_EquipmentDisplayData.stdEnabled or {}) do
				if (slots[i] == enabled_slot) then
					enabled = true;
				end
			end
			list.InsertTuble({name=GHI_SLOT_NAMES[slots[i]] or slots[i],id_name=slots[i],check=enabled,type=GHI_STANDARD});
		end 
		for id,slot in pairs(GHI_EquipmentDisplayData.customSlots or {}) do
			list.InsertTuble({name=slot.name,check=slot.enabled,type=GHI_CUSTOM,isCustom = true,id = id});
		end
		f:Show();
	end
end

function GHI_EqDisplayOnClick(btn,...)

	local obj = this.object;
	
	
	local objGotItem = (not(obj.refID == 0));
	local cursorGotRealItem = CursorHasItem();
	local cursorGotGHIItem = (GHI_GetCursor() == "item");
	
	if btn == "RightButton" and objGotItem then
		GHI_UseItem(unpack({GHI_FindItem(obj.refID)}))
		return
	end
	
	
	if cursorGotRealItem then
		return; --ClearCursor();
	end
	
	-- if objGotItem then
	-- save the item temp
	-- end
	
	if cursorGotGHIItem then
		local _,details = GHI_GetCursor();
		obj:SetInfo(details.id,details.iconTexture);
		PD:Update(true);
		
		SetPositionInfo(obj.slotRef,details.id);
		
		GHI_ResetCursor();
		GameTooltip:Hide();
		GHI_EqDisplayOnEnter(...);
		GHI_EqDisplayUpdated()
	else
		obj:SetInfo(0,"Interface\\PaperDoll\\UI-Backpack-EmptySlot.blp");
		PD:Update(true);
		GameTooltip:Hide();
		GHI_EqDisplayUpdated()
	end
	
	
	-- put the temp item on cursor
	
	
	
end

function GHI_EqDisplayOnEnter(doType)
	if doType == "GHI" then
		if not(this.object.refID==0) then  -- and not(GHI_GetCursor() == "item")
			GameTooltip:SetOwner(this, "ANCHOR_LEFT");
			GHI_ItemTooltip(this,this.object.refID) 
			this.UpdateTooltip = nil;
		else
			GameTooltip:SetOwner(this, "ANCHOR_LEFT");
			GameTooltip:AddLine(this.object.name, 1.0, 0.8196079, 0,1);
			GameTooltip:Show();
			this.UpdateTooltip = nil;
		end
	end
end

function GHI_ShowNewSlotMenu(editID)
	local f = GHM_NewFrame(GHI_NCS_Menu);
	f.edit = nil;
	f.ClearAll();
	
	if editID then
		local slot = (GHI_EquipmentDisplayData.customSlots or {})[editID];
		if not(type(slot)) == "table" then
			return;
		end
	
		f.edit = editID;
		f.ForceLabel("x",slot.x);
		f.ForceLabel("y",slot.y);
		f.ForceLabel("z",slot.z);
		f.ForceLabel("name",slot.name);
		f.ForceLabel("scale",slot.scale);
		f.ForceLabel("code",slot.code);
	end
	
	f:Show();
end

function GHI_ShowSlots(show)
	if PD and GHI_MiscData["hide_empty_slots"] then
		PD:ShowEmpty(show);
	else
		PD:ShowEmpty(true);
	end
end

function GHI_EqDisplaySetBackground(path)
	local t = GHI_EquipmentDisplayData or {};
	t.background = path;
	GHI_EquipmentDisplayData = t;
	PD:SetBackground(path)
	GHI_EqDisplayUpdated()
end

-- Communication
local subscribedPlayers = {};
local subscriptionsSend = {};
local EqDisplayDataFromPlayers = {};

function GHI_EqDisplaySubscripeForUpdates(player)
	if type(subscriptionsSend[player])=="number" and (GetTime() - subscriptionsSend[player]) < 120 then
		return;
	end
	GHI:SendPrioritizedMessage("NORMAL","WHISPER",player,false,"EqDSubscribe",120)
	subscriptionsSend[player] = GetTime();
	--print("Send subscription to "..player);
end

function GHI_EqDisplayRecieveSubscription(sender,subscriptionTime,...)
	subscribedPlayers[sender] = GetTime() + subscriptionTime;
	GHI_SendDisplayInfo(sender);
end
GHI:RegisterRecieve("EqDSubscribe",GHI_EqDisplayRecieveSubscription)

function GHI_UpdateSubscriptions()
	for player,timeout in pairs(subscribedPlayers) do
		if timeout < GetTime() then
			subscribedPlayers[player] = nil;
		end
	end
end

function GHI_EqDisplayUpdated()
	--for _,player in pairs(subscribedPlayers) do
	--	GHI_SendDisplayInfo(player);
	--end
	GHI_UpdateSubscriptions();
	GHI_SendDisplayInfo(subscribedPlayers);
end

function GHI_SendDisplayInfo(players)
	if not(type(players)=="table" or type(players)=="string") then return end;
	
	if not(PD) then
		GHI_ShowPlayerEquipmentDisplay()
		PD:Hide();
	end
	--[[	Returns slots with items (id), background
	--]]
	local objs = {};
	for _,o in pairs(PD.objects or {}) do
		if not(o.refID == 0) then
			local s = o.object:Serialize();
			table.insert(objs,s);
		end
	end
	
	local bg = (GHI_EquipmentDisplayData or {}).background;
	if type(players) == "string" then --print("Send to ",players);
		GHI:SendPrioritizedMessage("BULK","WHISPER",players,false,"EqDInfo",objs,bg);
		return
	end
	
	for p,_ in pairs(players) do --print("Send to more ",p);
		GHI:SendPrioritizedMessage("BULK","WHISPER",p,false,"EqDInfo",objs,bg);
	end
end

function GHI_EqDisplayUpdateWithKnownInfo(display)
	local t = EqDisplayDataFromPlayers[display.name];
	if type(t)=="table" then
		local objs = {};
		for _,infoPart in pairs(t.objs) do
			table.insert(objs,GH_DO:Create(infoPart));
		end
		if #(objs) > 0 then
			display:SetObjects(objs);
		end
		display:SetBackground(t.bg);
	else 
		display:SetBackground("");
	end
end

function GHI_EqDisplayRecieveInfo(sender,info,bg,...) --print("recieved")
	-- go trough all displays and find the senders 
	local updateItems;
	for i,display in pairs(Displays) do
		if display.name == sender then
			--print("Updaing display with new info");
			-- insert
			EqDisplayDataFromPlayers[sender]= {objs = info,bg=bg};
			
			local objs = {};
			for _,infoPart in pairs(info) do
				table.insert(objs,GH_DO:Create(infoPart));
			end
			if #(objs) > 0 then
				display:SetObjects(objs);
			end
			display:SetBackground(bg);
			
			-- request ghi data
			updateItems = true;
			-- update
			--print(#(objs).." objects");
			
		end
	end
	if updateItems then
		
	end
end
GHI:RegisterRecieve("EqDInfo",GHI_EqDisplayRecieveInfo)


function GHI_SetTargetEqDisplay(unit) -- unit is normally target
	if Displays[1] == nil and not(UnitName(unit)=="") and UnitIsPlayer(unit) then
		-- create a new display
		local d = New_GH_Display();
		d:SetUnit(unit);
		d:CreateStandaloneFrame();
		d:Show();
		
		
		
		-- todo: name frame and move "bar" for the frame
		local p = CreateFrame("Button",d.display:GetName().."_Bar",d.display);
		p:SetWidth(d.display:GetWidth()+10);
		p:SetHeight(16);
		p.main = d;
		p:SetPoint("TOP",0,14);
		--p:SetScript("OnClick",print);
		
		p:RegisterForDrag("LeftButton")
		p:SetMovable();
		
		p:SetScript("OnUpdate", function(b) if b.drag then GHI_DragEqDisplay(b.main) end end)
		p:SetScript("OnDragStart", function(b) b.drag = true end)
		p:SetScript("OnDragStop", function(b) b.drag = false end)
		
		local pf = p:CreateFontString();
		--pf:SetFont("Fonts\\FRIZQT__.TTF", 11, "OUTLINE, MONOCHROME")
		pf:SetFontObject("GameFontHighlight");
		pf:SetText(UnitName(unit));
		pf:SetPoint("CENTER",0,0,p);
		pf:Show();
		d.nameString = pf;
		
		local bg = "Interface/RAIDFRAME/UI-RaidFrame-GroupBg"; --Interface/Tooltips/UI-Tooltip-Border
		p:SetBackdrop({edgeFile = "", bgFile =  bg, edgeSize = 0, tile=false, insets = { left = 0, right = 0, top = 0, bottom = 0 }});
		p:SetFrameStrata("MEDIUM");
		p:SetFrameLevel(4);
		
		
		
		-- close button
		local b = CreateFrame("Button",d.display:GetName().."_Close",p,"UIPanelCloseButton");
		b:SetPoint("RIGHT",p,"RIGHT",10,0);
		b.main = d;
		b:SetScript("OnClick",function() this.main:Hide(); if this.num == 1 then GHI_ToggleTargetEqDisplay(); end  end);
		
		-- todo: button to "Copy" frame to show all time
		local b2 = CreateFrame("Button",d.display:GetName().."_Copy",p,"UIPanelButtonTemplate");
		b2:SetHeight(22)
		b2:SetWidth(22)
		b2:SetText("C");
		b2:SetPoint("LEFT",p,"LEFT",0,0);
		b2.main = d;
		d.copyBtn = b2;
		b2:SetScript("OnClick",function() GHI_CopyTargetEqDisplay() end);
		b2:Show();
		
		
		
		d.num = 1;
		
		Displays[1] = d;
		--GHI_EqDisplaySubscripeForUpdates(UnitName(unit));
		GHI_UpdateDisplay(Displays[1],unit);
		
		GHI_DragEqDisplay(d,{});
	elseif Displays[1] and UnitExists(unit) and UnitName(unit) then
		GHI_UpdateDisplay(Displays[1],unit);
				
		Displays[1]:Show();
	end
end

function GHI_UpdateDisplay(display,unit)
	display:ClearAllObjects()
	display:SetUnit(unit);
	GHI_EqDisplayUpdateWithKnownInfo(display);
	GHI_EqDisplaySubscripeForUpdates(UnitName(unit));
end

function GHI_DragEqDisplay(obj,pos)
	if not(type(obj)=="table") then return end
		
	local xpos, ypos;
	
	if (pos) then 
		if obj.num == 1 and type(GHI_EquipmentDisplayData) == "table" and type(GHI_EquipmentDisplayData["targetPos"])=="table" then
			xpos = pos[1] or GHI_EquipmentDisplayData["targetPos"][1] or 100;
			ypos = pos[2] or GHI_EquipmentDisplayData["targetPos"][2] or 300;
		else
			xpos = pos[1] or 100;
			ypos = pos[2] or 600;
		end
	end
	
	if (not xpos and not ypos) then
		local x, y = GetCursorPosition();
		local s = obj.parent:GetEffectiveScale();
		
		xpos, ypos = x/s, y/s;
		
	end
	
	--GHU_MiscData = GHU_MiscData or {};
	--GHU_MiscData["TargetButtonPos"] = {xpos,ypos};
	if obj.num == 1 then
		GHI_EquipmentDisplayData["targetPos"] = {xpos,ypos};
	end
	
	
	-- Hide the tooltip
	GameTooltip:Hide();
	
	-- Set the position
		
	obj.parent:SetPoint("TOP", UIParent, "BOTTOMLEFT", xpos, ypos);
end

function GHI_CopyTargetEqDisplay() -- make a copy of a equipment display
	local n = #(Displays)+1
	Displays[n] = Displays[1];
	Displays[n].num = n;
	
	Displays[1] = nil;
	
	-- move the frame
	local a,b,c,x,y = Displays[n].parent:GetPoint();
	Displays[n].parent:SetPoint(a,b,c,x+130,y-40);
	if Displays[n].copyBtn then
		Displays[n].copyBtn:Hide();
	end
	
	GHI_SetTargetEqDisplay("target")
	
	--Displays[1].parent:SetPoint(a,b,c,x,y);
end

local targetBtn;
local targetToggled;
function GHI_EqDisplayEvent()
	if event == "VARIABLES_LOADED" then
		-- set up GHT
		targetBtn = GHU_New("target");
		targetBtn:AddButton("TargetEqDisplay","",function()  
			GameTooltip:SetOwner(this, "ANCHOR_LEFT");
			GameTooltip:ClearLines()
			GameTooltip:AddLine(GHI_TOGGLE_TARGET_EQD,1,0.8196079,0);
			GameTooltip:Show()
		end,GHI_ToggleTargetEqDisplay,"FriendlyPlayer")
		
		if not(PD) then
			GHI_ShowPlayerEquipmentDisplay()
			PD:Hide();
		end
		
		return;
	elseif event == "PLAYER_TARGET_CHANGED" then
		if Displays[1] then
			if targetToggled and UnitExists("target") and UnitIsPlayer("target") and UnitIsFriend("target","player") then
				GHI_SetTargetEqDisplay("target");
			else
				Displays[1]:Hide();
			end
		end
	end
end
GHI_RegEvent("VARIABLES_LOADED",GHI_EqDisplayEvent);
GHI_RegEvent("PLAYER_TARGET_CHANGED",GHI_EqDisplayEvent);

function GHI_ToggleTargetEqDisplay()
	targetToggled = not(targetToggled);
	if targetToggled then
		GHI_SetTargetEqDisplay("target");
	elseif Displays[1] then
		Displays[1]:Hide();
	end
end


