--[[ script de traitement du curseur --]]

.namespace Cursor

FLAG_MOUSER_PRESSED = 1
FLAG_MOUSEL_PRESSED = 2
 
CURSOR_DEFAUT_OFFSET_X = 22
CURSOR_DEFAUT_OFFSET_Y = 12

VIBRATION_DEFAULT_LENGTH=0.2
VIBRATION_DEFAULT_POWER=0.25
VIBRATION_DEFAULT_PAD=1

-- DISTMINFORSCROLLING = 50 --paramétre pour le scrolling de background
-- TIMEBEFORESCROLLING = 0.15

TIMETOVALIDATETUTO = 1

--gestion freeze curseur
COMPTEURCLICKDECAY = 0.6 -- toutes les secondes on enléve un click
CLICKTRESHOLD = 3
DRAWCIRCLETIME = 4
CIRCLERADIUS = 100


--pointeur sur l'objet en cours de déplacement
g_ObjectDragged = nil

--si on a prit un objet d'écran lié à un objet d'inventaire, on drag l'objet d'inventaire
--il faut donc qu'on garde un lien vers l'objet originel
g_ScreenObjectDraggedName = ""

--si on relâche l'objet n'importe où, il retourne à sa place
--dans le cas d'un objet lié à un objet d'inventaire, c'est inutile puisqu'on joue sur Show/Hide
g_ObjectInitialPosition = { X = 0, Y = 0 }

--Au moment où on prend un objet, il faut couper le lien qui pourrait modifier son déplacement ou sa taille
--On stocke donc le parent d'origine avant de l'enlever, pour le remettre par la suite si besoin est
g_ObjectInitialParent=nil
g_ObjectInitialLayer=nil

--à quelle position doit être placé l'objet par rapport au curseur
g_ObjectOffsetPosition = { X = 0, Y = 0 }

--doit-on utiliser les sprites de curseur objet
g_UseObjectCursorSprite = true

g_LayerTab = {}

g_Time = OPTime.GetTime()
--tout est basé sur le UnitAts, qui lui appelle les callback OnWpbMouseLdown,Up et appelle un SetCursor quand le curseur est dessus
--par contre -> comment on gére le onmouseoff si on a besoin de faire plus qu'un changement de curseur ??

-- tableau de la liste des units sous le curseur, cette liste provient de la fonction
-- OPScene.UnitsAt(x,y) mais demande un certain tri pour être optimale 
	
g_clickcompteur = 0 --compteur de click pour le freeze
g_freezetimecompteur = 0	
g_isfreezed = false --indique si le curseur est en mode circle ou pas
g_circlecenter = {}
CURSORWINDATA = 
{
	[0] = "curseur_generique.cur",
	[1] = "curseur_info.cur",
	[2] = "curseur_use.cur",
	[3] = "curseur_prendre.cur",
	[4] = "curseur_enter.cur",
	[5] = "curseur_loupe.cur",
	[10] = "curseur_grandepince.cur",
	[11] = "curseur_retour.cur",
	[12] = "curseur_pas.cur",
	[13] = "curseur_bas.cur",
	[14] = "curseur_dial.cur",
}

g_curwindows = {} 

UNISTOCHECK = {} -- on transmet l'event dans ces units abstraites

function ChangeCursor(image , destination)
	self.SetFrame(image)
	
	--gestion text destination
	if type(destination) == "string" then
		Cursor_Destination.Text = GlobalFunctions.GetText(destination,"_SearchSite","")
		-- Cursor_Destination.Position_X = 64
		-- Cursor_Destination.Position_Y = -3
	else
		Cursor_Destination.Text = ""
	end	
		OPWinCursor.SetCursor(g_curwindows[image])
	--OPWinCursor.ShowCursor(true)
	
	return true
end


function SetVisible( value )
	self.RequestVisibility = value
	
	if self.RequestVisibility == false then
		self.Flags_Visible = false
		OPWinCursor.ShowCursor(false)
	elseif self.OutsideScreen == false and self.IsActive then
		if ProfilConfig.Get("HardwareCursor") == true then
			OPWinCursor.ShowCursor(true)
			self.Flags_Visible = false
		else
			OPWinCursor.ShowCursor(false)
			self.Flags_Visible = true
		end
	end
end



