map_window = {}

-- смещение стрелочки по окну
map_window._arrow_offset = sf.misc.FloatVector(-20, -7)
-- ограничение для окон сострелочкой
map_window._arrow_limits = {left = 50, top = 50, right = 1020, bottom = 700}

-- приоритеты направлений
map_window._directions = {"right_bottom", "left_bottom", "right_top", "left_top", "left_top_m"}

map_window._fade_time = 110
map_window._show_time = 250

map_window._pre_ach_delay = 200
map_window._pre_ach_time = 0


-- количество пройденых уровней для активации режима головоломик
map_window._level_number_for_open_puzzle = 18
-- количество пройденных урвоней необходимое для активации бесконечного режима
map_window._level_number_for_open_endles = 9

-- иконка для обозначения того что уровень можно прокачать
map_window._level_up_icon_id = "screens_town_icon_level_replay"
map_window._level_up_icon_tooltip_id = "$303"
-- смещение иконки относительно кнопки
map_window._level_up_icon_offset = sf.misc.FloatVector(5, 55)

-- функция для загрузки настроек карты
function map_window._LoadConstants()
	local puzzle_info = g_App.GetSettings().GetChild("Constants", false).GetChild("puzzle_otpions", false)
	
	map_window._puzzle_levels_in_group = tonumber(puzzle_info.GetValue("levels_in_group").c_str())
	__assert(map_window._puzzle_levels_in_group, "ошибка загрузки кочличества одновременно открываемых уровенй puzzle")
	
	local map_info = g_App.GetSettings().GetChild("Constants", false).GetChild("map_options", false)
	
    -- id клипа для свечения кнопки следующего или сохраненного уровня
	map_window._button_glow_clip_id = map_info.GetChild("button_glow", false).GetValue("clip_id").c_str()
	__assert(map_window._button_glow_clip_id ~= "", "ошибка загрузки map_options/button_glow")
	
	-- изображения для залоченого мач уровня
	map_window._locked_level_image = map_info.GetChild("base_level_button", false).GetValue("image_id").c_str()
	__assert(map_window._locked_level_image, "ошибка загрузки map_options/base_level_button")

	-- изображение для следующего уровня
	map_window._next_level_image = map_info.GetChild("next_level_button", false).GetValue("image_id").c_str()
	__assert(map_window._next_level_image, "ошибка загрузки map_options/next_level_button")
	
	--- изображения для кнопок уровней
	local buttons_images = map_info.GetChild("buttons_images", false)
	map_window._progess_buttons_images = {}
	
	map_window._progess_buttons_images[3] = buttons_images.GetValue("blue").c_str()
	__assert(map_window._progess_buttons_images[3] ~= "", "ошибка загрузки buttons_images/blue")
	
	map_window._progess_buttons_images[2] = buttons_images.GetValue("yellow").c_str()
	__assert(map_window._progess_buttons_images[2] ~= "", "ошибка загрузки buttons_images/yellow")
	
	map_window._progess_buttons_images[1] = buttons_images.GetValue("green").c_str()
	__assert(map_window._progess_buttons_images[1] ~= "", "ошибка загрузки buttons_images/green")
	
	-- изображения для залоченого мач уровня
	map_window._locked_level_image = buttons_images.GetValue("base").c_str()
	__assert(map_window._locked_level_image ~= "", "ошибка загрузки buttons_images/base")
	
	-- изображение для следующего уровня
	map_window._next_level_image = buttons_images.GetValue("next").c_str()
	__assert(map_window._next_level_image ~= "", "ошибка загрузки buttons_images/next")

	
	local position = map_info.GetChild("button_position", false) 
	map_window._buttons_pos = map_window._LoadButtonOffsets(position)
	
	local puzzle_position = map_info.GetChild("puzzle_button_position", false) 
	map_window._puzzle_buttons_pos = map_window._LoadButtonOffsets(puzzle_position)

	local hard_position = map_info.GetChild("hard_button_position", false) 
	map_window._hard_buttons_pos = map_window._LoadButtonOffsets(hard_position)
	
end

function map_window._LoadButtonOffsets(_info_group)
	local buttons_offsets = {}
	
	--- расстояния между соседними кнопками
	buttons_offsets._space_x = tonumber(_info_group.GetValue("horizontal_space").c_str())
	__assert(buttons_offsets._space_x, "ошибка загрузки button_position/horizontal_space")
	buttons_offsets._space_y = tonumber(_info_group.GetValue("vertical_space").c_str())
	__assert(buttons_offsets._space_y, "ошибка загрузки button_position/vertical_space")
	
	--- смещение первой кнопки на закладке
	local offset_x = tonumber(_info_group.GetValue("offset_x").c_str())
	__assert(offset_x, "ошибка загрузки button_position/offset_x")
	local offset_y = tonumber(_info_group.GetValue("offset_y").c_str())
	__assert(offset_y, "ошибка загрузки button_position/offset_y")
	buttons_offsets._start_offset = sf.misc.FloatVector(offset_x, offset_y)
	return buttons_offsets
