--	13.04.2020

local GlobalAddonName, BH = ...

BH.V = 0.7
BH.T = "R" -- "R" release ou "DU" debug 

BH.OnUpdate = {}		--> minuterie, fonction de mise a jour
BH.Slash = {}			--> fonctions d'appel en ligne de commande
BH.OnAddonMessage = {}	--> messages internes de l'addon
BH.MiniMapMenu = {}		--> changer ou charger le menu du bouton sur la minicarte
BH.Modules = {}		--> liste tout les modules
BH.ModulesLoaded = {}		--> liste des modules chargés [pour Dev & Advanced]
BH.ModulesOptions = {}
BH.Debug = {}
BH.RaidVersions = {}
BH.Temp = {}

BH.A = {}			--> lien vers tous les modules

BH.msg_prefix = {
	["BHADD"] = true,
	["MHADD"] = true,	--> Malkorok Helper (Curse client)
}

BH.L = {}			--> localistion
BH.locale = GetLocale()

---------------> Version <---------------
-- fonction permetant la verification de li'interface UIblizzard et l'addon
do
	local version, buildVersion, buildDate, uiVersion = GetBuildInfo()
	
	BH.clientUIinterface = uiVersion
	local expansion,majorPatch,minorPatch = (version or "2.0.0"):match("^(%d+)%.(%d+)%.(%d+)")
	BH.clientVersion = (expansion or 0) * 10000 + (majorPatch or 0) * 100 + (minorPatch or 0)
end
if BH.clientVersion >= 80300 then
	BH.is83 = true
else 
    print("erreur version")
end
-------------> smart DB <-------------
BH.SDB = {}
--data base sur les personnage 
do
	local realmKey = GetRealmName() or ""
	local charName = UnitName'player' or ""
	realmKey = realmKey:gsub(" ","")
	BH.SDB.realmKey = realmKey
	BH.SDB.charKey = charName .. "-" .. realmKey
	BH.SDB.charName = charName
	--BH.SDB.charLevel = UnitLevel'player'
end
-------------> global DB <------------
BH.GDB = {}
-------------> upvalues <-------------
local pcall, unpack, pairs, coroutine, assert = pcall, unpack, pairs, coroutine, assert
local GetTime, IsEncounterInProgress = GetTime, IsEncounterInProgress
local SendAddonMessage, strsplit = C_ChatInfo.SendAddonMessage, strsplit
local C_Timer_NewTicker, debugprofilestop = C_Timer.NewTicker, debugprofilestop

BH.NULLfunc = function() end --sert pour reset certaine fonction dans cd2
---------------> Modules <---------------
BH.mod = {}
BH.mod.__index = BH.mod

