
.namespace GlobalFunctions

PERFORMANCEFPS = 25 -- 25 par défaut si c en dessous, on "coupe" les anims inutiles et les shaders

LENGTHFRAMETEST = 15 -- longueur du test pour lancer une popup

WIDTH_SCREEN = 1280
HEIGHT_SCREEN = 800

g_smootharray = {}

g_dialogplayed = {}

firstupdate = true    
g_cumultime = 0
g_cumulcompteur = 0
g_curfps = 0
g_needtoopenpopupminconfig = false
g_configminihasbeenasked = false -- on le sauvegarde pas, c'est demandé à chaque exécution indépendamment du profil

function GetDebugOptions(name)
	if DebugOptions == nil then
		return true
	end
	return DebugOptions[name]
end

function OnEnable()
    --Text_Sprite.Text = Display(OPGraphic.GetAvailableScreenModes())
    --si on est en fullscreen, on passe auto en mode résolution native    
	
	--gestion debugoptions
	if type(DebugOptions) ~= "table" then
		--OPLua.Include('Inc/DebugOptionsDefault.lua')
		AssertPopup(false,"le debugoptions perso n'est pas défini pensez à copier debugoptionsdefaults.lua en debugoptions.lua !!")
	end
	
	-- if OPCore.GetPlatform() == "Wii" then
		-- OPWii.RegisterHBMListener()
	-- end	
	
	-- for i=1,SMOOTHWINDOWSIZE do
		-- g_smootharray[i] = {}
		-- g_smootharray[i].accx = 0
		-- g_smootharray[i].accy = 0
		-- g_smootharray[i].accz = 0
	-- end
	
	-- RegisterListenerGen(0, EVENT_PAD_EXTENSION + EVENT_PAD_CONNECT + EVENT_PAD_DISCONNECT)
end

function SwitchToCutscene()
	SetVariables("CurrentGamePhase","Cutscene")
	EnableRemotePointerGen( 1, false )
	if OPCore.GetPlatform() == "Wii" then
		--OPWii.EnableHBM(false)
	end
end

function FinishCutscene(phase)
	EnableRemotePointerGen( 1, true )
	SequencePlayer.g_currentlyplaying = ""
	SetVariables("CurrentGamePhase",phase)
	if OPCore.GetPlatform() == "Wii" and phase ~= "Cutscene" then
		--OPWii.EnableHBM(true)
	end
end

--on le fait ici le truc de réso auto
g_firstframe = true

function OnUpdate(dt)
	--on attend la premiere frame
	if  g_firstframe then
		g_firstframe = false
		--passage en reso supérieur en auto MAIS on lance en 1280*1024 par défaut pour la compatibilité
		SetResoAuto()
		if DebugOptions.ConsoleMode or DebugOptions.ShowInfo and TestCenter.Enabled == false then
			Font_Default.Enabled = true
			TestCenter.Enabled = true
			FontsSmall.Enabled = true
			--Enable("TestCenter","Unit")
		elseif DebugOptions.ConsoleMode == false and DebugOptions.ShowInfo == false then --on désactive les fonts inutiles pour gagner de la place
			Font_Default.Enabled = false
			FontsSmall.Enabled = false
		end
	end

	
	CheckFrameRate(dt)
	

	
end

function CheckFrameRate(dt)
	--on compte déjà les frame dans le testcenter mais on va le refaire ici car le comptage est différent :
	g_cumultime = g_cumultime + dt
	g_cumulcompteur = g_cumulcompteur + 1
	
	if (g_cumultime > LENGTHFRAMETEST) then
		g_curfps = g_cumulcompteur / LENGTHFRAMETEST
		g_cumultime = 0
		g_cumulcompteur = 0
		
		if (g_curfps < PERFORMANCEFPS) and not g_configminihasbeenasked then --on propose au joueur de passer en 1024*768
			--g_needtoopenpopupminconfig = true
		end
		
	end
	
	--c'est uniquement en searchsite , pas en vidéo, en closeup ...
	-- if g_needtoopenpopupminconfig and IsEqualVariables("CurrentGamePhase","SearchSite")  then
		-- g_configminihasbeenasked = true
		-- SetVariables("CurrentGamePhase","Paused")
		-- Popup_ConfigMini.Image = "media/common/graph/interface/InGame/PopupConfigMin/int_popup_configmin_"..DebugOptions.curlanguage..".png"
		-- Popup_ConfigMini.Enabled = true
		-- g_needtoopenpopupminconfig = false
		
	-- end
end

