deadpoolCharInfo = {}
local L = LibStub("AceLocale-3.0"):GetLocale("Deadpool", true)
local XITK = LibStub("XamInsightToolKit")
local EZBUP = LibStub("EZBlizzardUiPopups")

-- https://wow.gamepedia.com/RaceId
local raceID = {
   ["Human"] = 1,
   ["Orc"] = 2,
   ["Dwarf"] = 3,
   ["Night Elf"] = 4,
   ["Undead"] = 5,
   ["Tauren"] = 6,
   ["Gnome"] = 7,
   ["Troll"] = 8,
   ["Goblin"] = 9,
   ["Blood Elf"] = 10,
   ["Draenei"] = 11,
   ["Fel Orc"] = 12,
   ["Naga"] = 13,
   ["Broken"] = 14,
   ["Skeleton"] = 15,
   ["Vrykul"] = 16,
   ["Tuskarr"] = 17,
   ["Forest Troll"] = 18,
   ["Taunka"] = 19,
   ["Northrend Skeleton"] = 20,
   ["Ice Troll"] = 21,
   ["Worgen"] = 22,
   ["Gilnean"] = 23,
   ["Pandaren"] = 24,
   ["Pandaren"] = 25,
   ["Pandaren"] = 26,
   ["Nightborne"] = 27,
   ["Highmountain Tauren"] = 28,
   ["Void Elf"] = 29,
   ["Lightforged Draenei"] = 30,
   ["Zandalari Troll"] = 31,
   ["Kul Tiran"] = 32,
   ["ThinHuman"] = 33,
   ["Dark Iron Dwarf"] = 34,
   ["Vulpera"] = 35,
   ["Mag'har Orc"] = 36,
   ["Mechagnome"] = 37,
   ["Dracthyr"] = 52,
   ["Dracthyr"] = 70,
   ["Earthen"] = 84,
   ["Earthen"] = 85,
   ["Haranir"] = 86,
   ["Haranir"] = 91,
}

-- UnitRace returns differently for the following races, so need to include exceptions
-- Thanks to MogIt authors: Aelobin (The Maelstrom EU) & Lombra (Defias Brotherhood EU)
raceID["NightElf"] = raceID["Night Elf"]
raceID["Scourge"] = raceID["Undead"]
raceID["BloodElf"] = raceID["Blood Elf"]
raceID["FelOrc"] = raceID["Fel Orc"]
raceID["Naga_"] = raceID["Naga"]
raceID["ForestTroll"] = raceID["Forest Troll"]
raceID["NorthrendSkeleton"] = raceID["Northrend Skeleton"]
raceID["IceTroll"] = raceID["Ice Troll"]
raceID["HighmountainTauren"] = raceID["Highmountain Tauren"]
raceID["VoidElf"] = raceID["Void Elf"]
raceID["LightforgedDraenei"] = raceID["Lightforged Draenei"]
raceID["ZandalariTroll"] = raceID["Zandalari Troll"]
raceID["KulTiran"] = raceID["Kul Tiran"]
raceID["DarkIronDwarf"] = raceID["Dark Iron Dwarf"]
raceID["MagharOrc"] = raceID["Mag'har Orc"]

-- https://wowpedia.fandom.com/wiki/InstanceID
-- https://wowpedia.fandom.com/wiki/DifficultyID
-- https://wowpedia.fandom.com/wiki/LfgDungeonID
-- https://wago.tools/db2/Map

--[[
function getDpInstanceIDList()--/run tpotest()
	dpInstanceIDListTmp = {} -- Add to toc
	for i = 1, 3000 do
	local name, typeID, _, _, _, _, _, maxRecLevel, _, _, _, _, _, _, _, _, _, _, _, _, _, lfgMapID = GetLFGDungeonInfo(i)
		if typeID == 2 then
			dpInstanceIDListTmp[i] = lfgMapID..";"..maxRecLevel..";"..name
		end
		
	end
end
--]]

local dpInstanceIDList = {
	 [249] = 30, -- Onyxia's Lair
	 [409] = 30, -- Molten Core
	 [469] = 30, -- Blackwing Lair
	 [509] = 30, -- Ruins of Ahn'Qiraj
	 [531] = 30, -- Temple of Ahn'Qiraj
	 [532] = 30, -- Karazhan
	 [533] = 30, -- Naxxramas
	 [534] = 30, -- Hyjal Summit
	 [544] = 30, -- Magtheridon's Lair
	 [548] = 30, -- Serpentshrine Cavern
	 [550] = 30, -- Tempest Keep
	 [564] = 30, -- Black Temple
	 [565] = 30, -- Gruul's Lair
	 [580] = 30, -- Sunwell Plateau
	 [603] = 30, -- Ulduar
	 [615] = 30, -- The Obsidian Sanctum
	 [616] = 30, -- The Eye of Eternity
	 [624] = 30, -- Vault of Archavon
	 [631] = 30, -- Icecrown Citadel
	 [649] = 30, -- Trial of the Crusader
	 [669] = 35, -- Blackwing Descent
	 [671] = 35, -- The Bastion of Twilight
	 [720] = 35, -- Firelands
	 [724] = 30, -- The Ruby Sanctum
	 [754] = 35, -- Throne of the Four Winds
	 [757] = 35, -- Baradin Hold
	 [967] = 35, -- Dragon Soul
	 [996] = 35, -- Terrace of Endless Spring
	[1008] = 35, -- Mogu'shan Vaults
	[1009] = 35, -- Heart of Fear
	[1098] = 35, -- Throne of Thunder
	[1136] = 35, -- Siege of Orgrimmar
	[1205] = 40, -- Blackrock Foundry
	[1228] = 40, -- Highmaul
	[1448] = 40, -- Hellfire Citadel
	[1520] = 45, -- The Emerald Nightmare
	[1530] = 45, -- The Nighthold
	[1648] = 45, -- Trial of Valor
	[1676] = 45, -- Tomb of Sargeras
	[1712] = 45, -- Antorus, the Burning Throne
	[1861] = 50, -- Uldir
	[2070] = 50, -- Battle of Dazar'alor
	[2096] = 50, -- Crucible of Storms
	[2164] = 50, -- The Eternal Palace
	[2217] = 50, -- Ny'alotha
	[2296] = 60, -- Castle Nathria
	[2450] = 60, -- Sanctum of Domination
	[2481] = 60, -- Sepulcher of the First Ones
	[2522] = 70, -- Vault of the Incarnates
	[2569] = 70, -- Aberrus, the Shadowed Crucible
	[2549] = 70, -- Amirdrassil, the Dream's Hope
	[2657] = 80, -- Nerub-ar Palace
	[2792] = 80, -- Blackrock Depths
	[2769] = 80, -- Undermine
	[2810] = 80, -- Manaforge Omega
}

local willPlay, soundHandle

Deadpool_maxBets = 1

Deadpool_WindowsOptions = "All"

local function setDeadpoolPlayerData(aSession, aChar, aVersion)
	setDeadpoolData(aSession, aChar, DEADPOOLDATA_VERSION, aVersion)
end

