function getLastVisitedScene(tag)
	tag = tag or getDefaultGameStateTag()

	if HasGameState(LAST_VISITED_SCENE, nil, tag) then
		return GetGameState(LAST_VISITED_SCENE, tag):get(0)
	end

	return nil
end
---------------------------------------------------------------------------------------------------

--[[
 * Функция определяет с какой локации нужно стартонуть игровой процесс. Если какая-либо локация
 * уже была запущена, то процесс будет начат с нее. Если нет - то вернется локация с индексом 1.
 * @param	tag		Раздел gameState, в котором будет осущестляться сохранение и загрузка.
--]]
function getLevelToLoad(tag)
	tag = tag or EGameStateTag.SE

	local levelName
	local lastVisitedScene = HasGameState(LAST_VISITED_SCENE, nil, tag)
	
	if lastVisitedScene then
		levelName = 'l_'..GetGameState(LAST_VISITED_SCENE, tag):get(0)
	else
		local index = (tag == EGameStateTag.CE) and '1_ce' or '1'
		levelName = levels_index_map[index]
	end
	return levelName, lastVisitedScene
end
---------------------------------------------------------------------------------------------------

--[[
 * Функция предназначена для запуска игрового процесса. В теле функции с помощью функции  getLevelToLoad
 * определяется какую локацию нужно загрузить.
 * @param	tag		Раздел gameState, в котором будет осущестляться сохранение и загрузка.
--]]
function startGame(tag)
	tag = tag or EGameStateTag.SE
	
	local level, lastVisitedScene = getLevelToLoad(tag)
	
	if lastVisitedScene then
		startLevel(level)
	else
		if tag == EGameStateTag.SE then
			createIntroScreen()
		else
			createIntroCEScreen()
		end
	end
end
---------------------------------------------------------------------------------------------------

--[[
 * Функция предназначена для запуска игрового процесса с указаной локации.
 * @param	levelClassName		Имя класса сцены в фомате: l_[номер_сцены]_[имя_сцены]
--]]
function startLevel(levelClassName)
	local levelName = string.sub(levelClassName, 3) 

	if current_scene then
		current_scene:loadPlayField( levelName )
	else
		current_scene = GameScene(levelName)
		PopUpScreensMgr:push(current_scene, false, nil)
	end
end
---------------------------------------------------------------------------------------------------

function getLevelClassName(levelName)
	return 'l_'..levelName
end
---------------------------------------------------------------------------------------------------

function IsLevelCollectorsEdition(name)
	assert(levels['l_'..name])
	return levels['l_'..name].collectors_edition
end
---------------------------------------------------------------------------------------------------

function isQuestLevel(name)
	assert(levels['l_'..name])
	return levels['l_'..name].mode == level_modes.quest
end
---------------------------------------------------------------------------------------------------

function isHiddenObjectLevel(name)
	assert(levels['l_'..name])
	return levels['l_'..name].mode == level_modes.hidden_object
end
---------------------------------------------------------------------------------------------------

function isMinigameLevel(name)          -- Тут идет проверка, старт в каком режиме идет?
	assert(levels['l_'..name])
	return levels['l_'..name].mode == level_modes.mini_game
end
---------------------------------------------------------------------------------------------------

function isMinigameLevelType(name)      -- Тут Идет првоерка, данный левел. это вообще мини-игра?
	assert(levels['l_'..name])
	return levels['l_'..name].level_type == level_modes.mini_game
end
---------------------------------------------------------------------------------------------------

function isHiddenPictureLevel(name)
	assert(levels['l_'..name])
	return levels['l_'..name].mode == level_modes.hidden_picture
end
---------------------------------------------------------------------------------------------------

function isSceneVisited(scene_name, tag)
	return HasGameState(SCENE_VISITED, scene_name, tag)
end
---------------------------------------------------------------------------------------------------

function isSceneClosed(scene_name, tag)
	return HasGameState(SCENE_CLOSED, scene_name, tag)
