-- Positions
LeftAvatarPosition = IPoint(100, 300)
RightAvatarPosition = IPoint(900, 300)

-- Avatar fade alpha
ActiveFadeValue = 1.0
PassiveFadeValue = 0.75

-- Level finish allowed or not
function ForbidLevelFinish()
	tutSetBool("LevelIsAllowedToFinish", false)
end

function AllowLevelFinish()
	tutSetBool("LevelIsAllowedToFinish", true)
end

function LevelIsAllowedToFinish()
	return tutGetBool("LevelIsAllowedToFinish")
end

-- Dialog
local DialogCharactersIndex = 0
local DialogCharacters = {}
local DialogActions = {}
local DialogActionsIndex = 0
local DialogState = 0
local DialogLevelName = ""
local DialogPrevWho = ""
local DialogForLevelEndStarted = false
local ActionHandlers = {}
local DialogShouldHideTutorial = false
local DialogShouldHideArrows = true
local DialogStarted = false

function SetText(who, textId)
	if who == DialogPrevWho then
		tutorial:nSwitchText(who, textId)
	else
		tutorial:nSetText(who, textId)
		tutorial:nSetTextVisible(who, true)
	end
	DialogPrevWho = who
end

function HideText(who)
	tutorial:nSetTextVisible(who, false)
end

function DialogAddCharacterAtPositionAndOrientation(name, position, orientation)
	tutorial:nSetVisible(name, true)
	tutorial:nSetButtonVisible(name, false)

	tutorial:nSetOffset(name, position, orientation)

	DialogCharacters[DialogCharactersIndex] = name
	DialogCharactersIndex = DialogCharactersIndex + 1
end

function DialogAddCharacter(name, position)
	local orientation = false
	if position.x == RightAvatarPosition.x and position.y == RightAvatarPosition.y then
		orientation = true
	end
	
	DialogAddCharacterAtPositionAndOrientation(name, position, orientation)
end

function DialogAvatarSay(who, what)
	tutorial:nSetFading(who, ActiveFadeValue, false)
	SetText(who, what)
end

function DialogAvatarFade(who)
	tutorial:nSetFading(who, PassiveFadeValue, false)
	HideText(who)
end

function DialogInit(LevelName)
	DialogActions = {}
	DialogActionsIndex = 0

	DialogCharacters = {}
	DialogCharactersIndex = 0

	DialogState = 0
	DialogLevelName = LevelName
	DialogPrevWho = ""

	tutorial:show(0.25)
	tutSetFloat("TutorialShowDelayTime", 1.5)
	tutSetBool("TutorialLock", true)

	DialogShouldHideTutorial = true
	DialogShouldHideArrows = true
	DialogStarted = true
	tutSetBool("DialogAfterStatistics", false)
	tutSetBool("DialogOnFinishLevel", false)
	tutSetBool("DialogRegular", true)
end

function AddAction(type, action)
	local typedAction = {}
	typedAction[type] = action

	DialogActions[DialogActionsIndex] = typedAction
	DialogActionsIndex = DialogActionsIndex + 1
end

function DialogAddLine(who, what)
	local line = {}
	line[who] = what
	AddAction("line", line)
end

function DialogAddEffect(name, pos)
	local effect = {}
	effect["name"] = name
	effect["pos"] = pos
	AddAction("effect", effect)
end

function DialogAddEarthQuake(time, count, maxAmpl)
	local params = {}
	params["time"] = time
	params["count"] = count
	params["maxAmpl"] = maxAmpl
	AddAction("earthQuake", params)
end

function DialogAddLua(luaFunc)
	local func = {}
	func["func"] = luaFunc
	AddAction("luaFunc", func)
end

function DialogWait(time)
	local wait = {}
	wait["time"] = time
	AddAction("wait", wait)
end

function DialogPlaySample(sampleId)
	DialogAddLua(function()
		Sound:PlaySample(sampleId, false)
	end)
end

function DialogShowBlackScreen()
	DialogAddLua(function()
		tutorial:showBlackScreen(0.0)
	end)
end

function DialogHideBlackScreen()
	DialogAddLua(function()
		tutorial:nHide()
	end)
	DialogWait(0.25)
	DialogAddLua(function()
		tutorial:hideBlackScreen(0.0)
	end)
	DialogWait(0.25)
end