-- Initialize Deadpools Objects
function initDeadpoolBusinessObjects()
	-- DeadpoolData
	local name = XITK.playerCharacter() or UNKNOWN
	if not DeadpoolData then
		DeadpoolData = {}
	end
	if not DeadpoolData.DATA_ERROR then
		DeadpoolData.DATA_ERROR = {}
	end
	if not DeadpoolGlobal_SessionId then
		playerJoinsDeadpoolSession("DeadpoolSession_"..name, true, true)
	elseif DeadpoolData[DeadpoolGlobal_SessionId] and not DeadpoolData[DeadpoolGlobal_SessionId][name] then
		playerJoinsDeadpoolSession(DeadpoolGlobal_SessionId)
	else
		setDeadpoolPlayerData(DeadpoolGlobal_SessionId, name, C_AddOns.GetAddOnMetadata("Deadpool", "Version"))
	end

	-- DeadpoolOptionsData
	if not DeadpoolOptionsData then
		DeadpoolOptionsData = {}
	end

	-- DeadpoolWindow
	if not DeadpoolWindow then
		DeadpoolWindow = {}
	end
	if not DeadpoolWindow[Deadpool_WindowsOptions] then
		DeadpoolWindow[Deadpool_WindowsOptions] = {}
	end
	if DeadpoolWindow[name] then
		Deadpool_WindowsOptions = name
	end
	if not DeadpoolWindow[Deadpool_WindowsOptions]["DeadpoolFrameAlpha"] then
		DeadpoolWindow[Deadpool_WindowsOptions]["DeadpoolFrameAlpha"] = 0.7
	end
	if not DeadpoolWindow[Deadpool_WindowsOptions]["DeadpoolLigneHeight"] then
		DeadpoolWindow[Deadpool_WindowsOptions]["DeadpoolLigneHeight"] = 24
	end
	if not DeadpoolWindow[Deadpool_WindowsOptions]["DeadpoolHeight"] then
		DeadpoolWindow[Deadpool_WindowsOptions]["DeadpoolHeight"] = 360
	end
	
	-- DeadpoolTuto
	if not DeadpoolTuto then
		DeadpoolTuto = {}
	end

	-- Followers ids by name
	if not DeadpoolFollowersId then
		DeadpoolFollowersId = {}
	end
end

function prepareAndSendSimpleDeadpoolDataToRaid(aSession, aCharacter, anInfo, isOptionData)
	local Temp_DeadpoolData = {}
	if anInfo and not isOptionData then
		local value, dataTime = getDeadpoolData(aSession, aCharacter, anInfo)
		Temp_DeadpoolData[aCharacter] = {}
		local infoToSend = value or "nil"
		if dataTime then
			infoToSend = infoToSend.."|"..dataTime
		end
		Temp_DeadpoolData[aCharacter][anInfo] = infoToSend
	else
		Temp_DeadpoolData[aCharacter] = DeadpoolData[aSession][aCharacter]
	end
	encodeAndSendSimpleDeadpoolData(Temp_DeadpoolData)
end

local deadpoolVersionSignaled
local function signalDeadpoolVersion()
	if not deadpoolVersionSignaled then
		deadpoolVersionSignaled = true
		C_Timer.After(5, function()
			XITK.Error(Deadpool, Deadpool_name,string.format(L["DEADPOOL_VERSION_UPDATE"], Deadpool_logo))
			Deadpool:Print(string.format(L["DEADPOOL_VERSION_UPDATE_DESC"], Deadpool_logo))		
		end)
	end
end

local function setInitialDeadpoolPlayerData(aSession, aChar)
	setDeadpoolData(aSession, aChar, "credits", DEADPOOL_INITIAL_MONEY)
	setDeadpoolData(aSession, aChar, DEADPOOL_TRULYUNEQUIP, nil)
	setDeadpoolData(aSession, aChar, DEADPOOLDATA_VERSION, C_AddOns.GetAddOnMetadata("Deadpool", "Version"))
end

-- Get Roster Info
local groupLabel
function getDeadpoolRosterInfo()
	deadpoolCharInfo = {}
	
	deadpoolCharInfo[DEADPOOL_BANKER] = {}
	deadpoolCharInfo[DEADPOOL_BANKER]["localName"] = DEADPOOL_BANKER_NAME
	deadpoolCharInfo[DEADPOOL_BANKER]["isAPlayer"] = false

	local deadpoolPlayerCharacter = XITK.playerCharacter()
	local deadpoolPlayerVersion = XITK.getMainVersion(C_AddOns.GetAddOnMetadata("Deadpool", "Version"))

	addCharInList(deadpoolCharInfo, "player", deadpoolPlayerCharacter or UNKNOWN)
	DeadpoolGlobal_NumRealPlayers = 1
	DeadpoolGlobal_SessionCreatorIsOut = DeadpoolGlobal_SessionCreator and DeadpoolGlobal_SessionCreator ~= deadpoolPlayerCharacter
	
	local cancelBetsOnGonePlayers = true
	local everyoneIsHere = true
	local _, _, _, instanceID = UnitPosition("player")
	if not isInstanceAtLevel(UnitLevel("player")) then
		everyoneIsHere = false
	end
	
	groupLabel = getGroupType()

	local numGroupMembers = GetNumGroupMembers()
    if groupLabel then
		Deadpool_maxBets = floor(numGroupMembers / 2)
        for i = 1, numGroupMembers do
			local memberGroupLabel = groupLabel..i
			if UnitExists(memberGroupLabel) then
                local playerId = UnitIsPlayer(memberGroupLabel) and XITK.fullName(memberGroupLabel)
				if not playerId then
					_, _, _, _, _, playerId = strsplit("-", UnitGUID(memberGroupLabel))
				end
				if playerId then
					if DeadpoolGlobal_SessionCreator and DeadpoolGlobal_SessionCreator == playerId then
						DeadpoolGlobal_SessionCreatorIsOut = false
					end
					local isDeadpoolPlayer = getDeadpoolData(DeadpoolGlobal_SessionId, playerId, "credits")
					if isDeadpoolPlayer and UnitIsPlayer(memberGroupLabel) then
						DeadpoolGlobal_NumRealPlayers = DeadpoolGlobal_NumRealPlayers + 1
					end
					if not isDeadpoolPlayer and not UnitIsPlayer(memberGroupLabel) then
						setInitialDeadpoolPlayerData(DeadpoolGlobal_SessionId, playerId)
						isDeadpoolPlayer = true
					end
					local charVersion = XITK.getMainVersion(getDeadpoolData(DeadpoolGlobal_SessionId, playerId, DEADPOOLDATA_VERSION))
					local isDeadpoolPlayerUpToDate = deadpoolPlayerVersion == charVersion
					if charVersion > deadpoolPlayerVersion then
						signalDeadpoolVersion()
					end
					addCharInList(deadpoolCharInfo, memberGroupLabel, playerId)
					local _, _, _, instanceIDChar = UnitPosition(memberGroupLabel)
					if isDeadpoolPlayer and everyoneIsHere and UnitIsConnected(memberGroupLabel)
							and (not isDeadpoolPlayerUpToDate or instanceIDChar ~= instanceID or not isInstanceAtLevel(UnitLevel(memberGroupLabel))) then
						everyoneIsHere = false
					end
				else
					cancelBetsOnGonePlayers = false
				end
            end
        end
		loadBets(DeadpoolGlobal_SessionId, DEADPOOL_BANKER)
	end

	if everyoneIsHere then
		addBossInList(deadpoolCharInfo)--"|T521748:16:16:0:0|t Prochain boss")--Interface\\Buttons\\UI-Panel-SmallerButton-Up:15:15:0:0:32:32:7:25:8:26
	end

	clearCharacterDeadpoolData(deadpoolPlayerCharacter)

	-- Cancel the bets from players that left
	if cancelBetsOnGonePlayers --[[and groupLabel and numGroupMembers > 1]] and not dpFakeCharInfo then
		if DeadpoolData[DeadpoolGlobal_SessionId] then
			for index,value in pairs(DeadpoolData[DeadpoolGlobal_SessionId]) do
				if "Bank" ~= index and "DeadpoolSessionId" ~= index and not deadpoolAchievements[index] then
					if type(value) ~= "table" then
						-- Data corruption analysis
						DeadpoolData.DATA_ERROR[index] = {}
						DeadpoolData.DATA_ERROR[index].session = DeadpoolGlobal_SessionId
						DeadpoolData.DATA_ERROR[index].date = date("%m/%d/%Y %I:%M %p")
						DeadpoolData.DATA_ERROR[index].value = value
						DeadpoolData[DeadpoolGlobal_SessionId][index] = nil
					else
						if not deadpoolCharInfo[index] and DEADPOOL_BANKER ~= index then
							setDeadpoolData(DeadpoolGlobal_SessionId, index, "inCombat", "false")
							saveBets(DeadpoolGlobal_SessionId, index)
							if index == selectedDeadpoolCharacter then
								selectedDeadpoolLine = nil
								selectedDeadpoolCharacter = nil
							end
						end
						if value["bets"] then
							for index2,value2 in pairs(value["bets"]) do
								if not deadpoolCharInfo[index2] and value2 and XITK.tonumberzeroonblankornil(value2["nextDeathBet"]) > 0 then
									saveBets(DeadpoolGlobal_SessionId, index, index2)
								end
							end
						end
					end
				end
			end
		end
	end
	return deadpoolCharInfo
