--[[
Модуль, отвечающий за отображение и функционал блокнота.
]]

notepad = {}

notepad.settings = 
{
    pages = 
    {
		----- глава 1
        "1-2_machu-picchu", -- 1 я изучаю Мачу-Пикчу
		"3-4_scene01_01_statuette", --2 надо собрать 16 статуэток
        "5-6_scene01_01_scarabey", --3 нашел в лабе картинку со скарабеем
		"7-8_scene01_01_manual", --4 вода проводит электричество!
		----- глава 2
		"9-10_scene02_01_crystals", --5 символика кристаллов, надо найти части отверстия
		"11-12_scene02_02_newspaper", --6 про газету в ящике
		"13-14_scene02_04_map", --7 срисованная карта мачу-пикчу
		----- глава 3
		"15-16_scene03_04_begin", --8 про ступки инфа
		"17-18_scene03_04_sun", --9  так вот как надо лучи расставить!
		----- глава 4
		"19-20_scene04_01_key", --10 ох уж эти лаборанты, взяли ключ сломали
        "21-22_scene04_03_manual_", --11 рецепт очистки табличек
		----- глава 5
		"23-24_scene05_04_cloth", --12 рисунки с ткани
		"25-26_scene05_01_maze01", --13 о, какая последовательность символов в тайнике!
		"27-28_scene05_03_note", --14 у инков были обозначения сторон света!
		"29-30_scene05_01_maze02", --15 расшифровка последовательности
		----- глава 6
		"scene06_04_plate", -- 16 после того, как нашли табличку про прохождение интиуатаны
		"scene06_04_miniscenes", -- 17 заметка в блокноте про минисцены с идолами в тайной комнате
		"scene06_02_beams", -- 18 смешивание цветов
		"scene06_04_kipu" -- 19 после нахождения кипу в хоге в гл 6 
		
		
    },
    
	on_take_sound = "add_to_inventory",
	fly_alpha_time = 100, -- за какое время до конечной точки блокнота надо показать кнопочку
    
    window_layer = 1, -- слой, на котором создается виджет с блокнотом,
	
	-- НАСТРОЙКИ ТУТОРИАЛА
	tutorial = 
	{
		open_clip = "notebook", -- клип на туториал как открывать блокнот
		close_clip = "notebook_close", -- клип на туториал как закрывать блокнот
        after_close_clip = "tutorial_hint_button", -- клип туториала, который появляется после того, как закрыли блокнот
		close_clip_delay = 2000, -- пауза перед тем как показывать туториал на закрытие
		close_clip_time = 6000, -- максимальное время отображения туториала на закрытие блокнота
        after_close_clip_time = 6000, -- время, которое отображается туториал после закрытия блокнота
	}
}

local self = notepad

-- инициализирует список страниц блокнота
function self.InitPages()
    self._pages = {}
    for _, clip_id in ipairs(self.settings.pages) do
        local page = 
        {
            clip = clip_id,
            enabled = false,
        }
        table.insert(self._pages, page)
    end
    
    self._UpdatePages()
    
    self._current_page = profile.GetVariable("__np_current")
end

-- Делает доступной кнопку блокнота
function self.EnableButton()
    profile.SetVariable("__np_enabled", 1)
    self.ingame_lua_widget.EnableButton()
end

function self.IsButtonEnabled()
    return profile.GetVariable("__np_enabled") == 1
end

-- включает отображение туториала
function self.ShowOpenTutorial()
	self.ingame_lua_widget.ShowTutorial("open")
end

-- Делает страницу блокнота доступной
function self.EnablePage(_id)
    local page = self._pages[_id]
    __assert(page, "БЛОКНОТ: страница с идентификатором '"..tostring(_id).."' не найдена.")
    
    if profile.GetVariable("__np_"..tostring(_id)) == 1 then
        -- страница уже доступна
        return
    end
    
    page.enabled = true
    
    profile.SetVariable("__np_"..tostring(_id), 1)
    
    self.SetCurrentPage(_id)
    
    -- показываем эффект
    self.ingame_lua_widget.ShowButtonEffect()
end