end
---------------------------------------------------------------------------------------------------

function isMiniGameCompleted(scene_name, tag)
	return HasGameState(MG_COMPLETED, scene_name, tag)
end
---------------------------------------------------------------------------------------------------

function isMinigameRoundCompleted(scene_name, round, tag)
	return HasGameState(MG_ROUND_COMPLETED, scene_name .. "_" .. round, tag)
end
---------------------------------------------------------------------------------------------------

function isCollectorsEdition()
	return IS_COLLECTORS_EDITION
end
---------------------------------------------------------------------------------------------------

function completeSE()
	local state = ProfilesManager:getCurrentProfile().gameState

	state:setState(CE_OPENED,	 'true', EGameStateTag.GENERAL)
	state:setState(SE_COMPLETED, 'true', EGameStateTag.GENERAL) 		-- Запоминаем еще сюда, чтобы в любой момент времени можна было проверить прошли ли мы вообще хоть раз CE
	state:setState(SE_COMPLETED, 'true', EGameStateTag.SE)
end
---------------------------------------------------------------------------------------------------

function completeCE()
	local state = ProfilesManager:getCurrentProfile().gameState
	state:setState(CE_COMPLETED, 'true', EGameStateTag.GENERAL)
	state:setState(CE_COMPLETED, 'true', EGameStateTag.CE)
end
---------------------------------------------------------------------------------------------------

function reopenScene(scene_name)
	if isSceneClosed(scene_name) then
		RemoveGameState(SCENE_CLOSED, scene_name)
		
		local play_field = current_scene:getPlayField()
		
		local node = path_manager:findNode(NodeType.SCENE, scene_name)
		-- assert(node and "Can't find scene node to reopen it")
		if node then
			node:setState(NodeState.ENABLED)
		else
			Console:pushText("Can't find scene node to reopen it")
		end

		for triggerName, linkInfo in pairs(play_field.linked_scenes) do
			if linkInfo.level_name == scene_name then
				play_field:setLinkMarkerActive(triggerName, true)
				play_field:getEntityNamed(triggerName):show()
			end
		end
	end
end
---------------------------------------------------------------------------------------------------

function getZoomZoneOfObject(objectName)
    if current_scene == nil then
        return nil    
    end
	local play_field = current_scene:getPlayField()
	
	if play_field.zones then
		for _, zoom in pairs(play_field.zones) do
			if zoom:hasEntityNamed(objectName) then
				return zoom
			end
		end
	end
	return nil
end
---------------------------------------------------------------------------------------------------

function destroyCurrentScene()
	if current_scene then
		current_scene:getWindow():destroy()
		
		if current_scene:getPlayField() then
			current_scene:getPlayField():destroy()
		end
		
		current_scene = nil
	end
end
---------------------------------------------------------------------------------------------------

function exitToMainMenu()
	PopUpScreensMgr:destroyAll()
	destroyCurrentScene()
	
	createMainMenu()
end
---------------------------------------------------------------------------------------------------

--[[
 * Функция устанавливает уникальный для сцены ключ, указывающий на окончание какого-либо действия.
 * @param	actionName		Произвольное название действия, окончание которого помечается.
 * @param	levelName		Название сцены, на которой произошло действие. По-умолчанию: имя текущей сцены.
--]]
function AddActionCompletedState(actionName, levelName)
	assert(levelName or current_scene)
	levelName = levelName or current_scene:getPlayField():getName()
	
	local value = levelName..'('..actionName..')'
	AddUniqueGameState(ACTION_COMPLETED, value)
end
---------------------------------------------------------------------------------------------------

--[[
 * Функция проверяет, установлен ли уникальный для сцены ключ, указывающий на окончание какого-либо действия.
 * @param	actionName		Произвольное название действия, окончание которого проверяется.
 * @param	levelName		Название сцены, на которой произошло действие. По-умолчанию: имя текущей сцены.
--]]
function HasActionCompletedState(actionName, levelName)
	assert(levelName or current_scene)
	levelName = levelName or current_scene:getPlayField():getName()
	
	local value = levelName..'('..actionName..')'
	return HasGameState(ACTION_COMPLETED, value)