end

local function loadPlayerBets(playerId)
	local deadpoolPlayerCharacter = XITK.playerCharacter() or UNKNOWN
	if not XITK.isPlayerCharacter(playerId) and DeadpoolSavedBets then
		if DeadpoolSavedBets[deadpoolPlayerCharacter] then
			if DeadpoolSavedBets[deadpoolPlayerCharacter][playerId] then
				local savedBet = DeadpoolSavedBets[deadpoolPlayerCharacter][playerId]
				if savedBet then
					DeadpoolSavedBets[deadpoolPlayerCharacter][playerId] = nil
					setDeadpoolBets(DeadpoolGlobal_SessionId, deadpoolPlayerCharacter, playerId, savedBet)
				end
			end
			if DeadpoolSavedBets[deadpoolPlayerCharacter]["uniqueGamble"] and DeadpoolSavedBets[deadpoolPlayerCharacter]["uniqueGamble"] == playerId then
				DeadpoolSavedBets[deadpoolPlayerCharacter]["uniqueGamble"] = nil
				setDeadpoolUniqueGamble(DeadpoolGlobal_SessionId, deadpoolPlayerCharacter, playerId)
			end
		end
		loadBets(DeadpoolGlobal_SessionId, playerId)
	end
end

function addCharInList(deadpoolCharInfo, groupRank, playerId)
	local _, englishClass = UnitClass(groupRank)
	local _, raceEn = UnitRace(groupRank)
	local gender_code = UnitSex(groupRank)
	deadpoolCharInfo[playerId] = {}
	deadpoolCharInfo[playerId]["isAPlayer"] = UnitIsPlayer(groupRank)
	if not deadpoolCharInfo[playerId]["isAPlayer"] then
		DeadpoolFollowersId[UnitNameUnmodified(groupRank) or UNKNOWN] = playerId
	end
	deadpoolCharInfo[playerId]["localName"] = UnitNameUnmodified(groupRank) or UNKNOWN
	deadpoolCharInfo[playerId]["classFileName"] = englishClass
	deadpoolCharInfo[playerId]["groupRank"] = groupRank
	local role = "NONE"
	if UnitGroupRolesAssigned then
		role = UnitGroupRolesAssigned(groupRank)
	end
	deadpoolCharInfo[playerId]["groupRole"] = role
	deadpoolCharInfo[playerId]["race"] = (raceEn and raceID[raceEn]) or 1
	deadpoolCharInfo[playerId]["gender"] = (gender_code and gender_code - 2) or 0
	clearCharacterDeadpoolData(playerId)

	loadPlayerBets(playerId)
end

function addBossInList(deadpoolCharInfo)
	local bossTag = "boss"
	deadpoolCharInfo[bossTag] = {}
	deadpoolCharInfo[bossTag]["isAPlayer"] = false
	deadpoolCharInfo[bossTag]["localName"] = bossTag
	--deadpoolCharInfo[bossTag]["classFileName"] = "NONE"
	deadpoolCharInfo[bossTag]["groupRank"] = bossTag
	deadpoolCharInfo[bossTag]["groupRole"] = "NONE"
	deadpoolCharInfo[bossTag]["race"] = 1
	deadpoolCharInfo[bossTag]["gender"] = 0
	clearCharacterDeadpoolData(bossTag)

	loadPlayerBets(bossTag)
end

function loadBets(aSession, aChar)
	if DeadpoolSavedBets and DeadpoolSavedBets[aChar] then
		local savedBets = DeadpoolSavedBets[aChar]
		for index,value in pairs(savedBets) do
			if value then
				setDeadpoolBetLocally(aSession, aChar, index, value)
			end
			DeadpoolSavedBets[aChar][index] = nil
		end
		for index,value in pairs(DeadpoolSavedBets) do
			if value then
				for index2,value2 in pairs(value) do
					if value2 and index2 == aChar then
						setDeadpoolBetLocally(aSession, index, index2, value2)
					end
				end
			end
			DeadpoolSavedBets[aChar][index] = nil
		end
	end
end

function saveBets(aSession, aChar, aBetChar)
	if not aBetChar then
		local playerBets = DeadpoolData[aSession][aChar]["bets"]
		if playerBets then
			for index,value in pairs(playerBets) do
				if value and XITK.tonumberzeroonblankornil(value["nextDeathBet"]) > 0 then
					if not DeadpoolSavedBets then
						DeadpoolSavedBets = {}
					end
					if not DeadpoolSavedBets[aChar] then
						DeadpoolSavedBets[aChar] = {}
					end
					DeadpoolSavedBets[aChar][index] = value["nextDeathBet"]
					if XITK.isPlayerCharacter(aChar) then
						setDeadpoolBets(aSession, aChar, index, "0")
					else
						setDeadpoolBetLocally(aSession, aChar, index, "0")
					end
				end
			end
		end
		local uniqueGamble = getDeadpoolData(aSession, aChar, "uniqueGamble")
		if uniqueGamble and uniqueGamble ~= "NO_ONE" then
			if not DeadpoolSavedBets then
				DeadpoolSavedBets = {}
			end
			if not DeadpoolSavedBets[aChar] then
				DeadpoolSavedBets[aChar] = {}
			end
			DeadpoolSavedBets[aChar]["uniqueGamble"] = uniqueGamble
			if XITK.isPlayerCharacter(aChar) then
				setDeadpoolUniqueGamble(aSession, aChar, "NO_ONE")
			else
				setDeadpoolBetLocally(aSession, aChar, "uniqueGamble", "NO_ONE")
			end
		end
	else
		local playerBetsOnChar, _, _, playerBetsNumber = getDeadpoolBets(aSession, aChar, aBetChar)
		if playerBetsOnChar > 0 then
			if not DeadpoolSavedBets then
				DeadpoolSavedBets = {}
			end
			if not DeadpoolSavedBets[aChar] then
				DeadpoolSavedBets[aChar] = {}
			end
			DeadpoolSavedBets[aChar][aBetChar] = playerBetsOnChar
			if XITK.isPlayerCharacter(aChar) then
				setDeadpoolBets(aSession, aChar, aBetChar, "0")
			else
				setDeadpoolBetLocally(aSession, aChar, aBetChar, "0")
			end
		end
		local uniqueGamble = getDeadpoolData(aSession, aChar, "uniqueGamble")
		if uniqueGamble == aBetChar then
			if not DeadpoolSavedBets then
				DeadpoolSavedBets = {}
			end
			if not DeadpoolSavedBets[aChar] then
				DeadpoolSavedBets[aChar] = {}
			end
			DeadpoolSavedBets[aChar]["uniqueGamble"] = aBetChar
			if XITK.isPlayerCharacter(aChar) then
				setDeadpoolUniqueGamble(aSession, aChar, "NO_ONE")
			else
				setDeadpoolBetLocally(aSession, aChar, "uniqueGamble", "NO_ONE")
			end
		end
	end
end

function setDeadpoolBetLocally(aSession, aChar, aBetChar, aNextDeathBet)
	if aBetChar == "uniqueGamble" then
		setDeadpoolData(aSession, aChar, "uniqueGamble", aNextDeathBet)
	else
		local howManyGarmentToLose, afterTransactionCredits, _ = howManyGarmentToLose(aSession, aChar, aBetChar, aNextDeathBet)
		if howManyGarmentToLose == 0 or dpFakeCharInfo then
			local bets = nil
			if XITK.tonumberzeroonblankornil(aNextDeathBet) > 0 then
				bets = {}
				bets["dataTime"] = tostring(XITK.getTimeUTCinMS())
				bets["nextDeathBet"] = aNextDeathBet
			end
			DeadpoolData[aSession][aChar]["bets"][aBetChar] = bets
			setDeadpoolData(aSession, aChar, "credits", afterTransactionCredits)
		end
	end
end