function OnEnable()
	OPInput.RegisterListener(self , EVENT_MOUSE_MOVE+EVENT_MOUSE_LUP+EVENT_MOUSE_RUP+EVENT_MOUSE_LDOWN+EVENT_MOUSE_RDOWN +EVENT_KEY_UP+EVENT_KEY_DOWN )
	
	self.TabUnitsAt = {}

	self.LastCursorOwner = ""
	self.IsActive = true
	self.OutsideScreen = false
	self.RequestVisibility = true
	-- -- self.startscrolling = false
	-- self.scrollvalidated = false
	self.last_onmouseon = nil
	
	local usenbcursor = false
	
	OPLog.Log("taille mémoire vidéo "..OPGraphic.GetVideoMemoryStatistics().agp_total.." "..OPGraphic.GetVideoMemoryStatistics().total)
	if OPGraphic.GetVideoMemoryStatistics().total < 45 then
		ProfilConfig.Set("HardwareCursor", true)
		SaveManager.saveProfile()
		usenbcursor = true
	end
	
	for  i,path in pairs(CURSORWINDATA) do
		if usenbcursor then
			path = string.gsub(path,".cur","_nb.cur")
		end
		g_curwindows[i] = OPWinCursor.LoadCursor("media/common/graph/cursor/"..path)
	end
	OPWinCursor.ShowCursor(true)
	UNITSTOCHECK = {SubtitlesDisplay,PopupManager,SplashScreenManager,NewTutorialManager}
end

function OnKeyUp( key )
	if key == KEY_MENU or KEY_RETURN then
		k_alt = 0
		k_enter= 0
	end
	
	if key == KEY_ESCAPE and IsEqualVariables("CurrentGamePhase","SearchSite") then --on revient au menu principale
		
		-- Sauvegarde
		SaveManager.saveGame("Profil"..ProfilConfig.Get("CurrentProfil"))
		
		NavigationManager.SwitchTo(nil,"Menu_Start")
		
		return true
	end
	
	return false
	
end

function OnKeyDown( key )
	if key == KEY_MENU then
		k_alt = 1
	end
	if key == KEY_RETURN then
		k_enter = 1
	end
	if k_alt == 1 and k_enter == 1 then
			screen_state=ProfilConfig.Get("Fullscreen")
			OPGraphic.SetScreenMode({fullscreen=not screen_state}) 
			ProfilConfig.Set("Fullscreen",not screen_state)
			SaveManager.saveProfile()
	end
	
end


function SetObjectDragged( object, noUseSpriteCursor, useOffsetPosition )
	AssertPopup(object ~= nil and Enable(object)~= nil,"Erreur appel de SetObjectDragged sur un unit null")
	
	if noUseSpriteCursor ~= nil and noUseSpriteCursor == true then
		g_UseObjectCursorSprite = false
	end
	
	if object.ClassName == 'Object' and object.InventoryObject ~= nil and object.InventoryObject~= nil 
			and (g_UseObjectCursorSprite or (object.HotspotToUse ~= nil and object.HotspotToUse~= nil)) then
		g_ObjectDragged = object.InventoryObject
		g_ScreenObjectDraggedName = object.Name
		
		GameVariables.Set( 'CurrentObject', object.InventoryObject.Name )
		
		object.isDragged = true
		Hide(object)
		g_ObjectDragged.Enabled =true
		g_ObjectDragged.Flags_Visible = true
	else
		g_ObjectDragged = object
		g_ScreenObjectDraggedName = ""
		
		GameVariables.Set( 'CurrentObject', object.Name )
		
		g_ObjectInitialPosition_X = object.Position_X
		g_ObjectInitialPosition_Y = object.Position_Y
		
		g_ObjectInitialParent = object.Parent
		g_ObjectInitialLayer = object.Layer
	end
	
	local value, nbTokenImage = string.gsub(g_ObjectDragged.Image,'|','|')
	if useOffsetPosition ~= nil and useOffsetPosition == true then
		local cursorX, cursorY = GetCursorPosition()
		--AssertPopup(object.Parent ~= nil and object.Parent.Position ~= nil,"Erreur, paramètre useOffsetPosition indésirable pour cet objet")
		OPLog.Log("Curseur ("..cursorX..","..cursorY..") | Object ("..object.Position_X - object.Parent.Position_X..","..object.Position_Y - object.Parent.Position_Y..")")
		g_ObjectOffsetPosition_X = object.Position_X - object.Parent.Position_X - cursorX
		g_ObjectOffsetPosition_Y = object.Position_Y - object.Parent.Position_Y - cursorY
	elseif nbTokenImage > 0 and g_UseObjectCursorSprite then
		g_ObjectOffsetPosition_X = -45
		g_ObjectOffsetPosition_Y = -45
	else
		g_ObjectOffsetPosition_X = -1*g_ObjectDragged.Dimension_Width/2
		g_ObjectOffsetPosition_Y = -1*g_ObjectDragged.Dimension_Height/2
	end
	OPLog.Log("( "..g_ObjectOffsetPosition_X.." , "..g_ObjectOffsetPosition_Y.." )")
	
	g_ObjectDragged.Layer = LayerCursor01
	g_ObjectDragged.Parent = nil

