class 'Inventory' (Node)

local INVENTORY_CENTER_X = "InventoryCenterX"
local CELL_INDEX = "InvCellIndex_"
local TOOL_DOG_NAME = "dog"

function Inventory:__init(panel)
	Node.__init(self, panel:getMainEntity(), 'Inventory', order or 4)
	self.game_scene = panel.game_scene	

	self.settings = {
		[ 'DROP_MOVE_TIME' ] = 0.3,

		[ 'TOOL_NAME_TEXT_OFFSET_X' ] = 10,
		[ 'TOOL_NAME_TEXT_OFFSET_Y' ] = -30,

		[ 'TOOL_COUNTER_OFFSET' ] = {x = 5, y = 20},
		[ 'TOOL_COUNTER_FONT_SCALE' ] = 0.8,

    	[ 'ANCHOR_SCISSORS_TOP_X' ] = 176,
    	[ 'ANCHOR_SCISSORS_BOTTOM_X' ] = 848,
    	[ 'ANCHOR_SCISSORS_TOP_Y' ] = 698,

    	[ 'START_ANCHOR_POS' ] = { x = 512, y = 734 },

    	[ 'CELL_FULL_SIZE' ] = 64,
    	[ 'CELL_SMALL_SCALE' ] = 0.9,
    	[ 'CELL_SCALE_TIME' ] = 2/15,
    	[ 'CELL_WALL_WIDTH' ] = 3,

    	[ 'MIN_SHADOW_SHIFT' ] = 4,
    	[ 'MAX_SHADOW_SHIFT' ] = 12,

    	[ 'MAX_VELOCITY' ] = 300,
    	[ 'ACCELERATION' ] = 200,
    	[ 'STOP_ACCELERATION' ] = 1200,
    	[ 'MIN_EDGE_VELOCITY' ] = 4,
    	[ 'MAX_VISIBLE_TOOL_SHIFT' ] = 275,

    	[ 'TEXT_FONT' ] = 'Data/Fonts/Options.fnt',
	}

	--
    self.tools = {}
	self.tool_in_hand   = nil
	self.active_tools   = {}
	self.locked_tools   = {}
	self.flying_tools   = {}
	
	self.cells          = {}
	self.cells_next_unique_id   = 0;
	
	self.anchor         = nil
			
	self.hintedTool = nil

	self.velocity = 0
    self.colored = false
    self.is_full_icon_size = false
    
    self.cellsSizeEffectors = {}
    self.cellsColorOpacityEffectors = {}
    self.cellsGrayOpacityEffectors = {}
    -- self.cellsShadowOpacityEffectors = {}
    -- self.cellsShadowShiftEffectors = {}    
	
	-- Создаём таймер
	self.timer = Timer()
	
	-- Заставляем вызываться OnUpdate по сигналу
	local function update(entity, dt)
		self:onUpdate(dt)
	end
	self.game_scene:getWindow().onUpdate:add(update)
	
	-- Загружаем ресурсы
	if self.CreateLoaderTable then
		local table_resource = self:CreateLoaderTable()
		LoadScene(self.main_entity, table_resource)
	end

    self:getEntityNamed('area_rotate_left').onFocusIn:add(function() self.rotate_left = true end)
    self:getEntityNamed('area_rotate_left').onFocusOut:add(function() self.rotate_left = false end)
    self:getEntityNamed('area_rotate_right').onFocusIn:add(function() self.rotate_right = true end)
    self:getEntityNamed('area_rotate_right').onFocusOut:add(function() self.rotate_right = false end)

	-- Scissors - для отсечения области рендера тулзов
	self.anchor_scs = self:getEntityNamed('AnchorScissors')
	self.anchor_scs:setScissorBox(self.settings.ANCHOR_SCISSORS_TOP_X, self.settings.ANCHOR_SCISSORS_TOP_Y, self.settings.ANCHOR_SCISSORS_BOTTOM_X, WORK_H)
	self.anchor_scs:setAnimationSize(2000, 2000)
	self.anchor_scs:setColor(Colorf(0, 0, 0, 0))

	-- Anchors - к нему крепятся ячейки с тулзами
	self.anchor = self:getEntityNamed('ToolsAnchor')
	self.anchor:setAnimationSize(0, 0)
	self.anchor:setXY(self.settings.START_ANCHOR_POS.x, self.settings.START_ANCHOR_POS.y)

	-- Текст подсказка при наведении на тулзу
	self.hintText = self:getEntityNamed('HintOnTool')
	self.hintText:setVisible(false)	
	
	-- Загружаем все тулзы
	self:registerAllTools()

	self:restoreShift()
end
-------------------------------------------------------------------------------

function Inventory:postInit()
	-- Сбрасываем тулзу, если кликаем по инвентарю или панели
	local function try_to_drop_tool()
		if self.tool_in_hand then
			self:dropTool()
		end
	end
	
	self:getMainEntity():setHandlingChildEvents(true)
	self:getMainEntity().onClickBegin:add(try_to_drop_tool)
	
	self:getPanel():getControlsPanel():getMainEntity():setHandlingChildEvents(true)
	self:getPanel():getControlsPanel():getMainEntity().onClickBegin:add(try_to_drop_tool)
	
	self:getPanel():getControlsPanel():getHintAnimationLogic():getMainEntity():setHandlingChildEvents(true)
	self:getPanel():getControlsPanel():getHintAnimationLogic():getMainEntity().onClickBegin:add(try_to_drop_tool)
end
-------------------------------------------------------------------------------

function Inventory:getPlayField()
	return self.game_scene:getPlayField()
end
-------------------------------------------------------------------------------

function Inventory:getPanel()
	return self.game_scene:getPanel()
end
-------------------------------------------------------------------------------

function Inventory:getTimer()
	return self.timer
end
-------------------------------------------------------------------------------