function DialogNextAction()
	local typedAction = DialogActions[DialogState]

	for type, action in pairs(typedAction) do
		ActionHandlers[type](action)
	end
end

function DialogNiceDialogEndOnLevelFinish()
	DialogAddLua(function()
		tutorial:nHide()
	end)
	DialogWait(0.5)
end

function DialogPauseGame()
	tutorial:game():pauseLevelTime(true)
end

function DialogResumeGame()
	tutorial:game():pauseLevelTime(false)
end

function DialogForbidRentGeneration()
	tutorial:variables():setBool("TutorialRentgenEnabled", false)
end

function DialogAllowRentGeneration()
	DialogAddLua(function()
		tutorial:variables():setBool("TutorialRentgenEnabled", true)
		tutorial:game():GenerateRentForReachableHouse()
	end)
end
-----------------------------------------------------------------------------------------------------
-- Обработчики действий
-----------------------------------------------------------------------------------------------------
ActionHandlers["line"] = function(line)
	for who, what in pairs(line) do
		for i, name in pairs(DialogCharacters) do
			if name == who then
				DialogAvatarSay(name, what)
			else
				DialogAvatarFade(name)
			end
		end
	end
end

ActionHandlers["effect"] = function(effect)
	tutorial:addParticleEffect(effect["name"], effect["pos"])
end

ActionHandlers["earthQuake"] = function(params)
	tutorial:startEarthQuake(params["time"], params["count"], params["maxAmpl"])
end

ActionHandlers["luaFunc"] = function(action)
	action["func"]()
	tutorial:actionDidFinish()
end

ActionHandlers["wait"] = function(action)
	tutorial:wait(action["time"])
end
-----------------------------------------------------------------------------------------------------
-- Начало и конец туториала
-----------------------------------------------------------------------------------------------------
function DialogOnLevelLoad()
	tutSetBool("TutorialToSelect", true)
	--HideFAN()
end

function DialogStart()
	DialogWait(0.25)
	DialogNextAction()
	HideFAN()
	--ShowTutorialSkip()
end

function DialogFinish()
	ShowFAN()
	DialogFinishNoHide()
	tutorial:setObjectsAllowType(allowPass)
	if DialogShouldHideTutorial == true then
		tutorial:hide(0.25)
	end
	DialogStarted = false
	--HideTutorialSkip()
	--[[
	local arrowsCount = tutorial:arrowsCount()
	for arrowIndex = 0, arrowsCount - 1 do
		tutorial:removeArrow(0)
	end
	]]
end

function DialogFinishNoHide()
	tutSetBool("TutorialToSelect", true)
	SetTutShowed(DialogLevelName)
	AllowLevelFinish()
end

function DialogSkip()
	if tutGetBool("DialogRegular") == true then
		DialogState = DialogActionsIndex - 1

		tutorial:hideArrows(0.25)
		if tutGetBool("DialogAfterStatistics") == true then
			SetFinishTutShowed_AfterStatistics(DialogLevelName)
		end

		if tutGetBool("DialogOnFinishLevel") == true then
			DialogState = DialogActionsIndex - 5
		end

		DialogAllowRentGeneration()
		DialogNextAction()
	else
		avatar:hide()
		Pirat:hide()
		RE2A_04_01_StartDialog:arrowHideAll()
		RE2A_04_01_StartDialog:goToFinish()
		RE2A_04_01_StartDialog:disableSelection()
	end

	tutorial:hideSkipButton()
	GUI:getLayer("Tutorial"):getWidget("TutorialSkip"):AcceptMessage(Message("Active2", 0))
end

function DialogProcessMessage(message)
	-- Нет действий в туториале
	if DialogActionsIndex == 0 then return end 
	-- Диалог закончился
	if DialogStarted == false then return end
	-- Обрабатываем клик по туториалу для скипа
	-- Скрывание туториала
	-- Закончилось очередное действие
	if message:is("TutorialOk", "press") or message:is("MapTutorialDidHide") or message:is("GameTutorialActionFinished") then
		--PrintDebug("DialogProcessMessage, message is "..message:getPublisher().."\n")
		DialogState = DialogState + 1
		--PrintDebug("DialogProcessMessage, DialogState = "..tostring(DialogState).."\n")
		-- Действий всегда на одно больше. Последнее - скрываем туториал
		if DialogState < DialogActionsIndex + 1 then
			if DialogState < DialogActionsIndex then
				DialogNextAction()	-- Обычные действия - обрабатываем в обычном порядке
			else
				--PrintDebug("tutorial:nHide()\n")
				tutorial:nHide()	-- Прячем аватарки
			end
		else
			tutSetBool("TutorialLock", false)
			DialogFinish()			-- Прячем туториал
		end
	end