end


function UpdateCircleFreeze()
	local coeff = g_freezetimecompteur / DRAWCIRCLETIME
	
	if (coeff > 1 ) then
		g_isfreezed = false
		g_clickcompteur = 0
		--Cursor_WaitAnimation.Enabled = false
		self.Color.a = 255
		return
	end
	coeff= coeff *2* math.pi
	
	local vec = Vector:new(CIRCLERADIUS,0)
	vec = vec:rotate(coeff)
	vec = vec + g_circlecenter
	local x = math.cos(coeff)*CIRCLERADIUS + g_circlecenter.x
	local y = math.sin(coeff)*CIRCLERADIUS + g_circlecenter.y
	
	--vec:display()
	OPInput.SetMousePosition(vec.x,vec.y)
	
	--pas d'anim de cercle ?
	self.Position_X = vec.x - self.Dimension_Width/2
	self.Position_Y = vec.y - self.Dimension_Height/2
	
	-- PlaySoundEffect("int_click04")
end

function OnUpdate(dt)
	if self.IsActive == false then
		return
	end
	
	if UNITSTOCHECK == nil then
		UNITSTOCHECK = {SubtitlesDisplay,PopupManager,SplashScreenManager,NewTutorialManager}
	end
	
	g_freezetimecompteur = g_freezetimecompteur + dt
		
	if g_isfreezed then
		UpdateCircleFreeze()
		return
	end
	
	self.OutsideScreen = OPInput.IsMouseOutsideScreen()
	
	if self.RequestVisibility == true then
		--OPLog.Log("Le pointeur est actif et à l'écran")
		if ProfilConfig.Get("HardwareCursor") == true then
			OPWinCursor.ShowCursor(true)
			self.Flags_Visible = false
		else
			OPWinCursor.ShowCursor(false)
			self.Flags_Visible = true
		end
	end

	
	if IsEqualVariables("CurrentGamePhase","BlockClick") or IsEqualVariables("CurrentGamePhase","Transition") or SplashScreenManager.Enabled == true then
		self.Flags_Visible = false
		OPWinCursor.ShowCursor(IsEqualVariables("CurrentGamePhase","Cutscene"))
		return
	else
		if ProfilConfig.Get("HardwareCursor") == true then
			OPWinCursor.ShowCursor(true)
			self.Flags_Visible = false
		else
			OPWinCursor.ShowCursor(false)
			self.Flags_Visible = true
		end
	end
	
	--cas particulier curseur/tutorial on le remet à zéro en permanence
	-- if IsEqualVariables("CurrentGamePhase","Tutorial") and (TutorialManager.g_state ~= "scrollleft" and TutorialManager.g_state ~= "scrollright") then
		-- ChangeCursor(CURSOR_GENERIQUE)
	-- end
	

	
	local x,y = GetCursorPosition()
	
	self.TabUnitsAt = ComputeOrderedUnitsAt(x,y)
	
	-- on fait le test en permanence plutot que dans le onmouselup qui est moins fiable
	
	--ConsoleText0.Text = "state "..tostring(OPInput.GetMouseButtonState(1))


	
	-- si on travaille avec un objet d'inventaire, 2 solutions
	-- soit on le pose sur un hotspot actif possible, soit on le libére
	if self.IsDragging() then
		UpdateDraggingObjectCursor(x,y)
		return
	end
	

	--gestion scrolling dans les searchsite

	
	-- enfin, si on n'est dans aucune des conditions précédente, c'est juste que l'on scanne
	-- l'écran à la recherche de quelque chose d'interactif (area de dialogue, de closeup, hotspot ou objet)
	IIM_OnMouseOn(x,y) -- Version précise du onmouseon
	UpdateNormalCursor(x,y)

	
	if g_freezetimecompteur > COMPTEURCLICKDECAY then
		g_clickcompteur = math.max(0,g_clickcompteur - 1)
		g_freezetimecompteur = 0
	end