LANGCORRESPONDANCE=
{
	[1]="eng",
	[2]="ger",
	[3]="fre",
	[4]="spa",
	[5]="ita",
}

function UpdateLangWithSystem()
	UpdateLang(GetSystemLang())
end

function GetSystemLang()
	if OPCore.GetPlatform() == "Wii" then
		OPLog.Log("language console : "..Display(OPWii.GetConfig()))
		local newlang = LANGCORRESPONDANCE[OPWii.GetConfig().language]
		AssertPopup(newlang ~= nil, "probléme sur la langue systéme")
		return newlang
	else
		return "eng"
	end
end

function UpdateLang(newlang)

	if newlang == g_lastlang and TextData ~= nil then
		OPLog.Log("même langue, on change pas")
		return
	end
	
	OPLog.Log("changement langue "..newlang)

	OPLua.Include("script/inc/TextData_"..newlang..".lua")
	
	DebugOptions.curlanguage = newlang
	
	g_lastlang = newlang
end

function GetText( Id , silent)

	local lang = DebugOptions.curlanguage
	if TextData == nil then
		--lang = 
		--OPLua.Include("inc/TextData_"..lang..".lua")
		UpdateLangWithSystem()
	end

	if silent ~= true then
		AssertPopup( type(Id) == "string" , "prob param" )
		AssertPopup( TextData[lang][Id] ~= nil , "pas de texte pour l'id "..tostring(Id))
	end
	
	return TextData[lang][Id]
end


--on peut automatiquement la résolution max
function SetResoAuto()

	--cas debugoption
	if DebugOptions.Use_1024_768 == true and not OPCore.EditorMode() then
		SetGraphicMode(1024,768)
		return
	end

    local graphmode = OPGraphic.GetAvailableScreenModes()
	local graphnum = table.getn(graphmode)
	OPLog.Log(Display(tab))
     
	local width,height,pos
	local bestwidth = 0
	local bestheight = 0
	local curratio = 0
	for i=1,graphnum do
	---	OPLog.Log(i)
	--end
	--for u,reso in pairs(graphmode) do
		reso=graphmode[i]
		pos = string.find(reso,"x")
		width = tonumber(string.sub(reso,0,pos-1))
		height = tonumber(string.sub(reso,pos+1,string.len(reso)))
		local ratio = width/height
		OPLog.Log("reso "..reso)
		if width == WIDTH_SCREEN and height == HEIGHT_SCREEN then
			--on a notre réso on sort
			bestwidth = width 
			bestheight = height
			OPLog.Log("reso du jeu trouvé, on la prend")
			break
		end
		
		--on vérifie que la résolution augmente et que le ratio reste correcte
	--	if width >= bestwidth and width < MAXALLOWEDWIDTH and height >= bestheight and ratio >= (4/3) and ratio <= (16/9) then
	--		bestwidth = width
	--		bestheight = height
	--		curratio = ratio
	--	end
		
	end
	
	if bestheight*bestwidth == 0 then
		--AssertPopup(false, "erreur reso auto non trouvé " )
		OPLog.Log("La resolution du jeu n'est pas supportée, safe mode activé")
		SetGraphicMode(1024,768)
		return
	end
    
    OPLog.Log("reso auto final "..bestwidth.." "..bestheight)
    
	if not OPCore.EditorMode() then 
		SetGraphicMode(bestwidth,bestheight)
	end
        
end

function SetGraphicMode(width,height,justforvideo , sync)

	if OPCore.EditorMode() then
		return
	end
    --par sécu
    width=tonumber(width)
    height = tonumber(height)
    
	local diff,widthnormal,heightnormal
    local tab = {x = width , y= height}
    
    OPLog.Log("vsync "..tostring(sync))
    OPGraphic.SetScreenMode({width = width, height = height , antialiasing = 0 , vsync = sync})
    widthnormal = math.floor((16/10) * height)
    
    OPLog.Log(Display(OPGraphic.GetScreenMode()))
    
    --OPLog.Log("width widthnormal "..width.." "..widthnormal)
    if width > widthnormal then
        diff = math.floor((width - widthnormal)/2)
        
        --OPLog.Log("viewport "..diff.." "..width)
        OPGraphic.SetDefaultViewport(diff,0,width-diff,height)
		OPLog.Log("viewport "..diff.." ".."0".." "..(width-diff).." "..height)
    else
        --OPLog.Log("viewport full")
		heightnormal = 10/16 * width 
		diff = math.floor((height-heightnormal)/2)
        OPGraphic.SetDefaultViewport(0,diff,width,height-diff)
		OPLog.Log("viewport ".."0".." "..diff.." "..(width).." "..height-diff)
		
    end
    
	--on scale pour qu'on garde le même ratio hauteur/largeur
	OPGraphic.SetScale2D(width/WIDTH_SCREEN,height/HEIGHT_SCREEN)
    
	if justforvideo == nil then
		self.cur_width = width
		self.cur_height = height
		self.cur_ratioscale = (height/width) * (16/10) --ratio pour garder le même type d'affichage quoiqu'il arrive
	
	end
	OPLog.Log("résultat scale "..width/WIDTH_SCREEN.." "..height/HEIGHT_SCREEN)

