class 'ExtraReplayPageBase' (ExtraCollectionPageBase)

--[[
 * ExtraReplayPageBase - класс реализует коллекцию локаций для повторного прохождения.
--]]
function ExtraReplayPageBase:__init(extraScreen, name, order)
	ExtraCollectionPageBase.__init(self, extraScreen, name, order)

	self.levels			 = {}
	self.searchingTypes	 = {}
	self.lockPreviewName = 'lock'
end
-------------------------------------------------------------------------------

--[[
 * Переопределеный метод инициализации объектов предпросмотра. В методе происходит сначало
 * выборка локаций, отвечающих фильтру типов, а потом для каждой доступной локации создается
 * объект предпросмотра. Если локация не доступна, то в качестве объекта предпросмотра ставится
 * изображения замка. 
--]]
function ExtraReplayPageBase:initPreviews()
	self.levels = self:getLevels()
	self.count  = #self.levels
	self.index	= self:getStartIndex()

	self:getCurrentPreview():setOpacity(1)
end
-------------------------------------------------------------------------------

function ExtraReplayPageBase:getStartIndex()
	local lastReplayedScene = ExtraContentHelpers.getLastReplayedScene()

	if lastReplayedScene then
		for i, level in ipairs(self.levels) do
			if level.name == lastReplayedScene then
				ExtraContentHelpers.removeLastReplayedScene()
				return i
			end
		end
	end

	return self.index
end
-------------------------------------------------------------------------------

function ExtraReplayPageBase:getCurrentPreview()
	if not self.previews[self.index] then
		local info = self.levels[ self.index ]
		self.previews[self.index] = info.bEnable and self:createPreview( self.index )
												  or self:getEntityNamed( self.lockPreviewName )
	end

	return self.previews[self.index]
end
-------------------------------------------------------------------------------

--[[
 * Метод возвращает индексированную таблицу, содержащую данные про входящие в коллекцию локации.
 * Выборка локаций происходит из из глобальной таблицы локаций levels. Критерием отбора является
 * тип локации. Фильтр типов содержится в таблице searchingTypes.
--]]
function ExtraReplayPageBase:getLevels()
	local result = {}

	for level, levelInfo in pairs(levels) do
		if self:isRequiredLevel( levelInfo ) then
			local info = {}

			info.name	 = string.sub(level, 3)
			info.path	 = levelInfo.path
			info.tag	 = getLevelsGameStateTag( info.name )
			info.bEnable = self:isEnableLevel( info.name, info.tag )

			table.insert(result, info)
		end
	end

	local compare = function(info1, info2)
		return	(info1.tag == info2.tag and info1.name < info2.name) or
				(info1.tag ~= info2.tag and info1.tag == EGameStateTag.SE)
	end

	table.sort(result, compare)
	return result
end
-------------------------------------------------------------------------------

function ExtraReplayPageBase:onPreviewHided(index)
	local preview = self.previews[index]

	if (index ~= self.index) and preview and preview:getName() ~= self.lockPreviewName then
		preview:destroy()
		self.previews[index] = nil
	end
end
-------------------------------------------------------------------------------

--[[
 * Метод проверяет, относится ли локация из глобального списка levels к данной коллекции.
 * Решение принимается на основании вхождения типа локации в фильтр типов searchingTypes.
 * @param	levelInfo		Таблица, содержащая данные про локацию из глобального списка
 *							локаций levels
--]]
function ExtraReplayPageBase:isRequiredLevel(levelInfo)
	for i, searchingType in ipairs(self.searchingTypes) do
		if levelInfo.level_type == searchingType then
			return true
		end
	end

	return false
end
-------------------------------------------------------------------------------

--[[
 * Метод проверяет, доступна ли локация для повторного прохождения. По-умолчанию локация
 * считается доступной, если она была хоть раз загружена в основном игровом процессе.
 * @param	levelName		Имя проверяемой локации (без 'l_').
 * @param	tag				Раздел gameState, с которым связаны данная локация.
--]]
function ExtraReplayPageBase:isEnableLevel(levelName, tag)
	return self:isGameProgressCompleted(tag) or isSceneVisited(levelName, tag)
end
-------------------------------------------------------------------------------

function ExtraReplayPageBase:isGameProgressCompleted(gameProgressTag)
	return	(gameProgressTag == EGameStateTag.SE and HasGameState(SE_COMPLETED, 'true', EGameStateTag.GENERAL)) or
			(gameProgressTag == EGameStateTag.CE and HasGameState(CE_COMPLETED, 'true', EGameStateTag.GENERAL))
end
-------------------------------------------------------------------------------

--[[
 * Переопределенный метод получения имени объекта предпросмотра для локации, содержащайся
 * по указаному индексу в коллекции. В качестве уникальной части имени используется имя
 * локации.
 * @param	index		Индекс объекта предпросмотра в таблице previews данной коллекции.
--]]
function ExtraReplayPageBase:getPreviewName(index)
	local id = self.levels[index].name
	return string.format(self.previewNameFormat, id)
end
-------------------------------------------------------------------------------

--[[
 * Переопределенный метод получения пути к графическому файлу объекта предпросмотра.
 * В качестве уникальной части имени используется имя локации.
 * @param	index		Индекс объекта предпросмотра в таблице previews данной коллекции.
--]]
function ExtraReplayPageBase:getPreviewFilePath(index)
	local id = self.levels[index].name
	return string.format(self.previewFileFormat, index)