-- Устанваливает текущую страницу
function self.SetCurrentPage(_id)
    __assert(self._pages[_id], "БЛОКНОТ: страница с идентификатором '"..tostring(_id).."' не найдена.")
    profile.SetVariable("__np_current", _id)
    self._current_page = _id
end

-- Перемещает текущую страницу вперед или назад.
function self.MoveToNextPage(_dir)
    __assert(_dir == 1 or _dir == -1)
    
    local total_pages = #self._pages
    local cur_page = self._current_page + _dir
    while cur_page > 0 and cur_page <= total_pages do
        if self._pages[cur_page].enabled == true then
            self.SetCurrentPage(cur_page)
            break
        end
        cur_page = cur_page + _dir
    end
end

-- Проверяет на доступность страницы рядом с текущей
function self._IsPageNextAvailable(_dir)
    __assert(_dir == 1 or _dir == -1)
    
    local total_pages = #self._pages
    local cur_page = self._current_page + _dir
    while cur_page > 0 and cur_page <= total_pages do
        if self._pages[cur_page].enabled == true then
            return true
        end
        cur_page = cur_page + _dir
    end
    return false
end

-- Возвращает клип текущей страницы
function self.GetCurrentPageClip()
    __assert(self._current_page ~= 0)
    return  self._pages[self._current_page].clip
end

-- Обновляет доступность страниц блокнота
function self._UpdatePages()
    for id, page in ipairs(self._pages) do
        page.enabled = profile.GetVariable("__np_"..tostring(id)) == 1
    end
end

