--[[
Модуль отвечает за реализацию списка всплывающих локаций.
--]]

floating_locations = {}
floating_locations.settings = 
{
    -- НАСТРОЙКИ ОКНА
    -- прямоугольник, при наведении на который появится список локаций
    over_rect = { x = 104, y = 680, width = 77, height = 77 },
    -- позиция левого нижнего угла окошка локаций; окно привязано к ней
    bottom_left_pos = { x = 104, y = 620 }, 
    -- время, за которое список появляется и исчезает
    hide_show_time = 500,
    -- пауза перед появлением списка
    show_delay = 100,
    -- отображать отладочную информацию?
    debug_render = false,
    
    -- НАСТРОЙКИ ПУНКТА В СПИСКЕ ЛОКАЦИЙ
    location = 
    {
        -- размер пункта одной локации в списке локаций
        size = { width = 432, height = 87 }, 
        -- позиция левого верхнего угла иконки локации относительно левого верхнего угла пункта локации
        icon_offset = { x = 7, y = 5 }, 
        -- позиция левого верхнего угла названия локации относительно левого верхнего угла пункта локации
        title_offset = { x = 120, y = 33 },
        -- шрифт названий локаций
        title_font = "white_font_12",
        -- фон
        background = "windows_floating_location_back",
        -- подсветка
        selection_image = "windows_floating_location_effect_selected"
    },
    
    -- НАСТРОЙКИ ТУТОРИАЛА
    tutorial = 
    {
        clip = "floating_locations", -- клип туториала
        time = 10000, -- максимальное время отображения туториала
    }
}
local self = floating_locations

self.timer = __create_timer()

--[[ self.Init
    Должна вызывается из InitLevelScript.
    Связывает сцены с их иконками и названиями, инициализирует всплывающие локации.
    Формат _scenes_settings:
    {
        {
            id = "Scene Id",
            icon = "scene_icon_image",
            title = "Scene Title",
            disabled = false
        },
        {
            id = "Scene2 Id",
            icon = "scene2_icon_image",
            title = "Scene2 Title",
            disabled = true
        },
        ...
    }
--]]
function self.Init(_scenes_settings)
    self.timer.Get().SetTime(0)
    
    self.lua_widget.OnFloatingLocationsInit()

    for _, scene in ipairs(_scenes_settings) do
        __assert(scene.id and type(scene.id)=="string")
        __assert(scene.icon and type(scene.icon)=="string")
        __assert(scene.title and type(scene.title)=="string")
        __assert(scene.disabled == nil or type(scene.disabled)=="boolean")
    end
    
    local get_texture = function(_id)
        local texture = sf.core.g_Application.GetResourceManager().GetTexture(_id)
        __assert(texture and texture.GetTexture(0), "Всплывающие локации: изображение '".._id.."' не найдено")
        return texture.GetTexture(0)
    end
    
    self.scenes = {}
    for _, scene_settings in ipairs(_scenes_settings) do
        local scene = {}
        scene.id = scene_settings.id
        scene.icon = get_texture(scene_settings.icon)
        scene.title = sf.misc.g_StringTable.Instance().FormatByStringsID(scene_settings.title)
        scene.disabled = scene_settings.disabled
        table.insert(self.scenes, scene)
    end
    
    self.background = get_texture(self.settings.location.background)
    self.selection_image = get_texture(self.settings.location.selection_image)
    self.title_font = sf.core.g_Application.GetResourceManager().GetFont(self.settings.location.title_font)
    __assert(self.title_font, "Всплывающие локации: шрифт '"..self.settings.location.title_font.."' не найден")
    
    self._active = false
	
	-- откладываем загрузку состояния сцен
	-- т.к. в LevelInitScript игра еще не загружена
	-- скрипт из form_event вызовется уже после загрузки
	form_event([[
		if quest.g_LuaVariables.floating_locations then
			floating_locations._LoadState()
		else
			floating_locations._SaveState()
		end
	]])
    
    self.initialized = true
end

function self.IsInitialized()
    return self.initialized
end

-- сохраняет доступность сцен в quest.g_LuaVariables
function self._SaveState()
    quest.g_LuaVariables.floating_locations = {}
    for i, scene in ipairs(floating_locations.scenes) do
        quest.g_LuaVariables.floating_locations[i] = scene.disabled and 1 or 0
    end
end

-- загружает доступность сцен из quest.g_LuaVariables
function self._LoadState()
	__assert(quest.g_LuaVariables.floating_locations)
	for i, disabled in ipairs(quest.g_LuaVariables.floating_locations) do
		__assert(floating_locations.scenes[i], 
			"Всплывающие локации: в сохранении указана несуществующая сцена: "..tostring(i))
		floating_locations.scenes[i].disabled = disabled == 1
	end
end

-- включает отображение списка локаций
function self.Show()
    self._active = true