end

function SetTutShowed(levelId)
	gameInfo:setBoolData(levelId.."Tutorial", true)
end

function IsTutShowed(levelId)
	local id = levelId.."Tutorial"
	return gameInfo:isDataSet(id) and gameInfo:getBoolData(id)
end

function IsFinishTutShowed(levelId)
	local id = levelId.."FinishTutorial"
	return gameInfo:isDataSet(id) and gameInfo:getBoolData(id)
end

function SetFinishTutShowed_AfterStatistics(levelId)
	tutSetBool("DialogAfterStatistics", false)
	SetFinishTutShowed(levelId)
	tutorial:game():AcceptMessage(Message("StatisticsOk"))
end

function SetFinishTutShowed(levelId)
	gameInfo:setBoolData(levelId.."FinishTutorial", true)
end

function AddSmartHint(name)
	tutorial:queueAddMessage(name)
end

function ShowTutorialSkip()
	GUI:getLayer("Tutorial"):getWidget("TutorialSkip"):setVisible(true)
	GUI:getLayer("Tutorial"):getWidget("TutorialSkip"):AcceptMessage(Message("Active2", 1))
	tutorial:showSkipButton(-1.5)
end

function HideTutorialSkip()
	GUI:getLayer("Tutorial"):getWidget("TutorialSkip"):setVisible(false)
end

--[[
	Базовый "класс" для всех подсказок

	Пример использования:
	Создадим подсказку на основе hint

local hintInstance = hint:create("hintInstance")
-- Здесь содержится основная логика - обработка сообщений
function hintInstance:onProcessMessage(message)
	PrintDebug("hintInstance:onProcessMessage("..message:getPublisher()..")\n")
	-- Вызов вновь добавленного метода
	self:customMethod()
end

-- Новый метод
function hintInstance:customMethod()
	PrintDebug("Custom method\n")
end

-- Это функция подсказки
function NewTestHint(message)
	hintInstance:processMessage(message)
end
]]
hint = { 
	-- Идентификатор подсказки по умолчанию
	hintId = "hint",
}
hint_mt = { __index = hint }

--[[ 
	Создает объект типа "Подсказка". В качестве параметра принимает уникальный идентификатор
	У нового объекта можно переопределить методы:
		onInit
		onFinish
		onProcessMessage
		onStart
	 или добавить новые.
]]
function hint:create(hId)
	return setmetatable({ hintId = hId }, hint_mt)
end

-- Active - активна ли текущая подсказка в данный момент?
function hint:setActive(active) tutSetBool(self.hintId.."Active", active) end
function hint:isActive() return tutGetBool(self.hintId.."Active") end

-- State - состояние подсказки
function hint:setState(state) tutSetInt(self.hintId.."State", state) end
function hint:getState() return tutGetInt(self.hintId.."State") end

-- Time - обработка таймера
function hint:setTime(time) tutSetFloat(self.hintId.."Time", time) end
function hint:getTime() return tutGetFloat(self.hintId.."Time") end
function hint:updateTime(message) self:setTime(self:getTime() + message:getVariables():getFloat("TimeDelta")) end

-- Shown - показана ли уже подсказка (в случае, когда подсказку нужно показать один раз)
function hint:setShown(shown) tutSetBool(self.hintId.."Shown", shown) end
function hint:isShown() return tutGetBool(self.hintId.."Shown") end

-- ArrowIndex - номер стрелки
function hint:setArrowIndex(index) tutSetInt(self.hintId.."ArrowIndex", index) end
function hint:getArrowIndex() return tutGetInt(self.hintId.."ArrowIndex") end
function hint:incArrowIndex() self:setArrowIndex(self:getArrowIndex() + 1) end

-- ClickCount - количество кликов до необходимого действия
function hint:setClickCount(count) tutSetInt(self.hintId.."ClickCount", count) end
function hint:getClickCount() return tutGetInt(self.hintId.."ClickCount") end

-- ClickCounter - счетчик кликов
function hint:setClickCounter(count) tutSetInt(self.hintId.."ClickCounter", count) end
function hint:getClickCounter() return tutGetInt(self.hintId.."ClickCounter") end
function hint:decClickCounter() self:setClickCounter(self:getClickCounter() - 1) end