-- NOTEPAD LUA WIDGET
self.ingame_lua_widget = 
{
    -- делает доступной кнопку вызова блокнота
    EnableButton = function()  
        -- в редакторе не работает
        if not game then return end
        
        local button = self.ingame_lua_widget._notepad_button
        button.RemFlags(__or(button.FlagHidden, button.FlagDisabled))
    end,

    Load = function(_this)
        self.ingame_lua_widget._this = _this
        
        -- загружаем и настраиваем кнопку вызова блокнота
        self.ingame_lua_widget._notepad_button = __cast(_this.GetWidget("notepad_button", true).get(), 
            sf.gui.CButtonWidget)
        __assert(self.ingame_lua_widget._notepad_button, "NOTEPAD: кнопка 'notepad_button' не найдена!")
        self.ingame_lua_widget._notepad_button.AddFlags(
            __or(sf.gui.CButtonWidget.FlagHidden, sf.gui.CButtonWidget.FlagDisabled))
            
        -- загружаем и настраиваем кнопку закрытия блокнота
        self.ingame_lua_widget._close_notepad_button = __cast(_this.GetWidget("close_notepad_button", true).get(), 
            sf.gui.CButtonWidget)
        __assert(self.ingame_lua_widget._close_notepad_button, "NOTEPAD: кнопка 'close_notepad_button' не найдена!")
        self.ingame_lua_widget._HideCloseButton()
        
        -- находим клип виджет с эффектом на кнопку
        self.ingame_lua_widget._button_effect = __cast(_this.GetWidget("button_effect", true).get(), 
            sf.gui.CClipWidget)
        __assert(self.ingame_lua_widget._button_effect, "NOTEPAD: clip_widget 'button_effect' не найден!")
        
        -- если уже играли и кнопка должна быть доступна, то включаем её
        if self.IsButtonEnabled() then
            self.ingame_lua_widget.EnableButton()
        end
        
        -- если уже играли и кнопка блокнота должна подсвечиваться, то включаем подсветку
        -- иначе, прячем её
        if self.IsButtonEnabled() and profile.GetVariable("__np_highlight") == 1 then
            self.ingame_lua_widget.ShowButtonEffect()
        else
            self.ingame_lua_widget.HideButtonEffect()
        end    
        
        self.InitPages()
    end,

    -- колбэк на открытие окна блокнота
    OnNotepadOpen = function()
        self.ingame_lua_widget._notepad_button.DisableButton(true)
        self.ingame_lua_widget.HideButtonEffect()
        self.ingame_lua_widget._ShowCloseButton()
		
		self.ingame_lua_widget._HideTutorial()
		if profile.GetVariable("__np_closed") == 0 then
			form_event([[
				sleep(]]..self.settings.tutorial.close_clip_delay..[[)
				if profile.GetVariable("__np_closed") == 0 then
					notepad.ingame_lua_widget.ShowTutorial("close")
				end
			]])
		end
    end,
    
    -- колбэк на закрытие окна блокнота
    OnNotepadClose = function()
        self.ingame_lua_widget._notepad_button.DisableButton(false)
        self.ingame_lua_widget._HideCloseButton()
		
        self.ingame_lua_widget._HideTutorial()
        if profile.GetVariable("__np_closed") == 0 and profile.GetVariable("__hint_used") == 0 then
            self.ingame_lua_widget.ShowTutorial("after_close")
        end
        
		profile.SetVariable("__np_closed", 1)
    end,
    
    -- отображает эффект подсветки над кнопкой открытия блокнота
    ShowButtonEffect = function()
        if not self.IsButtonEnabled() then return end 
        
        profile.SetVariable("__np_highlight", 1)
        self.ingame_lua_widget._button_effect.RemFlags(
            __or(sf.gui.CWidget.FlagHidden, sf.gui.CWidget.FlagDisabled))
        self.ingame_lua_widget._button_effect.GetClip().Stop()
        self.ingame_lua_widget._button_effect.GetClip().Play()
    end,
	
	-- туториал на открытие
	ShowTutorial = function(_type)
		__assert(_type == "open" or _type == "close" or _type == "after_close")
		local clip = sf.misc.anim.CClip()
		clip.Load(self.settings.tutorial[_type .. "_clip"], true)
		clip.SetPos(sf.misc.FloatVector(1024/2, 768/2))
		self.ingame_lua_widget._tutorial = clip
        self.ingame_lua_widget._tutorial_type = _type
		if _type ~= "open" then
			local tutorial_start = quest.level_timer.Get().GetTime()
            self.ingame_lua_widget._tutorial_end = tutorial_start + self.settings.tutorial[_type .. "_clip_time"]
		end
	end,
	
	_HideTutorial = function()
		self.ingame_lua_widget._tutorial = nil
        self.ingame_lua_widget._tutorial_end = nil
        self.ingame_lua_widget._tutorial_type = nil
	end,
    
    -- прячет эффект подсветки над кнопкой
    HideButtonEffect = function()
        profile.SetVariable("__np_highlight", 0)
        self.ingame_lua_widget._button_effect.AddFlags(
            __or(sf.gui.CWidget.FlagHidden, sf.gui.CWidget.FlagDisabled))
        self.ingame_lua_widget._button_effect.GetClip().Stop()
    end,
    
    HideAfterCloseTutorial = function()
        if self.ingame_lua_widget._tutorial_type == "after_close" then
            self.ingame_lua_widget._HideTutorial()
        end
    end,
    
    -- показывает кнопку закрытия блокнота
    _ShowCloseButton = function()
        self.ingame_lua_widget._close_notepad_button.RemFlags(
            __or(sf.gui.CWidget.FlagHidden, sf.gui.CWidget.FlagDisabled))        
    end,
    
    -- прячет кнопку закрытия блокнота
    _HideCloseButton = function()
        self.ingame_lua_widget._close_notepad_button.AddFlags(
            __or(sf.gui.CWidget.FlagHidden, sf.gui.CWidget.FlagDisabled))
    end,
	
	DoUpdate = function(_this)
		-- обновляем туториал
		if self.ingame_lua_widget._tutorial then 
			self.ingame_lua_widget._tutorial.Update() 
			
			-- пропадание туториала по времени
			if self.ingame_lua_widget._tutorial_end then
				local time = quest.level_timer.Get().GetTime()
				if  time >= self.ingame_lua_widget._tutorial_end then
					self.ingame_lua_widget._HideTutorial()
				end
			end
		end
		
		return false
	end,
	
	DoDraw = function(_this, _renderer)
		-- отображаем туториал
		if self.ingame_lua_widget._tutorial then 
			self.ingame_lua_widget._tutorial.Draw(_renderer) 
		end
	
		return false
	end,
    
    _actions = 
    {
        notepad_button = 
        {
            pressed = function()
                self.window.Show()
            end
        },
        
        close_notepad_button = 
        {
            pressed = function()
                self.window.Close()
            end
        }
    },
    
    __CreateInstance = function()
        return "notepad.ingame_lua_widget"
    end
}
__inherite(self.ingame_lua_widget, null_lua_widget_handler(self.ingame_lua_widget._actions))

