class "AutoPlayer"

function AutoPlayer:__init(scene)
	self.scene = scene
	self.timer = scene:getTimer()
	
	self.stepPeriod = 0.2
	self.actionDelay = 0
	self.disableHintAnimation = true
	self.reloadMode = false
	self.destroySceneOnReload = false
	
	if AUTOPLAYER_PREVIOUS_LIFE then
    	self.stepPeriod = AUTOPLAYER_PREVIOUS_LIFE.stepPeriod
	    self.actionDelay = AUTOPLAYER_PREVIOUS_LIFE.actionDelay
	    self.disableHintAnimation = AUTOPLAYER_PREVIOUS_LIFE.disableHintAnimation
	    self.reloadMode = AUTOPLAYER_PREVIOUS_LIFE.reloadMode
	    self.destroySceneOnReload = AUTOPLAYER_PREVIOUS_LIFE.destroySceneOnReload
	    self.last_clicked_object_name = AUTOPLAYER_PREVIOUS_LIFE.last_clicked_object_name
    	AUTOPLAYER_PREVIOUS_LIFE = nil

    	self:setupNextStep(self:getStepPeriod())
	end
end

function AutoPlayer:start()
	self.playfield = self.scene:getPlayField()
	self.hint = self.playfield:getHint()
	
	if self.hint.getLastHintedObject == nil or self.hint.clearLastHintedObject == nil or self.hint.setAnimationDisabled == nil then
		Console:pushText("not supported by current hint version")
		return
	end

	self:makeGameStep()
	WriteInfo("autoplaying started.")
end

function AutoPlayer:stop()
	if self.next_step_action then
		self.next_step_action:kill()
		self.next_step_action = nil
	end
	if self.after_hint_action then
		self.after_hint_action:kill()
		self.after_hint_action = nil
	end
	WriteInfo("autoplaying stoped.")
end

function AutoPlayer:isActive()
	return self.next_step_action ~= nil or self.after_hint_action ~= nil
end

function AutoPlayer:setStepPeriod(stepPeriod)
	self.stepPeriod = stepPeriod
end

function AutoPlayer:getStepPeriod()
	return self.stepPeriod
end

function AutoPlayer:setActionDelay(actionDelay)
	self.actionDelay = actionDelay
end

function AutoPlayer:getActionDelay()
	return self.actionDelay
end

function AutoPlayer:setDisableHintAnimation(disableHintAnimation)
	self.disableHintAnimation = disableHintAnimation
end

function AutoPlayer:getDisableHintAnimation()
	return self.disableHintAnimation
end

function AutoPlayer:setReloadMode(reloadMode)
	self.reloadMode = reloadMode
end

function AutoPlayer:getReloadMode(reloadMode)
	return self.reloadMode
end

function AutoPlayer:setDestroySceneOnReload(destroySceneOnReload)
	self.destroySceneOnReload = destroySceneOnReload
	if not destroySceneOnReload then
	    AUTOPLAYER_PREVIOUS_LIFE = nil
	end
end

function AutoPlayer:getDestroySceneOnReload()
	return self.destroySceneOnReload
end

function AutoPlayer:makeGameStep()
	self.playfield = self.scene:getPlayField()
	self.panel = self.scene:getPanel()
	self.hint = self.playfield:getHint()

	local panel_mode  = self.panel:getMode()
	local tool_screen = self.scene:getToolFoundScreen()
	
	if panel_mode == EPanelMode.CUTSCENE then
		self:skipCutScene()
	elseif panel_mode == EPanelMode.COMICS and self.playfield:getMainEntity():isRespondable() then
		self:skipComics()
	elseif panel_mode == EPanelMode.MINIGAME and self.playfield:getMainEntity():isRespondable() then
		self:skipMinigame()
	elseif tool_screen then
		--close tool found windows
		local button = tool_screen:getEntityNamed("OKButton")
		button.onPress:notify(button, nil)
		WriteInfo("closing tool_found_window")
	elseif (panel_mode == EPanelMode.QUEST or panel_mode == EPanelMode.HIDDENOBJECT or panel_mode == EPanelMode.HIDDENPICTURE) and self.playfield:getMainEntity():isRespondable() then
		self.hint:clearLastHintedObject()
		self.hint:setAnimationDisabled(self.disableHintAnimation)
		self.hint:hint()
		self.hint:setAnimationDisabled(false)
		self:setupActionAfterHint(self:getActionDelay())
	end

	self:setupNextStep(self:getStepPeriod())