end

map_window._LoadConstants()
 
map_window._actions = {}

--- выход в главное меню
map_window._actions.menu_button = 
{
	pressed = function(_window) 
		s11.g_Achievements.Instance().SaveProfilesAchievements()
		main_menu.Show(nil, nil, nil, true)
	end
}

--- переход в город
map_window._actions.town_button = 
{
	pressed = function(_window) 
		town_window.Show()
	end
}

--- кнопка "Play"
map_window._actions.play_button = 
{
	pressed = function(_window) 
		-- проверяем что известен следующий уровень
		if not map_window._next_dif_level or not map_window._next_level_index then
			-- если следующий уровень неизвестен то ругаемся и не запускаем ничего
			__message("Unknown next level info")
			return
		end
		-- запускаем следующий уровнеь
		map_window._RunLevel(map_window._next_dif_level, map_window._next_level_index, map_window._load_game_on_play_button)
	end
}

function map_window.OnChildAction(_this, _action, _child)
	if not _child then return end
	local handler = map_window._actions[_child.GetId().c_str()]
	if handler then handler = handler[_action.c_str()] end
	if handler then handler(_this, _child) 

	elseif _action.c_str() == "lost_over" then
		button_id = _child.GetId().c_str()
		if map_window._info_window_widget and map_window._info_window_level_id == button_id then
			map_window._CloseInfoWindow()
		end
	
	elseif _action.c_str() == "overed" then
		button_id = _child.GetId().c_str()
		
		-- пытаемся приветсти id нажатой кнопки к координатам урвоня
		local dif_level, level_index = map_window._GetLevelIndexesByButtonId(_child.GetId().c_str())
		if dif_level == nil or level_index == nil then
			-- если неудалось, то выходим
			return
		end
		__sound("map_button_over")
		local offset = _child.GetAbsPos(true) + _child.GetSize()/2
		map_window._OpenLevelInfoWindow(dif_level, level_index, button_id, offset)
	elseif _action.c_str() == "pressed" then
		button_id = _child.GetId().c_str()
		
		-- пытаемся приветсти id нажатой кнопки к координатам урвоня
		local dif_level, level_index = map_window._GetLevelIndexesByButtonId(_child.GetId().c_str())
		if dif_level == nil or level_index == nil then
			-- если неудалось, то выходим
			return
		end
		__sound("map_button_press")
		-- если удалось получить координаты уровня, то запускаем его
		map_window._RunLevel(dif_level, level_index)
	elseif _action.c_str() == "panel_selected" then
		
		local tab_widget = __cast(_child, sf.gui.CTabWidget)
		local tab_index = tab_widget.GetSelectedPanel()
		if tab_index > 0 and map_window._tabs_close_table[tab_index] then
			tab_widget.SelectPanel(map_window._last_tab or 0)
			--__message(tostring("Tutorial on dif level"))
			if tab_index == 1 then
				dialog_do_modal("hard_disable_dialog", map_window._self)
			elseif tab_index == 2 then
				dialog_do_modal("expert_disable_dialog", map_window._self)
			end
		end
		map_window._last_tab = tab_widget.GetSelectedPanel()
		
	end
end

--- запуск диалога про уровень
--- в текст лейбла message_label будут подставлены параметры _dif_level, _level_index
function map_window._ShowLevelDialog(_dialog_id, _dif_level, _level_index )
	-- получаем номер главы и уровня в ней
	local level = map_window._levels_struct.GetLevel(_dif_level, _level_index)
	if not level then
		__message("Unknown level index "..tostring(_level_index)..", dif_index "..tostring(_dif_level))
		return 0
	end
	local chapter_index = level.GetChapterIndex()
	local level_index_in_chapter = level.GetLevelIndexInChapter()

	local dialog = sf.gui.CWindow()

	dialog.Load(
		g_App.GetSettings().GetChild("GUI", false).GetChildByAttribute("window", "id", _dialog_id, true), 
		g_App.GetSettings().GetChild("GUITemplates", false))
	dialog.UpdateLayout()
	
	local label_widget = get_child_widget(dialog, "message_label", sf.gui.CLabelWidget)
	if not label_widget then
		__message("Label message_label not found in continue_game_dialog window")
		return
	end

	label_widget.SetText(s11.StringFormat(label_widget.GetText(), map_window._levels_struct.GetLevelName(_dif_level, _level_index))) 
	
	
	return dialog_do_modal(dialog, map_window._self)
end