function getGroupType()
	local newGroupLabel = nil
	if IsInRaid() then
        newGroupLabel = "raid"
    elseif IsInGroup() then
        newGroupLabel = "party"
    --else
		--DEADPOOL_GROUPJOINED = nil
	end
	return newGroupLabel
end

function getDeadpoolCharInfo(aChar, anInfo)
	local value = nil
	if deadpoolCharInfo and deadpoolCharInfo[aChar] then
		value = deadpoolCharInfo[aChar][anInfo]
	end
	return value
end

function playerNameOrBankerName(fullName)
	if getDeadpoolCharInfo(fullName, "isAPlayer") then
		return fullName
	elseif fullName == "boss" then
		return BOSSES
	else
		local localName = getDeadpoolCharInfo(fullName, "localName")
		if localName then
			return localName
		else
			local npcName = XITK.GetNameFromNpcID(fullName)
			if npcName and npcName ~= "" then
				return npcName
			else
				return fullName
			end
		end
	end
end

function playerJoinsDeadpoolSession(aSession, isCreator, keepPlayerData)
	local playerCharacter = XITK.playerCharacter() or UNKNOWN
	if not DeadpoolGlobal_SessionId or DeadpoolGlobal_SessionId ~= aSession or isCreator then
		local playerData = nil
		local bankerData = nil
		local bankData = nil
		if keepPlayerData and DeadpoolGlobal_SessionId and DeadpoolData[DeadpoolGlobal_SessionId] then
			playerData = DeadpoolData[DeadpoolGlobal_SessionId][playerCharacter]
			bankerData = DeadpoolData[DeadpoolGlobal_SessionId][DEADPOOL_BANKER]
			bankData = DeadpoolData[DeadpoolGlobal_SessionId]["Bank"]
		end
		DeadpoolGlobal_SessionId = aSession
		DeadpoolGlobal_SessionCreator = DeadpoolGlobal_SessionId:match("^DeadpoolSession_([^%-]+%-%w+)") or DeadpoolGlobal_SessionId:match("^DeadpoolSession_(.+)$")
		DeadpoolData = {}
		DeadpoolData.DATA_ERROR = {}
		setInitialDeadpoolPlayerData(aSession, playerCharacter)
		setDeadpoolData(aSession, DEADPOOL_BANKER, "credits", DEADPOOL_INITIAL_MONEY)
		setDeadpoolData(DeadpoolGlobal_SessionId, "Bank", "credits", 0)
		DeadpoolData[aSession]["DeadpoolSessionId"] = aSession
		if keepPlayerData then
			if playerData then
				DeadpoolData[aSession][playerCharacter] = playerData
			end
			if bankerData then
				DeadpoolData[aSession][DEADPOOL_BANKER] = bankerData
			end
			if bankData then
				DeadpoolData[DeadpoolGlobal_SessionId]["Bank"] = bankData
			end
		end
		if not isCreator then
			prepareAndSendSimpleDeadpoolDataToRaid(aSession, playerCharacter)
		end
	elseif DeadpoolData and DeadpoolData[DeadpoolGlobal_SessionId] and not DeadpoolData[DeadpoolGlobal_SessionId][playerCharacter] then
		setInitialDeadpoolPlayerData(aSession, playerCharacter)
	else
		setDeadpoolPlayerData(aSession, playerCharacter)
	end
	Deadpool:UnequipLostItems()
end

--[[function isEveryoneDisconnected(aDeadpoolSessionId)
	local everyoneDisconnected = true
	local numGroupMembers = GetNumGroupMembers()
	if numGroupMembers > 0 then
		local i = 1
		while everyoneDisconnected and i <= numGroupMembers do
			local name, _, _, _, _, _, _, online, _, _, _ = GetRaidRosterInfo(i)
			name = XITK.addRealm(name)
			if name ~= XITK.playerCharacter() and getDeadpoolData(aDeadpoolSessionId, name, "credits") and online then
				everyoneDisconnected = false
			end
			i = i + 1
		end
	end
	return everyoneDisconnected
end--]]