-- NOTEPAD WINDOW
self.window = {}

-- открывает окно с блокнотом
function self.window.Show()
    if self.window._this then return end

    -- создаем виджет-окно блокнота
    local widget = sf.gui.CLuaWidget("__notepad_lua_widget_window", notepad.settings.window_layer, 0)
    
    -- создаем виджет, который будет отлавливать сообщения от мыши и останавливать их,
    -- чтобы они не дошли до нижележащих виджетов
    local broadcast_mask = __or(__or(__or(
                                sf.gui.CWidget.BroadcastOnMouseDown, 
                                sf.gui.CWidget.BroadcastOnMouseMove),
                                sf.gui.CWidget.BroadcastOnMouseUp), 
                                sf.gui.CWidget.BroadcastOnDoubleClick)
    local dummy_lua_widget = sf.gui.CLuaWidget("", 0, broadcast_mask)
    dummy_lua_widget.SetLua("qe_level")
    dummy_lua_widget.SetOverloadTable("notepad.window.dummy_lua_widget")
    dummy_lua_widget.SetSize(1024, 768)
    widget.AddWidget(dummy_lua_widget)
    
    -- инициализируем окно блокнота
    widget.Load(g_App.GetSettings().GetChild("GUI", false).GetChildByAttribute("window", "id", "notepad_window", true),
        g_App.GetSettings().GetChild("GUITemplates", false))
    
    widget.SetSize(1024, 768)
    widget.UpdateLayout()
    
    quest.global_quest_window.AddWidget(widget)
   
    self.window._this = widget
   
    -- находим кнопки и клип страницы
    self.window._page_clip_widget = __cast(widget.GetWidget("page_clip", true).get(), sf.gui.CClipWidget)
    __assert(self.window._page_clip_widget)
    
    self.window._left_button = __cast(widget.GetWidget("left", true).get(), sf.gui.CButtonWidget)
    __assert(self.window._left_button)
    
    self.window._right_button = __cast(widget.GetWidget("right", true).get(), sf.gui.CButtonWidget)
    __assert(self.window._right_button)
    
    self.window._InitPageClip()
    self.window._UpdateButtons()
    
    self.ingame_lua_widget.OnNotepadOpen()
    
    self.window.visible = true
    
    hints_lua_widget.HideHint()
    cursor_lua_widget.DropCursor()
    cursor_lua_widget.DropGameCursor()
    clear_cursor()
    quest.global_cursor.SetHintText("", false)
    scene_click_widget.Enable(false)
    
    -- перестаем отображать сцену
    if quest.global_scene_widget then
        quest.global_scene_widget.AddFlags(quest.global_scene_widget.FlagHidden)
    end
    
    -- если открыта полноэкранная миниигра, то прячем её кнопки
    if child_scenes.is_fullscreen_minigame_opened() then
        child_scenes.hide_fullscreen_minigame_buttons()
    elseif quest.global_minigame_opened then
        -- прячем неполноэкранную миниигру
        quest.global_minigame_opened.AddFlags(__or(sf.gui.CWidget.FlagHidden, sf.gui.CWidget.FlagDisabled))
    end

    -- делаем гую как в сложном режиме
    difficulty.ApplyDifLevelOwerload("hard")
    
    
    -- убираем подписи к объектам
    self.window._hints_disabled = quest.global_cursor.GetDisableHints()
    quest.global_cursor.SetDisableHints(true)

    -- прячем инвентарь
    local obj_box = objects_box_lua_widget.self
    self.window._obj_box_visible = 
        __and(obj_box.GetFlags(), sf.gui.CWidget.FlagHidden) == 0
    obj_box.AddFlags(sf.gui.CWidget.FlagHidden)
    self.window._obj_box_enabled = 
        __and(obj_box.GetFlags(), sf.gui.CWidget.FlagDisabled) == 0
    obj_box.AddFlags(sf.gui.CWidget.FlagDisabled)

    -- если открыт хог, то прячем его кнопку "закрыть"
    if hidden_object.GetActiveScene() then 
        hidden_object.lua_widget.HideWidget()
    end