-- функция, которая проверяет можно ли играть в уровень
function map_window._IsMatchLevelPlayable(_dif_level, _level_index)
	local level = map_window._levels_struct.GetLevel(_dif_level, _level_index)

	if __cast(level, s11.CHogLevelInfo) then
		return true
	end

	local match_level = __cast(level, s11.CMatchLevelInfo)

	if not match_level then
		return true
	end
	
	local dep_count = match_level.EnumDependences()
	if	dep_count == 0 then
		return true
	end
	__assert(dep_count == 1, "too many dependences")
		
	if map_window._current_profile.GetLevelProgress(_dif_level, _level_index).IsFinished() then
		return true
	end

	local current_dep = match_level.GetDependences().Get()
		
	local dep_item_id = current_dep.BuildingId.c_str()
	local dep_item_level = current_dep.BuildingLevel

	local player_item_level = map_window._current_profile.GetItemLevel(dep_item_id)

	__assert(player_item_level ~= -1, "Wrong dependence id :"..current_dep.BuildingId.c_str())

	if player_item_level < dep_item_level then
		return false
	end
	return true
end

--- функция, запускающая следующий уровень
function map_window._RunLevel(_dif_level, _level_index, _load)
	-- проверяем, что уровень можно запускать
	if not map_window._IsMatchLevelPlayable(_dif_level, _level_index) then
		-- если нельзя запускать то город показваем
		town_window.Show()
		return
	end
	local load_game = _load
	--- проверяем загружаем мы игру или нет
	if not load_game then
		-- если не загружаем, то смотрим есть ли сохраненная игра
		if map_window._current_profile.HasSavedLevelInfo() then
			-- если есть сохраенная игра
			-- получаем координаты сохраненного уровня
			local level_index = map_window._current_profile.GetSavedLevelIndex()
			local dif_level_index = map_window._current_profile.GetSavedLevelDifficulty()
			
			if _dif_level == dif_level_index and level_index == _level_index then
				--- если они совпадают с запускаемым, то показываем диалог о загрузке или перезапуске уровня
				local res = map_window._ShowLevelDialog("load_or_new_level_dialog", dif_level_index, level_index )
				if res == 1 then -- нажали загрузить уровень
					-- устанавливаем флаг того что уровень будет загружен
					load_game = true
				end
				if res == 2 then -- нажали отмену
					return
				end
			else
			    -- если запускаем отличный от сохраненного уровень то вызываем диалог подтвержения
				local res = map_window._ShowLevelDialog("new_level_dialog", dif_level_index, level_index )
				if res == 0 then -- если игрок не хочет затирать сохранение то выходим
					return
				end
			end
		end
	end
	
	-- получаем следующий уровень
	local level = map_window._levels_struct.GetLevel(_dif_level, _level_index)
	if not level then
		return
	end
	
	-- пытаемся привести уровень к мач-уровню
	if __cast(level, s11.CMatchLevelInfo) then
		if map_window._puzzle_mode then
			if not load_game then
				map_window._current_profile.DropSavedLevelInfo()
			end
			-- если удалсоь, то запускаем уровень
			puzzle_window.LoadLevelhints(_dif_level, _level_index)
			puzzle_window.Show(_dif_level, _level_index, load_game)

		else
			-- если удалсоь, то запускаем уровень
			game_window.Show(_dif_level, _level_index, load_game)
		end
		return
	end

	-- пытаемся привести уровень к хог-уровню
	if __cast(level, s11.CHogLevelInfo) then
		-- если удалсоь, то запускаем уровень
		hog_window.Show(_dif_level, _level_index, load_game)
		return
	end
	__message("Unknown level type")
end