end


function OnMouseLUp(x,y)
	
	if g_isfreezed then
		return
	end
		


	for ind,ut in pairs(UNITSTOCHECK) do
		if ut.ParentEnabled and ut.OnWbpMouseLUp ~= nil and ut.OnWbpMouseLUp() == true then
			return true
		end
	end
	
	if self.needtoignorenextmouselup == true then
		self.needtoignorenextmouselup = false
		return
	end
	
	if self.IsDragging() == true then --
		ReleaseObjectDragged(true)
		g_UseObjectCursorSprite = true --ça reste l'état par défaut donc on le force dès qu'on quitte le mode dragging
		return
	end
	
	local unitclicked
		
	for i,unit in pairs(self.TabUnitsAt) do
		--OPLog.Log("test de on mouse lup sur "..unit.Name)
		if unit ~= nil and unit.ParentEnabled and unit.OnWbpMouseLUp ~= nil and unit.OnWbpMouseLUp(x,y) == true then
			unitclicked = unit.Name
			break
		end
	end
	
	if IsEqualVariables("CurrentGamePhase","SearchSite") or 
					 GetCurrentManager().Name == "s07_c01" then --Cas specifique pour le closeup du bureau dans s07
	
		g_clickcompteur = g_clickcompteur + 1
		
		if g_clickcompteur > CLICKTRESHOLD and DebugOptions.Spamclic==true then
			g_isfreezed = true
			g_freezetimecompteur = 0
			g_circlecenter = GetCenter(self)
			--Cursor_WaitAnimation.Enabled = true
			--self.Color.a = 0
			PlaySoundEffect("int_freeze")
		end
		--OPLog.Log("click "..g_clickcompteur)
	end	
	
	CloseOpenedMenuIfNecessary(unitclicked)

end

function CloseOpenedMenuIfNecessary(unitclicked)
	--on ferme ce bouton quoiqu'il arrive
	if IsEqualVariables("CurrentGamePhase","SearchSite")  then
		
		if unitclicked == "Inventory_hotspot" or unitclicked == "Inventory_arrow" or unitclicked == "Inventory_bg" or unitclicked == "LeftInterface_bg"  then
			return
		elseif unitclicked ~= nil then
			LeftInventory.CloseInventory()
		end
	end
end

function DisplayDebug(tab)
	local s=""
	local x,y = GetCursorPosition()
	local tabinit = OPScene.UnitsAt(x,y)
	for u,unit in pairs(tabinit) do
		s=s..unit.Name.."\r"
	end
	s = s.. "-------------\r"
	for u,unit in pairs(tab) do
		s=s..unit.Name.."\r"
	end
	return s
end

function OnMouseLDown(x,y)
	if g_isfreezed then
		return
	end
	

	
	if self.IsActive == false or self.OutsideScreen == true then
		return
	end
	

	-- self.scrollvalidated = false
	
	--enclenchement du scrolling
	-- if (IsEqualVariables("CurrentGamePhase","SearchSite") or 
		-- (IsEqualVariables("CurrentGamePhase","Tutorial") and (TutorialManager.g_state == "scrollleft" or TutorialManager.g_state == "scrollright"))) 
		-- and GetCurrentManager().Enabled and IsEqualVariables("scrollingactive",true)  then
		-- --on détecte le scrolling 
		-- self.onmouseldowntime = OPTime.GetTime()
		-- self.startscrolling = true
		-- --GetCurrentManager().StartScroll(x)
		-- self.startscrollx = -1
	-- end
	
	for i,unit in pairs(self.TabUnitsAt) do
		--OPLog.Log("je test "..unit.Name)
		--dans un searchsite, il faut que ce soit sur le onmouselup pour gérer les conflits avec le scrolling
		if unit ~= nil and unit.ParentEnabled and unit.OnWbpMouseLDown ~= nil and unit.OnWbpMouseLDown(x,y) == true then
			--cas particulier "merdique" mais bon je le met aussi
			--si on click sur l'interface on invalide le scroll
			-- if GetUpperParent(unit).Name == "SearchInterface" then
				-- self.startscrolling = false
			-- end			
		
			break
		end
	end
