local Rivenpacker =  Class(function(self, inst)
	self.inst = inst
	self.canpackfn = nil
	self.rivenpackage = nil
end)
function Rivenpacker:Hasrivenpackage()
	return self.rivenpackage ~= nil
end

function Rivenpacker:SetCanPackFn(fn)
	self.canpackfn = fn
end

function Rivenpacker.DefaultCanPackTest(target)
	return target
		and target:IsValid()
		and not target:IsInLimbo()
		and not (
			target:HasTag("teleportato")
			or target:HasTag("irreplaceable")
			or target:HasTag("player")
			or target:HasTag("nonpackable")
		)
end

function Rivenpacker:CanPack(target)
	return self.inst:IsValid()
		and (not target.components
			or not target.components.rivenpacker
			)
		and not self:Hasrivenpackage()
		and self.DefaultCanPackTest(target)
		and (not self.canpackfn or self.canpackfn(target, self.inst))
		and not target:HasTag("FX") and not target.components.circler
end

local function get_name(target,raw_name)
	local name = raw_name or target:GetDisplayName() or (target.components.named and target.components.named.name)
	if not name or name == "MISSING NAME" then return end
	if target.components.stackable then
		local size = target.components.stackable:StackSize()
		if size > 1 then
			name = name.." x"..tostring(size)
		end
	end
	return name
end

function Rivenpacker:Pack(target)
	if not self:CanPack(target) then
		return false
	end
	self.rivenpackage = {
		prefab = target.prefab,
		name = STRINGS.NAMES.RIVENPACKAGED..get_name(target),
	}
	self.rivenpackage.data, self.rivenpackage.refs = target:GetPersistData()
	target:Remove()
	return true
end

function Rivenpacker:GetName()
	return self.rivenpackage and self.rivenpackage.name
end

local function freshen_refs(self)
	if self.rivenpackage and self.rivenpackage.refs then
	end
end
function Rivenpacker:Unpack(pos)
	if not self.rivenpackage then return end
	pos = pos and Game.ToPoint(pos) or self.inst:GetPosition()
	freshen_refs(self)
	local target = shitswap(self.rivenpackage.prefab)
	if target then
		target.Transform:SetPosition( pos:Get() )
		local newents = {}
		if self.rivenpackage.refs then
			for _, guid in ipairs(self.rivenpackage.refs) do
				newents[guid] = {entity = _G.Ents[guid]}
			end
		end
		target:SetPersistData(self.rivenpackage.data, newents)
		local newents2=newents
		local savedata2=self.rivenpackage.data
		if newents2 and savedata2 and savedata2.childid then
			local child2 = newents2[savedata2.childid]
			if not child2 or not child.entity then
				newents[self.rivenpackage.data.childid]=nil
			end
		end 
		if newents2 and savedata2 then
		    for k,p in pairs(savedata2) do
		        local cmp = target.components[k]
		        if cmp and cmp.LoadPostPass then
		        	local savedata3 = p
		            if savedata3 and savedata3.childrenoutside then
		                for k,v in pairs(savedata3.childrenoutside) do
		                    local child = newents2[v]
		                    if not (child and child.entity) then
		                    	newents[v]=nil
		                    end
		                end
		            end
		        end
		    end
		end
		target:LoadPostPass(newents, self.rivenpackage.data)
		target.Transform:SetPosition( pos:Get() )
		self.rivenpackage = nil
		return true
	end
end
function Rivenpacker:OnSave()
	if self.rivenpackage then
		freshen_refs(self)
		return {rivenpackage = self.rivenpackage}, self.rivenpackage.refs
	end
end
function Rivenpacker:OnLoad(data)
	if data and data.rivenpackage then
		self.rivenpackage = data.rivenpackage
	end
end
return Rivenpacker