-- Load Received Data
function loadReceivedDeadpoolData(messageType)
	local receivedDataWasObsolete = false
	local playerTrulyUnequipValueChanged = nil
	local someoneProposedTrulyUnequip = nil
	--Deadpool:Print(time().." - Processing data.")
	if DeadpoolReceivedData then
		if DeadpoolReceivedData["DeadpoolSessionId"] and DeadpoolReceivedData["DeadpoolSessionId"] ~= DeadpoolGlobal_SessionId then
			if messageType == "SimpleData" then
				return
			else
				playerJoinsDeadpoolSession(DeadpoolReceivedData["DeadpoolSessionId"])
			end
		end
		if DeadpoolReceivedData[DeadpoolGlobal_SessionId] then
			checkBetsOnPlayerChanged(DeadpoolGlobal_SessionId, DeadpoolReceivedData)
			for index,value in pairs(DeadpoolReceivedData[DeadpoolGlobal_SessionId]) do
				if index == "DeadpoolSessionId" then -- Update admin config
					local actualData = DeadpoolData[DeadpoolGlobal_SessionId][index]
					local newData = DeadpoolReceivedData[DeadpoolGlobal_SessionId][index]
					local newValue, myValueWasObsolete = Deadpool_getMostRecentTimedValue(actualData, newData)
					DeadpoolData[DeadpoolGlobal_SessionId][index] = newValue
					if actualData ~= newData and not myValueWasObsolete then
						receivedDataWasObsolete = true
					end
					DeadpoolReceivedData[DeadpoolGlobal_SessionId][index] = nil
				elseif deadpoolAchievements[index]
					and DeadpoolReceivedData[DeadpoolGlobal_SessionId][index]
						and DeadpoolReceivedData[DeadpoolGlobal_SessionId][index]["achiever"] then
					local achievementChar, achievementTime = getDeadpoolData(DeadpoolGlobal_SessionId, index, "achiever", DeadpoolReceivedData)
					local precAchievementChar = getDeadpoolData(DeadpoolGlobal_SessionId, index, "achiever")
					if not precAchievementChar or precAchievementChar == "" then
						if not deadpoolAchievements[index][DEADPOOL_ISBESTACHIVERACHIEVEMENT] then
							local noNotif = (not DeadpoolOptionsData and not DeadpoolOptionsData["DeadpoolAchievementAnnounceDisabled"] and not (DeadpoolOptionsData["DeadpoolAchievementAnnounceDisabled"] == true))
								or (UnitGUID("boss1") and DeadpoolOptionsData["DeadpoolNotificationsInBossFightsDisabled"])
									or (C_ChallengeMode.IsChallengeModeActive() and not DeadpoolOptionsData["DeadpoolNotificationsInMythicPlus"])
							if achievementChar and noNotif then
								Deadpool:Print(string.format(L["NEW_TITLE_FOR"], achievementChar)..XITK.GetPunctuationSpace()..": "..deadpoolAchievements[index]["label"])
							end
							if CustomAchieverData and XITK.isPlayerCharacter(achievementChar) then
								CustAc_CompleteAchievement(index, nil, noNotif, DeadpoolOptionsData["DeadpoolSoundsDisabled"])
							elseif not noNotif and achievementTime and achievementTime + 60 > time() then -- If earned in the past minute
								EZBUP.ToastFakeAchievement(Deadpool, not DeadpoolOptionsData["DeadpoolSoundsDisabled"], 4, nil, deadpoolAchievements[index]["label"], 0, nil, false, string.format(L["NEW_TITLE_FOR"], achievementChar), true, function()  Deadpool:DeadpoolShow()  end)
							end
						else
							setDeadpoolData(DeadpoolGlobal_SessionId, index, "value", getDeadpoolData(DeadpoolGlobal_SessionId, index, "value", DeadpoolReceivedData))
						end
						if achievementChar then
							setDeadpoolData(DeadpoolGlobal_SessionId, index, "achiever", achievementChar)
						end
					end
					DeadpoolReceivedData[DeadpoolGlobal_SessionId][index] = nil
				else -- Update characters list data
					if not DeadpoolData[DeadpoolGlobal_SessionId][index] then -- If player has no data for character
						DeadpoolData[DeadpoolGlobal_SessionId][index] = DeadpoolReceivedData[DeadpoolGlobal_SessionId][index]
						DeadpoolReceivedData[DeadpoolGlobal_SessionId][index] = nil
					else
						for index2, value2 in pairs(DeadpoolReceivedData[DeadpoolGlobal_SessionId][index]) do
							if index2 == "bets" then
								local actualData = DeadpoolData[DeadpoolGlobal_SessionId][index][index2]
								local newData = DeadpoolReceivedData[DeadpoolGlobal_SessionId][index][index2]
								if not actualData or not actualData["dataTime"] then
									DeadpoolData[DeadpoolGlobal_SessionId][index][index2] = newData
								elseif newData then
									local newDataTime = DeadpoolReceivedData[DeadpoolGlobal_SessionId][index][index2]["dataTime"]
									if newDataTime and newDataTime > actualData["dataTime"] then
										DeadpoolData[DeadpoolGlobal_SessionId][index][index2] = newData
									else
										receivedDataWasObsolete = true
									end
								end
								DeadpoolReceivedData[DeadpoolGlobal_SessionId][index][index2] = nil
							else
								local actualData, actualDataTime = getDeadpoolData(DeadpoolGlobal_SessionId, index, index2)
								if actualData and actualDataTime then
									actualData = actualData.."|"..actualDataTime
								end
								local newData = tostring(DeadpoolReceivedData[DeadpoolGlobal_SessionId][index][index2])
								if actualData == nil or actualData ~= newData then
									--Deadpool:Print(time().." - Processing new data.", index2, newData)
									if index2 == "offItemsNumber" and (not actualData or newData > actualData) then
										if ((not UnitGUID("boss1") or not DeadpoolOptionsData["DeadpoolNotificationsInBossFightsDisabled"])
												and (not C_ChallengeMode.IsChallengeModeActive() or DeadpoolOptionsData["DeadpoolNotificationsInMythicPlus"])) then
											dpShowModel(index)
										end
									end
									
									local playerCharacter = XITK.playerCharacter()
									if index2 == DEADPOOL_TRULYUNEQUIP then
										local myValue, _ = strsplit("|", getDeadpoolData(DeadpoolGlobal_SessionId, playerCharacter, DEADPOOL_TRULYUNEQUIP) or "", 2)
										local receivedValue, _ = strsplit("|", newData, 2)
										if index == playerCharacter then -- Security to prevent data hacking on TRULYUNEQUIP
											playerTrulyUnequipValueChanged = myValue
										else
											if receivedValue == "true" and (not myValue or myValue == "" or myValue == "false") then
												someoneProposedTrulyUnequip = index
											end
										end
									end
									
									local newValue, myValueWasObsolete = Deadpool_getMostRecentTimedValue(actualData, newData, true)
									if index2 ~= DEADPOOL_TRULYUNEQUIP or index ~= playerCharacter then -- Security to prevent data hacking on TRULYUNEQUIP
										setDeadpoolData(DeadpoolGlobal_SessionId, index, index2, newValue)
									end
									if not myValueWasObsolete and actualData ~= newData then
										receivedDataWasObsolete = true
									end
									DeadpoolReceivedData[DeadpoolGlobal_SessionId][index][index2] = nil
								else
									if actualData == newData then
										DeadpoolReceivedData[DeadpoolGlobal_SessionId][index][index2] = nil
									end
								end
							end
						end
					end
				end
				if DeadpoolReceivedData[DeadpoolGlobal_SessionId][index] 
					and XITK.countTableElements(DeadpoolReceivedData[DeadpoolGlobal_SessionId][index]) == 0 then
					DeadpoolReceivedData[DeadpoolGlobal_SessionId][index] = nil
				end
			end
			if XITK.countTableElements(DeadpoolReceivedData[DeadpoolGlobal_SessionId]) == 0 then
				DeadpoolReceivedData[DeadpoolGlobal_SessionId] = nil
			end
		end
	end
	--Deadpool:Print(time().." - Data processed.")
	if receivedDataWasObsolete and messageType ~= "SimpleData" then
		encodeAndSendDeadpoolSessionInfo(DeadpoolData[DeadpoolGlobal_SessionId], DeadpoolReceivedData["Sender"], DeadpoolReceivedData["CallTime"])
	end
	if playerTrulyUnequipValueChanged then
		setUnequipItemsValue(playerTrulyUnequipValueChanged) -- Security to prevent data hacking on TRULYUNEQUIP
	end
	if someoneProposedTrulyUnequip and not DeadpoolOptionsData["NeverUnequip"] then
		if not DeadpoolOptionsData["LastUnequipProposedSession"] or DeadpoolOptionsData["LastUnequipProposedSession"] ~= DeadpoolGlobal_SessionId then
			--StaticPopup_Show("TRULY_UNEQUIP_ITEMS", someoneProposedTrulyUnequip)
			popDeadpoolYesNoDialog(someoneProposedTrulyUnequip, L["TRULY_UNEQUIP_ITEMS"],
				function (self)
					setUnequipItemsValue(true)
					DeadpoolTrulyUnequip_UpdateCooldown(DeadpoolTrulyUnequipSwitch)
					Deadpool:UnequipLostItems()
				end,
				function (self)
					setUnequipItemsValue(false)
				end)
			DeadpoolOptionsData["LastUnequipProposedSession"] = DeadpoolGlobal_SessionId
		end
	end
	generateDeadpoolTable()
end

function checkBetsOnPlayerChanged(aDeadpoolSessionId, newDeadpoolData)
	local player = XITK.playerCharacter()

	if player then
		local _, nbNextDeathBets = getDeadpoolTotalBets(aDeadpoolSessionId, "nextDeathBet", player)
		local _, newNbNextDeathBets = getDeadpoolTotalBets(aDeadpoolSessionId, "nextDeathBet", player, newDeadpoolData)
	
		local totalUniqueGambleOnChar, _ = getDeadpoolTotalUniqueGamble(aDeadpoolSessionId, player)
		local newTotalUniqueGambleOnChar, _ = getDeadpoolTotalUniqueGamble(aDeadpoolSessionId, player, newDeadpoolData)

		if nbNextDeathBets ~= newNbNextDeathBets or totalUniqueGambleOnChar ~= newTotalUniqueGambleOnChar then
			Deadpool:Print(L["DEADPOOLUI_BETSCHANGEDONCHAR"])
			XITK.PlaySound(865, "SFX", DeadpoolOptionsData["DeadpoolSoundsDisabled"])
		end
	end
end

function clearCharacterDeadpoolData(aFullName)
	if aFullName and DeadpoolData and DeadpoolData[DeadpoolGlobal_SessionId]
			and DeadpoolData[DeadpoolGlobal_SessionId][aFullName]
				and XITK.countTableElements(DeadpoolData[DeadpoolGlobal_SessionId][aFullName]) == 0 then
		DeadpoolData[DeadpoolGlobal_SessionId][aFullName] = nil
	end
end

function getDeadpoolData(aSession, aChar, anInfo, aDeadpoolDataObject)
	local value = nil
	local dataTime = nil

	if not aDeadpoolDataObject then
		aDeadpoolDataObject = DeadpoolData
	end

	if aSession and aChar and anInfo then
		if aDeadpoolDataObject 
			and aDeadpoolDataObject[aSession]
				and aDeadpoolDataObject[aSession][aChar] then
			value = aDeadpoolDataObject[aSession][aChar][anInfo]
			if value ~= nil then
				value, dataTime = strsplit("|", tostring(value), 2)
				if dataTime and dataTime == "" then
					dataTime = nil
				end
				if value == "nil" then
					value = nil
				end
			end
		end
	end
	return value, dataTime
end

