--[[
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"] = {3.122545001	,0,-0.196758709}; --{2.845844923,0,-0.177884383};	-- ok
CamDir["Human-Male"] = {-1,0,0.021059619}; --{-1,0,0.017852564};
CamPos["NightElf-Male"] = {4.057864672,0,-0.34};		-- ok
CamDir["NightElf-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["NightElf-Female"]={4.23034501440184,0,-0.0379146954580338}
CamDir["NightElf-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["BloodElf-Male"]={3.86825416179682,0,0.0417639353605309}
CamDir["BloodElf-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["BloodElf-Female"]={3.2892542673688,0,0.0118071713949199}
CamDir["BloodElf-Female"]={-1,0,-0.017794584841872}






local StdSlots = {};
--StdSlots["x"] = {belt={},left_foot={},right_foot={},left_ring={},right_ring={},chest={},face={},head={},back={},legs_left_side={},leg_right_side={}};
StdSlots["Human-Male"] 			= {head={0.11,-0.01,0.55,0.8},leg_right_side={0.08,-0.1,-0.37,1},chest={0.13,-0.02,0.25,1},face={0.16,-0.01,0.46,0.8},right_foot={0.06,-0.14,-0.76,1},leg_left_side={0.17,0.05,-0.33,1},belt={0.1,-0.02,0.03,0.8},back={-0.1,0.02,0.23,1.2},left_foot={0.1,0.09,-0.76,1},left_ring={0.03,0.23,-0.21,0.8},right_ring={-0.05,-0.31,-0.21,0.8},};
StdSlots["Human-Female"] 		= {head={0.11,-0.01,0.55,0.8},leg_right_side={0.08,-0.08,-0.22,1},chest={0.1,-0.02,0.31,1},face={0.06,-0.01,0.46,0.8},right_foot={0.01,-0.06,-0.64,1},leg_left_side={0.17,0.07,-0.22,1},belt={0.1,-0.02,0.03,0.8},back={-0.1,0,0.28,1.2},left_foot={0.07,0.09,-0.63,1},left_ring={-0.01,0.19,-0.05,0.8},right_ring={-0.06,-0.19,-0.05,0.8},};

StdSlots["Undead-Male"] 		= {head={0.3,-0.08,0.55,1},leg_right_side={0,-0.21,-0.47,1},chest={0.01,-0.09,0.19,1.5},face={0.28,-0.07,0.46,1},right_foot={0.001,-0.21,-0.93,1.5},leg_left_side={0.07,0.32,-0.46,1},belt={0.001,0.03,-0.05,1},back={-0.23,-0.12,0.33,1.5},left_foot={-0.04,0.34,-0.94,1.5},left_ring={0.1,0.36,-0.36,1},right_ring={-0.19,-0.3,-0.24,1},};
StdSlots["Undead-Female"] 		= {head={0.26,-0.01,0.71,0.8},leg_right_side={0.08,-0.08,-0.27,1},chest={0.1,-0.02,0.36,1},face={0.23,-0.01,0.61,0.8},right_foot={-0.05,-0.06,-0.74,1},leg_left_side={0.17,0.07,-0.26,1},belt={0.1,0,0.14,0.8},back={-0.1,0,0.38,1.2},left_foot={0.07,0.15,-0.73,1},left_ring={0.14,0.28,-0.1,0.8},right_ring={0.06,-0.3,-0.08,0.8},};

StdSlots["Draenei-Male"] 		= {head={0.08,-0.03,0.63,1},leg_right_side={0.34,-0.12,-0.73,1},chest={0.22,0.09,0.23,1.5},face={0.19,0.05,0.56,1},right_foot={0.16,-0.21,-1.28,1.5},leg_left_side={0.07,0.39,-0.78,1},back={-0.01,-0.12,0.25,1.5},belt={0.19,0.1,-0.23,1},left_foot={-0.04,0.22,-1.29,1.5},left_ring={0.01,0.55,-0.49,1},right_ring={0.27,-0.3,-0.45,1},};
StdSlots["Draenei-Female"]		= {head={0.16,0.01,0.99,1},leg_right_side={0.08,-0.08,-0.27,1},chest={0.1,0.04,0.68,1},face={0.18,0.02,0.89,0.8},right_foot={0.14,-0.06,-0.85,1},leg_left_side={0.09,0.15,-0.26,1},back={-0.1,0,0.57,1.2},belt={0.1,0.04,0.32,0.8},left_foot={0.02,0.18,-0.83,1},left_ring={0.02,0.27,0.02,0.8},right_ring={0.01,-0.24,0.09,0.8},};

StdSlots["NightElf-Male"] 		= {head={0.08,-0.03,0.63,1},leg_right_side={0.11,-0.16,-0.71,1},chest={0.1,0,0.23,1.5},face={0.15,-0.02,0.49,1},right_foot={0.05,-0.23,-1.29,1.5},leg_left_side={0.05,0.19,-0.71,1},right_ring={0,-0.3,-0.45,1},belt={0.14,0,-0.07,1},left_foot={0.04,0.22,-1.29,1.5},left_ring={0.01,0.3,-0.49,1},back={-0.17,0,0.25,1.5},};
StdSlots["NightElf-Female"]	= {head={0.01,0.04,0.95,1.00},right_foot={0.1,.17,-1.08,1.00},right_ring={0.1,.33,-0.13,1.00},left_foot={0.1,-0.23,-1.06,1.00},belt={0.1,0.06,0.21,1.00},chest={0.1,0,0.48,1.00},left_ring={0.1,-0.28,-0.13,1.00},face={0.01,0.04,0.79,1.00},back={-0.01,0,0.44,1.00},leg_left_side={0.1,-0.13,-0.47,1.00},leg_right_side={0.1,.16,-0.47,1.00}};

StdSlots["BloodElf-Male"] 		= {head={0.18,-0.03,0.94,1},leg_right_side={0.11,-0.13,-0.21,1},chest={0.2,-0.05,0.63,1.5},face={0.04,-0.02,0.97,1.2},right_foot={0.11,-0.15,-0.69,1},leg_left_side={0.01,0.17,-0.23,1},right_ring={-0.11,-0.3,0.1,0.8},back={-0.12,-0.14,0.72,1.5},left_foot={0.04,0.22,-0.71,1.5},left_ring={-0.02,0.3,0.11,1},belt={0.2,-0.05,0.41,1.2},};
StdSlots["BloodElf-Female"] 	= {head={0.01,-0.03,0.75,1},leg_right_side={0.08,-0.17,-0.33,1},chest={0.1,-0.02,0.35,1},face={0.01,-0.03,0.65,0.8},right_foot={0.01,-0.27,-0.83,1},leg_left_side={0.05,0.02,-0.34,1},belt={0.05,-0.03,0.17,0.8},back={-0.1,0,0.32,1.2},left_foot={0.01,0.02,-0.79,1},left_ring={0.02,0.15,-0.09,0.8},right_ring={0.01,-0.24,-0.06,0.8},};

StdSlots["Troll-Male"] 			= {head={0.55,0.02,0.77,1.5},leg_right_side={0.11,-0.24,-0.74,1},chest={0.05,0.01,0.3,1.5},face={0.56,0,0.58,1.2},right_foot={-0.1,-0.36,-1.34,1.5},leg_left_side={0.01,0.33,-0.77,1},back={-0.19,-0.02,0.51,2},belt={0,0,0.01,1.5},left_foot={0.04,0.42,-1.39,1.5},left_ring={0.06,0.61,-0.75,1},right_ring={0.01,-0.53,-0.74,0.8},};
StdSlots["Troll-Female"] 		= {head={0.01,0.01,0.64,1},leg_right_side={0.08,-0.13,-0.6,1},chest={0.1,-0.02,0.25,1},face={0.1,0,0.58,0.8},right_foot={0.01,-0.12,-1.16,1},leg_left_side={0.05,0.17,-0.63,1},right_ring={0.02,-0.3,-0.36,0.8},belt={0.05,0,-0.01,0.8},left_foot={0.01,0.18,-1.16,1},left_ring={-0.06,0.34,-0.39,0.8},back={-0.11,-0.08,0.18,1.2},};

StdSlots["Orc-Male"]			= {head={0.43,-0.02,0.64,1},leg_right_side={0.17,-0.32,-0.48,1.5},chest={0.19,-0.02,0.25,1.3},face={0.47,-0.01,0.5,1},right_foot={0.04,-0.4,-1.11,1.5},leg_left_side={0.15,0.25,-0.47,1.5},back={-0.26,0.01,0.42,2},belt={0.05,0,-0.01,1.5},left_foot={0.01,0.31,-1.07,1.5},left_ring={0.11,0.51,-0.41,0.8},right_ring={0.02,-0.59,-0.41,0.8},};
StdSlots["Orc-Female"] 			= {head={0.03,0,0.58,0.8},leg_right_side={0.08,-0.14,-0.27,1},chest={0.05,0.01,0.3,1},face={0.05,0,0.53,1},right_foot={0.05,-0.15,-0.85,1},leg_left_side={0.01,0.13,-0.33,1},right_ring={-0.15,-0.3,-0.21,0.8},belt={0.06,0,0.09,1},left_foot={-0.18,0.14,-0.87,1},left_ring={-0.2,0.31,-0.18,0.8},back={-0.19,-0.02,0.29,1.2},};

StdSlots["Tauren-Male"] 		= {head={0.5,0.02,0.69,1},leg_right_side={0.14,-0.25,-0.48,1.5},chest={0.23,-0.02,0.25,1.3},face={0.53,-0.01,0.5,1},right_foot={-0.07,-0.27,-0.91,1.5},leg_left_side={0.15,0.25,-0.47,1.5},right_ring={0.02,-0.56,-0.41,0.8},back={-0.26,0.01,0.42,2},left_foot={0.3,0.27,-0.92,1.5},left_ring={0.02,0.51,-0.41,0.8},belt={0.13,0,-0.01,1.5},};
StdSlots["Tauren-Female"] 		= {head={0.28,0,0.32,1},leg_right_side={0.08,-0.16,-0.7,1.5},chest={0.17,-0.02,0,1.3},face={0.32,-0.01,0.22,1},right_foot={0,-0.16,-1.14,1.5},leg_left_side={0.25,0.16,-0.68,1.5},belt={0.12,0,-0.31,1},back={-0.25,0.03,0.06,1.5},left_foot={0.21,0.14,-1.12,1.5},left_ring={0.1,0.35,-0.66,0.8},right_ring={0.02,-0.37,-0.47,0.8},};

StdSlots["Dwarf-Male"]			= {head={0.06,0.01,0.37,1},leg_right_side={0.07,-0.18,-0.41,1},chest={0.16,0,0.03,1.5},face={0.09,0.01,0.3,1},right_foot={0.031,-0.21,-0.72,1.5},leg_left_side={0.15,0.17,-0.39,1},right_ring={0.02,-0.38,-0.32,1},belt={0.001,0,-0.14,1},left_foot={0.22,0.15,-0.67,1.5},left_ring={0.01,0.36,-0.36,1},back={-0.22,0,0.03,1.5},}
StdSlots["Dwarf-Female"] 		= {head={0.06,0.03,0.26,1},leg_right_side={0.07,-0.08,-0.36,0.75},chest={0.11,0.02,0.03,1},face={0.09,0.02,0.28,0.7},right_foot={0.081,-0.05,-0.59,0.8},leg_left_side={0.11,0.13,-0.35,0.75},back={-0.12,-0.01,0.03,1},belt={0.001,0,-0.14,0.75},left_foot={0.09,0.15,-0.58,0.75},left_ring={0.01,0.28,-0.21,0.75},right_ring={0.02,-0.24,-0.23,0.75},};

StdSlots["Gnome-Male"] 			= {head={0.12,0.01,0.26,1},leg_right_side={0.07,-0.08,-0.36,0.75},chest={0.11,0.02,0.03,1},face={0.09,0.02,0.28,0.7},right_foot={0.081,-0.15,-0.59,0.8},leg_left_side={0.11,0.13,-0.35,0.75},right_ring={0.02,-0.24,-0.23,0.75},back={-0.12,-0.01,0.03,1},left_foot={0.09,0.15,-0.58,0.75},left_ring={0.01,0.28,-0.21,0.75},belt={0.001,0,-0.14,0.75},};
StdSlots["Gnome-Female"] 		= {head={0.12,0.01,0.34,0.75},leg_right_side={0.07,-0.08,-0.21,0.75},chest={0.11,0,0.03,0.75},face={0.09,0,0.22,0.7},right_foot={0.081,-0.15,-0.33,0.8},leg_left_side={0.01,0.07,-0.21,0.75},right_ring={0.01,-0.2,-0.12,0.75},belt={0.001,0,-0.06,0.75},left_foot={0.03,0.15,-0.32,0.75},left_ring={0.01,0.22,-0.12,0.75},back={-0.12,-0.01,0.03,1},};

GH_Display_BG_List = {
	{p="",x=128,y=256},
	{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},
}


local function drawsize(size)
	return size*GetCVar("uiscale")/0.85;
end


function New_GH_Display(parent)
	local i = 1000;
	while( _G["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)
		
	_G[varName] = GH_Display; 
	
	local obj = {}             -- our new object
	setmetatable(obj, _G[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(self)
		self.rotation = 0;
		self.x = 0;
		self.y = 0;
		self.z = 0;
		--print("OnShow");
		self:SetRotation(0);
		self:SetPosition(0,0,0);
		--if not(self.orig_SetPos) then self.orig_SetPos = self.SetPosition end
		--self.SetPosition = function(t,...) print(...); t.orig_SetPos(t,...); end;
		self.main:Update(true);
		
		--self.main:SetPosition(self.main.x,self.main.y,self.main.z);
		self.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
	
	_G[varName]=obj; 
	return obj;
end

function GH_Display:CreateStandaloneFrame()
	if not(self.parent) then
		-- Create the frame for Normal background and border
		local f = CreateFrame("Frame",self.display:GetParent());
		
		f:SetPoint("CENTER",UIParent);
		f:SetWidth(drawsize(128 ));
		f:SetHeight(drawsize(256 ));
		f:SetFrameStrata("LOW");
		
		--[[
		local bg = ""--"Interface/GLUES/MODELS/UI_MAINMENU/MM_sky_01";
		f:SetBackdrop({edgeFile = "Interface/Tooltips/UI-Tooltip-Border", bgFile =  bg, edgeSize = 16, insets = { left = 0, right = 0, top = 0, bottom = 0 }});
		f:SetFrameLevel(1);
		f:SetFrameStrata("BACKGROUND"); --]]
		local f2 = CreateFrame("Frame",f);
		f2:SetPoint("CENTER",f);
		f2:SetWidth(drawsize(128));
		f2:SetHeight(drawsize(256));
		f2:SetBackdrop({edgeFile = "Interface/Tooltips/UI-Tooltip-Border", bgFile = "", edgeSize = 16, insets = { left = 4, right = 4, top = 4, bottom = 4 }});
		f2:SetFrameLevel(2);
		f2:SetFrameStrata("LOW");
		f.bgFrame = f2;
		
		
		-- create extra black backdrop frame, which is only shown when there is no other background
		local f2 = CreateFrame("Frame",f);
		f2:SetPoint("CENTER",f);
		f2:SetWidth(drawsize(128));
		f2:SetHeight(drawsize(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);
		
		
		-- Bar with name
		local p = CreateFrame("Button",self.display:GetName().."_Bar",self.display);
		p:SetWidth(self.display:GetWidth()+10);
		p:SetHeight(16);
		p.main = self;
		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; GHI_DragEqDisplay(b.main,nil,1) end)
		p:SetScript("OnDragStop", function(b) b.drag = false; GHI_DragEqDisplay(b.main,nil,2) end)
		
		local pf = p:CreateFontString();
		--pf:SetFont("Fonts\\FRIZQT__.TTF", 11, "OUTLINE, MONOCHROME")
		pf:SetFontObject("GameFontHighlight");
		pf:SetText(self.name);
		pf:SetPoint("CENTER",0,0,p);
		pf:Show();
		self.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(1);
		
		-- close Button
		local b = CreateFrame("Button",self.display:GetName().."_Close",p,"UIPanelCloseButton");
		b:SetPoint("RIGHT",p,"RIGHT",10,0);
		b.main = self;
		
		f.main = self;
		self.parent = f;
		
		f:Show();
		
		
		
		-- register for container anchors
		GHI_ContainerAnchorFrame(self.parent,"display");
		
		

	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];
		--print("Campos",self.CamPos[1],self.CamPos[2],self.CamPos[3]);
	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];
		--print("Camdir",self.CamDir[1],self.CamDir[2],self.CamDir[3]);
	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:SetAlpha(1);
	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:GetNumObjects()
	return #(self.objects or {});
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.bgFrame: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
		if self.parent.bgFrame then
			self.parent.bgFrame:Show();
		end
		if self.parent.anchorPlate then
			self.parent.anchorPlate:Show();
		end
	end
	
	self.display:Hide();
	self.display:Show();
	GHI_updateContainerFrameAnchors() 
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
		if self.parent.bgFrame then
			self.parent.bgFrame:Hide();
		end
	else
		self.display:Hide();
	end
	if self.parent.anchorPlate then
		self.parent.anchorPlate:Hide();
	end
	--GHI_updateContainerFrameAnchors() 
	if self.disposeOnHide then 
		GHI_RemoveAnchorFrame(self.parent.anchorPlate);
		table.wipe(self.parent);
		table.wipe(self);
	else
		GHI_updateContainerFrameAnchors();
	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,self.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)

	end ]]
	

	--[[
	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 self
	--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( _G["GH_DO"..i] ) do
		i = i + 1;
	end
	varName = "GH_DO"..i;
	
	_G[varName]=GH_DO; 
	
	local obj = {}             -- our new object
	setmetatable(obj, _G[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;
		obj.codeReq = codeReq;
	end
	obj.type = "GH_DO";
	_G[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
	
	if type(self.codeReq) == "string" and string.len(self.codeReq) > 0 then
		SHOW = false;
		GHI_DoScript(self.codeReq);
		if not(SHOW == true) then
			frame:Hide()
			return;
		end
	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(self,...);
	end
end

function GH_DO:OnEnter(...)
	if self.object.tooltipType then
		GHI_EqDisplayOnEnter(self,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


-- =========================================
--				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 or info.ref);
	o.SetPositionInfo = SetPositionInfo;
	o.slotRef = slotRef; -- ref for position data
	PD:AddObject(o);
	PD:Update(true);
	GHI_UpdatePlayerEquipmentDisplay();
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(self,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(self) GameTooltip:SetOwner(self, "ANCHOR_LEFT");
				GameTooltip:ClearLines()
				GameTooltip:AddLine(self.tttext,1,0.8196079,0);
				GameTooltip:Show()
				self.UpdateTooltip = nil;
			end);
			b:SetScript("OnLeave",function() GameTooltip:Hide(); end);
			b:SetScript("OnClick",function(self) GHI_PlayerEDBtnClick(self.ref); end);
		end
		
		-- close button
		--local b = CreateFrame("Button","GHI_PDB_Close",PD.display,"UIPanelCloseButton");
		--b:SetPoint("TOPRIGHT",17,17);
		--b.main = PD;
		local b = _G[PD.display:GetName().."_Close"];
		b:SetScript("OnClick",function(self) self.main:Hide(); end);
		
		-- initialize data first time 
		if GHI_EquipmentDisplayData == nil then
			GHI_EquipmentDisplayData = {};
		end
		if GHI_EquipmentDisplayData.stdEnabled == nil then
			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;
	
	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);
	else
		PD:ClearAllObjects();
	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(self,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(self,GHI_Calb_Menu);
		f:Show();
	elseif btnRef == "background" then
		local f = GHM_NewFrame(self,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(self,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(self,btn,...)

	local obj = self.object;
	local id = obj.refID;
	
	local objGotItem = (not(id == 0) and id);
	local cursorGotRealItem = CursorHasItem();
	local cursorGotGHIItem = (GHI_GetCursor() == "item" or GHI_GetCursor() == "item/ability");
	
	if btn == "RightButton" and objGotItem then
		GHI_UseItem(unpack({GHI_FindItem(id)}))
		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(btn,...);
		GHI_EqDisplayUpdated()
	else
		obj:SetInfo(0,"Interface\\PaperDoll\\UI-Backpack-EmptySlot.blp");
		PD:Update(true);
		GameTooltip:Hide();
		
		local temp = {};			
		local name,icon = GHI_GetItemInfo(id);
		temp.iconTexture = icon;
		temp.id = id;
		GHI_SetCursor("item/ability",temp);
		SetPositionInfo(obj.slotRef,nil);
		GHI_ShowSlots(true)
		GHI_EqDisplayUpdated()
	end
	
	
	-- put the temp item on cursor
	
	
	
end

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

function GHI_ShowNewSlotMenu(editID)
	local f = GHM_NewFrame(self,GHI_NCS_Menu);
	f.edit = nil;
	f.ClearAll(self);
	
	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 then
		if GHI_MiscData["hide_empty_slots"] then
			PD:ShowEmpty(show);
		else
			PD:ShowEmpty(true);
		end
	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
		o = o.object;
		if not(o.refID == 0) and o.refID then
			local s = o:Serialize();
			table.insert(objs,s);
			
			-- send item info to player
			local version = GHI_GetVersions(o.refID);
			--print(o.refID,version);
			if version then
				if type(players) == "string" then
					GHI:SendPrioritizedMessage("ALERT","WHISPER",players,false,"ItemVersion",o.refID,version)
				elseif type(players) == "table" then
					for p,_ in pairs(players) do 
						GHI:SendPrioritizedMessage("ALERT","WHISPER",p,false,"ItemVersion",o.refID,version)
					end					
				end
			end
		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();
		
		
		-- close button script
		local b = _G[d.display:GetName().."_Close"];
		b:SetScript("OnClick",function(self) self.main:Hide(); if self.main.num == 1 then GHI_ToggleTargetEqDisplay(); end  if self.num == 2 then GHI_ToggleTargetEqDisplay() end end);
		
		-- todo: button to "Copy" frame to show all time
		local b2 = CreateFrame("Button",d.display:GetName().."_Copy",_G[d.display:GetName().."_Bar"],"UIPanelButtonTemplate");
		b2:SetHeight(22)
		b2:SetWidth(22)
		b2:SetText("C");
		b2:SetPoint("LEFT",_G[d.display:GetName().."_Bar"],"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,state)
	if not(type(obj)=="table") then return end
	
	if state == 1 then -- start drag
		GHI_RemoveAnchorFrame(obj.parent.anchorPlate);
		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);
	
	if state == 2 and (GetScreenWidth() - obj.parent:GetRight()) < obj.parent:GetWidth()*2 then
		
		--GHI_ContainerAnchorFrame(obj.parent,"display");
		--GHI_updateContainerFrameAnchors();
		
		local ap = obj.parent.anchorPlate;
		obj.parent:ClearAllPoints();
		obj.parent:SetPoint("CENTER",ap,"CENTER",0,0);
		GHI_ContainerAnchorFrame(obj.parent,"display");
	end
	
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
	Displays[n].disposeOnHide = true;
	
	GHI_SetTargetEqDisplay("target")
	
	--Displays[1].parent:SetPoint(a,b,c,x,y);
end

local targetBtn;
local targetToggled;
function GHI_EqDisplayEvent(event)
	if event == "VARIABLES_LOADED" then
		-- set up GHT
		targetBtn = GHU_New("target");
		targetBtn:AddButton("TargetEqDisplay","",function(self)  
			GameTooltip:SetOwner(self, "ANCHOR_LEFT");
			GameTooltip:ClearLines()
			GameTooltip:AddLine(GHI_TOGGLE_TARGET_EQD,1,0.8196079,0);
			
			local ver = GHI_AddOns:GetPlayerAddOnVer(UnitName("target"),"GHI");
			if ver then
				GameTooltip:AddLine("GHI v."..ver,0,1,0);
			else
				GameTooltip:AddLine(GHI_NO_GHI_DETECTED,1,0,0)
			end 
			
			GameTooltip:Show()
		end,GHI_ToggleTargetEqDisplay,"FriendlyPlayer")
		
		GHI_DoScript("GHI_ShowPlayerEquipmentDisplay(); GHI_GetPlayerEquipmentDisplay():Hide()",3);
		
		return;
	elseif event == "PLAYER_TARGET_CHANGED" then
		if Displays[1] then
			if targetToggled == true 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