end
-------------------------------------------------------------------------------

--[[
 * Медтод возвращает таблицу, которая содержит необходимые для подготовки локации к
 * повторному прохождению настройки. Основными полями таблицы являются:
 * - applyTools -	перечень тулзов (tools), которые нужно пометить как примененные перед
 *					загрузкой локации. Это поле является тоже таблицей, содержащей поля
 *					toolName и targets.
 * - beforeStart -	функция, которая вызывается ПЕРЕД созданием локации. В этой функции
 *					при необходимости должна происходить нестандартая подготовка локации.
 *					Не обязательное поле.
 * - afterStart -	функция, которая вызывается ПОСЛЕ создания локации. В этой функции
 *					при необходимости должна происходить нестандартая настройка уже созданой
 *					локации. Не обязательное поле.
 * @param	sceneName		Имя локации, для которой необходимо получить таблицу настройки.
 * Метод должен быть переопределен в классе-наследнике от данного.
 *
 * Example:
	 	local config = {}

		if sceneName == '01_Piano' then
			config.applyTools =
			{
				{ toolName = '02_shawl',		targets = {'area_apply_tool_shawl'}			},
				{ toolName = '02_treble_clef',	targets = {'area_apply_tool_treble_clef'}	}
			}

			config.beforeStart = function(e)
				print('Test onStartCallback: '..e.sceneName)
			end

			config.afterStart = function(e)
				print('Test onStartCallback: '..e.playfield:getName())
			end
		end

		return config
--]]
function ExtraReplayPageBase:getSceneConfig(sceneName)
	local config = {}

	config.applyTools	= nil
	config.beforeStart	= nil
	config.afterStart	= nil
	--config.closeCondition	= nil

	return config
end
-------------------------------------------------------------------------------

--[[
 * Метод предначначен для выполения действий, необходимых для подготовки сцены к
 * повторному прохождению. Выполняется перед вызовом startLevel. В методе выполняется
 * применение необходимых тулзов и, при необходимости, выполнение произвольнх действий.
 * @param	sceneName		Имя сцены, которая будет запущена для повторного прохождения.
--]]
function ExtraReplayPageBase:prepareScene(sceneName)
	local config = self:getSceneConfig( sceneName )

	if config.applyTools then
		for i=1, #config.applyTools do
			local info		= config.applyTools[ i ]
			local toolName	= info.toolName
			local targets	= type(info.targets) == 'string' and {info.targets} or info.targets

			if targets then
				for _,targetName in ipairs(targets) do
					local state, value	= GenerateToolTargedUsed(toolName, targetName, sceneName)
					AddUniqueGameState(state, value)
				end
			end

			AddUniqueGameState(TOOL_APPLIED, toolName)
		end
	end

	if config.beforeStart then
		local event		= {}
		event.sceneName	= sceneName

		config.beforeStart(event)
	end
end
-------------------------------------------------------------------------------

--[[
 * Метод предначначен для выполения действий, необходимых для конфигурирования уже созданой
 * сцены таким образом, чтоб она отвечала требованиям бдя повторного прохождения. Выполняется
 * зразу после вызова глобальной функции startLevel.
 * @param	sceneName		Имя сцены, которая уже была создана и нуждается в конфигурировании
 *							для повторного прохождения.
--]]
function ExtraReplayPageBase:configurateScene(sceneName)
	local config	= self:getSceneConfig( sceneName )
	local playfield	= current_scene:getPlayField()

	if config.afterStart then
		local event		= {}
		event.sceneName	= sceneName
		event.playfield	= playfield

		config.afterStart(event)
	end
--[[
	if config.closeCondition then
		local action =	function()
							local bClose = config.closeCondition(playfield)

							if bClose then
								playfield:close()
							end
						end

		playfield:getMainEntity().onUpdate:add(	action )
	end
]]--
end
-------------------------------------------------------------------------------

function ExtraReplayPageBase:play()
   	local info  = self.levels[self.index]
    
    if info.bEnable then
    	local state = ProfilesManager:getCurrentProfile().gameState
		state:clear(EGameStateTag.EXTRA)
		setPrimaryGameStateTag(EGameStateTag.EXTRA)
		state:setState(PLAY_MODE, EPlayMode.CASUAL, EGameStateTag.EXTRA)

		ExtraContentHelpers.setLastReplayedScene( info.name )
		PopUpScreensMgr:destroyAll()

		self:prepareScene(info.name)
		startLevel('l_'..info.name)
		self:configurateScene(info.name)

		local config	= self:getSceneConfig( info.name )
		if config.completeCondition then
			local playfield = current_scene:getPlayField()
			local conn
			local updateCallback =	function()
										if current_scene and config.completeCondition(playfield) then
											conn:remove()
											current_scene:getMainEntity():setRespondable(false)
											if config.closeDelay then
												playfield.timer:add(function()
																		playfield:close()
																	end, config.closeDelay)
											else
												playfield:close()
											end
										end
									end

			conn = playfield:getMainEntity().onUpdate:add(updateCallback)
		end
	else
		local msg = StringManager:getString('CE_CONTENT_NOT_AVAILABLE')
		createOkScreen(msg, nil, false)
	end
end
-------------------------------------------------------------------------------