function setDeadpoolData(aSession, aChar, anInfo, aValue)
	if aSession and aChar and anInfo then
		local value, dataTime = strsplit("|", tostring(aValue), 2)
		if not DeadpoolData then
			DeadpoolData = {}
		end
		if not DeadpoolData.DATA_ERROR then
			DeadpoolData.DATA_ERROR = {}
		end
		if not DeadpoolData[aSession] then
			DeadpoolData[aSession] = {}
		end
		if not DeadpoolData[aSession][aChar] then
			DeadpoolData[aSession][aChar] = {}
		end
		if not dataTime or dataTime == "" then
			dataTime = tostring(XITK.getTimeUTCinMS())
		end
		DeadpoolData[aSession][aChar][anInfo] = value.."|"..dataTime
	end
	DeadpoolGlobal_SessionCreator = DeadpoolGlobal_SessionId:match("^DeadpoolSession_([^%-]+%-%w+)") or DeadpoolGlobal_SessionId:match("^DeadpoolSession_(.+)$")
end

function getDeadpoolBets(aSession, aChar, aBetChar)
	local bet = 0
	local dataTime = nil
	local totalBets = 0
	local betsNumber = 0
	if aSession and aChar then
		if DeadpoolData
			and DeadpoolData[aSession]
				and DeadpoolData[aSession][aChar]
					and DeadpoolData[aSession][aChar]["bets"] then
			local bets = DeadpoolData[aSession][aChar]["bets"]
			if bets then
				for index,value in pairs(bets) do
					local readBet = XITK.tonumberzeroonblankornil(value["nextDeathBet"])
					if index == aBetChar then
						bet = readBet
						dataTime = value["dataTime"]
					end
					totalBets = totalBets + readBet
					if readBet > 0 then
						betsNumber = betsNumber + 1
					end
				end
			end
		end
	end
	return bet, dataTime, totalBets, betsNumber
end

function addDeadpoolBets(aSession, aChar, aBetChar, nextDeathBet)
	if aChar then
		if "unique" ~= nextDeathBet then
			local betToSend = XITK.tonumberzeroonblankornil(nextDeathBet)
			local playerBetsOnChar, _, _, playerBetsNumber = getDeadpoolBets(aSession, aChar, aBetChar)
			if playerBetsOnChar == 0 and playerBetsNumber >= Deadpool_maxBets then
				XITK.Error(Deadpool, Deadpool_name,string.format(L["DEADPOOLUI_MAXBETS"], Deadpool_maxBets))
				return
			end
			if not nextDeathBet then
				betToSend = XITK.tonumberzeroonblankornil(getDeadpoolData(aSession, aChar, "credits"))
				if betToSend > 0 then
					setDeadpoolBets(aSession, aChar, aBetChar, betToSend + playerBetsOnChar)
				else
					XITK.Error(Deadpool, Deadpool_name,L["DEADPOOLUI_NOMORECHIPS"])
				end
			elseif nextDeathBet == "0" then
				setDeadpoolBets(aSession, aChar, aBetChar, betToSend)
			else
				setDeadpoolBets(aSession, aChar, aBetChar, betToSend + playerBetsOnChar)
			end
		else
			setDeadpoolUniqueGamble(aSession, aChar, aBetChar)
		end
	end
end

function setDeadpoolBets(aSession, aChar, aBetChar, aNextDeathBet)
	if aSession and aChar and aBetChar and aNextDeathBet then
		if aChar == aBetChar and not DeadpoolGlobal_Debug then
			tellTutorialText("DEADPOOLTUTO_TUTO4")
			XITK.Error(Deadpool, Deadpool_name,L["SELF_BET_NOT_ALLOWED"])
		else
			Deadpool:CheckDeath()
			local unitInCombat = getDeadpoolData(aSession, aBetChar, "inCombat")
			local playerInCombat = UnitAffectingCombat("player") or UnitExists("boss1")
			if unitInCombat == "true" or playerInCombat then
				tellTutorialText("DEADPOOLTUTO_TUTO5")
				XITK.Error(Deadpool, Deadpool_name,L["UNIT_IN_COMBAT"])
			else
				local howManyGarmentToLose, afterTransactionCredits, nextDeathBet = howManyGarmentToLose(aSession, aChar, aBetChar, aNextDeathBet)
				if howManyGarmentToLose > 0 then
					local dialog = StaticPopup_Show("NOT_ENOUGH_CREDITS", howManyGarmentToLose, DEADPOOL_GARMENT_REWARD..deadpoolChipTextureString)
					dpShowModel(aChar, dialog)
					if (dialog) then
						dialog.data = {}
						dialog.data["session"] = aSession
						dialog.data["char"] = aChar
						dialog.data["betChar"] = aBetChar
						dialog.data["nextDeathBet"] = nextDeathBet
						dialog.data["afterTransactionCredits"] = afterTransactionCredits
						dialog.data["howManyGarment"] = howManyGarmentToLose
					end
				elseif afterTransactionCredits < 0 then
					XITK.Error(Deadpool, Deadpool_name,L["DEADPOOLUI_NOMORECHIPS"])
				else
					saveDeadpoolBets(aSession, aChar, aBetChar, aNextDeathBet, afterTransactionCredits)
				end
			end
		end
	end
end

function howManyGarmentToLose(aSession, aChar, aBetChar, aNextDeathBet)
	local howManyGarmentToLose = 0
	local oldNextDeathBet = 0
	local nextDeathBet = XITK.tonumberzeroonblankornil(aNextDeathBet)
	if not DeadpoolData then
		DeadpoolData = {}
	end
	if not DeadpoolData.DATA_ERROR then
		DeadpoolData.DATA_ERROR = {}
	end
	if not DeadpoolData[aSession] then
		DeadpoolData[aSession] = {}
	end
	if not DeadpoolData[aSession][aChar] then
		DeadpoolData[aSession][aChar] = {}
	end
	if not DeadpoolData[aSession][aChar]["bets"] then
		DeadpoolData[aSession][aChar]["bets"] = {}
	else
		if DeadpoolData[aSession][aChar]["bets"][aBetChar] then
			oldNextDeathBet = XITK.tonumberzeroonblankornil(DeadpoolData[aSession][aChar]["bets"][aBetChar]["nextDeathBet"])
		end
	end

	local playerCredits = XITK.tonumberzeroonblankornil(getDeadpoolData(aSession, aChar, "credits")) + oldNextDeathBet
	local afterTransactionCredits =  playerCredits - nextDeathBet

	if afterTransactionCredits < 0 then
		howManyGarmentToLose = -floor(afterTransactionCredits / DEADPOOL_GARMENT_REWARD)
	end

	local charLostItems = XITK.tonumberzeroonblankornil(getDeadpoolData(aSession, aChar, "offItemsNumber"))
	if charLostItems + howManyGarmentToLose > DEADPOOL_GARMENT_NUMBER then
		local overfull = charLostItems + howManyGarmentToLose - DEADPOOL_GARMENT_NUMBER
		howManyGarmentToLose = DEADPOOL_GARMENT_NUMBER - charLostItems
		nextDeathBet = playerCredits + howManyGarmentToLose * DEADPOOL_GARMENT_REWARD
		--afterTransactionCredits = 0
	end

	return howManyGarmentToLose, afterTransactionCredits, nextDeathBet
end

function setDeadpoolUniqueGamble(aSession, aChar, aBetChar)
	if aSession and aChar and aBetChar then
		local bankCredits = XITK.tonumberzeroonblankornil(getDeadpoolData(aSession, "Bank", "credits"))
		if bankCredits <= 0 then
			XITK.Error(Deadpool, Deadpool_name,L["EMPTY_BANK"])
		elseif aChar == aBetChar then
			tellTutorialText("DEADPOOLTUTO_TUTO4")
			XITK.Error(Deadpool, Deadpool_name,L["SELF_BET_NOT_ALLOWED"])
		else
			Deadpool:CheckDeath()
			local groupRank = getDeadpoolCharInfo(aBetChar, "groupRank")
			local unitInCombat = UnitAffectingCombat(groupRank)
			local playerInCombat = UnitAffectingCombat("player") or UnitExists("boss1")
			if unitInCombat or playerInCombat then
				tellTutorialText("DEADPOOLTUTO_TUTO5")
				XITK.Error(Deadpool, Deadpool_name,L["UNIT_IN_COMBAT"])
			elseif aBetChar ~= getDeadpoolData(aSession, aChar, "uniqueGamble") then
				DeadpoolTuto["chipPiles"] = "Done"
				if DEADPOOL_SOLEIL == getDeadpoolCharInfo(aChar, "localName") then
					XITK.Error(Deadpool, Deadpool_name,L["DEADPOOL_SOLEILBET"])
					Deadpool_dropAnItem(aChar, 1, true)
					Deadpool_updateStat(aSession, aChar, DEADPOOL_SOLEILBET, 1)
				end
				tellTutorialText("DEADPOOLTUTO_TUTO7")
				setDeadpoolData(aSession, aChar, "uniqueGamble", aBetChar)
				XITK.PlaySound(865, "SFX", DeadpoolOptionsData["DeadpoolSoundsDisabled"])
				prepareAndSendSimpleDeadpoolDataToRaid(DeadpoolGlobal_SessionId, aChar)
				generateDeadpoolTable()
			end
		end
	end
