scene_effects = {}

-- PLACE OBJECTS
scene_effects.place_objects = 
{
	Init = function()
		local scene_widget = quest.global_scene_widget
		assert(scene_widget)
		assert(not scene_widget.GetWidget("__place_objects", false).get())
		
		local self = scene_effects.place_objects		
		
		local constants = quest.game_resources.GetChild("Constants", false).GetChildRef("place_objects", false)
		if not constants then
			__message("Элемент place_objects не найден в constants.xml!")
			return
		end
		
		self.amulet_place = sf.core.g_Application.GetResourceManager().GetTexture("gui_game_gui_panel_patch")
		assert(self.amulet_place)
		self.amulet_place = self.amulet_place.GetTexture(0)
		assert(self.amulet_place)
		
		self.separation = sf.graphics.CImage(constants.GetValue("vertical_line_image"))
		local line_size = self.separation.GetTextureSize()
		self.separation.SetRect(sf.misc.FloatRect(
			tonumber(constants.GetValue("vertical_line_pos_x").c_str()) - line_size.X/2, 
			tonumber(constants.GetValue("vertical_line_pos_y").c_str()) - line_size.Y/2, 0, 0))
		
		local scene = qe.CSceneWidget("standart", false, quest.game_resources.GetChild("GUITemplates", true))
		__assert(quest.global_played_level.EnumScenes()>=2, 
			"place_objects: уровень '"..tostring(quest.global_played_level.GetId()).."' должен содержать как минимум 2 сцены")
			
		local it = quest.global_played_level.GetScenes()
		it.Next()
		local second_scene = it.Get()
		scene.SetScene(second_scene)
		scene.SetOffset(self.separation.GetRect().X + line_size.X - 1, 0)
		scene_widget.AddWidget(scene)
		
		-- АХТУНГ! Костыльная связность с task_lua_widget
		tasks_lua_widget.completed_tasks_label_text = sf.misc.g_StringTable.Instance().GetString(951).c_str() --"Objects found %i/%i"
		
		local description_widget = quest.global_quest_window.GetWidget("place_objects_description", true).get()
		description_widget = description_widget and __cast(description_widget, sf.gui.CLabelWidget)
		__assert(description_widget, "label_widget 'find_differences_description' не найден")
		local color = sf.graphics.Color(description_widget.GetColor())
		color.Alpha = 255
		description_widget.SetColor(color)
		
		self._effect_list = visual_effects.CreateEffectsList()
		
		quest.global_cursor.SetDisableHints(true)
		
		self.take_objects = {}
		local iter = second_scene.GetObjects()
		while not iter.IsEnd() do
			local id = tostring(iter.Get().GetIdRef())
			if string.match(id, "_", string.len(id)) then
				local group = __cast(iter.Get(), qe.CSceneGroup)
				__assert(group, "Объект "..id.." должен быть группой!")
				__assert(group.EnumChilds()==1, "Объект "..id.." должен содержать ровно 1 состояние!" )
				local width = self._GetObjectWidthInCells(group.GetChilds().Get())
				table.insert( self.take_objects, {id = id, width = width} )
				--__message("width = "..iter.Get().GetSize().X.."  cells_width = " ..width)
			end
			iter.Next()
		end
		
		form_event('scene_effects.place_objects._UpdateInventory()')
		
		local place_objects = sf.gui.CLuaWidget("__place_objects", 0, sf.gui.CWidget.BroadcastOnMouseMove)
		place_objects.SetLua(quest.g_Lua.GetId())
		place_objects.SetOverloadTable("scene_effects.place_objects")
		place_objects.SetSize(1024, 768)
		scene_widget.AddWidget(place_objects)
	end,
	
	DoDraw = function(_this, _renderer)
		local self = scene_effects.place_objects
		
		self.separation.Draw(_renderer)
		
		self._effect_list:PreDraw(_renderer)
		self._effect_list:PostDraw(_renderer)
		
		_renderer.RenderTexture(self.amulet_place, 142.5 - self.amulet_place.GetRect().Width/2,  721.5 - self.amulet_place.GetRect().Height/2, 
			sf.graphics.Color(255, 255, 255, 255))
		return true
	end,
	
	DoUpdate = function(_this)
		local self = scene_effects.place_objects

		self._effect_list:Update()
		
		if not self._completed then
			self._completed = true
			for _,task in ipairs(quest.global_tasks) do
				if task.state~=3 then 
					self._completed = false 
					break 
				end
			end
			if self._completed then
				form_event("complete_level()")
			end
		end
		return true
	end,
	
	_GetObjectWidthInCells = function(_obj)
		local size = _obj.GetSize().X
		return math.floor(size/(objects_box_lua_widget.CellSize.X + 1)) + 1
	end,
	
	_UpdateInventory = function()
		local self = scene_effects.place_objects
		
		local full_cells = 0
		local inv = objects_box_lua_widget.objects_list.GetObjects()
		while not inv.IsEnd() do
			full_cells = full_cells + self._GetObjectWidthInCells(inv.Get().InventState)
			inv.Next()
		end
		local free_cells = objects_box_lua_widget.VisibleCellsCount - full_cells
		
		while free_cells>0 do
			local objects = {}
			for i,o in ipairs(self.take_objects) do
				if o.id and o.width<=free_cells and is_object_on_level(o.id) then
					table.insert(objects, o)
				end
			end
			if #objects>=1 then
				local obj = objects[math.random(#objects)]
				form_event("inventory.momental_take('"..obj.id.."')")
				obj.id = nil
				free_cells = free_cells - obj.width
			else
				break
			end
		end
	end,
	
	ShowStartDialog = function()
		if not s10 then return end
		
		local window = quest.global_quest_window
		local dialog = sf.gui.CWindow()
		local info = g_App.GetSettings().GetChild("GUI", false).GetChildByAttributeRef("window", "id", "s10_place_objects_description", true)
		assert(info)
        dialog.Load(info, g_App.GetSettings().GetChild("GUITemplates", false))
        dialog.UpdateLayout()
        dialog.SetOffset((window.GetSize().X - dialog.GetSize().X)/2, (window.GetSize().Y - dialog.GetSize().Y)/2)
        MoveWindowToCenter(window, dialog)

        local dialog_ptr = sf.gui.CBaseWindowPtrT(dialog)
        window.AddChildWindow(dialog_ptr)
	end,
	
	ClickEffect = function(_cursor_obj, _id)
		local self = scene_effects.place_objects
		
		--__message("cursor(_cursor_obj)="..(cursor(_cursor_obj) and "true" or "false"))
		if not cursor(_cursor_obj) then return false end
		
		add_score("take_type", 1)
	
		assert(_id)
		local pos = quest.get_object_pos(_id)
		
		self._effect_list:CreateInstantEffect("PlaceObjectCorrectClick", pos)
		remove(_cursor_obj)
		-- SLEEP
		sleep(500)
		
		self._UpdateInventory()
		return true
	end,
	
	DialogAction = function(_this, _action, _child)
		if tostring(_action)=="pressed" then _this.AddFlags(_this.FlagDead) end
	end,
	
	__CreateInstance = function() return "scene_effects.place_objects" end
}
__inherite(scene_effects.place_objects, null_lua_widget_handler())

-- MIRROR MAGIC
scene_effects.mirror_magic = 
{
	Init = function()
        quest.SetDefaultWrongAction(false)
		local scene_widget = quest.global_scene_widget
		assert(scene_widget)
		assert(not scene_widget.GetWidget("__mirror_magic", false).get())
		
		local self = scene_effects.mirror_magic		
		
		local constants = quest.game_resources.GetChild("Constants", false).GetChildRef("mirror_magic", false)
		
		self.other_cursor = sf.core.g_Application.GetResourceManager().GetTexture(constants.GetValue("target_cursor_image"))
		assert(self.other_cursor)
		self.other_cursor = self.other_cursor.GetTexture(0)
		assert(self.other_cursor)
		
		self.amulet_place = sf.core.g_Application.GetResourceManager().GetTexture("gui_game_gui_panel_patch")
		assert(self.amulet_place)
		self.amulet_place = self.amulet_place.GetTexture(0)
		assert(self.amulet_place)
		
		self.separation = sf.graphics.CImage(constants.GetValue("vertical_line_image"))
		local line_size = self.separation.GetTextureSize()
		self.separation.SetRect(sf.misc.FloatRect(
			tonumber(constants.GetValue("vertical_line_pos_x").c_str()) - line_size.X/2, 
			tonumber(constants.GetValue("vertical_line_pos_y").c_str()) - line_size.Y/2, 0, 0))
		
		local scene = qe.CSceneWidget("standart", false, quest.game_resources.GetChild("GUITemplates", true))
		__assert(quest.global_played_level.EnumScenes()>=2, 
			"mirror_magic: уровень '"..tostring(quest.global_played_level.GetId()).."' должен содержать как минимум 2 сцены")
			
		local it = quest.global_played_level.GetScenes()
		it.Next()
		scene.SetScene(it.Get())
		scene.SetOffset(self.separation.GetRect().X + line_size.X - 1, 0)
		scene_widget.AddWidget(scene)
		
		-- АХТУНГ! Костыльная связность с task_lua_widget
		tasks_lua_widget.completed_tasks_label_text = sf.misc.g_StringTable.Instance().GetString(835).c_str()
		
		local description_widget = quest.global_quest_window.GetWidget("find_differences_description", true).get()
		description_widget = description_widget and __cast(description_widget, sf.gui.CLabelWidget)
		__assert(description_widget, "label_widget 'find_differences_description' не найден")
		local color = sf.graphics.Color(description_widget.GetColor())
		color.Alpha = 255
		description_widget.SetColor(color)
		
		self._effect_list = visual_effects.CreateEffectsList()
		
		quest.global_cursor.SetDisableHints(true)
		
		local mirror_magic = sf.gui.CLuaWidget("__mirror_magic", 0, sf.gui.CWidget.BroadcastOnMouseMove)
		mirror_magic.SetLua(quest.g_Lua.GetId())
		mirror_magic.SetOverloadTable("scene_effects.mirror_magic")
		mirror_magic.SetSize(1024, 768)
		scene_widget.AddWidget(mirror_magic)
	end,
	
	DoDraw = function(_this, _renderer)
		local self = scene_effects.mirror_magic
		
		self.separation.Draw(_renderer)
		
		self._effect_list:PreDraw(_renderer)
		self._effect_list:PostDraw(_renderer)
		
		local pos = sf.misc.FloatVector(sf.gui.g_Cursor.Instance().GetPosition())
		pos.X = self._MirrorPos(pos.X) - self.other_cursor.GetRect().Width/2
		pos.Y = pos.Y - self.other_cursor.GetRect().Height/2
		_renderer.RenderTexture(self.other_cursor, pos.X, pos.Y, sf.graphics.Color(255, 255, 255, 255))
		
		
		_renderer.RenderTexture(self.amulet_place, 142.5 - self.amulet_place.GetRect().Width/2,  721.5 - self.amulet_place.GetRect().Height/2, 
			sf.graphics.Color(255, 255, 255, 255))
		return true
	end,
	
	DoUpdate = function(_this)
		local self = scene_effects.mirror_magic
        if self.mouse_down == true then
            self.mouse_down = nil
            if not self.true_action then
                quest.WrongAction()
            end
        end
        if self.true_action == true then
            self.true_action = nil   
        end

		self._effect_list:Update()
		
		if not self._completed then
			self._completed = true
			for _,task in ipairs(quest.global_tasks) do
				if task.state~=3 then 
					self._completed = false 
					break 
				end
			end
			if self._completed then
				form_event("complete_level()")
			end
		end
		return true
	end,
	
	OnMouseDown = function(_this, _pos, _button, _state, _broadcast)
		local self = scene_effects.mirror_magic
		
		if not self._guard then
            self.mouse_down = true
			self._guard = true
			local pos = sf.misc.FloatVector(_pos)
			pos.X = self._MirrorPos(pos.X)
			_this.GetParentWidget().OnMouseDown(pos, _button, _state, _broadcast)
			self._guard = false
		end
		return false
	end,
	
	_MirrorPos = function(_pos)
		return math.mod(_pos + 1024/2, 1024)
	end,
	
	ShowStartDialog = function()
		if not s10 then return end
		
		local window = quest.global_quest_window
		local dialog = sf.gui.CWindow()
		local info = g_App.GetSettings().GetChild("GUI", false).GetChildByAttributeRef("window", "id", "s10_mirror_magic_description", true)
		assert(info)
        dialog.Load(info, g_App.GetSettings().GetChild("GUITemplates", false))
        dialog.UpdateLayout()
        dialog.SetOffset((window.GetSize().X - dialog.GetSize().X)/2, (window.GetSize().Y - dialog.GetSize().Y)/2)
        MoveWindowToCenter(window, dialog)

        local dialog_ptr = sf.gui.CBaseWindowPtrT(dialog)
        window.AddChildWindow(dialog_ptr)
	end,
	
	ClickEffect = function(_id)
		local self = scene_effects.mirror_magic
        self.true_action = true
		
		add_score("take_type", 1)
	
		local _id = _id or quest.global_current_script_object and quest.global_current_script_object.GetId()
		assert(_id)
		local pos = quest.get_object_pos(_id)
		
		self._effect_list:CreateInstantEffect("MirrorMagicCorrectClick", pos)
		pos.X = self._MirrorPos(pos.X)
		self._effect_list:CreateInstantEffect("MirrorMagicCorrectClick", pos)
	end,
	
	DialogAction = function(_this, _action, _child)
		if tostring(_action)=="pressed" then _this.AddFlags(_this.FlagDead) end
	end,
	
	__CreateInstance = function() return "scene_effects.mirror_magic" end
	
}
__inherite(scene_effects.mirror_magic, null_lua_widget_handler())

-- ЭФФЕКТ ФОНАРИКА
scene_effects.flashlight = 
{
	Init = function(_back_id, _mask_id, _spot_id)
		if s10==nil then return end
		
		local scene_widget = __cast(quest.global_scene_widget, qe.CSceneWidget)
		assert(scene_widget)
		assert(not scene_widget.GetWidget("__flashlight", false).get())
		
		scene_effects.flashlight.back = sf.core.g_Application.GetResourceManager().GetTexture(_back_id)
		assert(scene_effects.flashlight.back)
		scene_effects.flashlight.mask = sf.core.g_Application.GetResourceManager().GetTexture(_mask_id)
		assert(scene_effects.flashlight.mask)
		
		if _spot_id then
			scene_effects.flashlight.spot = sf.core.g_Application.GetResourceManager().GetTexture(_spot_id)
			assert(scene_effects.flashlight.spot)
			scene_effects.flashlight.spot = scene_effects.flashlight.spot.GetTexture(0)
			assert(scene_effects.flashlight.spot)
		else
			scene_effects.flashlight.spot = nil
		end
	
		local flashlight = sf.gui.CLuaWidget("__flashlight", 0, sf.gui.CWidget.BroadcastOnMouseMove)
		flashlight.SetLua(quest.g_Lua.GetId())
		flashlight.SetOverloadTable("scene_effects.flashlight")
		scene_widget.AddWidget(flashlight)
		
		scene_effects.flashlight.abs_pos = flashlight.GetAbsPos(true)
	end,
	
	DoDraw = function(_this, _renderer)
		_renderer.PushState()
		
		local cursor_pos = sf.gui.g_Cursor.Instance().GetPosition() - scene_effects.flashlight.abs_pos
		s10.misc.RenderFlashlightEffect(_renderer, scene_effects.flashlight.back, scene_effects.flashlight.mask, cursor_pos.X, cursor_pos.Y)
		if scene_effects.flashlight.spot then
			_renderer.SetBlendMode(_renderer.BlendAdditive)
			local rect = scene_effects.flashlight.spot.GetRect()
			_renderer.RenderTexture(scene_effects.flashlight.spot, cursor_pos.X - rect.Width/2, cursor_pos.Y - rect.Height/2, sf.graphics.Color(255, 255, 255, 255))
		end
		_renderer.PopState()
		return true
	end,
	
	__CreateInstance = function() return "scene_effects.flashlight" end
}
__inherite(scene_effects.flashlight, null_lua_widget_handler())

-- ЭФФЕКТ ЗЕМЛЕТРЯСЕНИЯ
scene_effects.shake = 
{
	Init = function(_shake_time, _delay_min, _delay_max, _radius, _period, _interval_x, _interval_y, _parent, _window, _show_effect, _play_sound)
		--if s10==nil then return end
		
		local self = scene_effects.shake
		local scene_widget = _parent
		if not scene_widget then scene_widget = quest.global_scene_widget end
		assert(not scene_widget.GetWidget("__shake", false).get())
		
		self._shake_time = _shake_time
		self._delay_min = _delay_min
		self._delay_max = _delay_max
		self._radius = _radius
		self._period = _period
		self._interval = sf.misc.FloatVector(_interval_x, _interval_y)
		self._window = _window
		
		if not self._window then self._window = quest.global_quest_window end
		
		local shake = sf.gui.CLuaWidget("__shake", 0, 0)
		shake.SetLua(quest.g_Lua.GetId())
		shake.SetOverloadTable("scene_effects.shake")
		scene_widget.AddWidget(shake)
		
		self._timer = sf.core.CTimerWrapper(sf.core.g_Application.GetTimeManager().GetTimer("qe_level").AttachTimer(""))
		self._stop = false
		
		self._InitTime(_show_effect, _play_sound)
		
		form_event([[
			if quest.global_current_main_scene and quest.global_current_main_scene.IsContentObject("gui_amulet_present") then
				scene_effects.shake.Stop(true)
			end
		]])
	end,
	
	_InitTime = function(_show_effect, _play_sound)
		local self = scene_effects.shake
		self._end_time = self._shake_time + math.random(self._delay_min, self._delay_max)
		self._timer.Get().SetTime(0)
		self._show_effect = _show_effect
		self._play_sound = _play_sound
		self._effect_showed = false
		self._sound_played = false
	end,
	
	Stop = function(_stop)
		scene_effects.shake._stop = _stop
	end,
	
	DoOnce = function(_shake_time, _delay_min, _delay_max, _radius, _period, _interval_x, _interval_y)	
		local self = scene_effects.shake
		
		self._store_params = {}		
		self._store_params._shake_time = self._shake_time
		self._store_params._delay_min = self._delay_min
		self._store_params._delay_max = self._delay_max
		self._store_params._radius = self._radius
		self._store_params._period = self._period
		self._store_params._interval = sf.misc.FloatVector(self._interval)
		
		self._shake_time = _shake_time
		self._delay_min = _delay_min
		self._delay_max = _delay_max
		self._radius = _radius
		self._period = _period
		self._interval = sf.misc.FloatVector(_interval_x, _interval_y)
		
		self._InitTime(self._show_effect, self._play_sound)
	end,
	
	DoUpdate = function(_this)
		local self = scene_effects.shake
		local time = self._timer.Get().GetTime()
		if time >= self._end_time then
			self._InitTime(self._show_effect, self._play_sound)
		elseif time >= self._shake_time or scene_effects.shake._stop then
			if self._show_effect and not self._effect_showed then 
				if not self._stop then over_scene_effect_widget.AddEffect("ShakeScene", sf.misc.FloatVector(1024/2, 50)) end
				self._effect_showed = true
			end
			self._window.SetRotation(sf.misc.MatrixIdentity())
			if self._store_params then
				self._shake_time = self._store_params._shake_time
				self._delay_min = self._store_params._delay_min
				self._delay_max = self._store_params._delay_max
				self._radius = self._store_params._radius
				self._period = self._store_params._period
				self._interval = sf.misc.FloatVector(self._store_params._interval)
				self._store_params = nil
			end
		else
			if self._play_sound and not self._sound_played then 
				if not self._stop then sound("earthquake") end
				self._sound_played = true
			end
			local tangle = (math.mod(time, self._period)/self._period) * 6.28;
		
			self._window.SetRotation(sf.misc.MatrixTranslation(
					self._radius * math.cos(tangle) + self._interval.X/2 - self._interval.X * math.random(1000)/1000, 
					self._radius * math.sin(tangle) + self._interval.Y/2 - self._interval.Y * math.random(1000)/1000))
		end
		return false
	end,
	
	__CreateInstance = function() return "scene_effects.shake" end
}

function force_shake(_shake_time, _delay_min, _delay_max, _radius, _period, _interval_x, _interval_y)
	scene_effects.shake.DoOnce(_shake_time, _delay_min, _delay_max, _radius, _period, _interval_x, _interval_y)
end

__inherite(scene_effects.shake, null_lua_widget_handler())