--- открытие окна карты
function map_window.Show(_show_saved_game_dialog, _unload_resources)

	s11.g_GameBackground.Instance().DisableSounds(true)

	---- выбрал место где кеширваоние клипа начала уровня не будет сильно мешать
	start_level_effect.FormStartClipsChache()
	
	visual_effects.PreCacheClips()

	local window = __ChangeWindowWithEffect(nil, _unload_resources)
	if not window then
		return
	end
	map_window.OnShowWindow = nil
	
	sf.core.g_Application.GetTimeManager().GetTimer("game_timer").SetK(1)
	map_window._last_tab = nil
	
	map_window._timer = sf.core.CTimerWrapper(sf.core.g_Application.GetTimeManager().GetTimer("game_timer").AttachTimer(""))
	map_window._pre_ach_time = map_window._pre_ach_delay

	
	local buttons_pos  = map_window._buttons_pos
	
	map_window._puzzle_mode = nil
	map_window._levels_struct = s11.g_GameStruct.Instance().GetLevelsSystem(s11.CGameStruct.GameTypeClassic)
	
	map_window._skip_dialog_show = true
	map_window._info_window_widget = nil
	map_window._info_window_level_id = nil
	map_window._tabs_close_table = {}

	map_window._LoadConstants()
	window.Load(
		g_App.GetSettings().GetChild("GUI", false).GetChildByAttribute("window", "id", "map_window", true), 
		g_App.GetSettings().GetChild("GUITemplates", false))
	map_window._self = window
	
	local profile = s11.g_ProfileManager.Instance().GetCurrentProfile()
	map_window._game_mode_flags = profile.GetGameModeFlags()
	
	
	map_window._current_profile = profile.GetClassicData()
	local player_level = map_window._current_profile.GetPlayerLevel()
	if not map_window._current_profile then
		__message("Current profile is NULL")
		return 
	end

	map_window.tab_widget = get_child_widget(window, "levels_tab_list", sf.gui.CTabWidget, "Cant find tab widget for map" )
	if not map_window.tab_widget then
		return
	end
		
	-- сбрасываем координаты для следующего уровня(определяют наличии е кнопки Play)
	local next_level_info = map_window._current_profile.GetNextNotPlayedLevel()
	map_window._next_dif_level = next_level_info.DifLevel
	map_window._next_level_index = next_level_info.LevelIndex
	
	if map_window._next_dif_level == -1 or map_window._next_level_index == -1 then
		map_window._next_dif_level = nil
		map_window._next_level_index = nil
	end

	map_window.green_mask_count = 0
	map_window.yellow_mask_count = 0
	-- флаг того, что мы нашли следующий уровень
	map_window._total_levels_count = 0
	local last_level_found = false
	local passed_level_count = 0
	--- обходим закладки карты, индекс закладки соотвествует уровняю сложности
	local panels_num = map_window.tab_widget.EnumPanels()
	for dif_index = 0, panels_num - 1 do
		if dif_index > 0 then
			buttons_pos = map_window._hard_buttons_pos
		end
		local bar_table = {}
		map_window._tabs_close_table[dif_index] = last_level_found
		
		-- получаем содержимое закладки
		local current_tab_widget = map_window.tab_widget.GetPanelContent(dif_index)	
		-- обходим все уровни для текущей сложности
		local levels_count = map_window._levels_struct.GetLevelsCount(dif_index)
		for level_index = 0, levels_count - 1 do
		    --- получаем информацию о текущем уровне
			local level = map_window._levels_struct.GetLevel(dif_index, level_index)
			
			-- если этот уровень - хог, то пытаемся получить изображение кнопки для него
			local hog_button_tempalte = nil
			local level_grow_flag = nil
			if level then
				local level_info = __cast(level, s11.CMatchLevelInfo)
				if not level_info then
					local hog_level_info = __cast(level, s11.CHogLevelInfo)
					hog_button_tempalte = tostring(hog_level_info.GetButtonImage())
				else
					map_window._total_levels_count = map_window._total_levels_count + 1
					-- смотрим есть ли у игрока возможность увеличить урвоень на этом уровне
					local max_player_level = level_info.GetCharacterLevelLimit()
					if max_player_level > player_level then
						level_grow_flag = true
					end
				end
			end
			local chapter_index = level.GetChapterIndex()
			local current_bar = bar_table[chapter_index+1]
			if not current_bar then
				current_bar = {}
				bar_table[chapter_index+1] = current_bar
			end
			
			local level_index_in_chapter = level.GetLevelIndexInChapter()
			
			--- устанавливаем изображения для кнопки по умолчанию - уровень в который еще не играли
			local button_image_id = map_window._locked_level_image
			
			local level_locked = false

			-- получаем у профайла лучшее время для данного уровня
			
			local level_progress_info = map_window._current_profile.GetLevelProgress(dif_index, level_index)
			
			--смотрим завершен ли урвоень
			if level_progress_info.IsFinished() then
				-- если уровень уже пройден, то устанавливаем кнопке соответсвующее изображение
				local progress = level_progress_info.GetProgress()
				if progress == 1 then
					map_window.green_mask_count = map_window.green_mask_count + 1
				elseif progress == 2 then
					map_window.yellow_mask_count = map_window.yellow_mask_count + 1
				end

				button_image_id = map_window._progess_buttons_images[progress]
				
			else
				current_bar.not_finished = true
				-- если уровень еще не пройден, то смотрим не является ли он первым непройденным уровнем
				if map_window._next_dif_level == dif_index and map_window._next_level_index == level_index then
					-- елси это первый не пройденный уровень, то изображение для следующего урвоня ставим
					button_image_id = map_window._next_level_image
					level_grow_flag = false
				else
					-- если не следующий и еще не пройденый то вообе залочиваем его
					level_locked = true
					last_level_found = true
				end
			end
			if not last_level_found then
				passed_level_count = passed_level_count + 1
			end
			
			-- если это хог уровень то заменяем изображение кнопки
			-- на изображение для соответсвующего уровня
			button_image_id = hog_button_tempalte or button_image_id

			-- формируем новую кнопку
			local image = sf.graphics.CImage(button_image_id)
			local button_id = map_window._FormLevelButtonId(dif_index, level_index)

			local new_button = sf.gui.CButtonWidget(image, nil, button_id, 0, 0)
			
			-- если уровень недоступен то дизеблим кнопку
			new_button.DisableButton(level_locked)
			
			-- устанавливаем кнопке смещение на основании номера главы и номера уровня в ней
			local offset  = sf.misc.FloatVector(buttons_pos._start_offset.X + buttons_pos._space_x * level_index_in_chapter, 
			                      buttons_pos._start_offset.Y + buttons_pos._space_y * chapter_index)
			
			new_button.SetOffset(offset.X, offset.Y)
								  
			-- добавляем кнопку на закладку
			current_tab_widget.AddWidget(new_button)
			--[[
			-- добавляем изображение возможного увеливения уровня
			if level_grow_flag and level_locked == false then
				local image = qe.CAlphaImageWidget(map_window._level_up_icon_id, "level_up", 0, 0)
				image.AddToolTip(map_window._level_up_icon_tooltip_id)
				image.SetOffset(offset.X + map_window._level_up_icon_offset.X, offset.Y + map_window._level_up_icon_offset.Y)
				current_tab_widget.AddWidget(image)
			end
			]]
		end
		for id,obj in ipairs(bar_table) do
			if not obj.not_finished then
				local bar_imgae = get_child_widget(current_tab_widget, "bar_"..tostring(id), sf.gui.CImageWidget)
				bar_imgae.SetImage("screens_map_level_completed")
			end
		end
		
	end
	map_window._FormMapEffects(window)
	
	window.UpdateLayout()
	
	window.SetOffset(0, 0)
	
	s11.g_TrackManager.Instance().UpdateCurrentTrack("town_map", false)
	
    
	-- эмулируем перемещение мышки, что бы снять наведенное состояние созданных кнопок
	window.OnMouseMove(sf.misc.IntVector(0, 0), 0, true)

	-- формируем событие на открытие окна
	map_window.OnShowWindow = function ()
		if not map_window._game_mode_flags.ReadFlag(s11.CProfile.GameModeFlagPuzzle) 
			and passed_level_count > map_window._level_number_for_open_puzzle then
			-- сообщение о активации puzzle режима
			--__message("puzzle game mode")
			map_window._game_mode_flags.RaiseFlag(s11.CProfile.GameModeFlagPuzzle) 
			s11.g_ProfileManager.Instance().Save()
			if dialog_do_modal("puzzle_enable_dialog", map_window._self) == 1 then
				puzzle_window.LoadLevelhints(0, 0)
				puzzle_window.Show(0, 0)
			end
		end
		
		if not map_window._game_mode_flags.ReadFlag(s11.CProfile.GameModeFlagEndless) 
			and passed_level_count > map_window._level_number_for_open_endles then
			-- сообщение о активации endless режима
			--__message("endless game mode")
			map_window._game_mode_flags.RaiseFlag(s11.CProfile.GameModeFlagEndless) 
			s11.g_ProfileManager.Instance().Save()
			if dialog_do_modal("endless_enable_dialog", map_window._self) == 1 then
				local endless_data = profile.GetEndlessData()
				endless_data.DropPlayerData()
				endless_window.Show(0, 0)
			end
		end
		
		if _show_saved_game_dialog then
			map_window._CheckForSavedGame()
		end
		achievements.RefreshAchievement("gold_time_20_levels", map_window.green_mask_count)		
		
		achievements.RefreshAchievement("gold_silver_time_30_levels", map_window.yellow_mask_count + map_window.green_mask_count)		
		
		if map_window._total_levels_count == map_window.green_mask_count then
			achievements.GetAchievement("gold_time_all_levels")		
		end
		
		if map_window._tabs_close_table[1] == false then
			achievements.GetAchievement("first_levels")		
		end
		
	end

	window = nil
	collectgarbage()