end

function saveDeadpoolBets(aSession, aChar, aBetChar, nextDeathBet, afterTransactionCredits)
	if DEADPOOL_SOLEIL == getDeadpoolCharInfo(aChar, "localName") and nextDeathBet > 0 then
		XITK.Error(Deadpool, Deadpool_name,L["DEADPOOL_SOLEILBET"])
		Deadpool_dropAnItem(aChar, 1, true)
		Deadpool_updateStat(aSession, aChar, DEADPOOL_SOLEILBET, 1)
	end
	DeadpoolTuto["chipPiles"] = "Done"
	tellTutorialText("DEADPOOLTUTO_TUTO2")
	local bets = {}
	bets["dataTime"] = tostring(XITK.getTimeUTCinMS())
	bets["nextDeathBet"] = nextDeathBet
	DeadpoolData[aSession][aChar]["bets"][aBetChar] = bets
	setDeadpoolData(aSession, aChar, "credits", afterTransactionCredits)
	XITK.PlaySound(865, "SFX", DeadpoolOptionsData["DeadpoolSoundsDisabled"])
	prepareAndSendSimpleDeadpoolDataToRaid(DeadpoolGlobal_SessionId, aChar)
	generateDeadpoolTable()
end

function Deadpool_updateStat(aDeadpoolSessionId, aChar, aStat, aValue)
	local isNotBoss = (aChar ~= "boss")
	local achievementPopped = false
	local statValue = XITK.tonumberzeroonblankornil(getDeadpoolData(aDeadpoolSessionId, aChar, aStat)) + aValue
	setDeadpoolData(aDeadpoolSessionId, aChar, aStat, statValue)
	if isNotBoss then
		local achiever = getDeadpoolData(aDeadpoolSessionId, aStat, "achiever")
		if not achiever or achiever == "" then
			if deadpoolAchievements[aStat] then
				if statValue >= deadpoolAchievements[aStat]["value"] then
					local noNotif = (not DeadpoolOptionsData and not DeadpoolOptionsData["DeadpoolAchievementAnnounceDisabled"] and not (DeadpoolOptionsData["DeadpoolAchievementAnnounceDisabled"] == true))
						or (UnitGUID("boss1") and DeadpoolOptionsData["DeadpoolNotificationsInBossFightsDisabled"])
							or (C_ChallengeMode.IsChallengeModeActive() and not DeadpoolOptionsData["DeadpoolNotificationsInMythicPlus"])
					if noNotif then
						Deadpool:Print(string.format(L["NEW_TITLE_FOR"], aChar)..XITK.GetPunctuationSpace()..": "..deadpoolAchievements[aStat]["label"])
					end
					if CustomAchieverData and XITK.isPlayerCharacter(aChar) then
						CustAc_CompleteAchievement(aStat, nil, noNotif, DeadpoolOptionsData["DeadpoolSoundsDisabled"])
					elseif not noNotif then
						EZBUP.ToastFakeAchievement(Deadpool, not DeadpoolOptionsData["DeadpoolSoundsDisabled"], 4, nil, deadpoolAchievements[aStat]["label"], 0, nil, false, string.format(L["NEW_TITLE_FOR"], aChar), true, function()  Deadpool:DeadpoolShow()  end)
					end
					setDeadpoolData(aDeadpoolSessionId, aStat, "achiever", aChar)
					achievementPopped = true
					prepareAndSendSimpleDeadpoolDataToRaid(DeadpoolGlobal_SessionId, aStat)
				end
			end
		end
	end
	return achievementPopped and isNotBoss
end

function Deadpool_prepareStats()
	local creator = "  "..(DeadpoolGlobal_SessionCreator or UNKNOWN).."|n"
	local winsStats = ""
	local gainsStats = ""
	local firstDeathStats = ""
	local deathsStats = ""
	local deathsOnBossStats = ""
	local lostItemsStats = ""
	local earningsStats = ""
	local lossesStats = ""
	for index,value in pairs(DeadpoolData[DeadpoolGlobal_SessionId]) do
		local stat = XITK.tonumberzeroonblankornil(getDeadpoolData(DeadpoolGlobal_SessionId, index, DEADPOOL_WINS))
		local highestStat = 0
		local highestStatPlayer = nil
		if stat > 0 then
			winsStats = winsStats.."  "..playerNameOrBankerName(index)..XITK.GetPunctuationSpace()..": "..stat.."|n"
		end
		stat = XITK.tonumberzeroonblankornil(getDeadpoolData(DeadpoolGlobal_SessionId, index, DEADPOOL_CREDITSGAIN))
		if stat > 0 then
			gainsStats = gainsStats.."  "..playerNameOrBankerName(index)..XITK.GetPunctuationSpace()..": "..stat..deadpoolChipTextureString.."|n"
		end
		stat = XITK.tonumberzeroonblankornil(getDeadpoolData(DeadpoolGlobal_SessionId, index, DEADPOOL_FIRSTDEATH))
		if stat > 0 then
			firstDeathStats = firstDeathStats.."  "..playerNameOrBankerName(index)..XITK.GetPunctuationSpace()..": "..stat.."|n"
		end
		stat = XITK.tonumberzeroonblankornil(getDeadpoolData(DeadpoolGlobal_SessionId, index, DEADPOOL_DEATHS))
		if stat > 0 then
			deathsStats = deathsStats.."  "..playerNameOrBankerName(index)..XITK.GetPunctuationSpace()..": "..stat.."|n"
		end
		stat = XITK.tonumberzeroonblankornil(getDeadpoolData(DeadpoolGlobal_SessionId, index, DEADPOOL_DEATHSONBOSS))
		if stat > 0 then
			deathsOnBossStats = deathsOnBossStats.."  "..playerNameOrBankerName(index)..XITK.GetPunctuationSpace()..": "..stat.."|n"
		end
		stat = XITK.tonumberzeroonblankornil(getDeadpoolData(DeadpoolGlobal_SessionId, index, DEADPOOL_LOSTITEMS))
		if stat > 0 then
			lostItemsStats = lostItemsStats.."  "..playerNameOrBankerName(index)..XITK.GetPunctuationSpace()..": "..stat.."|n"
		end
		stat = XITK.tonumberzeroonblankornil(getDeadpoolData(DeadpoolGlobal_SessionId, index, DEADPOOL_BALANCE))
		if stat > 0 then
			earningsStats = earningsStats.."  "..playerNameOrBankerName(index)..XITK.GetPunctuationSpace()..": "..stat..deadpoolChipTextureString.."|n"
		end
		if stat < 0 then
			lossesStats = lossesStats.."  "..playerNameOrBankerName(index)..XITK.GetPunctuationSpace()..": "..(-stat)..deadpoolChipTextureString.."|n"
		end
	end

	local stats = "|cFF00FF00"..L["DEADPOOLCOLLUMNS_STATS_CREATOR"].."|r|n"
	stats = stats..creator
	stats = stats.."|n|cFF00FF00"..L["DEADPOOLCOLLUMNS_STATS_WINS"].."|r|n"
	stats = stats..winsStats
	stats = stats.."|n|cFF00FF00"..L["DEADPOOLCOLLUMNS_STATS_CREDITSGAIN"].."|r|n"
	stats = stats..gainsStats
	stats = stats.."|n|cFF00FF00"..L["DEADPOOLCOLLUMNS_STATS_FIRSTDEATH"].."|r|n"
	stats = stats..firstDeathStats
	stats = stats.."|n|cFF00FF00"..L["DEADPOOLCOLLUMNS_STATS_DEATHS"].."|r|n"
	stats = stats..deathsStats
	stats = stats.."|n|cFF00FF00"..L["DEADPOOLCOLLUMNS_STATS_DEATHSONBOSS"].."|r|n"
	stats = stats..deathsOnBossStats
	stats = stats.."|n|cFF00FF00"..L["DEADPOOLCOLLUMNS_STATS_LOSTITEMS"].."|r|n"
	stats = stats..lostItemsStats
	stats = stats.."|n|cFF00FF00"..L["DEADPOOLCOLLUMNS_STATS_EARNINGS"].."|r|n"
	stats = stats..earningsStats
	stats = stats.."|n|cFF00FF00"..L["DEADPOOLCOLLUMNS_STATS_LOSSES"].."|r|n"
	stats = stats..lossesStats
	return stats