end

-- закрывает окно блокнота
function self.window.Close()
    if not self.window._this then return end
    
    self.window._this.AddFlags(self.window._this.FlagDead)
    self.ingame_lua_widget.OnNotepadClose()
    self.window._this = nil
    self.window.visible = false
    
    -- снова показываем сцену
    if quest.global_scene_widget then
        quest.global_scene_widget.RemFlags(quest.global_scene_widget.FlagHidden)
    end
    
    -- если открыта полноэкранная миниигра, то отображаем её кнопки
    local fullscreen_minigame_opened = child_scenes.is_fullscreen_minigame_opened() 
    if fullscreen_minigame_opened then
        child_scenes.show_fullscreen_minigame_buttons()
    elseif quest.global_minigame_opened then
        -- показываем неполноэкранную миниигру
        quest.global_minigame_opened.RemFlags(__or(sf.gui.CWidget.FlagHidden, sf.gui.CWidget.FlagDisabled))
    end
    
    -- возвращаем отображение хинтов к первоначальному состоянию
    if not self.window._hints_disabled then
        quest.global_cursor.SetDisableHints(false)
    end
            
    -- показываем инвентарь, если он был видимым до открытия блокнота
    local obj_box = objects_box_lua_widget.self
    if self.window._obj_box_visible then
        obj_box.RemFlags(sf.gui.CWidget.FlagHidden)
    end
    if self.window._obj_box_enabled then
        obj_box.RemFlags(sf.gui.CWidget.FlagDisabled)
    end
    
    -- если открыт хог, то отображаем его кнопку "закрыть"
    local hog_opened = hidden_object.GetActiveScene()
    if hog_opened then 
        hidden_object.lua_widget.ShowWidget()
    end
    
    -- возвращаем гую как была
    if not hog_opened and not fullscreen_minigame_opened then
        difficulty.ApplyDifLevel()
    end
end

-- перемещает отображение на одну страницу вперед или назад
function self.window._MovetoNextPage(_dir)
    __assert(_dir == 1 or _dir == -1)
    
    local last_clip = self.GetCurrentPageClip()
    self.MoveToNextPage(_dir)
    if self.GetCurrentPageClip() ~= last_clip then
        self.window._InitPageClip()
    end
    self.window._UpdateButtons()
end

-- отключает/включает кнопки "вперед" и "назад" в зависимости от доступности следующей и предыдущей страниц
function self.window._UpdateButtons()
    self.window._left_button.DisableButton(not self._IsPageNextAvailable(-1))
    self.window._right_button.DisableButton(not self._IsPageNextAvailable(1))
end

function self.window._InitPageClip()
    local clip_id = self.GetCurrentPageClip()
    self.window._page_clip_widget.GetClip().Load(clip_id)
end

function self.window.DoUpdate()
    -- делаем гую как в сложном режиме
    difficulty.ApplyDifLevelOwerload("hard")
    return true
end

function self.window.__CreateInstance()
    return "notepad.window"
end

self.window._actions = 
{    
    left = 
    {
        pressed = function(_this)
            self.window._MovetoNextPage(-1)
        end
    },
    
    right = 
    {
        pressed = function(_this)
            self.window._MovetoNextPage(1)
        end
    },
}
__inherite(self.window, null_lua_widget_handler(self.window._actions))

-- виджет перехватывающий сообщения мыши
self.window.dummy_lua_widget =
{
   OnMouseMove = function(_this)
        return true
    end,
    
    OnMouseUp = function(_this)
        return true
    end,
    
    OnDoubleClick = function(_this)
        return true
    end,
    
    OnMouseDown = function(_this)
        return true
    end,

    __CreateInstance = function()
        return "notepad.window.dummy_lua_widget"
    end
}
__inherite(self.window.dummy_lua_widget, null_lua_widget_handler())