end


--- открытие окна карты
function map_window.ShowPuzzleMap(_show_saved_game_dialog, _unload_resources)

	local window = __ChangeWindowWithEffect(nil, _unload_resources)
	if not window then
		return
	end
	
	s11.g_GameBackground.Instance().DisableSounds(true)

	map_window.OnShowWindow = nil
	map_window._last_tab = nil
	map_window._timer = sf.core.CTimerWrapper(sf.core.g_Application.GetTimeManager().GetTimer("game_timer").AttachTimer(""))
	
	map_window._pre_ach_time = map_window._pre_ach_delay
	
	local buttons_pos = map_window._puzzle_buttons_pos
	
	map_window._puzzle_mode = true

	map_window._levels_struct = s11.g_GameStruct.Instance().GetLevelsSystem(s11.CGameStruct.GameTypePuzzle)
	map_window._current_profile = s11.g_ProfileManager.Instance().GetCurrentProfile().GetPuzzleData()

	map_window._skip_dialog_show = true
	map_window._info_window_widget = nil
	map_window._info_window_level_id = nil

	
	-- сбрасываем координаты для следующего уровня(определяют наличии е кнопки Play)
	local next_level_info = map_window._current_profile.GetNextNotPlayedLevel()
	map_window._next_dif_level = next_level_info.DifLevel
	map_window._next_level_index = next_level_info.LevelIndex
	
	if map_window._next_dif_level == -1 or map_window._next_level_index == -1 then
		map_window._next_dif_level = nil
		map_window._next_level_index = nil
	end

	map_window._LoadConstants()

	window.Load(
		g_App.GetSettings().GetChild("GUI", false).GetChildByAttribute("window", "id", "puzzle_map_window", true), 
		g_App.GetSettings().GetChild("GUITemplates", false))

	map_window._self = window
	
	if not map_window._current_profile then
		__message("Current profile is NULL")
		return 
	end

	map_window.tab_widget = get_child_widget(window, "levels_tab_list", sf.gui.CTabWidget, "Cant find tab widget for map" )
	if not map_window.tab_widget then
		return
	end
	
	--- обходим закладки карты, индекс закладки соотвествует уровняю сложности

	panels_num = map_window._levels_struct.GetDifLevelsCount()
	
	local levels_in_group = map_window._puzzle_levels_in_group
	local level_in_group_index = 0
	local level_group_acces = true
	local not_passed_level = nil
	map_window.total_levels = 0
	map_window.levels_for_min_moves = 0 
	for dif_index = 0, panels_num - 1 do
		local bar_table = {}
		-- получаем содержимое закладки
		local current_tab_widget = map_window.tab_widget.GetPanelContent(dif_index)	
		-- обходим все уровни для текущей сложности
		local levels_count = map_window._levels_struct.GetLevelsCount(dif_index)
		for level_index = 0, levels_count - 1 do
		    map_window.total_levels = map_window.total_levels + 1
			--- получаем информацию о текущем уровне
			local level = map_window._levels_struct.GetLevel(dif_index, level_index)
			
			-- если этот уровень - хог, то пытаемся получить изображение кнопки для него
			local hog_button_tempalte = nil
			local level_grow_flag = nil
			local moves_to_win = -1
			if level then
				local level_info = __cast(level, s11.CMatchLevelInfo)
				if not level_info then
					local hog_level_info = __cast(level, s11.CHogLevelInfo)
					hog_button_tempalte = tostring(hog_level_info.GetButtonImage())

				else
					moves_to_win = level_info.GetMinMovesForWin()
				end
			end
			local chapter_index = level.GetChapterIndex()
			local current_bar = bar_table[chapter_index+1]
			if not current_bar then
				current_bar = {}
				bar_table[chapter_index+1] = current_bar
			end
			local level_index_in_chapter = level.GetLevelIndexInChapter()
			
			--- устанавливаем изображения для кнопки по умолчанию - уровень в который еще не играли
			local button_image_id = map_window._locked_level_image
			
			local level_locked = false

			-- получаем у профайла лучшее время для данного уровня
			button_image_id = map_window._next_level_image

			if level_in_group_index == levels_in_group then
				level_in_group_index = 0
				if not_passed_level then
					level_group_acces = nil
				end
			end
			

			local level_progress_info = map_window._current_profile.GetLevelProgress(dif_index, level_index)
			
			if level_group_acces == true then
			
				if level_progress_info.IsFinished() then
					local moves_on_level = level_progress_info.GetMovesCount();
					if moves_to_win == -1 or moves_on_level <= moves_to_win then
						button_image_id = map_window._progess_buttons_images[1]
						map_window.levels_for_min_moves = map_window.levels_for_min_moves + 1
					else
						button_image_id = map_window._progess_buttons_images[2]
					end
					
					-- если уровень уже пройден, то устанавливаем кнопке соответсвующее изображение
					--button_image_id = map_window._progess_buttons_images[level_progress_info.GetProgress()]
				else
					button_image_id = map_window._next_level_image
					not_passed_level = true
					current_bar.not_finished = true
				end
			
			else
				button_image_id = map_window._locked_level_image
				level_locked = true
				current_bar.not_finished = true
			end
	
			-- если это хог уровень то заменяем изображение кнопки
			-- на изображение для соответсвующего уровня
			button_image_id = hog_button_tempalte or button_image_id

			-- формируем новую кнопку
			local image = sf.graphics.CImage(button_image_id)
			local button_id = map_window._FormLevelButtonId(dif_index, level_index)

			local new_button = sf.gui.CButtonWidget(image, nil, button_id, 0, 0)
			
			-- если уровень недоступен то дизеблим кнопку
			new_button.DisableButton(level_locked)
			
			-- устанавливаем кнопке смещение на основании номера главы и номера уровня в ней
			local offset  = sf.misc.FloatVector(buttons_pos._start_offset.X + buttons_pos._space_x * level_index_in_chapter, 
			                      buttons_pos._start_offset.Y + buttons_pos._space_y * chapter_index)
			
			new_button.SetOffset(offset.X, offset.Y)
								  
			-- добавляем кнопку на закладку
			current_tab_widget.AddWidget(new_button)
			level_in_group_index = level_in_group_index + 1
		end
		for id,obj in ipairs(bar_table) do
			if not obj.not_finished then
				local bar_imgae = get_child_widget(current_tab_widget, "bar_"..tostring(id), sf.gui.CImageWidget)
				bar_imgae.SetImage("screens_map_level_completed")
			end
		end
	end
	
	map_window._FormMapEffects(window)
	
	window.UpdateLayout()
	
	window.SetOffset(0, 0)
	
	s11.g_TrackManager.Instance().UpdateCurrentTrack("town_map", false)
	
	
	-- эмулируем перемещение мышки, что бы снять наведенное состояние созданных кнопок
	window.OnMouseMove(sf.misc.IntVector(0, 0), 0, true)
	-- формируем собтие на завершение откртия окна
	
	map_window.OnShowWindow = function ()
		s11.g_GameBackground.Instance().Init(map_window._current_chapter, map_window._current_level_in_chapter)
		s11.g_GameBackground.Instance().SetUseClip(false)
	
		if _show_saved_game_dialog then
			map_window._CheckForSavedGame()
		end
		
		achievements.RefreshAchievement("superpuzzle", map_window.levels_for_min_moves)		
		
	end
	window = 0

	collectgarbage()