end

function ChangeGraphicMode(mode)
    --AssertPopup(mode == "43" or mode =="169" or mode =="1610", "Erreur Param")
    local height,width
    if mode == '43'  or mode == "1024" then
        width = 1024
        height = 768
    elseif mode == "1610" then
        width = 1280
        height = 800
    elseif mode == "1680" then
        width = 1680
        height = 1050
    elseif mode =="hd" then
        width = 1280
        height = 1024
    else
        width = 1024
        height = 768
    end
    
    SetGraphicMode(width,height)    
end
    --on arrete tous les sons en cours si besoin
function StopSound(ut)
    --si ce n'est pas une musique on arret le truc, si c'est une musique on laisse jouer et on fait un fade
    if ut.Type ~= "music" then
        ut.Stop()
        ut.Finished = true
    end
end

function PlaySoundForAnim(animname)
    if SoundForAnim[animname] ~= nil and SoundForAnim[animname]~="" then
        PlaySoundEffect(SoundForAnim[animname])
    end
end

--met à jour les sons en fonction du nouveau volume
function ApplyNewVolumeToSound(oldvoice,oldmusic)
	AssertPopup(false ,"ne pas utiliser ?")

    AssertPopup(type(oldvoice) == "number" and type(oldmusic) =="number" ,"erreur params")


    coeffsfx=ProfilConfig.Get('GeneralVolume') / oldvoice
    coeffmusic=GetUserData('LoopAndMusicVolume') / oldmusic
    
    OPLog.Log("coeff "..coeffsfx.." "..coeffmusic)
    
    function ChangeVolume(unit)
        if unit.Type=='gameplay' or unit.Type=='interface' or unit.Type =='oneliners' then
            unit.Volume=unit.Volume*coeffsfx
        elseif unit.Type=='music'  or unit.Type=='loop' then
            unit.Volume=unit.Volume*coeffmusic * coeffsfx
            --on met à jour les fades aussi
            SoundFader.ScaleSound(unit.Name,coeffmusic)
        end
    end
    
    function ChangeVolumeBink(unit)
        unit.Volume=unit.Volume*coeffsfx
    end    
    
    ApplyToClass('SimpleSound',ChangeVolume)
    ApplyToClass('BinkCutScene',ChangeVolumeBink)
    
end


function UF_explode(sep, str)
    if (str == nil) then
        OPLog.Log('[ERROR] Explode : str is nil ! (sep : ' .. tostring(sep) .. ')')
        return nil
    end

    local t, lastIdx, idx
    array = {}
    lastIdx = 0
    while true do
        idx = string.find(str, sep, lastIdx + 1, true)
        if idx ~= nil then -- if "not not" found then..
            table.insert(array, string.sub(str, lastIdx, idx - 1))
            lastIdx = idx + 1
        else
            table.insert(array, string.sub(str, lastIdx))
            break 
        end
    end
    return array
end


--function sur les tableaux
--indique si X est dans tabin
function IsInFct(tabin, x)

    if tabin == nil then
        return false
    end
    
    local comp1, comp2
    i = next(tabin)
    
    if type(x) == "string" then    
        comp1 = string.lower(x)
        while not(i == nil) do
            comp2 = string.lower(tabin[i])
            if comp1 == comp2  then
                return true
            end
            i = next(tabin, i)
        end   
    else
        comp1 = x
        while not(i == nil) do
            comp2 = tabin[i]
            if comp1 == comp2  then
                return true
            end
            i = next(tabin, i)
        end
    end
    
    return false    
        
end

--vire x de tabin, si s'il se trouve dedans
function RemoveInTableFct(tabin, x)
  if not(tabin == nil) then
    local i = next(tabin)
    while not(i == nil) do
      if x == tabin[i] then
        table.remove(tabin, i)
        tabin[i] = 0
      end
      i = next(tabin, i)
    end
  end