-- функция взятия блокнота в гую со сцены
-- _flying_object - id объекта, который летит в гую
function self.TakeNotepad(_flying_object)
	local current_object = quest.global_current_script_object 
	if _flying_object ~= nil then
		current_object = quest.FindRootObjectById(_flying_object)
        quest.show_object_find_error(_flying_object, current_object)
	end
	-- позиция объекта
	local widget_pos = quest.get_object_pos(current_object.GetId()) 
    if not widget_pos then
        widget_pos = sf.misc.FloatVector(0, 0)    
    end
	
	--смещение объектов относительно окна	
	local object_list_abs_pos = sf.misc.FloatVector(0,0)
    object_list_abs_pos = objects_box_lua_widget.self.GetAbsPos(false)  
	-- создаем эффект
	if current_object ~= nil and objects_box_lua_widget.objects_list ~= nil then
		if self.settings.on_take_sound then
			sound(self.settings.on_take_sound)
		end
		local new_take_effect = self._CreateTakeEffect() -- новая таблица
		-- инициализируем
		local end_pos = self.ingame_lua_widget._notepad_button.GetOffset()- object_list_abs_pos +
						self.ingame_lua_widget._notepad_button.GetSize()/2
		local taked_object = current_object
		local group_object = __cast(taked_object, qe.CSceneGroup)
		if group_object then
			taked_object = group_object.GetStateById("__inv") 
		end
		__assert(taked_object, "У объекта блокнота должно быть состояние __inv")
		
		local take_time = new_take_effect:Init(taked_object, invent_timer.Get().GetTime(), "take_time", widget_pos - object_list_abs_pos, end_pos)
		objects_box_lua_widget.InsertEffect(new_take_effect)
		quest.RemoveObject(current_object.GetId().c_str())
		if notepad.settings.fly_alpha_time then
			take_time = take_time - notepad.settings.fly_alpha_time
		end
		sleep(take_time)
		self.EnableButton()
		self.ShowOpenTutorial()
	else
		__message("Не найден объект, укажите его в параметре функции notepad.TakeNotepad()")
	end	
end
-- таблица для эффекта взятия блокнота
function self._CreateTakeEffect()
	local new_take_effect = 
    {
	-- инициализация параметров полета
        Init = function(_self, _invent_object, _start_time, _total_time, _start_pos, _end_pos )
            _self.start_pos = _start_pos
			_self.end_pos = _end_pos
            _self.fly_obj_pos = _start_pos
            _self.particle_effect = objects_box_lua_widget.effects_list:CreateEffect("TakeObject", _self.fly_obj_pos)            

			_self._object = _invent_object
			_self._pos = _invent_object.GetPos()
            _self.start_time = _start_time
            _self.total_time = ((sf.misc.CalculateFloatVectorModule(_start_pos - _end_pos))/objects_box_lua_widget.take_speed)*1000
            _self.end_time = _self.start_time + _self.total_time
            return _self.total_time
        end,
	-- отрисовка эффекта
        Draw = function(_self, _renderer)
                if _self.fly_obj_pos ~= nil then
                    local object_pos = _self._pos
                    _renderer.PushState()
                    _renderer.ApplyMatrix( sf.misc.MatrixTranslation(-object_pos.X + _self.fly_obj_pos.X , - object_pos.Y + _self.fly_obj_pos.Y))
                    _self._object.DrawGame(_renderer)
                    _renderer.PopState()
                end
        end,
	-- вычисление новых координат
        Update = function(_self, _time)
            local koef = (_time - _self.start_time)/_self.total_time

            _self.fly_obj_pos = _self.start_pos + (_self.end_pos - _self.start_pos)*koef
			if koef >= 1 then
			end			
            _self.particle_effect:SetPos( sf.misc.FloatVector(_self.fly_obj_pos.X, _self.fly_obj_pos.Y))
            if _time > _self.end_time then
                _self:InstantApply()
            end
        end,
	-- объект долетел
        InstantApply = function(_self)
            if not _self.is_dead then
                _self.particle_effect:Kill(false)
            end
            _self.is_dead = true
        end,
        
        end_pos = nil, -- куда летим
        is_dead = false, -- долетели ли
        object_InventState = nil, -- инв.состояние - его передвигаем
        end_time = nil, -- конец передвижения
        total_time = nil, -- время передвижения
        start_time = nil, -- начало передвижения
        start_pos = nil, -- начальное положение
        fly_obj_pos = nil -- где сейчас находимся
    }
    return new_take_effect
end