do
	local function mod_LoadOptions(this) -- met le nom traduit dans la liste a gauche
		if not InCombatLockdown() or this.enableLoadInCombat then
			this:Load()
			if not this.OnShow_disableNil then
				this:SetScript("OnShow",nil)
			end
			BH.F.dprint(this.moduleName.."'s options loaded")
			this.isLoaded = true
		else
			print(BH.L.SetErrorInCombat)
		end
	end
	local function mod_Options_CreateTitle(self)
		self.title = BH.lib:Text(self,self.name,16):Point(20,-5):Top()
	end
	function BH.mod:New(moduleName,localizatedName,disableOptions,enableLoadInCombat)
		if BH.A[moduleName] then
			return false
		end
		local self = {}
		setmetatable(self, BH.mod)
		
		if not disableOptions then
			self.options = BH.Options:Add(moduleName,localizatedName)
			self.options:Hide()
			self.options.moduleName = moduleName
			self.options.name = localizatedName or moduleName
			self.options:SetScript("OnShow",mod_LoadOptions)	
			self.options.CreateTilte = mod_Options_CreateTitle
			self.options.enableLoadInCombat = true		
			BH.ModulesOptions[#BH.ModulesOptions + 1] = self.options		
		end
		
		self.main = CreateFrame("Frame", nil)
		self.main.events = {}
		self.main:SetScript("OnEvent",BH.mod.Event)	
		if BH.T == "DU" then
			self.main.eventsCounter = {}
			self.main:HookScript("OnEvent",BH.mod.HookEvent)
			
			self.main.name = moduleName
		end		
		self.db = {}
		self.name = moduleName
		table.insert(BH.Modules,self)
		BH.A[moduleName] = self
		BH.F.dprint("New module: "..moduleName)
		return self
	end
	BH.New = BH.mod.New
end

function BH.mod:Event(event,...)
	self[event](self,...)
end

if BH.T == "DU" then
	local BHDebug = BH.Debug
	function BH.mod:Event(event,...)
		local dt = debugprofilestop()
		self[event](self,...)
		BHDebug[#BHDebug+1] = {debugprofilestop() - dt,self.name,event}
	end
end

function BH.mod:HookEvent(event)
	self.eventsCounter[event] = self.eventsCounter[event] and self.eventsCounter[event] + 1 or 1
end

function BH.mod:RegisterEvents(...) --debug pendant le combat
	for i=1,select("#", ...) do
		local event = select(i,...)
		if event ~= "COMBAT_LOG_EVENT_UNFILTERED" then
			self.main:RegisterEvent(event)
		else
			if not self.CLEU then self.CLEU = CreateFrame("Frame") end
			self.CLEU:SetScript("OnEvent",self.main.COMBAT_LOG_EVENT_UNFILTERED)
			self.CLEU:RegisterEvent('COMBAT_LOG_EVENT_UNFILTERED')
		end
		self.main.events[event] = true
		BH.F.dprint(self.name,'RegisterEvent',event)
	end
end

function BH.mod:UnregisterEvents(...) --debug combat
	for i=1,select("#", ...) do
		local event = select(i,...)
		if event ~= "COMBAT_LOG_EVENT_UNFILTERED" then
			self.main:UnregisterEvent(event)
		else
			if self.CLEU then
				self.CLEU:SetScript("OnEvent",nil)
				self.CLEU:UnregisterAllEvents()
			end
		end
		self.main.events[event] = nil
		BH.F.dprint(self.name,'UnregisterEvent',event)
	end
end

function BH.mod:RegisterUnitEvent(...) --debug combat
	self.main:RegisterUnitEvent(...)
	local event = ...
	self.main.events[event] = true
	BH.F.dprint(self.name,'RegisterUnitEvent',event)
end

do
	local Timers_modulesNames = {}
	function BH.mod:RegisterTimer()
		local pos = nil
		for i=1,#Timers_modulesNames do
			if Timers_modulesNames[i] == self.name then
				pos = i
				break
			end
		end
		if not pos then
			pos = #BH.OnUpdate + 1
			Timers_modulesNames[pos] = self.name
		end
		BH.OnUpdate[ pos ] = self
	end
	
	function BH.mod:UnregisterTimer()
		for i=1,#Timers_modulesNames do
			if Timers_modulesNames[i] == self.name then
				tremove(Timers_modulesNames,i)
				tremove(BH.OnUpdate,i)
				break
			end
		end
	end
end

function BH.mod:RegisterSlash()
	BH.Slash[self.name] = self
end

function BH.mod:UnregisterSlash()
	BH.Slash[self.name] = nil
end

function BH.mod:RegisterAddonMessage()
	BH.OnAddonMessage[self.name] = self
end

function BH.mod:UnregisterAddonMessage()
	BH.OnAddonMessage[self.name] = nil
end

function BH.mod:RegisterEgg()
	BH.Eggs[self.name] = self
end

function BH.mod:UnregisterEgg()
	BH.Eggs[self.name] = nil
end

function BH.mod:RegisterMiniMapMenu()
	BH.MiniMapMenu[self.name] = self
end

function BH.mod:UnregisterMiniMapMenu()
	BH.MiniMapMenu[self.name] = nil
end

do --fonction qui permet de cacher l'addon pendant les combat de pet
	local hideOnPetBattle = {}
	local petBattleTracker = CreateFrame("Frame")
	petBattleTracker:SetScript("OnEvent",function (self, event)
		if event == "PET_BATTLE_OPENING_START" then
			for _,frame in pairs(hideOnPetBattle) do
				if frame:IsShown() then
					frame.petBattleHide = true
					frame:Hide()
				else
					frame.petBattleHide = nil
				end
			end
		else
			for _,frame in pairs(hideOnPetBattle) do
				if frame.petBattleHide then
					frame.petBattleHide = nil
					frame:Show()
				end
			end
		end
	end)
	petBattleTracker:RegisterEvent("PET_BATTLE_OPENING_START")
	petBattleTracker:RegisterEvent("PET_BATTLE_CLOSE")
	
	function BH.mod:RegisterHideOnPetBattle(frame)
		hideOnPetBattle[#hideOnPetBattle + 1] = frame
	end
end


BH.Coroutinies = {}
function BH.mod:AddCoroutine(func)
	local c = coroutine.create(func)
	BH.Coroutinies[func] = c
	
	return c
end

function BH.mod:GetCoroutine(func)
	return BH.Coroutinies[func]
end

function BH.mod:RemoveCoroutine(func)
	BH.Coroutinies[func] = nil
end

---------------> Mods <---------------

BH.F = {}
BH.mds = BH.F

-- Moved to Functions.lua

do
	local function TimerFunc(self)
		self.func(unpack(self.args))
	end
	function BH.F.ScheduleTimer(func, delay, ...)
		local self = nil
		if delay > 0 then
			self = C_Timer_NewTicker(delay,TimerFunc,1)
		else
			self = C_Timer_NewTicker(-delay,TimerFunc)
		end
		self.args = {...}
		self.func = func
		
		return self
	end
	function BH.F.CancelTimer(self)
		if self then
			self:Cancel()
		end
	end
	function BH.F.ScheduleETimer(self, func, delay, ...)
		BH.F.CancelTimer(self)
		return BH.F.ScheduleTimer(func, delay, ...)
	end
	
	BH.F.NewTimer = BH.F.ScheduleTimer
	BH.F.Timer = BH.F.ScheduleTimer
end

---------------> Data <---------------

BH.F.defFont = "Interface\\AddOns\\BH\\libs\\media\\skurri.ttf"
BH.F.barImg = "Interface\\AddOns\\BH\\libs\\media\\bar17.tga"
BH.F.defBorder = "Interface\\AddOns\\BH\\libs\\media\\border.tga"
BH.F.textureList = {
	"Interface\\AddOns\\BH\\libs\\media\\bar1.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar2.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar3.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar4.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar5.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar6.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar7.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar8.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar9.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar10.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar11.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar12.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar13.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar14.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar15.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar16.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar17.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar18.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar19.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar20.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar21.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar22.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar23.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar24.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar24b.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar25.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar26.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar27.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar28.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar29.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar30.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar31.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar32.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar33.tga",
	"Interface\\AddOns\\BH\\libs\\media\\bar34.tga",
	"Interface\\AddOns\\BH\\libs\\media\\White.tga",
	[[Interface\TargetingFrame\UI-StatusBar]],
	[[Interface\PaperDollInfoFrame\UI-Character-Skills-Bar]],
	[[Interface\RaidFrame\Raid-Bar-Hp-Fill]],
}
BH.F.fontList = {
	"Interface\\AddOns\\BH\\libs\\media\\skurri.ttf",
	"Fonts\\ARIALN.TTF",
	"Fonts\\FRIZQT__.TTF",
	"Fonts\\MORPHEUS.TTF",
	"Fonts\\NIM_____.ttf",
	"Fonts\\SKURRI.TTF",
	"Fonts\\FRIZQT___CYR.TTF",
	"Fonts\\ARHei.ttf",
	"Fonts\\ARKai_T.ttf",
	"Fonts\\2002.ttf",
	"Interface\\AddOns\\BH\\libs\\media\\TaurusNormal.ttf",
	"Interface\\AddOns\\BH\\libs\\media\\UbuntuMedium.ttf",
	"Interface\\AddOns\\BH\\libs\\media\\TelluralAlt.ttf",
	"Interface\\AddOns\\BH\\libs\\media\\Glametrix.otf",
	"Interface\\AddOns\\BH\\libs\\media\\FiraSansMedium.ttf",
	"Interface\\AddOns\\BH\\libs\\media\\alphapixels.ttf",
	"Interface\\AddOns\\BH\\libs\\media\\ariblk.ttf",
}

if BH.locale and BH.locale:find("^zh") then		--China & Taiwan fix
	BH.F.defFont = "Fonts\\ARHei.ttf"
elseif BH.locale == "koKR" then			--Korea fix
	BH.F.defFont = "Fonts\\2002.ttf"
end

----------> Version Checker <----------

local isVersionCheckCallback = nil
local function DisableVersionCheckCallback()
	isVersionCheckCallback = nil
end

---------------> Slash <---------------

SlashCmdList["BHSlash"] = function (arg)
	local argL = strlower(arg)
	if argL == "icon" then
		VBH.Addon.IconMiniMapHide = not VBH.Addon.IconMiniMapHide
		if not VBH.Addon.IconMiniMapHide then 
			BH.MiniMapIcon:Show()
		else
			BH.MiniMapIcon:Hide()
		end
	elseif argL == "getver" then
		BH.F.SendExMsg("needversion","")
		isVersionCheckCallback = BH.F.ScheduleETimer(isVersionCheckCallback, DisableVersionCheckCallback, 1.5)
	elseif argL == "getverg" then
		BH.F.SendExMsg("needversiong","","GUILD")
		isVersionCheckCallback = BH.F.ScheduleETimer(isVersionCheckCallback, DisableVersionCheckCallback, 1.5)
	elseif argL == "set" then
		BH.Options:Open()
	elseif argL == "quit" then
		for mod,data in pairs(BH.A) do
			data.main:UnregisterAllEvents()
			if data.CLEU then
				data.CLEU:UnregisterAllEvents()
			end
		end
		BH.frame:UnregisterAllEvents()
		BH.frame:SetScript("OnUpdate",nil)
		print("BH Disabled")
	elseif string.len(argL) == 0 then
		BH.Options:Open()
		return
	end
	for _,mod in pairs(BH.Slash) do
		mod:slash(argL,arg)
	end
end
SLASH_BHSlash1 = "/BH"
SLASH_BHSlash2 = "/bh"

---------------> Global addon frame <---------------

local reloadTimer = 0.1

BH.frame = CreateFrame("Frame")

BH.frame:SetScript("OnEvent",function (self, event, ...)
	if event == "ADDON_LOADED" then
		local addonName = ...
		if addonName ~= GlobalAddonName then
			return
		end
		VBH = VBH or {}
		VBH.Addon = VBH.Addon or {}
		VBH.Addon.Timer = 0.3
		reloadTimer = VBH.Addon.Timer

		if VBH.Addon.IconMiniMapLeft and VBH.Addon.IconMiniMapTop then
			BH.MiniMapIcon:ClearAllPoints()
			BH.MiniMapIcon:SetPoint("CENTER", VBH.Addon.IconMiniMapLeft, VBH.Addon.IconMiniMapTop)
		end
		
		if VBH.Addon.IconMiniMapHide then 
			BH.MiniMapIcon:Hide() 
		end

		for prefix,_ in pairs(BH.msg_prefix) do
			C_ChatInfo.RegisterAddonMessagePrefix(prefix)
		end
		
		VBH.Addon.Version = tonumber(VBH.Addon.Version or "0")
		VBH.Addon.PreVersion = VBH.Addon.Version
		
		if not BH.F.FUNC_FILE_LOADED then
			print("|cffff0000Beta heal:|r after updating may work incorrectly, please restart your game client")
		end
		
		if BH.A.Profiles then
			BH.A.Profiles:ReselectProfileOnLoad()
		end
		
		BH.F.dprint("ADDON_LOADED event")
		BH.F.dprint("MODULES FIND",#BH.Modules)
		for i=1,#BH.Modules do
			local isSuccessful = pcall(BH.Modules[i].main.ADDON_LOADED,self) 	-- BE CARE ABOUT IT
			if not isSuccessful then
				BH.F.dprint("|cffff0000Error loading",BH.Modules[i].name)
			end
			BH.ModulesLoaded[i] = true
			
			BH.F.dprint("ADDON_LOADED",i,BH.Modules[i].name)
		end

		VBH.Addon.Version = BH.V
		
		BH.F.ScheduleTimer(function()
			BH.frame:SetScript("OnUpdate", BH.frame.OnUpdate)
		end,1)
		self:UnregisterEvent("ADDON_LOADED")

		BH.AddonLoaded = true

		return true	
	end
end)

do
	local encounterTime,isEncounter = 0,nil
	local BH_OnUpdate = BH.OnUpdate
	local frameElapsed = 0
	function BH.frame:OnUpdate(elapsed)
		frameElapsed = frameElapsed + elapsed
		if frameElapsed > reloadTimer then
			if not isEncounter and IsEncounterInProgress() then
				isEncounter = true
				encounterTime = GetTime()
			elseif isEncounter and not IsEncounterInProgress() then
				isEncounter = nil
			end
			
			for i=1,#BH_OnUpdate do
				local mod = BH_OnUpdate[i]
				if mod then
					mod:timer(frameElapsed)
				end
			end
			frameElapsed = 0
		end
	end
	
	if BH.T == "DU" then
		local BHDebug = BH.Debug
		function BH.frame:OnUpdate(elapsed)
			frameElapsed = frameElapsed + elapsed
			if frameElapsed > reloadTimer then
				if not isEncounter and IsEncounterInProgress() then
					isEncounter = true
					encounterTime = GetTime()
				elseif isEncounter and not IsEncounterInProgress() then
					isEncounter = nil
				end
				
				for i=1,#BH_OnUpdate do
					local mod = BH_OnUpdate[i]
					if mod then
						local dt = debugprofilestop()
						mod:timer(frameElapsed)
						BHDebug[#BHDebug+1] = {debugprofilestop() - dt,mod.name,"Timer"}
					end
				end
				frameElapsed = 0
			end
		end
	end
	
	function BH.F.RaidInCombat()
		return isEncounter
	end
	
	function BH.F.GetEncounterTime()
		if isEncounter then
			return GetTime() - encounterTime
		end
	end
end

-- Fonction de message dans l'onglet principale pour dire la version de chancun

function BH.F.SendExMsg(prefix, msg, tochat, touser, addonPrefix)
	addonPrefix = addonPrefix or "BHADD"
	msg = msg or ""
	--print (msg)
	if tochat and not touser then
		SendAddonMessage(addonPrefix, prefix .. "\t" .. msg, tochat)
	elseif tochat and touser then
		SendAddonMessage(addonPrefix, prefix .. "\t" .. msg, tochat,touser)
	else
		local chat_type, playerName = BH.F.chatType()
		if chat_type == "WHISPER" and playerName == BH.SDB.charName then
			BH.F.GetExMsg(BH.SDB.charName, prefix, strsplit("\t", msg))
			return
		end
		SendAddonMessage(addonPrefix, prefix .. "\t" .. msg, chat_type, playerName)
	end
end

function BH.F.GetExMsg(sender, prefix, ...)
	if prefix == "needversion" then
		BH.F.SendExMsg("version2", BH.V)
	elseif prefix == "needversiong" then
		BH.F.SendExMsg("version2", BH.V, "WHISPER", sender)
	elseif prefix == "version" then
		local msgver = ...
		print(sender..": "..msgver)
		BH.RaidVersions[sender] = msgver
	elseif prefix == "version2" then
		BH.RaidVersions[sender] = ...
		if isVersionCheckCallback then
			local msgver = ...
			print(sender..": "..msgver)
		end
	end
	for _,mod in pairs(BH.OnAddonMessage) do
		mod:addonMessage(sender, prefix, ...)
	end
end

_G["GBH"] = BH
BH.frame:RegisterEvent("ADDON_LOADED") 