local me,ns=...
ns.Configure()
local addon=addon --#addon
--upvalue
local setmetatable=setmetatable
local rawset=rawset
local tContains=tContains
local wipe=wipe
local tremove=tremove
local tinsert=tinsert
local pcall=pcall
local type=type
local pairs=pairs
local format=format
-- Temporary party management
local empty={}
local parties=setmetatable({},{
	__index=function(t,k)  rawset(t,k,
		{
			members={},
			threats={},
			perc=0,
			itemLevel=0,
			followerUpgrade=0,
			xpBonus=0,
			gold=0,
			goldMultiplier=1,
			partyBuffs=empty,
			materialMultiplier=empty,
			resources=0,
			totalTimeString="Not Running",
			totalTimeSeconds=0
		}) return t[k] end
})
function ns.inParty(missionID,followerID)
	return tContains(ns.parties[missionID].members,followerID)
end
--- Follower Missions Info
--
local followerMissions=setmetatable({},{
	__index=function(t,k)  rawset(t,k,{}) return t[k] end
})
local function addPartyMissionInfo(desttable,missionID)
	if type(desttable) == "table" then
		desttable.totalTimeString,
		desttable.totalTimeSeconds,
		desttable.isMissionTimeImproved,
		desttable.perc,
		desttable.partyBuffs,
		desttable.isEnvMechanicCountered,
		desttable.xpBonus,
		desttable.materialMultiplier,
		desttable.goldMultiplier = G.GetPartyMissionInfo(missionID)
	end
end
ns.party={}
local party=ns.party --#party
local ID,maxFollowers,members,ignored,threats=0,1,{},{},{}
function party:Open(missionID,followers)
	maxFollowers=followers
	ID=missionID
	local mechanics=G.GetMissionUncounteredMechanics(ID)
	if (type(mechanics)=="table") then
		for enemy,menaces in pairs(mechanics) do
			for i=1,#menaces do
				tinsert(threats,format("%d:%d",enemy,menaces[i]))
			end
		end
	end
	holdEvents()
end
function party:Ignore(followerID)
	ignored[followerID]=true
end
function party:IsIgnored(followerID)
	return ignored[followerID]
end

function party:IsIn(followerID)
	return tContains(members,followerID)
end
function party:MaxSlots()
	return maxFollowers
end
function party:FreeSlots()
	return maxFollowers-#members
end
function party:CurrentSlot()
	return #members +1
end
function party:IsEmpty()
	return maxFollowers>0 and #members==0
end
function party:IsFull()
	return maxFollowers and #members>=maxFollowers
end

function party:Dump()
--[===[@debug@
	print("Dumping party for mission",ID)
	for i=1,#members do
		print(addon:GetFollowerData(members[i],'fullname'),G.GetFollowerStatus(members[i] or 1))
	end
	print(G.GetPartyMissionInfo(ID))
--@end-debug@]===]
end

function party:AddFollower(followerID)
	if (followerID:sub(1,2) ~= '0x') then ns.xtrace(followerID .. "is not an id") end
	if (self:FreeSlots()>0) then
		local rc,code=pcall (G.AddFollowerToMission,ID,followerID)
		if (not rc and code==false) then
			pcall(G.RemoveFollowerFromMission,ID,followerID)
			rc,code=pcall (G.AddFollowerToMission,ID,followerID)
		end
		if (rc and code) then
			tinsert(members,followerID)
			return true
		end
	end
end
function party:RemoveFollower(followerID)
	for i=1,maxFollowers do
		if (followerID==members[i]) then
			tremove(members,i)
			local rc,code=pcall(G.RemoveFollowerFromMission,ID,followerID)
--[===[@debug@
			if (not rc) then trace("Unable to remove", G.GetFollowerName(members[i]),"from",ID,code) end
--@end-debug@]===]
		return true end
	end
end

function party:StoreFollowers(table)
	wipe(table)
	for i=1,#members do
		tinsert(table,members[i])
	end
	return #table
end
local function fsort(a,b)
	--return addon:GetFollowerData(a,"rank")>addon:GetFollowerData(b,"rank")
	local rank1=addon:GetAnyData(0,a,"rank")
	local rank2=addon:GetAnyData(0,b,"rank")
	if tonumber(rank1) and tonumber(rank2) then
		return rank1 < rank2
	else
--[===[@debug@
		print(a,rank1)
		print(b,rank2)
		print(G.GetFollowerName(a))
		print(G.GetFollowerName(b))
--@end-debug@]===]
		return 0
	end
end
function party:Close(desttable)
	local perc
	table.sort(members,fsort)
	for i=1,#members do
		local bias=G.GetFollowerBiasForMission(ID,members[i])
		for _id,ability in pairs(G.GetFollowerAbilities(members[i])) do
			if not ability.isTrait then
				for counter,data in pairs(ability.counters) do
					for j=1,#threats do
						local enemy,threat,oldbias,follower,name=strsplit(":",threats[j])
						oldbias=tonumber(oldbias) or -2
						if bias >oldbias and tonumber(threat)==tonumber(counter) then
							threats[j]=format("%d:%d:%f:%s:%s",enemy,threat,bias or -2,members[i],G.GetFollowerName(members[i]))
						end
					end
				end
			end
		end
	end
	if (desttable) then
		addPartyMissionInfo(desttable,ID)
		desttable.full=self:FreeSlots()==0
		desttable.threats=desttable.threats or {}
		wipe(desttable.threats)
		for i=1,#threats do
			tinsert(desttable.threats,threats[i])
		end
		perc=desttable.perc
	else
		perc=select(4,G.GetPartyMissionInfo(ID))
	end
	for i=1,3 do
		if (members[i]) then
			local rc,code=pcall(G.RemoveFollowerFromMission,ID,members[i])
--[===[@debug@
			if (not rc) then print("Unable to pop", G.GetFollowerName(members[i])," from ",ID,code,debugstack()) end
--@end-debug@]===]

		else
			break
		end
	end
	releaseEvents()
	wipe(members)
	wipe(ignored)
	wipe(threats)
	return perc or 0
end
function addon:GetParties()
	return self:GetParty()
end

function addon:GetParty(missionID,key,default)
	if not missionID then return parties end
	local party=parties[missionID]
	party.missionID=missionID
	if not party then
--[===[@debug@
		print(GetTime(),missionID,G.GetMissionName(missionID),"Empty")
--@end-debug@]===]
	end
	if not party then return default end
	if #party.members==0 and self:GetMissionData(missionID,'inProgress') then
		party.perc=G.GetMissionSuccessChance(missionID)
		party.full=true
		local followers=self:GetMissionData(missionID,'followers')
		if followers then
			for i=1,#followers do
				party.members[i]=followers[i]
			end
		end
	end
	if key then
		if type(default)=="number" and type(party[key])~="number" then return default end
		return party[key] or default
	else
		return party
	end

end