local Packer =  Class(function(self, inst)
	self.inst = inst

	self.canpackfn = nil

	self.package = nil
end)


function Packer:HasPackage()
	return self.package ~= nil
end

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

-- Note: does NOT take an object as 'self'.
function Packer.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

--inst.components.packer.package.prefab
function Packer:CanPack(target)
	return self.inst:IsValid()
		and (not target.components
			or not target.components.packer
			)
		and not self:HasPackage()
		and self.DefaultCanPackTest(target)
		and (not self.canpackfn or self.canpackfn(target, self.inst))
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

	--имена и так слишком длинные получаются
	--local adj = target:GetAdjective()
	--if adj then
	--	name = adj.." "..name
	--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 Packer:Pack(target)
	if not self:CanPack(target) then
	---	self:DebugSay("Refused to pack [", target, "].")
		return false
	end

---	self:DebugSay("Packing [", target, "].")

	self.package = {
		prefab = target.prefab,
		name = STRINGS.NAMES.PACKAGED..get_name(target),
	}
	
	--self. --Помечаем предмет, как холст
	
	--Жестко вмешиваемся в работу русификатора
	if(rawget(_G,"GAMELANGUAGE")=="RU" and target.prefab and STRINGS.NAMES[string.upper(target.prefab)]) then
		local base_name=STRINGS.NAMES[string.upper(target.prefab)]
		--Определяем пол и число предмета
		local gender="he"
		if (NamesGender["he2"][target.prefab]) then gender="he2"
		elseif (NamesGender["she"][target.prefab]) then gender="she"
		elseif (NamesGender["it"][target.prefab]) then gender="it"
		elseif (NamesGender["plural"][target.prefab]) then gender="plural"
		elseif (NamesGender["plural2"][target.prefab]) then gender="plural2"
		end
		local pack_str={ --приставлки для разных склоненией
			he={"Застывший ","Застывшему ","Застывший "},
			he2={"Застывший ","Застывшему ","Застывшего "},
			she={"Застывшая ","Застывшей ","Застывшую "},
			it={"Застывшее ","Застывшее ","Застывшему "},
			plural={"Застывшие ","Застывшим ","Застывшие "},
			plural2={"Застывшие ","Застывшим ","Застывших "},
		}
		local new_name = pack_str[gender][1]..get_name(target,base_name) --новое полное имя холста (включая приставку)
		self.package.name=new_name --переименовываем на новый лад
		if (russiannames[base_name]) then --если есть исключение в русификаторе, то
			--добавляем в таблицу исключений русификатора на основе существующего.
			--Пример: "Застывшие Семена x40".
			--print("new_name = "..new_name)
			russiannames[new_name]={
				WALKTO=pack_str[gender][2]..get_name(target,russiannames[base_name].WALKTO),
				DEFAULTACTION=pack_str[gender][3]..get_name(target,russiannames[base_name].DEFAULTACTION),
			}
			self.package.rus=russiannames[new_name] --Возобновляем поведение при сохранении и загрузке игры.
		--else print("No base name "..target.prefab.." "..base_name)
		--else --иначе
			--Не создаем исключение,
			--и указываем русификатору пол нового предмета, потому что префаб совпадает.
			--Название предмета оставляем с большой буквы, чтобы автосклонялка работала корректно.
			--Пример: "Застывшая Красная птица".
		end
	end
	

	self.package.data, self.package.refs = target:GetPersistData()

	target:Remove()

	--self:DebugSay("Packed.")

	return true
end

function Packer:GetName()
	return self.package and self.package.name
end


local function isValidGUID(guid)
	local inst = _G.Ents[guid]
	return inst and inst:IsValid()
end

local function freshen_refs(self)
	if self.package and self.package.refs then
	---	table.FilterArrayInPlace(self.package.refs, isValidGUID)
	end
end

function Packer:Unpack(pos)
	if not self.package then return end

	pos = pos and Game.ToPoint(pos) or self.inst:GetPosition()

	---self:DebugSay("Unpacking a ", self.package.prefab, " at ", pos, ".")

	freshen_refs(self)

	local target = SpawnPrefab(self.package.prefab)
	if target then
		target.Transform:SetPosition( pos:Get() )

		local newents = {}
		if self.package.refs then
			for _, guid in ipairs(self.package.refs) do
				newents[guid] = {entity = _G.Ents[guid]}
			end
		end

		target:SetPersistData(self.package.data, newents)
		target:LoadPostPass(newents, self.package.data)

		target.Transform:SetPosition( pos:Get() ) -- insurance
		self.package = nil
	--	self:DebugSay("Unpacked.")
		return true
	end
end


function Packer:OnSave()
	if self.package then
		freshen_refs(self)
		return {package = self.package}, self.package.refs
	end
end

function Packer:OnLoad(data)
	if data and data.package then
		self.package = data.package
		--Восстанавливаем таблицу исключений русификатора
		if (rawget(_G,"GAMELANGUAGE")=="RU" and self.package.rus) then
			russiannames[self.package.name]=self.package.rus
		end
	end
end


return Packer