end

--right click pour gérer le dragndrop
function OnMouseRDown(x,y)
	if g_isfreezed then
		return
	end
	
	
	if self.IsActive == false or self.OutsideScreen == true then
		return
	end
	
	for i,unit in pairs(self.TabUnitsAt) do
		if unit ~= nil and unit.ParentEnabled and unit~= nil and unit.OnWbpMouseRDown ~= nil and unit.OnWbpMouseRDown(x,y) == true then
			break
		end
	end
end

-- dragndrop toujours
function OnMouseRUp(x,y)
	if g_isfreezed then
		return
	end
	


	if self.IsActive == false or self.OutsideScreen == true then
		return
	end
	
	for i,unit in pairs(self.TabUnitsAt) do
		if unit ~= nil and unit.ParentEnabled and unit~= nil and unit.OnWbpMouseRUp ~= nil and unit.OnWbpMouseRUp(x,y) == true then
			break
		end
	end
end


function IsDragging()
	if g_ObjectDragged == nil then
		return false
	end	
	return true
end


function ReleaseObjectDragged(fromClic)
	AssertPopup( self.IsDragging() == true and g_ObjectDragged ~= nil,"Erreur, aucun objet n'est lié au curseur" )
	
	local x,y = GetCursorPosition()
	
	g_ObjectDragged.Layer = nil
	g_ObjectDragged.isDragged = false
	
	-- quoiqu'il arrive, on vient de lâcher un objet, on change donc la frame pour revenir à la frame écran
	g_ObjectDragged.SetFrame(0)
	
	local hotspot = nil
	--Sinon, on parcours la liste des Units sous le curseur jusqu'à trouver un hotspot, s'il existe
	--MODIF de Fabien  : on teste le dropobject sur toutes les classes, pas que sur les hotspots
	for i,unit in pairs(self.TabUnitsAt) do
		if unit.CanClickOn ~= nil and unit.ParentEnabled and unit.CanClickOn() and unit.OnDropObject ~= nil  then --les background peuvent récup le drop d'un objet si besoin
			hotspot = unit
			break
		end
	end
	
	if hotspot == nil then
		--On lit un dialogue lorsqu'on relache un objet au mauvais endroit
		SequencePlayer.PlayRandomSequence({"OB_0","OB_1","OB_2","OB_3","OB_4"},nil,nil)
		PlaySoundEffect("gmp_forbiddendrop")
	end
	--dans tous les cas sur Hidden on cahque l'objet par la suite
	g_ObjectDragged.Enabled = false
	
	--Si pas de hotspot, alors retour à l'état normal
	if hotspot ~= nil and fromClic ~= nil and fromClic == true then
		local res = hotspot.OnDropObject()
		if res == true then --si le dropobject a eu une conséquence, on met à jour la sauvegarde
			SaveManager.saveGame("Profil"..ProfilConfig.Get("CurrentProfil"))
		else
			SequencePlayer.PlayRandomSequence({"OB_0","OB_1","OB_2","OB_3","OB_4"},nil,nil)
		end
		
		if g_ScreenObjectDraggedName ~= "" and g_ObjectDragged.FatherSpot ~= nil then
			OPUnitFactory.GetUnit(g_ScreenObjectDraggedName,'Object').isDragged = false
			OPUnitFactory.GetUnit(g_ScreenObjectDraggedName,'Object').AddFlag( OBJECT_PICKED )
		end
		g_ScreenObjectDraggedName = ""
		g_ObjectDragged = nil
		GameVariables.Set( 'CurrentObject', "" )
		

		--on met à jour l'interface d'inventaire au cas où on a un objet en plus ou en moins
		--si c'est un "drop" sur un bouton d'inventaire, on le fait pas
		if Search_ButtonInventory.Enabled and hotspot.ClassName ~= "InventoryBox" then
			Search_ButtonInventory.UpdateVignettes()
		end
		if hotspot.ClassName ~= "ValuableItem" then
			LeftInventory.UpdateVignettes()
		end
		-- a quoi ça sert ? Ca bug donc on commente...
		-- if GameVariables.IsEqual("CurrentGamePhase", "SearchSite")
				-- or GameVariables.IsEqual("CurrentGamePhase", "Closeup") then
			-- GetCurrentManager().popups_content()
		-- end
	else


		--Objet d'inventaire provenant de l'iris, on ne fait rien
		if fromClic ~= nil and fromClic == true then
			g_ObjectDragged.Layer = LayerCursor
		else
			g_ObjectDragged.Flags_Visible = false
			g_ObjectDragged = nil
			GameVariables.Set( 'CurrentObject', "" )
		end
	end
	
	g_ObjectDragged = nil
	GameVariables.Set( 'CurrentObject', "" )
	
	if self.IsActive then
		Show(self)
	end
	PlaySoundEffect("gmp_drop")
	--InventoryBag.Desactive()