end

function AutoPlayer:reload()
	local tool_screen = self.scene:getToolFoundScreen()
	if tool_screen then
		WriteInfo("closing tool_found_window")
		local button = tool_screen:getEntityNamed("OKButton")
		button.onPress:notify(button, nil)
	end

	if self:getDestroySceneOnReload() then
		AUTOPLAYER_PREVIOUS_LIFE = self
		PopUpScreensMgr:destroyAll()
		destroyCurrentScene()
		
		startLevel("l_" .. self.scene:getPlayField():getName())
	else
	AUTOPLAYER_PREVIOUS_LIFE = nil
		self.scene.playfield:getMainEntity():setRespondable(false)
		self.scene:loadPlayField(self.scene:getPlayField():getName())
	end
	WriteInfo("reloading " .. self.scene:getPlayField():getName())
end

function AutoPlayer:setupActionAfterHint(delay)
	self.after_hint_action = 
		self.timer:add(
			function()
				local object_to_process = self.object_to_process_on_next_step or self.hint:getLastHintedObject()
				self.object_to_process_on_next_step = nil
				self:doActionToObject(object_to_process)
			end,
	        delay
		)
end


function AutoPlayer:setupNextStep(delay)
	self.next_step_action = 
		self.timer:add(
			function()
				self:makeGameStep()
			end,
	        delay
		)
end
-------------------------------------------------------------------------------------------------
function AutoPlayer:skipComics()
	self.panel:getComicsPanel():onSkipButtonPress()
	WriteInfo("skipping comics")
end

function AutoPlayer:skipCutScene()
	local skip_button = self.panel:getCutScenePanel():getSkipButton()
	if skip_button:isGlobalRespondable() then
		skip_button.onPress:notify(skip_button, nil)
		WriteInfo("skipping cutscene")
	end
end

function AutoPlayer:skipMinigame()
	self.panel:getControlsPanel():getHintAnimationLogic():onSkipButtonClick()
	WriteInfo("skipping minigame")
end

function AutoPlayer:doActionToObject(object)
	if object == nil  then
		self:onHintReturnsNothing()
		return
	end

	local obj_name = object:getName()

	if not object:isGlobalRespondable() then
		return
	else
		WriteInfo("processing " .. obj_name)
	end

	if obj_name:sub(1, 10) == "area_zoom_" then
		self:openZoomByTarget(obj_name)
	elseif obj_name == "area_link_exitFromMG" then
		self.playfield:close()
	elseif obj_name == "area_link_exit_from_ho" then
		self.playfield:close()
	elseif obj_name == "area_link_exit_from_hp" then
	    if self.playfield.autoplayer_exit_allowed then
		    self.playfield:close()
		end
	elseif self.playfield:getToolApplyObjectNames()[obj_name] then
		self:processToolTarget(object)
	elseif self:getDragObjectByTarget(object) then
		self:processDragObject(object)
	elseif self.tryCustomAction then
		if self:tryCustomAction(object) == false then
			self:clickOn(object)
		end
	else
		self:clickOn(object)
	end
end

function AutoPlayer:onHintReturnsNothing()
	if self.playfield:getActiveZones():GetTop() and self.playfield:getActiveZones():GetTop():getMainEntity():isGlobalRespondable() then
		--close top zoom
		self.playfield:getActiveZones():GetTop():close()
		WriteInfo("closing zoom")
	end
end

function AutoPlayer:clickOn(object)
	object.onClickBegin:notify(object, nil)
	self:tryReloading(object)
end

function AutoPlayer:tryReloading(object)
	if self:getReloadMode() == true and not self.scene.oldPlayfield then
		if self.last_clicked_object_name == nil then
			self.timer:add(function() self:reload()	end, 0)
		elseif self.last_clicked_object_name ~= object:getName() then
			self.timer:add(function() self:reload()	end, 0)
		end
	end
	self.last_clicked_object_name = object:getName()
end

function AutoPlayer:openZoomByTarget(obj_name)
	for i, v in pairs(self.playfield:getZones()) do
		local trigger_name = v:getTriggerName()
		if obj_name == v:getTriggerName() then
			v:open()
			break
		end
	end
end