-- Обработан ли клик в текущем кадре?
function hint:setClickAccepted(accepted) tutSetBool(self.hintId.."ClickAccepted", accepted) end
function hint:isClickAccepted() return tutGetBool(self.hintId.."ClickAccepted") end

-- Прощелкали ли туториал
function hint:isPassed(message) return message:is("TutorialOk", "press") end

-- Функция вызывается один раз при запуске уровня (на событие LoadLevel)
function hint:init()
	self:setShown(false)
	self:setClickCount(1)
	self:onInit()

	self:reset()
end

-- Сбрасывает подсказку в начальное состояние (при завершении текущего цикла подсказки)
-- Однако не сбрасывает признак isShown() чтобы не показывать подсказку второй раз, если это не требуется
function hint:reset()
	self:setActive(false)
	self:setState(0)
	self:setTime(0.0)
	self:setArrowIndex(0)
	self:setClickCounter(self:getClickCount())
	self:setClickAccepted(false)

	self:onReset()
end

-- Завершает очередной цикл показа подсказки. Подсказка может быть показана вновь, если isShown() не равен true
function hint:finish()
	self:arrowRemoveAll()
	self:unlock()
	self:reset()

	self:onFinish()
end

-- Начинает показывать подсказку - стрелки, аватарки, все дела
function hint:start()
	tutorial:setObjectsAllowType(allowPass)
	tutorial:show(0.25)
	--DialogStartCount = DialogStartCount + 1
	--PrintDebug("hint:start(), DialogStartCount = "..tostring(DialogStartCount).."\n")

	self:lock()
	self:setActive(true)

	self:onStart()
end

-- Вызывается, когда нужно завершить текущий цикл показа подсказки (чтобы она исчезла)
function hint:goToFinish()
	self:setTime(0.0)
	self:setState(999)
	DialogResumeGame()
end

-- Активна ли в текущий момент какая-либо подсказка?
function hint:lock() tutSetBool("TutorialLock", true) end
function hint:unlock() tutSetBool("TutorialLock", false) end
function hint:isLocked() return tutGetBool("TutorialLock") end

-- 
-- Стрелки
-- 
function hint:getArrowIndexParamName(arrowIndex)
	local paramName = self.hintId.."Arrow"..tostring(arrowIndex)
	return paramName
end

function hint:arrowAdd(pos, angle)
	local arrowId = tutorial:addArrow()
	tutorial:getArrow(arrowId):setPosition(pos.x, pos.y)
	tutorial:getArrow(arrowId):setAngle(angle)
	tutorial:getArrow(arrowId):setIgnoreContext(true)

	return arrowId
end

function hint:arrowGetId(arrowIndex)
	if arrowIndex >= 0 and arrowIndex < self:getArrowIndex() then
		local paramName = self:getArrowIndexParamName(arrowIndex)
		local arrowId = tutGetInt(paramName)
		return arrowId
	end
end

function hint:arrowGet(arrowIndex)
	local arrowId = self:arrowGetId(arrowIndex)
	if arrowId ~= nil then
		return tutorial:getArrow(arrowId)
	else
		return nil
	end
end

function hint:arrowSave(arrowId)
	local paramName = self:getArrowIndexParamName(self:getArrowIndex())
	tutSetInt(paramName, arrowId)
	self:incArrowIndex()
	--PrintDebug("hint:arrowSave, paramName = "..paramName..", arrowId = "..tostring(arrowId)..", self:arrowIndex() = "..tostring(self:getArrowIndex()).."\n")
end

function hint:arrowShow(arrowIndex, time)
	if arrowIndex >= 0 and arrowIndex < self:getArrowIndex() then
		local paramName = self:getArrowIndexParamName(arrowIndex)
		local arrowId = tutGetInt(paramName)
		tutorial:getArrow(arrowId):show(time)
	end
end

function hint:arrowShowAtPosition(pos, arrowIndex, time)
	if arrowIndex >= 0 and arrowIndex < self:getArrowIndex() then
		local paramName = self:getArrowIndexParamName(arrowIndex)
		local arrowId = tutGetInt(paramName)
		tutorial:getArrow(arrowId):setPosition(pos.x, pos.y)
		tutorial:getArrow(arrowId):show(time)
	end