end

-- формируем эффекты на сохраненном уровне и кнопке играть
function map_window._FormMapEffects(_window)
	--- проверяем есть ли сохранненая игра
	map_window._load_game_on_play_button = nil
	
	if map_window._current_profile.HasSavedLevelInfo() then
	   -- если есть то заменяем информацию о следующем уровне на сохраненную
		map_window._next_dif_level = map_window._current_profile.GetSavedLevelDifficulty()
		map_window._next_level_index = map_window._current_profile.GetSavedLevelIndex()
		map_window._load_game_on_play_button = true
	end

	-- параметры для фона по умолчанию
	local current_chapter = 0
	local current_level_in_chapter = 0
	
	-- если есть информация о сохраннной игре или следующем урвоен, 
	-- то добавляем на кнопку этого уровня свечение
	-- и инициализируем фон
	if map_window._next_dif_level and map_window._next_level_index then
		
		-- получаем виджет закладки текущего уровня
		local current_tab_widget = map_window.tab_widget.GetPanelContent(map_window._next_dif_level)	
		
		-- получаем id кнопки с сохраненеим
		local saved_button_id = map_window._FormLevelButtonId(map_window._next_dif_level, map_window._next_level_index)
		--- получаем видждет кнопки следующей
		local saved_button = get_child_widget(current_tab_widget, saved_button_id, sf.gui.CButtonWidget, "Cant find saved_button_widget" )
		
		-- создаем клип для свечения
		local glow_clip = sf.gui.CClipWidget("glow_clip", 10, 0) 
		glow_clip.GetClip().Load(map_window._button_glow_clip_id, true)
		local clip_size = glow_clip.GetPreferredSize()
		glow_clip.SetSize(clip_size.X, clip_size.Y)
		
		-- устанавливаем свечение над нужно кнопкой
		local glow_offset = saved_button.GetOffset() + saved_button.GetSize()/2 - glow_clip.GetSize()/2
		glow_clip.SetOffset(glow_offset.X, glow_offset.Y)
		
		-- добавляем сыечение на фон
		current_tab_widget.AddWidget(glow_clip)
		
		-- если есть сохраненный или следующий руовень то меняем 
		-- настройки для отображения фона
		local level = map_window._levels_struct.GetLevel(map_window._next_dif_level, map_window._next_level_index)
		if level then
			current_chapter = level.GetChapterIndex()
			current_level_in_chapter = level.GetLevelIndexInChapter()
		end

	end
	
	--- тут будет определение положение эффекта, который указывает на следующий уровень
	--- устанавливаем текущую панель в соответсвии со сложностью текущего уровня
	map_window.tab_widget.SelectPanel(map_window._next_dif_level or 2)

	
	--- находим кнопку "Play"
	local play_button_widget = get_child_widget(_window, "play_button", sf.gui.CButtonWidget, "ошибка" )
	if play_button_widget then
		-- если нам известны координаты следующего уровня, то активируем кнопку
		play_button_widget.DisableButton(not (map_window._next_dif_level and map_window._next_level_index))
	end
	-- инициализируем фон
	map_window._current_chapter = current_chapter
	map_window._current_level_in_chapter = current_level_in_chapter

	map_window.OnStartShowWindow = function ()
		s11.g_GameBackground.Instance().Init(map_window._current_chapter, map_window._current_level_in_chapter)
		s11.g_GameBackground.Instance().SetUseClip(false)
	end