end
---------------------------------------------------------------------------------------------------

--[[
 * Функция определяет раздел gameState, с которым необходимо работать при сохранении/закгрузке игрового
 * процесса для указаной локации. Раздел определяется по тому, относится ли локация к collectors edition
 * или нет.
 * @param    levelName      Название сцены, для которой определяется раздел gameState.
 *                          По-умолчанию: имя текущей сцены.
--]]
function getLevelsGameStateTag(levelName)
	assert(levelName or current_scene)
	levelName = levelName or current_scene:getName()

	local bCollectors = IsLevelCollectorsEdition( levelName )
	return bCollectors and EGameStateTag.CE or EGameStateTag.SE
end
---------------------------------------------------------------------------------------------------

--[[
 * Функция устанавливает раздел gameState, который будет приоритетным в методе получения tag по-умолчанию.
--]]
function setPrimaryGameStateTag(tag)
	PRIMARY_GAME_STATE_TAG = tag
end
---------------------------------------------------------------------------------------------------

--[[
 * Функция возвращает раздел gameState, который будет приоритетным в методе получения tag по-умолчанию.
--]]
function getPrimaryGameStateTag()
	return PRIMARY_GAME_STATE_TAG
end

-------------------------------------------------------------------------------
--[[
* Функция возвращает true если на локации остались какие-либо не отработанные узлы хинта
]]

function IsCompletedLocation(level_name)

    local current_node = path_manager:findNode(NodeType.SCENE, level_name)
    local result = true

    local function proceed_node(current_node) 
        for node, _ in pairs(current_node.connected_nodes) do
            if node.type ~= NodeType.SCENE then
                
                    if node.type == NodeType.LINK then
                       local scene_name = node.info
                       local level_type = levels['l_'..scene_name].level_type
                       if level_type == 'hidden_object' or level_type == 'hidden_picture' then
                             if not current_scene:getPlayField():IsHOCompleted(scene_name) then
                                result = false
                             end
                       elseif level_type == 'mini_game' then
                          if not isMiniGameCompleted(scene_name) then
                             result = false
                          end
                       end
                    else
                       if node.state 
							and node.state ~= NodeState.TRIGGERED 
							and node.type ~= NodeType.ZOOM
						then
                           result = false
                       end
                    end     
                    proceed_node(node)            
            end
        end
    end

    if current_node ~= nil then
        proceed_node(current_node)
    else
        result = false
    end

    return result
    
end

--------------------------------------------------------------------------
function IsThereSomethingToDo(level_name)

    local current_node = path_manager:findNode(NodeType.SCENE, level_name)
    local result = false

    local function checkNode(node)
          for local_node, _ in pairs(node.connected_nodes) do
              if local_node:isAccessible(true) and local_node.state == NodeState.ENABLED then
                 result = true
              else
              end
              checkNode(local_node)
          end
          
    end
    local function proceed_node(current_node) 
        if current_node:isAccessible(true) then
            for node, _ in pairs(current_node.connected_nodes) do
                if node:isAccessible(true) then
                    if node.type ~= NodeType.SCENE then
                        
                        proceed_node(node)
                        if ( node.type ~= NodeType.ZOOM) then
                            if node.type == NodeType.LINK then
                               local scene_name = node.info
                               local level_type = levels['l_'..scene_name].level_type
                               if level_type == 'hidden_object' or level_type == 'hidden_picture' or level_type == 'mini_game' then
                                  checkNode(node)
                                  
                               end
                            else
                               if node.state == NodeState.ENABLED then
                                  result = true
                               end
                            end
                                     
                        end                                       
                    end
                end
            end
        end
    end

    if current_node ~= nil then
        proceed_node(current_node)
    else
        result = false
    end

    return result
    
end

---------------------------------------------------------------------------------------------------