end

function hint:arrowHide(arrowIndex)
	if arrowIndex >= 0 and arrowIndex < self:getArrowIndex() then
		local paramName = self:getArrowIndexParamName(arrowIndex)
		local arrowId = tutGetInt(paramName)
		tutorial:getArrow(arrowId):hide(time)
	end
end

function hint:arrowHideAll()
	tutorial:hideArrows(0.25)
end

function hint:arrowRemoveAll()
	for arrowIndex = 0, self:getArrowIndex() do
		local paramName = self:getArrowIndexParamName(arrowIndex)
		tutorial:variables():eraseName(paramName)
	end

	self:setArrowIndex(0)
end

-- Обработка сообщений - вся логика здесь
function hint:processMessage(message)
	-- Начальная инициализация (при загрузке уровня)
	if message:is("LoadLevel") then
		self:init()
	end

	self:onProcessMessageRegardlessLock(message)

	-- Подсказка вот-вот пропадет
	if self:isActive() and self:getState() == 999 then
		if message:is("Update") then
			self:updateTime(message)
			if self:getTime() >= 0.5 then
				self:finish()
			end
		end
	end

	-- Активна подсказка, но не эта
	if self:isLocked() and not self:isActive() then 
		return
	end

	if self:isShown() then return end
	self:onProcessMessage(message)
end

-- OVERRIDE
function hint:onInit()
	--PrintDebug("hint:onInit\n")
end

-- OVERRIDE
function hint:onReset()
	--PrintDebug("hint:onReset\n")
end

-- OVERRIDE
function hint:onFinish()
	--PrintDebug("hint:onFinish\n")
end

-- OVERRIDE
function hint:onStart()
end

-- OVERRIDE
function hint:onProcessMessage(message)
	--PrintDebug("hint:onProcessMessage("..message:getPublisher()..")\n")
end

-- OVERRIDE
function hint:onProcessMessageRegardlessLock(message)
end
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
--[[
local hintInstance = hint:create("hintInstance")
function hintInstance:onProcessMessage(message)
	PrintDebug("hintInstance:onProcessMessage("..message:getPublisher()..")\n")
	self:customMethod()
end

function hintInstance:customMethod()
	PrintDebug("Custom method\n")
end

function NewTestHint(message)
	if message:is("LoadLevel") then
		hintInstance:processMessage(message)
	end
end
]]

------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
--[[
Управление аватаркой Седрика
]]
avatar = {
	-- В умных подсказках будет только Седрик
	name = "Sedrik",
	-- Положение Седрика по умолчанию
	pos = IPoint(20, 150),
	orientation = false
}
avatar_mt = { __index = avatar }

function avatar:create(who)
	return setmetatable({ name = who }, avatar_mt)
end

--
-- Седрик
--
-- Показать текст
function avatar:setText(textId)
	tutorial:nSetText(self.name, textId)
	tutorial:nSetTextVisible(self.name, true)
end

-- Спрятать текст
function avatar:hideText()
	tutorial:nSetTextVisible(self.name, false)
end

-- Поменять текст
function avatar:switchText(textId)
	tutorial:nSwitchText(self.name, textId)
end

-- Показать аватарку с текстом
function avatar:show(textId)
	self:addCharacter(self.name)
	self:setText(textId)
	self:setFaded(false)

	tutorial:setAutoCompleteAfterReadingFinished(false)
	tutSetFloat("TutorialShowDelayTime", 0.0)
	tutSetBool("TutorialLock", true)
	tutorial:show(0.25)
	DialogPauseGame()
end

-- Спрятать аватарку
function avatar:hide()
	tutorial:nHide()
end

-- Добавляет аватарку (но не показывает)
function avatar:addCharacter()
	tutorial:nSetVisible(self.name, true)
	tutorial:nSetButtonVisible(self.name, false)
	tutorial:nSetOffset(self.name, self.pos, self.orientation)
end

function avatar:hideCharacter()
	tutorial:nSetVisible(self.name, false)
end

function avatar:setOffset(pos, orientation)
	self.pos = pos
	self.orientation = orientation
	tutorial:nSetOffset(self.name, self.pos, self.orientation)
end

function avatar:setFaded(faded)
	if faded == true then
		tutorial:nSetFading(self.name, PassiveFadeValue, false)
	else
		tutorial:nSetFading(self.name, ActiveFadeValue, false)
	end
end