end

-- приедложение перейти к сохраненной игре если она есть
function map_window._CheckForSavedGame()

	--- если нет информации о сохраненном уровне, то выходим
	if not map_window._current_profile.HasSavedLevelInfo() then
		return
	end

	local level_index = map_window._current_profile.GetSavedLevelIndex()
	local dif_level_index = map_window._current_profile.GetSavedLevelDifficulty()
	
	local res = map_window._ShowLevelDialog("continue_game_dialog", dif_level_index, level_index)	

	if res == 1 then
		--- если игрок хочет продолжить то запускаем уровень с параметром _load_game = true
		map_window._RunLevel(dif_level_index, level_index, true)
	end
end

--- сформировать id кнопки карты
function map_window._FormLevelButtonId(_dif_level, _level_index)
	return string.format("#%d&%d", _dif_level, _level_index)
end

--- получить координаты уровня по его id
function map_window._GetLevelIndexesByButtonId(_id)
	local str = _id
	local dif_index = string.find(str, "#")
	local level_index = string.find(str, "&")
	local dif_level = nil
	local level_number = nil
	if dif_index and level_index then
		local len = string.len(str)
		dif_level = tonumber(string.sub(str, dif_index+1, level_index-1))
		level_number = tonumber(string.sub(str, level_index+1, len))
	end
	return dif_level, level_number