end


function ChangeCursorToGeneric()
	if IsDragging() then
		self.ChangeCursor(CURSOR_DRAGGING)
		return
	end
	
	self.ChangeCursor(CURSOR_GENERIQUE)
end


function UpdateDraggingObjectCursor(x,y)
	
	
	if g_ObjectDragged== nil then
		AssertPopup(false,"il y a eu soucis avec le dragobject !!")
		g_ObjectDragged = nil
		return
	end
	-- on centre l'objet draggé sous le curseur	
	g_ObjectDragged.Position_X = x + g_ObjectOffsetPosition_X
	g_ObjectDragged.Position_Y = y + g_ObjectOffsetPosition_Y
	
	-- si c'est un objet qu'on a sélectionné dans l'inventaire, on cache le curseur
	if (g_ObjectDragged.ClassName=="InventoryObject"
				and (g_ObjectDragged.FatherSpot == nil or g_ObjectDragged.FatherSpot== nil)
				and g_ScreenObjectDraggedName == "") then
		self.Flags_Visible = false
		OPWinCursor.ShowCursor(false)
	else
		if ProfilConfig.Get("HardwareCursor") == true then
			OPWinCursor.ShowCursor(true)
			self.Flags_Visible = false
		else
			OPWinCursor.ShowCursor(false)
			self.Flags_Visible = true
		end
		self.ChangeCursor(CURSOR_DRAGGING)
	end
	
	g_ObjectDragged.Flags_Visible = true
	
	local value, nbTokenImage = string.gsub(g_ObjectDragged.Image,'|','|')
	

	--à partir de là, ça signifie que le curseur ballade un objet d'inventaire
	--on va donc voir si on est sur un hotspot qui l'accepte et ainsi passer en highlight
	--sinon rien
	
	for i,unit in pairs(self.TabUnitsAt) do
		if i >= 1 and unit.SetCursor ~= nil and unit.ClassName ~= "InventoryObject" then
			if unit.SetCursor() then
				-- un objet draggé ne doit réagir qu'à un hotspot sur lequel on peut le poser
				-- dans tous les autres cas, il ne se passe rien
				if unit.ClassName ~= 'AreaHotspot' or not unit.CanClickOn() then
					GameVariables.Set("CursorOwner",unit.Name)
					--OPLog.Log("Dragging : CurrentOwner -> "..unit.Name)
					g_ObjectDragged.Color.a = 128
					return
				end

				g_ObjectDragged.Color.a = 255
				return
			end
		end
	end
	
	g_ObjectDragged.Color.a = 128
	
	--AssertPopup(false,"Attention, aucune unit n'a réagit au curseur")
end

function UpdateNormalCursor(x,y)
	-- curseur normal, on change d'état et on lance un rumble dès qu'on change de zone interactive
	for i,unit in pairs(self.TabUnitsAt) do
		if unit.SetCursor ~= nil then
			if unit.SetCursor() then
				SetVariables("CursorOwner",unit.Name)
				return
			end
		end
	end