end

local InventorySlotsToUnequip = {}

function Deadpool_updateInventorySlotsToUnequip()
	local slotsToUnequipNb = XITK.tonumberzeroonblankornil(getDeadpoolData(DeadpoolGlobal_SessionId, XITK.playerCharacter(), "offItemsNumber"))
	InventorySlotsToUnequip = {}
	for i = 1, slotsToUnequipNb do
		tinsert(InventorySlotsToUnequip, deadpoolUndressingOrder[i]["slot"])
		if i > 6 then
			tinsert(InventorySlotsToUnequip, INVSLOT_TABARD)
			tinsert(InventorySlotsToUnequip, INVSLOT_BODY)
			tinsert(InventorySlotsToUnequip, INVSLOT_BACK)
		end
	end
end

-- Code by SDPhantom - https://www.wowinterface.com/forums/member.php?u=34145
function Deadpool_UnequipItems()
	if not UnitAffectingCombat("player") then
		local trulyUnequipItems = getDeadpoolData(DeadpoolGlobal_SessionId, XITK.playerCharacter(), DEADPOOL_TRULYUNEQUIP)
		if trulyUnequipItems and trulyUnequipItems == "true" then
			Deadpool_updateInventorySlotsToUnequip()
				
			if #InventorySlotsToUnequip<=0 then return end -- Sanity check
			local slotindex=1
		 
			ClearCursor() -- Make sure the cursor isn't holding anything, otherwise we might accidentally issue an item swap instead of an unequip
			for bag=NUM_BAG_SLOTS or NUM_TOTAL_EQUIPPED_BAG_SLOTS,0,-1 do -- CE and Wrath use NUM_BAG_SLOTS, DF uses NUM_TOTAL_EQUIPPED_BAG_SLOTS
				local free,type=(C_Container or _G).GetContainerNumFreeSlots(bag) -- C_Container is used in Wrath and DF, CE still has this in _G
				free=(type==0 and free or 0) -- Uses a quirk with this style of condition, only process bags with no item type restriction with fallback to zero if no bag is there (if free is nil, it'll fallback to zero even if the condition is true)
		 
				for _=1,free do -- Variable is unused, we just need to loop for every free slot we see
					local invslot=InventorySlotsToUnequip[slotindex] -- Cache slot mapped to current index
					while not GetInventoryItemID("player",invslot) do -- Loop if no item in slot and until we find one
						if slotindex<#InventorySlotsToUnequip then slotindex=slotindex+1 else return end-- Increment to next index or stop when we have no more inventory slots to process
						invslot=InventorySlotsToUnequip[slotindex] -- Update to new slot
					end
		 
					-- This pair is a complete operation, cursor is expected to be clear by the time both of these lines have run
					PickupInventoryItem(invslot);
					(bag==0 and PutItemInBackpack or PutItemInBag)((C_Container or _G).ContainerIDToInventoryID(bag)) -- First set of parenthesis chooses function to run before calling it, PutItemInBackpack() doesn't accept any args, so ContainerIDToInventoryID() is safe to run regardless
		 
					if slotindex<#InventorySlotsToUnequip then slotindex=slotindex+1 else return end -- Increment to next index or stop when we have no more inventory slots to process
				end
			end
		end
	end
end

function Deadpool_dropAnItem(aChar, numberOfItems, getNoNewCredits)
	local enoughItems = true
	local newCredits = 0
	local offItemsNumber = XITK.tonumberzeroonblankornil(getDeadpoolData(DeadpoolGlobal_SessionId, aChar, "offItemsNumber"))
	if not offItemsNumber then
		offItemsNumber = 0
	end
	if offItemsNumber + numberOfItems <= XITK.countTableElements(deadpoolUndressingOrder) then
		local credits = XITK.tonumberzeroonblankornil(getDeadpoolData(DeadpoolGlobal_SessionId, aChar, "credits"))
		if not getNoNewCredits then
			newCredits = DEADPOOL_GARMENT_REWARD * numberOfItems
		end
		setDeadpoolData(DeadpoolGlobal_SessionId, aChar, "offItemsNumber", offItemsNumber + numberOfItems)
		
		Deadpool_UnequipItems()
		
		Deadpool_updateStat(DeadpoolGlobal_SessionId, aChar, DEADPOOL_LOSTITEMS, numberOfItems)
		setDeadpoolData(DeadpoolGlobal_SessionId, aChar, "credits", credits + newCredits)
		DeadpoolSummaryFrame_Update()
		XITK.PlaySound(1202, "SFX", DeadpoolOptionsData["DeadpoolSoundsDisabled"])
	else
		XITK.Error(Deadpool, Deadpool_name,L["NOT_ENOUGH_ITEMS"])
		enoughItems = false
	end
	dpShowModel(aChar)
	return enoughItems, newCredits
end

function Deadpool_getMostRecentTimedValue(myValueTime, newValueTime, forceNew)
	local myValue, myDataTime, newValue, newDataTime
	local myValueIsObsolete = false

	if myValueTime then
		myValue, myDataTime = strsplit("|", myValueTime, 2)
	end
	if newValueTime then
		newValue, newDataTime = strsplit("|", newValueTime, 2)
		myValueIsObsolete = true
	end
	if myDataTime and newDataTime and myDataTime ~= "" and newDataTime ~= "" then
		myDataTime = tonumber(myDataTime)
		newDataTime = tonumber(newDataTime)
		if not forceNew and myDataTime >= newDataTime then
			newValue = myValue
			newDataTime = myDataTime
			myValueIsObsolete = false
		end
	end
	
	local returnedValue = newValue
	if newDataTime and newDataTime ~= "" then
		returnedValue = returnedValue.."|"..newDataTime
	end

	return returnedValue, myValueIsObsolete
end

function Deadpool_GetLocale(key)
	return L[key]
end

function isInstanceAtLevel(level)
	if level then
		local _, instanceType, difficultyID , _, _, _, _, instanceID, _, lfgDungeonID = GetInstanceInfo()
		if instanceType == "raid" then
			local minLevel, maxLevel, recLevel, minRecLevel, maxRecLevel
			if lfgDungeonID then
				_, _, _, minLevel, maxLevel, recLevel, minRecLevel, maxRecLevel = GetLFGDungeonInfo(lfgDungeonID)
			elseif instanceID and dpInstanceIDList[instanceID] then
				maxRecLevel = dpInstanceIDList[instanceID]
			end
			if maxRecLevel and level <= maxRecLevel then
				return true
			end
		end
	end
	return false
end

-- Fonction to check if item is in set
function Deadpool_isItemInSet(givenItemId, setName)
    local equipmentSetIDs = C_EquipmentSet.GetEquipmentSetIDs()
    for _, setID in ipairs(equipmentSetIDs) do
        local name = C_EquipmentSet.GetEquipmentSetInfo(setID)
        if name == setName then
            local items = C_EquipmentSet.GetItemIDs(setID)
            for _, itemID in pairs(items) do
                if itemID then
                    if givenItemId == itemID then
                        return true
                    end
                end
            end
        end
    end
    return false
end