end

function map_window.DoDraw(_this, _renderer)
    s11.g_GameBackground.Instance().Draw(_renderer)
end

function map_window.DoUpdate(_this)
	
	if map_window.OnStartShowWindow then
		map_window.OnStartShowWindow()
		map_window.OnStartShowWindow = nil
	end

	if map_window.OnShowWindow then
		if not s11.WindowHasEffects(map_window._self) then
			local show_func = map_window.OnShowWindow
			map_window.OnShowWindow = nil
			show_func()
		end
	end

	if map_window._pre_ach_time > 0 then
		local frame_delta = map_window._timer.Get().GetFrameDelta()
		map_window._pre_ach_time = map_window._pre_ach_time - frame_delta
		if map_window._pre_ach_time < 0 then
			if map_window._next_dif_level and map_window._next_dif_level == 1 then
				if achievements.GetAchievement("first_levels") then
					s11.g_Achievements.Instance().SaveProfilesAchievements()
				end
			end
		end
	end

    s11.g_GameBackground.Instance().Update()
end

function map_window.OnChar(_this, _char, _keyboard_state, _state, _broadcast)
    if _this.SuperOnChar(_char, _keyboard_state, _state, _broadcast) then return true end	
    return false
end

function map_window.OnKeyDown(_this, _key, _keyboard_state, _state, _broadcast)
	if _this.SuperOnKeyDown( _key, _keyboard_state, _state, _broadcast) then
        return true
    end
    return false
end

function map_window.OnKeyUp(_this, _key, _keyboard_state, _state, _broadcast)
	return _this.SuperOnKeyUp( _key, _keyboard_state, _state, _broadcast)
end

function map_window.OnMouseMove(_this, _pos, _state, _broadcast)
	return _this.SuperOnMouseMove( _pos, _state, _broadcast) 
end

function map_window.OnMouseDown(_this, _pos, _button, _state, _broadcast)
	return _this.SuperOnMouseDown( _pos, _button, _state, _broadcast) 
end

function map_window.OnMouseUp(_this, _pos, _button, _state, _broadcast)
	return _this.SuperOnMouseUp( _pos, _button, _state, _broadcast) 
end

function map_window.OnDoubleClick(_this, _pos, _state, _broadcast)
	return _this.SuperOnDoubleClick( _pos, _state, _broadcast) 
end

function map_window.OnMouseWheel(_this, _pos, _delta, _state, _broadcast)
	return _this.SuperOnMouseWheel( _pos, _delta, _state, _broadcast)
end

-- функция закрытия окна
function map_window._CloseInfoWindow()
	-- планое пропадание
	local widget = map_window._info_window_widget
	widget.RemoveAllEffects()
	s11.AddEffectToWidget(widget, sf.graphics.Color(0, 255, 255, 255), map_window._fade_time, 0)
	s11.AddRemoveEffectToWidget(widget, map_window._fade_time)
	map_window._info_window_widget = nil
	map_window._info_window_level_id = nil
end

--- открытие окна с информацией о уровне
function map_window._OpenLevelInfoWindow(_dif_infex, _level_index, _level_id, _offset)
	-- если это окно уже открыто, то выходим
	if map_window._info_window_level_id == _level_id then
		return
	end

	--- если есть другое открытое окно, то закрываем его
	if map_window._info_window_widget and map_window._info_window_level_id then
		map_window._CloseInfoWindow()
	end
	
	local level_info_widget = nil
	if map_window._puzzle_mode then
		level_info_widget = level_info_window.FormPuzzleLevelInfoWidget(_dif_infex, _level_index, map_window._current_profile, map_window._levels_struct) 
	else
		level_info_widget = level_info_window.FormLevelInfoWidget(_dif_infex, _level_index, map_window._current_profile, map_window._levels_struct) 
	end
	
	--- если из-за чего-то окно не создалось, то ругаемся и выходим
	if not level_info_widget then
		__message("Level info creation error.")
		return
	end

	map_window._info_window_widget = level_info_widget

	map_window._info_window_level_id = _level_id
	
	arrow_setter.MoveArrow(level_info_widget, _offset, map_window._arrow_offset, map_window._arrow_limits, map_window._directions)

	level_info_widget.SetColor(sf.graphics.Color(0, 255, 255, 255))
	-- плавное появление окна
	s11.AddEffectToWidget(level_info_widget, sf.graphics.Color(255, 255, 255, 255), map_window._show_time, 0)

    --- добавляем окно задния
	map_window._self.AddWidget(level_info_widget)		
end