end
function IIM_OnMouseOn(x,y)
		--On a besoin d'un OnMouseOn très précis pour les lieux dans l'inventaire
		i = 1
		local tab = OPScene.UnitsAt(x,y) -- Manifestement ça marche mal avec self.TabUnitsAt, on prend les objets tels quel
		for i,unit in pairs(tab) do
			if unit.IIM_OnMouseOnDo ~= nil  then
				if self.last_onmouseon == nil or self.last_onmouseon.Name ~= unit.Name then -- Si on est déjà sur l'objet on renvoi pas l'info
					unit.IIM_OnMouseOnDo()
					self.last_onmouseon = unit
				end	
				return -- On a trouvé ce qu'on cherchait
			end
			
		end
end
--unit que l'on vire lors du tri des units
UNITIGNORE = 
{
	Search_NewObject = true,
}

--même chose pour les classe
CLASSIGNORE =
{
	Cursor = true,
	Text = true,
	Particle2DEmitter = true,
	ParticlesHighlightObjects = true,
	TakeObjectEffect = true,
}


--on traite les cas spécifique pour ignorer les clicks
function SpecificIgnore(ut)
	if GetUpperParent(ut).ClassName == "Closeup" and not( IsEqualVariables("CurrentGamePhase","Closeup") or  IsEqualVariables("CurrentGamePhase","Tutorial"))  then
		return false
	end
	
	return true
end

--[[
		Cette fonction, appelée à chaque frame si on est en Search_Site, en closeup
		récupère la liste des units sous le curseur et la réordonne pour palier au fait que les units de type area
		soient toujours les premières prises en compte

		Pour se faire, on scanne le layer de ces units pour déterminer leur ordre
		
		ensuite, si on a un objet sur un hotspot de même layer, l'objet est prioritaire puisqu'on ne peut pas être sur qu'il sera
		devant le hotspot
		
		enfin, dans tous les autres cas où 2 units sont sur le même layer, on concerve l'ordre de parcours de OPScene.UnitsAt
																																		--]]
function ComputeOrderedUnitsAt(x,y)
	local resList = {}
	local firstList = OPScene.UnitsAt(x,y)
	
	local ind = 1
	for u,unit in pairs(firstList) do
		if CLASSIGNORE[unit.ClassName] ~= true and UNITIGNORE[unit.Name] ~= true and SpecificIgnore(unit) then
			resList[ind] = unit
			ind = ind+1
		end
	end
	
	--table.sort(resList,SortUnit)
	resList = InsertTri(resList , SortUnit)
	
	
	return resList
		
end

function GetUpperParent(ut)
	local ut2 = ut
	
	while (ut2.Parent ~= nil) do
		ut2 = ut2.Parent
	end
	return ut2
end

--tri par insertion en place
function InsertTri(array , sortfct)
	local i
	for j = 2,table.getn(array) do
        i = j - 1
        tmp = array[j]
        while i > 0 and sortfct(tmp,array[i]) do
            array[i+1] = array[i]
            i = i-1
		end
        array[i+1] = tmp
	end

	return array
end

--à peaufiner, si on tombe sur l'interface on la fait passer devant (sauf si l'autre c'est déjà l'interface
--TODO passer complétement à un systéme de layer ??
function SortUnit(ut1,ut2)

	--OPLog.Log("test sortunit de "..ut1.Name.." "..ut2.Name)
	if ut1.ClassName == "InventoryBox" or ut1.ClassName == "ValuableItems" or ut1.ClassName == "LocationPhoto" then -- prio de l'objet d'inventaire sur le reste de l'interface
		return true
	end
	
	-- if GetUpperParent(ut1).Name == "SearchInterface" and GetUpperParent(ut2).Name ~= "SearchInterface"  then
		-- return true
	-- end
	
	--à optimiser sans doute
	local layers1 = GetLayerPriority(ut1)
	local layers2 = GetLayerPriority(ut2)
	
	if layers1 ~= -1 and layers2 ~= -1 then
		return layers1 > layers2
	end
	
	return false
end

function GetLayerPriority( unit)
	if unit.Layer == nil then
		if unit.Parent ~= nil then
			return GetLayerPriority(unit.Parent) + 1 --on ajoute un pour être sur que l'enfant soit devant son parent
		else
			return -1
		end
	else
		return LAYERSPRIORITY[unit.Layer.Name]	
	end	
end


-- retourne x,y les coordonnées du curseur
function GetCursorPosition()
	local x = self.Position_X + self.Hotspot_X
	local y = self.Position_Y + self.Hotspot_Y
	
	return x,y
end