function AutoPlayer:tryTakeTool(toolName)
	if TEMP_USE_OLD_INVENTORY then
		if IsToolFound(toolName) then
			local inventory = self.playfield:getGameScene():getPanel():getInventory()
			local tool_info = inventory:getToolInfoByName(toolName)
			self.playfield:getInventory():dropTool(0)
			if tool_info and not tool_info.notInInventoryYet then
				WriteInfo("taking tool "..toolName)
				inventory:takeTool(tool_info)
				return true
			end
		end
	else
		if IsToolFound(toolName) then
			local inventory	= self.playfield:getGameScene():getPanel():getInventory()
			local toolInfo	= inventory:getActiveToolInfo(toolName)

			inventory:dropAllTools(0)

			if toolInfo and not toolInfo.notInInventoryYet then
				local cell = inventory:getCellByToolInfo(toolInfo)

				if not cell:getTakeBlocker():isHold() then
					local takeTarget = cell:getTakeTarget()

					local screenFocus = self:createFakeFocus()
					screenFocus.x = takeTarget:getScrX()
					screenFocus.y = takeTarget:getScrY()
					screenFocus.pointedResponder = takeTarget

					WriteInfo("taking tool "..toolName)
					toolInfo:getDragObject():takeProcess(takeTarget, screenFocus)
					return true, toolInfo
				end
			end
		end
	end
	
	return false
end

function AutoPlayer:processToolTarget(object)
	if TEMP_USE_OLD_INVENTORY then
		local obj_name = object:getName()

		local tools = self.playfield:getToolApplyObjectNames()[obj_name]
		if type(tools) == "string" then
			tool_name = tools
			self:tryTakeTool(tool_name)
		elseif type(tools) == "table" then
			for _, tool_name in pairs(tools) do
				if self:tryTakeTool(tool_name) then
					break
				end
			end
		end

		self:clickOn(object)
	else
		local obj_name	= object:getName()
		local tool_info	= nil
		local bTake		= false

		local tools = self.playfield:getToolApplyObjectNames()[obj_name]
		if type(tools) == "string" then
			tool_name = tools
			bTake, tool_info = self:tryTakeTool(tool_name)
		elseif type(tools) == "table" then
			for _, tool_name in pairs(tools) do
				local theToolInfo
				bTake, theToolInfo = self:tryTakeTool(tool_name)

				if bTake then
					tool_info = theToolInfo
					break
				end
			end
		end

		if bTake then
			self.playfield:tryToolApply(tool_info, object)
			
			--необходимая мера в связи с использованием фейкового screenFocus
			local inventory = self.playfield:getGameScene():getPanel():getInventory()
			if inventory:isActiveTool(tool_info) then
			    tool_info:getDragObject():dropProcess(true)
			end
		end
	end
end

function AutoPlayer:getDragObjectByTarget(object)
	local function searchCondition(dragObject)
		 return dragObject:isDropTarget(object) and not dragObject:isDropOnTarget(object:getName())
	end

	return self.playfield:getDragManager():find(searchCondition)
end

function AutoPlayer:processDragObject(object)
	local dragObject = self:getDragObjectByTarget(object)
	local takeArea = dragObject:getTakeTarget()

	local screenFocus = self:createFakeFocus()
	screenFocus.x = takeArea:getScrX()
	screenFocus.y = takeArea:getScrY()
	screenFocus.pointedResponder = object

	if not dragObject:isDragging() then
		dragObject:takeProcess(takeArea, screenFocus)
		self.object_to_process_on_next_step = object
		WriteInfo("taking dragobject "..dragObject:getDraggedEntity():getName())
	else
		dragObject:placeTo(object:getScrPosition())
		dragObject:dropProcess(false)
		WriteInfo("dropping dragobject "..dragObject:getDraggedEntity():getName())
		self:tryReloading(object)
	end
end

function AutoPlayer:createFakeFocus()
	local focus = {}
	local cursor = {}

	focus.cursor = cursor
	focus.getCursor = function(self) return self.cursor end
	focus.getScrX = function(self) return self.x end
	focus.getScrY = function(self) return self.y end
	focus.getPointedResponder = function(self) return self.pointedResponder end

	local mt = {}
	mt.__index = function()
		return function() return nil end
	end

	setmetatable(focus, mt)
	setmetatable(cursor, mt)
	
	return focus
end