end

--renvoie un tableau contenant uniquement les élements présent à la fois dans tab1 et dans tab2
function IntersectFct(tab1,tab2)
--on fait l'intersection des deux tables
    if (tab1==nil or tab2==nil) then
        AssertPopup(false,'intersect : tableau vide')
        return {}
    end

    local result={}
    local i = next(tab1)
    while not(i == nil) do
        if IsIn(tab2,tab1[i]) then
            table.insert(result,tab1[i])
        end
        i = next(tab1, i)
    end
    return result
end


--Retourne la taille d'un tableau. StartToOne indique si le tableau est indexé à partir de 1.
--utiliser GETN
--fonction temporaire, en attendant de trouver une solution pour la taille des arrays of units
function GetSize(Table, StartToOne)
	local count=0
	if(StartToOne) then
		count=1
	end
	while (Table[count]~= nil) do
		count=count+1
	end
	return count
end

function GetIndex(Table, value,  StartToOne)
	local count=0
	if(StartToOne) then
		count=1
	end
	while (Table[count]~=value) do
		count=count+1
		if Table[count]~= nil then
			return nil
		end
	end
	return count
end

--[[ Fonction pour afficher des chrono de manière rapide 
--]]
function ConvertTimeToString(n)
    n=math.floor(n)
    local sec=math.mod(n,60)
    local min=math.floor((n-sec)/60)
    if sec<10 then
        sec='0'..sec
    end
    if min<10 then
        min='0'..min
    end
    if tonumber(min)>0 then    
        return min..' : '..sec
    else
        return sec
    end
end