function Inventory:createCell(tool_info)
	local index
	
	if tool_info then
		if HasGameState(CELL_INDEX..tool_info.name) then
			index = tonumber(GetGameState(CELL_INDEX..tool_info.name):get(0))
		else
			if tool_info.additional_info.collection then
				for _, name_tool in pairs(tool_info.additional_info.collection:get_tools()) do
					if HasGameState(CELL_INDEX..name_tool) then
						index = tonumber(GetGameState(CELL_INDEX..name_tool):get(0))
						AddGameState(CELL_INDEX..tool_info.name, index)
						break
					end
				end
			end
		end
		
		if index then			
			if self.cells[index] then				
				local info = self.cells[index]
				info.tool_info = tool_info
				return info
			end
		else
		    if tool_info.name == TOOL_DOG_NAME then
		        index = 1
		    else
			    index = math.ceil((#self.cells + 2)/2)
			end
		end
	else
		index = 1
	end

	local uniqueId = self.cells_next_unique_id
	
	local cellZ = 1
	
	local entity = CreateSpriteEntity('')
	entity:setAnimationSize(self.settings.CELL_FULL_SIZE, self.settings.CELL_FULL_SIZE)
	entity:attachTo(self.anchor)
	entity:setName('ToolHolder_'..uniqueId)
	entity:setXY(0, 0)
	entity:setOrder(cellZ)
	entity:setColor(1, 1, 1, 0.00392157)

	local cell_info = {
						cell_entity = entity,
						tool_info   = tool_info,
						eff         = nil,
						show        = false,
						actions     = nil
					  }
	
	if not self.cells[index] then
	    self.cells[index] = cell_info
    else		
	    table.insert(self.cells, index, cell_info)
	end
		
	for i = index, #self.cells do
	    if self.cells[i] and self.cells[i].tool_info then
		    SetGameState(CELL_INDEX..self.cells[i].tool_info.name, tostring(i))
		    
		    if self.cells[i].tool_info.additional_info.collection then
				for _, name_tool in pairs(self.cells[i].tool_info.additional_info.collection:get_tools()) do
					if HasGameState(CELL_INDEX..name_tool) then
						SetGameState(CELL_INDEX..name_tool, tostring(i))
					end
				end
			end
		end
	end

	self.cells_next_unique_id = self.cells_next_unique_id + 1
	
	return cell_info
end
-------------------------------------------------------------------------------

function Inventory:removeCell(tool_info)
	local cell_info, index = self:getCellInfoByToolInfo(tool_info)
	local cell_entity  = cell_info.cell_entity

	-- Удаляем все сигналы, которые связаны с ячейкой    
	if cell_info.actions then
		for i, v in pairs(cell_info.actions) do
			v:remove()
		end
		cell_info.actions = nil
	end

	if self.cellsSizeEffectors[tool_info] then
        self.cellsSizeEffectors[tool_info] = nil
    end	
    if self.cellsColorOpacityEffectors[tool_info] then
        self.cellsColorOpacityEffectors[tool_info] = nil
    end
    -- if self.cellsShadowOpacityEffectors[tool_info] then
    --     self.cellsShadowOpacityEffectors[tool_info] = nil
    -- end
    -- if self.cellsShadowShiftEffectors[tool_info] then
    --     self.cellsShadowShiftEffectors[tool_info] = nil
    -- end
		
	table.remove(self.cells, index)
	
	if HasGameState(CELL_INDEX..tool_info.name) then
	    RemoveGameState(CELL_INDEX..tool_info.name)
	end  
	if tool_info.additional_info.collection then
        for _, name_tool in pairs(tool_info.additional_info.collection:get_tools()) do
		    if HasGameState(CELL_INDEX..name_tool) then
			    RemoveGameState(CELL_INDEX..name_tool)
			end
		end    
	end
	
	for i = index, #self.cells do
		if self.cells[i].tool_info then
			SetGameState(CELL_INDEX..self.cells[i].tool_info.name, tostring(i))
		end
	end

	cell_entity:destroy()
end

function Inventory:checkCellsOpacity(time)
	--	Not Implemented
end

function Inventory:addTool(tool_info)
	local tool_ent = tool_info.entities.tool_ent
	local tool_gray_ent = tool_info.entities.tool_gray_ent
	--local tool_shadow_ent = tool_info.entities.tool_shadow_ent
	
	tool_ent:setVisible(true)
	tool_gray_ent:setVisible(true)
	--tool_shadow_ent:setVisible(true)

	self.active_tools[tool_info.name] = tool_info
	self:moveToolToFreeSlot(tool_info, 0)
	self:makeCellColored(tool_info, self.colored, 0)
end

function Inventory:takeTool(tool_info)
	tool_info.entities.tool_ent:attachTo(self:getMainEntity())

	tool_info.entities.tool_gray_ent:setVisible(false)
	--tool_info.entities.tool_shadow_ent:setVisible(false)
	
	self.tool_in_hand = tool_info
	if tool_info.additional_info.collection_text then
		tool_info.additional_info.collection_text:setVisible(false)
	end

	self:setCellAreaRespondable(self:getCellInfoByToolInfo(tool_info).cell_entity, false, 'TakeDrop')
	
	if tool_info.on_get then
		local event = {}
		event.toolName = name
		tool_info.on_get(event)
	end

	self:changeCellScale(tool_info, 0)
    self:makeCellColored(tool_info, true, 0)
	
	getHandledCursor():setState('CursorTool')
	getHandledCursor():lockState()
end

function Inventory:dropTool(custom_move_time)
	if self.tool_in_hand == nil then
		return
	end
	
	local time = 0
	local name = self.tool_in_hand.name
	
	self:moveToolToFreeSlot(self.tool_in_hand, time)

	if self.tool_in_hand.additional_info.collection_text then
		self.tool_in_hand.additional_info.collection_text:setVisible(true)
	end

	self:setCellAreaRespondable(self:getCellInfoByToolInfo(self.tool_in_hand).cell_entity, true, 'TakeDrop')
	self:changeCellScale(self.tool_in_hand, self:getCurrentSmallCellScale())
    self:makeCellColored(self.tool_in_hand, self.colored, 0)
	
	self.tool_in_hand = nil
	
	if getHandledCursor():stateIsLocked() then   
		getHandledCursor():unlockState()
		getHandledCursor():setState('CursorDefault')
	end
	
	if self.tools[name].on_drop then
		local event    = {}
		event.toolName = name
		
		self.tools[name].on_drop(event)
	end
end

function Inventory:removeTool(tool_info)
	if self.tool_in_hand and self.tool_in_hand.name == tool_info.name then
		local fade_time = 0.25
		local obj = self.tool_in_hand.entities.tool_ent
		
		self.tool_in_hand.entities.tool_ent:ChangeOpacity(1, 0, fade_time)
		self.tool_in_hand = nil
		
		self.timer:add(function() obj:destroy() end, fade_time)
		
		if getHandledCursor():stateIsLocked() then
			getHandledCursor():unlockState()
			getHandledCursor():setState('CursorDefault')
		end
	else
		tool_info.entities.tool_ent:destroy()
	end
	
	self.active_tools[tool_info.name] = nil
	self:removeCell(tool_info)
end

function Inventory:lockTool(tool_info)
	self.locked_tools[tool_info.name] = true
	
	if not self:isFlyingTool(tool_info) then
		tool_info.entities.tool_ent:setVisible(false)
		tool_info.entities.tool_gray_ent:setVisible(false)
		--tool_info.entities.tool_shadow_ent:setVisible(false)
		if tool_info.additional_info.collection_text then
			tool_info.additional_info.collection_text:setVisible(false)
		end
		if self:getCellInfoByToolInfo(tool_info).tool_info.name == tool_info.name then
			self:changeCellScale(tool_info, 0, 0)
		end
	end
end

function Inventory:unlockTool(tool_info)
	self.locked_tools[tool_info.name] = nil
	
	if not self:isFlyingTool(tool_info) then
		tool_info.entities.tool_ent:setVisible(true)
		tool_info.entities.tool_gray_ent:setVisible(true)
		--tool_info.entities.tool_shadow_ent:setVisible(true)
		if tool_info.additional_info.collection_text then
			tool_info.additional_info.collection_text:setVisible(true)
		end

		if self:getCellInfoByToolInfo(tool_info).tool_info.name == tool_info.name then
			self:changeCellScale(tool_info, self:getCurrentSmallCellScale())
        	self:makeCellColored(tool_info, self.colored, 0)
        end
	end
end

function Inventory:moveToolToFreeSlot(tool_info, time)
	local cell_info = self:getCellInfoByToolInfo(tool_info)
	
	-- Если для тулзы не найдена ячейка
	if not cell_info then
		-- Проверяем, входит ли тулза в коллекцию
		local collection = tool_info.additional_info.collection
		if collection then
			for _, t_name in ipairs( collection:get_tools() ) do
				if tool_info.name ~= t_name and self.active_tools[t_name] then
					cell_info = self:getCellInfoByToolInfo(self.active_tools[t_name])
					break
				end
			end
			
			-- Если попали сюда, то это первый тулз из коллекции
			tool_info.additional_info.collection_owner = true
		end
	
		--
		if not cell_info then
			cell_info = self:createCell(tool_info)
			self:changeCellScale(tool_info, self:getCurrentSmallCellScale(), 0)
		end

		tool_info.entities.tool_gray_ent:attachTo(cell_info.cell_entity)
		tool_info.entities.tool_gray_ent:setOrder(2)
		tool_info.entities.tool_gray_ent:setXY(0, 0)
		
		-- tool_info.entities.tool_shadow_ent:attachTo(cell_info.cell_entity)
		-- tool_info.entities.tool_shadow_ent:setOrder(1)
		-- tool_info.entities.tool_shadow_ent:setXY(self.settings.MIN_SHADOW_SHIFT, self.settings.MIN_SHADOW_SHIFT)
	end
	
	local cell_entity = cell_info.cell_entity
	tool_info.entities.tool_ent:setOrder(3)
	
	self.flying_tools[tool_info.name] = true
	
	if time == 0 then
		tool_info.entities.tool_ent:setScrXY(cell_entity:getScrX(),cell_entity:getScrY())
		self:onToolMoveToInventoryFinish(tool_info, cell_entity)
	else
		local eff = tool_info.entities.tool_ent:MoveTo(cell_entity:getScrX(), cell_entity:getScrY(), time, nil, true)
		self:lockTool(tool_info)
		self.timer:add( function()
							self:onToolMoveToInventoryFinish(tool_info, cell_entity)
							self:unlockTool(tool_info)
						end, time)
	end
end

function Inventory:onToolMoveToInventoryFinish(tool_info, target_cell_entity)
	self.flying_tools[tool_info.name] = nil
	
	local tool_ent = tool_info.entities.tool_ent
	local cell = self:getCellInfoByToolInfo(tool_info)
	
	-- Устанавливаем обработчик для взятия тулзы
	local function on_click_cell_check(cell_entity, info)
		if cell_entity then
			if self.tool_in_hand then
				self:dropTool()
			end
			
			local cell_info = self:getCellInfoByEntity(cell_entity)
			local new_tool = cell_info.tool_info
			
			if not self:isLockedTool(new_tool) and
			   not self:isFlyingTool(new_tool)
			then
				self:takeTool(new_tool)
			end
			
			self.hintText:setVisible(false)
	
			if not self:getPlayField():getMouseBlocker():isHold() then
				self:getPlayField():hideBlackBar()
			end
		end
	end
	
	-- Обработчик получения фокуса ячейкой
	local function on_cell_focus_in(cell_entity)
		if not self.tool_in_hand then			
			self.hintedTool = self:getCellInfoByEntity(cell_entity).tool_info

			self:changeCellScale(self.hintedTool, 1)
			
			self.hintText:setVisible(true)

			local text = StringManager:getString(self.hintedTool.texts.hint_text)
			if isUniqueTool(self.hintedTool.name) then
				text = getUniqueNamedTool(self.hintedTool.name)
			end

			self.hintText:setText(text)
		end
	end
	
	-- Обработчик потери фокуса ячейкой
	local function on_cell_focus_out(cell_entity)
		if self.hintedTool and cell_entity:isRespondable() then
			self:changeCellScale(self.hintedTool, self:getCurrentSmallCellScale())
		end

		self.hintedTool = nil
		self.hintText:setVisible(false)
	end
	
	tool_ent:destroyEffectors()
	tool_ent:attachTo(target_cell_entity)
	tool_ent:setOrder(2)
	tool_ent:setXY(0, 0)
	
	if cell.tool_info.name == tool_info.name then
		target_cell_entity:setCursorOverName('CursorActive')
		if not cell.actions then
			cell.actions = {}
			cell.actions['onClickBegin'] = target_cell_entity.onClickBegin:add(on_click_cell_check)
			cell.actions['onFocusIn'] = target_cell_entity.onFocusIn:add(on_cell_focus_in)
			cell.actions['onFocusOut'] = target_cell_entity.onFocusOut:add(on_cell_focus_out)
			target_cell_entity:setSendEventsToParent(false)
		end
		
		if self:isLockedTool(tool_info) then
			tool_ent:setVisible(false)
			tool_info.entities.tool_gray_ent:setVisible(false)
			--tool_info.entities.tool_shadow_ent:setVisible(false)
		else
			tool_ent:setVisible(true)
			tool_info.entities.tool_gray_ent:setVisible(true)
			--tool_info.entities.tool_shadow_ent:setVisible(true)
		end		
	else
		-- Если попали сюда, значить этот предмет летит в коллекцию		
		tool_ent:setVisible(false)
		tool_info.entities.tool_gray_ent:setVisible(false)
		--tool_info.entities.tool_shadow_ent:setVisible(false)
	end
	
	self:updateCollectionText(cell)
end

function Inventory:isActiveTool(tool_info)
	assert(tool_info)
	if self.active_tools[tool_info.name] then
		return true
	end
	
	return false
end

function Inventory:isFlyingTool(tool_info)
	assert(tool_info)
	return (self.flying_tools[tool_info.name] == true)
end

function Inventory:isLockedTool(tool_info)
	assert(tool_info)
	return (self.locked_tools[tool_info.name] == true)
end

function Inventory:getToolInHand()
	return self.tool_in_hand
end

function Inventory:getToolInfoByName(name)
	assert(name)
	return self.active_tools[name]
end

function Inventory:getCellInfoByEntity(entity)
	assert(entity)
	for i, info in pairs(self.cells) do
		if info.cell_entity:getName() == entity:getName() then
			return info
		end
	end
	
	return nil
end

function Inventory:getCellInfoByToolInfo(tool_info)
	assert(tool_info)
	for index, cell_info in pairs(self.cells) do
		if cell_info.tool_info then
			-- 
			if cell_info.tool_info.name == tool_info.name then
				return cell_info, index
				
			-- Поиск тулзы в коллекции
			elseif cell_info.tool_info.additional_info.collection then
				for i, t_name in pairs(cell_info.tool_info.additional_info.collection:get_tools()) do
					if t_name == tool_info.name and self:isActiveTool(cell_info.tool_info) then
						return cell_info, index
					end
				end
			end
		end
	end
	
	return nil, nil
end

function Inventory:checkSlideBtnsEnable()
	--	Not implemented
end

function Inventory:onToolFound(tool_info)
	self.active_tools[tool_info.name].notInInventoryYet = nil    
	tool_info.entities.tool_ent:setVisible(true)
end

function Inventory:onUpdate(dt)
	self.timer:update(dt)
	
	if self.tool_in_hand then
		local mouse_pos = GetCursorEntity():getScrPosition()
		self.tool_in_hand.entities.tool_ent:setScrXY(mouse_pos.x, mouse_pos.y)
		self.tool_in_hand.entities.tool_ent:setOrder(100) -- Можно уменьшить, если что
	end

	self:redrawCells(dt)
	
	self:updateHintText()
end

function Inventory:updateHintText()
	local cell_info
	if self.hintedTool then
		cell_info = self:getCellInfoByToolInfo(self.hintedTool)
	end
	
	if  cell_info
		and cell_info.tool_info
		and not self.tool_in_hand
		and not self:isFlyingTool(cell_info.tool_info)
		and not self:isLockedTool(cell_info.tool_info)
	then
		local tool_name = cell_info.tool_info.name
		local mouse = GetCursorEntity():getScrPosition()
		
		self.hintText:setScrXY(mouse.x + self.settings.TOOL_NAME_TEXT_OFFSET_X, mouse.y + self.settings.TOOL_NAME_TEXT_OFFSET_Y)
	end
end

function Inventory:registerAllTools()
	local auxRegisterTool = function(toolName, inv_path, gri_path, sdi_path, window_path, add_tmp_mark)
		assert(toolName and "All parameters haven't been specified!")
		
		local additional_info 			= {}
		additional_info.global_targets 	= getToolGlobalTargets(toolName)
		additional_info.collection 		= getCollectionTools(toolName)

		local function create_tool()
			local entity = CreateSpriteEntity(inv_path)
			entity:setName(toolName..TOOL_INVENTORY_SUFFIX)
			entity:setXY(512, 384)
			entity:setOrder(1)
			entity:setRespondable(false)
			
			if decorateToolSprite then
				decorateToolSprite(toolName, entity, false)
			end
				
			if add_tmp_mark then
				local tmp_mark = CreateSpriteEntity("")
				tmp_mark:setName(toolName..TOOL_INVENTORY_SUFFIX.."_tmp_mark")
				tmp_mark:setAnimationSize(10,10)
				WriteInfo("Temporaty tool mark created.")
				tmp_mark:setXY(-32, -32)
				tmp_mark:setColor(1,0,0,1)
				tmp_mark:setRespondable(false)
				tmp_mark:attachTo(entity)
			end
			
			return entity
		end

		local function create_tool_gray()
			local entity = CreateSpriteEntity(gri_path)
			entity:setName(toolName..TOOL_GRAY_SUFFIX)
			entity:setXY(512, 384)
			entity:setOrder(1)
			entity:setRespondable(false)
			return entity
		end
		
		-- local function create_tool_shadow()
		-- 	local entity = CreateSpriteEntity(sdi_path)
		-- 	entity:setName(toolName..TOOL_SHADOW_SUFFIX)
		-- 	entity:setXY(512, 384)
		-- 	entity:setOrder(1)
		-- 	entity:setRespondable(false)
		-- 	return entity
		-- end
		
		local function create_info_icon()
			local entity = CreateSpriteEntity(window_path)
			entity:setName(toolName..TOOL_WINDOW_SUFFIX)
			entity:setXY(512, 384)
			entity:setOrder(1)
			entity:setRespondable(false)
			
			if decorateToolSprite then
				decorateToolSprite(toolName, entity, true)
			end
			
			return entity
		end
		
		local create_entities_functions = {}
		create_entities_functions.create_tool = create_tool
		create_entities_functions.create_tool_gray = create_tool_gray
		create_entities_functions.create_tool_shadow = create_tool_shadow
		create_entities_functions.create_info_icon = create_info_icon
		
		self:registerTool(toolName, create_entities_functions, additional_info)
	end

	local function parseToolsFolders(toolFolder)
		local toolInfoVec = getResourceFolderSubfolders(toolFolder)
		for i = 0, toolInfoVec:size() - 1 do
			local path = toolInfoVec:get(i)
			local name_tool = ExtractFileName(path)
			local inv_path
			local gri_path
			local sdi_path
			local window_path
			local add_tmp_mark
			
			local iconsInfoVec = getResourceFolderFiles(path)
			
			for j = 0, iconsInfoVec:size() - 1 do
				local icon = iconsInfoVec:get(j)
				if string.find(icon, 'inv') then
					inv_path = icon					
				elseif string.find(icon, 'gri') then
					gri_path = icon
				elseif string.find(icon, 'sdi') then
					sdi_path = icon
				elseif string.find(icon, 'wnd') then
					window_path = icon
				elseif string.find(icon, 'tmp') then
					add_tmp_mark = true
				end
			end
			
			auxRegisterTool(name_tool, inv_path, gri_path, sdi_path, window_path, add_tmp_mark)
		end
	end

	local level_name = current_scene.name
	local toolsFolder = nil
	if IsLevelCollectorsEdition(level_name) then
		toolsFolder = TOOL_FOLDER_EXTRA
	else
		toolsFolder = TOOL_FOLDER
	end

	parseToolsFolders(toolsFolder)

	-- Добавляем в команду консоли поика тулзов.
	if isBuildForCustomerMode() == false then
		local command = Console:getCommand('findTool')
		if command then
			for tool_name, _ in pairs(self.tools) do
				if not IsToolFound(tool_name) then
					command:addPossibleParam(tool_name)
				end
			end
		end
	end
end

function Inventory:registerTool(tool_name, create_entities_functions, additional_info)
	-- Инициализация структуры
	local tool_info = {}
	tool_info.name = tool_name
	tool_info.create_entities_functions = table.copy(create_entities_functions)
	tool_info.additional_info = table.copy(additional_info)
	tool_info.texts = {}
	tool_info.texts.info_text = 'TOOL_INFO_' .. tool_name:upper()
	tool_info.texts.hint_text = 'TOOL_HINT_' .. tool_name:upper()
	tool_info.entities = {}

	-- Сохранение в общую таблицу
	self.tools[tool_name] = tool_info

	-- Добавляем ранее найденые тулзы в инвентарь
	if IsToolFound(tool_name) and not IsToolApplied(tool_name) then
		assert(tool_info.create_entities_functions.create_tool ~= nil)
		
		-- Создаём иконки
		tool_info.entities.tool_ent = tool_info.create_entities_functions.create_tool()
		tool_info.entities.tool_gray_ent = tool_info.create_entities_functions.create_tool_gray()
		--tool_info.entities.tool_shadow_ent = tool_info.create_entities_functions.create_tool_shadow()

		if HasGameState(TOOL_INFO_SHOWN, name) then
			self:addTool(tool_info)
		end
	end
end

function Inventory:getToolInfoCollectionOwner(tool_info)
	for i, v in	pairs(self.tools) do
		if v.additional_info.collection and v.additional_info.collection:is_exist_tool(tool_info.name) then
			if v.additional_info.collection_owner then
				return v
			end
		end
	end

	return nil
end

function Inventory:updateCollectionText(cell_info)
	local tool_info = self:getToolInfoCollectionOwner(cell_info.tool_info)
	local collection
	if tool_info then
		collection = tool_info.additional_info.collection
	end
	
	if collection then
		local size_tools_found  = collection:get_size_tools_found()
		local size_tools        = collection:get_size_tools()
		local text              = tostring(size_tools_found)..'/'..tostring(size_tools)
		local x                 = self.settings.TOOL_COUNTER_OFFSET.x
		local y                 = self.settings.TOOL_COUNTER_OFFSET.y
		
		if not tool_info.additional_info.collection_text then
			local collection_text = CreateTextEntity()
			collection_text:setFont			( self.settings.TEXT_FONT )
			collection_text:attachTo		( cell_info.cell_entity )
			collection_text:setXY			( x, y )
			collection_text:setScale		( self.settings.TOOL_COUNTER_FONT_SCALE )
			collection_text:setOrder		( 3 ) -- устанавливаем выше тени и тулзы
			collection_text:setRespondable	( false )
			--collection_text:hide()
		
			tool_info.additional_info.collection_text = collection_text
		end
		
		tool_info.additional_info.collection_text:setText(text)
	end
end

function Inventory:clearToolsEvents()
	for i, v in pairs(self.tools) do
		v.on_apply = nil
		v.on_get = nil
		v.on_drop = nil
		v.on_find = nil
		v.on_tool_window_close = nil
	end
end

----------------------------------------------------------------------------------
--	NEW METHODS
----------------------------------------------------------------------------------
function Inventory:setCellAreaRespondable(area, respondable, key)
	if not self.cell_area_respondable_keys then
		self.cell_area_respondable_keys = {}
	end

	local area_name = area:getName()

	if not self.cell_area_respondable_keys[area_name] then
		self.cell_area_respondable_keys[area_name] = {}
	end

	if not respondable then
        if self.cell_area_respondable_keys[area_name][key] == nil then
            self.cell_area_respondable_keys[area_name][key] = true
        else
            return
        end
    else
        if self.cell_area_respondable_keys[area_name][key] ~= nil then
            self.cell_area_respondable_keys[area_name][key] = nil
            
            if table.size(self.cell_area_respondable_keys[area_name]) > 0 then
                return
            end
        else
            return
        end
    end

    area:setRespondable(respondable)
end

function Inventory:makeAllCellsColored(colored, time)
    self.colored = colored
    
    for i = 1,#self.cells do
        if self.cells[i] ~= nil and self.cells[i].tool_info ~= nil and not self.locked_tools[self.cells[i].tool_info.name] then
        	if not self.tool_in_hand or self.tool_in_hand.name ~= self.cells[i].tool_info.name then
            	self:makeCellColored(self.cells[i].tool_info, colored, time) 
           	end
        end                
    end
    if colored then
    	self:getEntityNamed('InventoryRoot'):setRespondable(true)
    else
        self:getEntityNamed('InventoryRoot'):setRespondable(true)
    end
end

function Inventory:makeCellColored(tool_info, colored, time)
    local obj = tool_info.entities.tool_ent
    local obj_gray = tool_info.entities.tool_gray_ent
    --local obj_shadow = tool_info.entities.tool_shadow_ent
    
    local cell = self:getCellInfoByToolInfo(tool_info)
    
    if self.cellsColorOpacityEffectors[tool_info] then
        self.cellsColorOpacityEffectors[tool_info]:destroy()
        self.cellsColorOpacityEffectors[tool_info] = nil
    end

    if self.cellsGrayOpacityEffectors[tool_info] then
        self.cellsGrayOpacityEffectors[tool_info]:destroy()
        self.cellsGrayOpacityEffectors[tool_info] = nil
    end
    
    -- if self.cellsShadowOpacityEffectors[tool_info] then
    --     self.cellsShadowOpacityEffectors[tool_info]:destroy()
    --     self.cellsShadowOpacityEffectors[tool_info] = nil
    -- end
    
    targetOpacity = colored and 1 or 0
    currentOpacity = obj:getOpacity()
    
    local time_factor
    if time ~= nil then
        time_factor = time
    else
        time_factor = self.settings.CELL_SCALE_TIME
    end
    
    requiredTime = time_factor * math.abs(targetOpacity - currentOpacity)
    	
	local eff = CreateAnimationEffector()
    eff:attachTo(obj)
    eff:setKey(_TRACK_O, 0, currentOpacity)
    eff:setKey(_TRACK_O, requiredTime, targetOpacity)
    eff:play()      
    self.cellsColorOpacityEffectors[tool_info] = eff
    
    eff = CreateAnimationEffector()
    eff:attachTo(obj_gray)
    eff:setKey(_TRACK_O, 0, currentOpacity)
    eff:setKey(_TRACK_O, requiredTime, 1-targetOpacity)
    eff:play()      
    self.cellsGrayOpacityEffectors[tool_info] = eff
    
    -- eff = CreateAnimationEffector()
    -- eff:attachTo(obj_shadow)
    -- eff:setKey(_TRACK_O, 0, currentOpacity)
    -- eff:setKey(_TRACK_O, requiredTime, targetOpacity)
    -- eff:play()
    -- self.cellsShadowOpacityEffectors[tool_info] = eff
end

function Inventory:setIncreasedCellScale(value, time)
    self.is_full_icon_size = value and true or false
    
    local time_factor
    if time ~= nil then
        time_factor = time
    else
        time_factor = self.settings.CELL_SCALE_TIME
    end
    
    self:updateCurrentSmallCellScale(time_factor)
end

function Inventory:getCurrentSmallCellScale()
    return self.is_full_icon_size and 1 or self.settings.CELL_SMALL_SCALE
end

function Inventory:updateCurrentSmallCellScale(time)
    for i = 1,#self.cells do
        if self.cells[i] ~= nil and self.cells[i].tool_info and not self.locked_tools[self.cells[i].tool_info.name] then
            self:changeCellScale(self.cells[i].tool_info, self:getCurrentSmallCellScale(), time)
        end                
    end
    self:redrawCells(0)
end

function Inventory:changeCellScale(tool_info, targetScale, time)
	local cell_info, index = self:getCellInfoByToolInfo(tool_info)
	
    local obj = cell_info.cell_entity
    
    if self.cellsSizeEffectors[tool_info] then
        self.cellsSizeEffectors[tool_info]:destroy()
        self.cellsSizeEffectors[tool_info] = nil
    end    
    
    local time_factor
    if time ~= nil then
        time_factor = time
    else
        time_factor = self.settings.CELL_SCALE_TIME
    end

    local currentScale = obj:getScale().x
		
	local requiredTime = time_factor * math.abs(targetScale - currentScale)/(1-self.settings.CELL_SMALL_SCALE)
	    
    local onethirdScale = targetScale >= currentScale and currentScale + (targetScale-currentScale)*0.4 or currentScale + (targetScale-currentScale)*0.25
    local twothirdScale = targetScale >= currentScale and currentScale + (targetScale-currentScale)*0.75 or currentScale + (targetScale-currentScale)*0.6
	
	local eff = CreateAnimationEffector()
    eff:attachTo(obj)
    eff:setKey(_TRACK_SX, 0,            currentScale)
    eff:setKey(_TRACK_SY, 0,            currentScale)
    eff:setKey(_TRACK_SX, requiredTime*1/3,            onethirdScale)
    eff:setKey(_TRACK_SY, requiredTime*1/3,            onethirdScale)
    eff:setKey(_TRACK_SX, requiredTime*2/3,            twothirdScale)
    eff:setKey(_TRACK_SY, requiredTime*2/3,            twothirdScale)
    eff:setKey(_TRACK_SX, requiredTime,         targetScale)
    eff:setKey(_TRACK_SY, requiredTime,         targetScale)
    eff:play()      
    self.cellsSizeEffectors[tool_info] = eff
        
    --local obj_shadow = tool_info.entities.tool_shadow_ent
    
    -- if self.cellsShadowShiftEffectors[tool_info] then
    --     self.cellsShadowShiftEffectors[tool_info]:destroy()
    --     self.cellsShadowShiftEffectors[tool_info] = nil
    -- end	
    -- local function calculate_shadow_shift(scale)
    --     local scale = scale > 0 and scale or 0
    --     local res = self.settings.MIN_SHADOW_SHIFT + (self.settings.MAX_SHADOW_SHIFT - self.settings.MIN_SHADOW_SHIFT)*(1-scale)
    --     return res>self.settings.MIN_SHADOW_SHIFT and res or self.settings.MIN_SHADOW_SHIFT
    -- end
    -- local currentShadowShift = calculate_shadow_shift(currentScale)
    -- local onethirdShadowShift = calculate_shadow_shift(onethirdScale)
    -- local twothirdShadowShift = calculate_shadow_shift(twothirdScale)
    -- local targetShadowShift = calculate_shadow_shift(targetScale)
    -- eff = CreateAnimationEffector()
    -- eff:attachTo(obj_shadow)
    -- eff:setKey(_TRACK_X, 0,            currentShadowShift)
    -- eff:setKey(_TRACK_Y, 0,            currentShadowShift)
    -- eff:setKey(_TRACK_X, requiredTime*1/3,            onethirdShadowShift)
    -- eff:setKey(_TRACK_Y, requiredTime*1/3,            onethirdShadowShift)
    -- eff:setKey(_TRACK_X, requiredTime*2/3,            twothirdShadowShift)
    -- eff:setKey(_TRACK_Y, requiredTime*2/3,            twothirdShadowShift)
    -- eff:setKey(_TRACK_X, requiredTime,         targetShadowShift)
    -- eff:setKey(_TRACK_Y, requiredTime,         targetShadowShift)
    -- eff:play()      
    -- self.cellsShadowShiftEffectors[tool_info] = eff
end

function Inventory:restoreShift()
 	if HasGameState(INVENTORY_CENTER_X) then
		self.tools_center_x = tonumber(GetGameState(INVENTORY_CENTER_X):get(0))   
    end
    
    self:redrawCells(0, true)
end

function Inventory:redrawCells(dt, force_set_center)
    local tools_width = 0
    
    local tools_scales = {}
    
    for i = 1,#self.cells do
        if self.cells[i] ~= nil and self.cells[i].tool_info.name ~= nil then
            tools_scales[self.cells[i].tool_info.name] = self.cells[i].cell_entity:getScale().x
            tools_width = tools_width + (self.settings.CELL_FULL_SIZE + 2*self.settings.CELL_WALL_WIDTH) * tools_scales[self.cells[i].tool_info.name]
        end            
    end    
    
    local tools_center_x
    if self.tools_center_x == nil then
        tools_center_x = self.anchor:getX()
    else
        tools_center_x = self.tools_center_x
    end
    
    if self.tools_target_x == nil then
        self.tools_target_x = tools_center_x
    end
    
    if tools_width > 2*self.settings.MAX_VISIBLE_TOOL_SHIFT then
        if self.rotate_right then
            if self.velocity > - self.settings.MAX_VELOCITY then
                self.velocity = self.velocity - self.settings.ACCELERATION * dt
                if self.velocity < - self.settings.MAX_VELOCITY then
                    self.velocity = - self.settings.MAX_VELOCITY
                end
            end
        elseif self.rotate_left then
            if self.velocity < self.settings.MAX_VELOCITY then
                self.velocity = self.velocity + self.settings.ACCELERATION * dt
                if self.velocity > self.settings.MAX_VELOCITY then
                    self.velocity = self.settings.MAX_VELOCITY
                end
            end
        elseif self.velocity ~= 0 then
            local sign = self.velocity / math.abs(self.velocity)
            self.velocity = self.velocity - sign * self.settings.STOP_ACCELERATION * dt
            if sign * self.velocity < 0 then
                self.velocity = 0
            end
        end
    
        local max_shift = (tools_width - 2 * self.settings.CELL_WALL_WIDTH - 2 * self.settings.MAX_VISIBLE_TOOL_SHIFT)/2                                                                        
        
        if self.velocity > 0 then            
            if self.velocity > ((WORK_W/2 + max_shift) - tools_center_x) + self.settings.MIN_EDGE_VELOCITY then
                self.velocity = ((WORK_W/2 + max_shift) - tools_center_x) + self.settings.MIN_EDGE_VELOCITY
            end
        
            self.tools_target_x = self.tools_target_x + self.velocity * dt                                 
        elseif self.velocity < 0 then
            if self.velocity < ((WORK_W/2 - max_shift) - tools_center_x) - self.settings.MIN_EDGE_VELOCITY then
                self.velocity = ((WORK_W/2 - max_shift) - tools_center_x) - self.settings.MIN_EDGE_VELOCITY
            end
        
            self.tools_target_x = self.tools_target_x + self.velocity * dt           
        end     
        if self.tools_target_x > WORK_W/2 + max_shift then
            self.tools_target_x = WORK_W/2 + max_shift
            self.velocity = 0
        elseif self.tools_target_x < WORK_W/2 - max_shift then
            self.tools_target_x = WORK_W/2 - max_shift
            self.velocity = 0
        end
    else
        self.tools_target_x = WORK_W/2
    end        

    if self.tools_target_x ~= self.tools_center_x or force_set_center then
        if self.tools_target_x > tools_center_x then
            tools_center_x = tools_center_x + (self.settings.MIN_EDGE_VELOCITY + 2*(self.tools_target_x - tools_center_x)) * dt
            if tools_center_x > self.tools_target_x then
                tools_center_x = self.tools_target_x 
            end
        else
            tools_center_x = tools_center_x - (self.settings.MIN_EDGE_VELOCITY + 2*(tools_center_x - self.tools_target_x)) * dt
            if tools_center_x < self.tools_target_x then
                tools_center_x = self.tools_target_x 
            end
        end
        
        if tools_center_x ~= self.tools_center_x  or force_set_center then
            SetGameState(INVENTORY_CENTER_X, ''..tools_center_x)
        
            self.anchor:setX(tools_center_x)
            self.tools_center_x = tools_center_x
        end
    end    
    
    local tools_shift = -tools_width/2
    
    if self.tools_abs_x_poses == nil then
        self.tools_abs_x_poses = {}
    end
    if self.tools_opacities == nil then
        self.tools_opacities = {}
    end
    
    for i = 1,#self.cells do
        if self.cells[i] ~= nil and self.cells[i].tool_info.name ~= nil then                    
            local tool_obj = self.cells[i].cell_entity
        
            local tool_scale = tools_scales[self.cells[i].tool_info.name]
    
            local tool_x = tools_shift + tool_scale * (self.settings.CELL_FULL_SIZE + 2 * self.settings.CELL_WALL_WIDTH) / 2
        
            tools_shift = tool_x + tool_scale * (self.settings.CELL_FULL_SIZE + 2 * self.settings.CELL_WALL_WIDTH) / 2
        
            if tools_center_x + tool_x  ~= self.tools_abs_x_poses[self.cells[i].tool_info.name] then            
                self.tools_abs_x_poses[self.cells[i].tool_info.name] = tools_center_x + tool_x          
        
                local tool_opacity
                if (tool_x + tools_center_x < WORK_W/2 - self.settings.MAX_VISIBLE_TOOL_SHIFT - tool_scale * (self.settings.CELL_FULL_SIZE + self.settings.CELL_WALL_WIDTH) / 2) or (tool_x + tools_center_x > WORK_W/2 + self.settings.MAX_VISIBLE_TOOL_SHIFT + tool_scale * (self.settings.CELL_FULL_SIZE + self.settings.CELL_WALL_WIDTH) / 2) then
                    tool_opacity = 0
                else                                                 
                    tool_obj:setX(tool_x)
                
                    tool_opacity = 1
                    if tool_x + tools_center_x <= WORK_W/2 - self.settings.MAX_VISIBLE_TOOL_SHIFT then                    
                        tool_opacity = (tool_x + tools_center_x - (WORK_W/2 - self.settings.MAX_VISIBLE_TOOL_SHIFT - tool_scale * (self.settings.CELL_FULL_SIZE + self.settings.CELL_WALL_WIDTH) / 2)) / (tool_scale * (self.settings.CELL_FULL_SIZE + self.settings.CELL_WALL_WIDTH) / 2)                
                    elseif tool_x + tools_center_x >= WORK_W/2 + self.settings.MAX_VISIBLE_TOOL_SHIFT then
                        tool_opacity = ((WORK_W/2 + self.settings.MAX_VISIBLE_TOOL_SHIFT + tool_scale * (self.settings.CELL_FULL_SIZE + self.settings.CELL_WALL_WIDTH) / 2) - (tool_x + tools_center_x)) / (tool_scale * (self.settings.CELL_FULL_SIZE + self.settings.CELL_WALL_WIDTH) / 2)
                    end        
                    
                    tool_opacity = math.pow(tool_opacity, 0.4)
                
                    if tool_opacity>1 then
                        tool_opacity = 1
                    elseif tool_opacity<0 then
                        tool_opacity = 0
                    end
                        
                end
                if tool_opacity ~= self.tools_opacities[self.cells[i].tool_info.name] then
                    tool_obj:setOpacity(tool_opacity)
                    if tool_opacity > 0 then
                    	self:setCellAreaRespondable(tool_obj, true, 'OutOfVisibleZone')
                    else
                    	self:setCellAreaRespondable(tool_obj, false, 'OutOfVisibleZone')
                    end
                    self.tools_opacities[self.cells[i].tool_info.name] = tool_opacity
                end
            end
        end
    end
end

--------------------------------------------------------------------------------
--                      GENERATED CONTENT. DO NOT EDIT.                       --
--------------------------------------------------------------------------------

function Inventory:CreateLoaderTable()
	local objects =
	{
		{ name = 'InventoryRoot',  entityType = 'SpriteEntity',  x = 0,  y = 0,  order = 2,  color = {r = 1, g = 1, b = 1, a = 0.00392157},  editingLocked = false,  treeItemIsExpanded = true,  hotSpot = {x = 50, y = 50},  width = 100,  height = 100,  },
		{ name = 'AnchorScissors',  entityType = 'SpriteEntity',  parentName = 'InventoryRoot',  x = 0,  y = 0,  order = 5,  color = {r = 1, g = 1, b = 1, a = 0.00392157},  editingLocked = false,  treeItemIsExpanded = true,  hotSpot = {x = 50, y = 50},  width = 100,  height = 100,  },
		{ name = 'ToolsAnchor',  entityType = 'SpriteEntity',  parentName = 'AnchorScissors',  x = 0,  y = 0,  order = 0,  color = {r = 1, g = 1, b = 1, a = 0.00392157},  editingLocked = false,  treeItemIsExpanded = true,  hotSpot = {x = 50, y = 50},  width = 100,  height = 100,  },
		{ name = 'area_rotate_left',  entityType = 'SpriteEntity',  parentName = 'InventoryRoot',  x = 168,  y = 733,  order = 9,  isVisible = false,  editingLocked = false,  treeItemIsExpanded = true,  hotSpot = {x = 24, y = 36},  width = 48,  height = 72,  },
		{ name = 'area_rotate_right',  entityType = 'SpriteEntity',  parentName = 'InventoryRoot',  x = 856,  y = 733,  order = 9,  isVisible = false,  editingLocked = false,  treeItemIsExpanded = true,  hotSpot = {x = 24, y = 36},  width = 48,  height = 72,  },
		{ name = 'HintOnTool',  entityType = 'TextEntity',  x = 905,  y = 22,  order = 10,  isRespondable = false,  editingLocked = false,  treeItemIsExpanded = true,  localizationKey = 'EMPTY',  font = 'Data/Fonts/Options.fnt',  height = 26,  },
	}
	return objects
end