end

function self.IsVisible()
    return self._active
end

-- закрывает список локаций
function self.Hide()
    self._active = false
end

function self.ShowTutorial()
    self.lua_widget.ShowTutorial(self.settings.tutorial.clip)
end

-- возвращает прямоугольную область, которую занимает список локаций
function self.GetRect()
    local visible_scenes = self.EnumEnabledLocations()
    local pos = self.settings.bottom_left_pos
    local size = self.settings.location.size
    local height = visible_scenes * size.height
    local rect = sf.misc.FloatRect(pos.x, pos.y - height, size.width, height)
    return rect
end

-- подсвечивает сцену по номеру _scene_number в списке локаций
function self.HighlightScene(_scene_number)
    for i, scene in ipairs(self.scenes) do
        scene.highlighted = (i == _scene_number)
    end
end

-- закрывает список и переходит на сцену по номеру _scene_number
function self.SelectScene(_scene_number)
    __assert(_scene_number >= 1 and _scene_number <= #self.scenes)
    show_scene(self.scenes[_scene_number].id)
    self.Hide()
end

-- делает сцену доступной в списке
function self.EnableScene(_scene_id)
    self._GetScene(_scene_id).disabled = false
    self._SaveState()
end

-- делает сцену недоступной в списке
function self.DisableScene(_scene_id)
    self._GetScene(_scene_id).disabled = true
    self._SaveState()
end

-- находит сцену по её id
function self._GetScene(_scene_id)
    for _, scene in ipairs(self.scenes) do
        if scene.id == _scene_id then
            return scene
        end
    end
    __assert(false, "Всплывающие локации: сцена с id '".._scene_id.."' не найдена")
end

-- возвращает кол-во достпуных локаций
function self.EnumEnabledLocations()
    local count = 0
    for _, scene in ipairs(self.scenes) do
        if not scene.disabled then count = count + 1 end
    end
    return count
end

self.lua_widget = 
{
    OnFloatingLocationsInit = function()
        __assert(self.lua_widget._this, 
            "Всплывающие локации: в игровом окне отсутствует виджет floating_locations.lua_widget")
        self.lua_widget._can_activate = true -- может ли наведение на амулет активировать список локаций
        self.lua_widget._activate_delay = nil -- хранит данные для работы паузы перед появлением списка
    end,
    
    OnMouseDown = function(_this, _pos, _button, _state, _broadcast)
        if not self.IsInitialized() or not self.IsVisible() then 
            return false 
        end
        
        -- обрабатываем клик на локацию в списке
        local scene_number = self.lua_widget._GetSceneNumberByPos(_pos.X, _pos.Y)
        if scene_number then
            self.SelectScene(scene_number)
            self.lua_widget._HideTutorial()
            return true
        end
        
        -- кликнули за пределами списка локаций
        self.Hide()
        
        -- если клик произошел по over_rect, значит включился амулет
        local rect = self.settings.over_rect
        if _pos.X >= rect.x and _pos.X <= rect.x + rect.width
        and _pos.Y >= rect.y and _pos.Y <= rect.y + rect.height then
            self.lua_widget._can_activate = false
            self.lua_widget._activate_delay = nil
        end
        
        return false
    end,
    
    OnMouseMove = function(_this, _pos, _state, _broadcast)
        if not self.IsInitialized() then
            return false
        end
        
        -- отображаем список, если навели на прямоугольник over_rect
        local rect = self.settings.over_rect
        if _pos.X >= rect.x and _pos.X <= rect.x + rect.width
        and _pos.Y >= rect.y and _pos.Y <= rect.y + rect.height then
            if self.lua_widget._CanActivate() and not self.IsVisible() and not self.lua_widget._activate_delay then
                self.lua_widget._activate_delay = { start_time = self.timer.Get().GetTime() }
            end
            return false
        end
        
        self.lua_widget._can_activate = true
        self.lua_widget._activate_delay = nil
        
        -- обрабатываем наведение на локацию в списке
        if self.IsVisible() then
            local scene = self.lua_widget._GetSceneNumberByPos(_pos.X, _pos.Y)
            self.HighlightScene(scene)
            if scene then 
                quest.global_cursor.SetHintText("", false)
                sf.gui.g_Cursor.Instance().SetCursor(sf.gui.CCursor.CursorHand)
                return true 
            end
        end
        
        return false
    end,
    
    -- признак возможности использования всплывающих локаций
    _CanActivate = function()
        return self.lua_widget._can_activate 
            and not hidden_object.GetActiveScene()
            and not quest.global_minigame_opened
            and not notepad.window.visible
    end,
    
    -- возвращает порядковый номер сцены в self.scenes
    _GetSceneNumberByPos = function(_x, _y)
        local rect = self.GetRect()
        if rect.IsContains(_x, _y) then
            local visible_scenes = self.EnumEnabledLocations()
            local scene_number = visible_scenes - math.floor((_y - rect.Y) / self.settings.location.size.height)
            if scene_number < 1 then scene_number = 1
            elseif scene_number > visible_scenes then scene_number = visible_scenes end
                
            local current_scene = 0
            for i, scene in ipairs(self.scenes) do
                if not scene.disabled then
                    current_scene = current_scene + 1
                    if current_scene == scene_number then
                        return i
                    end
                end
            end
        end
    end,
    
    -- запускает отображение туториала на всплывающие локации
    ShowTutorial = function(_clip)
        if self.lua_widget._tutorial then return end
        
        self.lua_widget._tutorial_start = self.timer.Get().GetTime()
        local clip = sf.misc.anim.CClip()
        clip.Load(self.settings.tutorial.clip, true)
        clip.SetPos(sf.misc.FloatVector(1024/2, 768/2))
        self.lua_widget._tutorial = clip
    end,
    
    -- прячет туториал
    _HideTutorial = function()
        self.lua_widget._tutorial = nil
        self.lua_widget._tutorial_start = nil
    end,
    
    DoDraw = function(_this, _renderer)
        if not self.IsInitialized() then
            return false
        end
    
        -- отображаем туториал
        if self.lua_widget._tutorial then self.lua_widget._tutorial.Draw(_renderer) end
    
        _renderer.PushState()
        _renderer.SetColor(sf.graphics.Color(self.lua_widget._alpha, 255, 255, 255))
        
        
        local bottom_left_pos = self.settings.bottom_left_pos
        local location = self.settings.location
        local rect = sf.misc.FloatRect(
                        bottom_left_pos.x, bottom_left_pos.y - location.size.height,
                        location.size.width, location.size.height)
        local color = sf.graphics.Color(255, 255, 255, 255)
        
        -- отображаем список локаций
        for _, scene in ipairs(self.scenes) do
            if not scene.disabled then
                -- фон
                _renderer.RenderTextureBox(self.background, rect, self.background.GetRect(), color)
                -- подсветка
                 if scene.highlighted then
                     _renderer.RenderTextureBox(self.selection_image, rect, self.selection_image.GetRect(), color)
                 end
                -- иконка
                _renderer.RenderTexture(scene.icon, 
                    rect.X + location.icon_offset.x, rect.Y + location.icon_offset.y, color)
                -- текст
                _renderer.RenderString(self.title_font, scene.title, 
                    rect.X + location.title_offset.x, rect.Y + location.title_offset.y, -1, -1, 1, 
                    sf.graphics.Color(255, 0, 0, 0) , 0)
                
                rect.Y = rect.Y - location.size.height
            end
        end
        
        _renderer.PopState()
        
        
        if self.settings.debug_render then
            -- ображаем over_rect
            sf.graphics.RenderRect(_renderer, 
                sf.misc.FloatRect(self.settings.over_rect.x, self.settings.over_rect.y,
                    self.settings.over_rect.width, self.settings.over_rect.height),
                sf.graphics.Color(255, 0, 255, 0))
            -- ображаем rect списка
            sf.graphics.RenderRect(_renderer, 
                self.GetRect(),
                sf.graphics.Color(255, 0, 0, 255))
        end
        
        return false
    end,

	DoUpdate = function(_this)
        if not self.IsInitialized() then
            return false
        end
        
        -- обновляем туториал
        if self.lua_widget._tutorial then
			self.lua_widget._tutorial.Update()
		
			-- пропадание туториала по времени
			if self.timer.Get().GetTime() - self.lua_widget._tutorial_start >= self.settings.tutorial.time then
				self.lua_widget._HideTutorial()
			end
        end
        
        -- плавное появление/исчезновение
        local alpha_delta = 1000 / self.settings.hide_show_time * 255 * (self.timer.Get().GetFrameDelta()/1000)
        if not self.IsVisible() then alpha_delta = -alpha_delta end
        local alpha = self.lua_widget._alpha + alpha_delta
        if alpha < 0 then alpha = 0
        elseif alpha > 255 then alpha = 255 end
        self.lua_widget._alpha = alpha
        
        -- пауза перед активацией списка
        if self.lua_widget._activate_delay then
            local current_time = self.timer.Get().GetTime()
            if current_time >= self.lua_widget._activate_delay.start_time + self.settings.show_delay then
                self.Show()
                self.lua_widget._activate_delay = nil
            end
        end
        
		return false
	end,
    
    Load = function(_this, _info, _templates)
        self.lua_widget._this = _this
        return true
    end,

    __CreateInstance = function()
        return "floating_locations.lua_widget"
    end,
    
    _alpha = 0
}

__inherite(self.lua_widget, null_lua_widget_handler(self.lua_widget._actions))