--[[ Crée un timer :
    -- name : utilisé pour identifié le timer
    -- delay,autoplay,loop,autodisable sont les paramétres du timer comme dans l'éditeur --]]
function CreateTimer(name,delay,autoplay,loop,autodisable, UnitToNotify)
    -- on appel le load en mode "silent"
    local timer = Load(name..'WBPTimer','WBPTimer',true)
    if (timer== nil) then
        timer=OPUnitFactory.CreateUnit('WBPTimer')
        timer.Time=delay
        if (autoplay ~= nil) then
            timer.Autoplay=autoplay
            timer.Loop=loop
            timer.Autodisable=autodisable
        end
        timer.UnitNotify=UnitToNotify
        timer.Name=name..'WBPTimer'

		timer.Type = UnitToNotify.ClassName
		--timer.Enabled=false
    end
	
	        
	if autoplay then
		timer.Started = true
		timer.InitialDelay = self.Time
	end
	
	timer.InitialDelay = delay
	
	--OPLog.Log("on renvoit timer : "..timer.Name)
    return timer
end

--crée le timer systéme
function CreateTimerSystem(name,delay,autoplay,loop,autodisable, UnitToNotify)
    -- on appel le load en mode "silent"
    local timer = Load(name..'Timer','Timer',true)
    if (timer== nil) then
        timer=OPUnitFactory.CreateUnit('Timer')
        timer.Time=delay
        if (autoplay ~= nil) then
            timer.Autoplay=autoplay
            timer.Loop=loop
            timer.Autodisable=autodisable
        end
        timer.UnitNotify=UnitToNotify
        timer.Name=name..'Timer'
        timer.Enabled=false
		
		
    end
    return timer
end


function CreateUnit(unitClass, unitName)

    AssertPopup(type(unitClass) == "string","")
    --cout("CreateUnit("..tostring(unitClass).. ", " .. tostring(unitName)..")")
    
    local ut
    
    if type(unitName) == "string" then
        ut = OPUnitFactory.GetUnit(unitName, unitClass)
        if ut~= nil then
            OPLog.Log("CreateUnit: Unit " .. unitName .. " already exists. Closing it.")
            ut.Enabled = false
            OPUnitFactory.CloseUnit(ut)
        end
    end        

    ut = OPUnitFactory.CreateUnit(unitClass)
    
    AssertPopup(ut~= nil,"Erreur CreateUnit")

    if type(unitName) == "string" then
        ut.Name = unitName
    end

    return ut
    
end

--fonction utilisé pour du debug qui permet d'afficher un tableau de maniére claire dans un GUIText
function Display(tab)
    --AssertPopup(type(tab) == "table", "Erreur param display")
    
    if type(tab) ~= "table" then
        if type(tab)=='number' then
            return string.sub(tostring(tab),1,5)
        else
        end
            return tostring(tab)
    end
    --transforme un tableau en chaine de caractére
    local s=''
    local s1
    for u,v in pairs(tab) do
        if type(v)=='table' then
            s=s..tostring(u)
            s=s..' = '
            s= s..Display(v)..'\r'
        elseif u=='uidx' then --celui signifie que tab est une unit
            s=s..tab.Name
            return s
        else
            s1=tostring(v)
            if type(v)=='number' then
                s1=string.sub(s1,1,5)
            end
                s = s..tostring(u)
                s= s..' = '
                s= s..s1..'\r'
        end
    end
    return s
end

function CheckOneSound(ut)
	if ut.Type == "Dialog" then
		g_diagfound = true
	end
end


function DesactiveInterfaceIG()
	--[[
	ToolsManager.SetSelectedTool('', true)
	--InventoryManager.SetSelectedObject(nil)
	if Cursor.IsDragging() then
		Cursor.ReleaseObjectDragged(false)
	end
	
	SlotCenter.Desactive()
	Pad.Enabled = false
	ExitCloseup.Enabled = false
	MoneyInfo.Enabled = false
	
	LifeManager.Enabled = false]]
end

--convertie les secondes au bon format pour l'affichage du profil
function mySecAsTime(_sec)
	--[[if (_sec == 0) then
		return 'N/A'
	end]]
	local sec = math.floor(_sec)
	local min = math.floor(sec / 60)
	sec = sec - (min * 60)
	local hour = math.floor(min / 60)
	min = min - (hour * 60)
	local day = math.floor(hour / 24)
	hour = hour - (day * 24)
	return hour .. ':' .. goodNumber(min) 
	
end

function goodNumber(_number)
	return string.format("%02d", tonumber(_number))
end

function AddDialog( diagname)
	g_dialogplayed[diagname] = 1
end

function IsPlayed(diagname)
	return g_dialogplayed[diagname]
end

g_lowbatterydisplayed = false --c'est lcoal et pas à sauvegarder

--TODO  a appeler lors de la popup et lors du loading du menu aprés le load de profil
function SwitchToMinConfig()
	SetGraphicMode(1024,768)
	-- je les redésactives aussi dans les searchsite
	-- bien penser à mettre les particles "utiles" dans une autre classe
	ApplyToClass("Particle2DEmitter",Disable) end

function ResetGame()
	ApplyToClass("InventoryObject",UnEquip)
	--todo il faudra lister les datarray par la suite
	--SampleLevel.Reset()
end

function UnEquip(ut)

	ut.Equipped = false
end

--lance un blink sur une unit2d
--les paramétre de positionnement sont optionnels, on prend le centre du sprite dans ce cas
function StartBlinkUnit(ut , refpointx,refpointy)
	local blink = OPUnitFactory.CopyUnit(BlinkStarAnimation)
	ut.attackedblink = blink
	blink.AliasName = "BlinkStarAnimation"
	blink.Name = "blinkfor_"..ut.Name
	blink.LaunchBlink()
	blink.Parent = ut
	
	if refpointx == nil then
		blink.Position_X = ut.Dimension_Width / 2 - blink.Dimension_Width / 2
		blink.Position_Y = ut.Dimension_Height / 2 - blink.Dimension_Height / 2
	else
		blink.Position_X = refpointx - blink.Dimension_Width / 2
		blink.Position_Y = refpointy - blink.Dimension_Height / 2
	end
	
	blink.Enabled = true

	--il faudra penser à le désactiver !
	return blink
end

-- Lance une particule "blink" sur une untit2d
--les paramétre de positionnement sont optionnels, on prend le centre du sprite dans ce cas
function StartParticuleUnit(ut , refpointx,refpointy)
	local fxblink = OPUnitFactory.CopyUnit(FX_blink)
	fxblink.StartDelay = -5
	ut.attackedblink = fxblink
	fxblink.AliasName = "ParticuleStarAnimation"
	fxblink.Name = "fxfor_"..ut.Name	
	fxblink.Parent = ut
	
	if refpointx == nil then
		fxblink.Position_X = ut.Dimension_Width / 2
		fxblink.Position_Y = ut.Dimension_Height / 2
	else
		fxblink.Position_X = refpointx
		fxblink.Position_Y = refpointy
	end
	
	fxblink.Enabled = true
	
	--il faudra penser à le désactiver !
	return fxblink
end

function DisplayUnitsTab(tab)
	local s = ""
	for n,ut in pairs(tab) do
		s = s..ut.Name.." "..ut.ClassName.."\r"
	end
	return s
end