--
-- World handling and information
--

-- Updates the world
function world_update( time_step, is_lpad, is_rpad )
	-- Update the paddles
	if not world_had_lpad and is_lpad and not scene_tilt then SoundPlay( "01_maila.wav", 0.4 ) end
	if not world_had_rpad and is_rpad and not scene_tilt then SoundPlay( "01_maila.wav", 0.4 ) end
	world_had_lpad = keys.lpad
	world_had_rpad = keys.rpad

	local pad_force = 2000
	if is_lpad and not scene_tilt then
		ObjectAddTorque( obj_lpad, -pad_force )
		ObjectAddTorque( obj_lmpad, -pad_force )
	else
		ObjectAddTorque( obj_lpad, pad_force )
		ObjectAddTorque( obj_lmpad, pad_force )
	end
	if is_rpad and not scene_tilt then ObjectAddTorque( obj_rpad, pad_force ) else ObjectAddTorque( obj_rpad, -pad_force ) end

	-- Update the blinking objects
	for key,value in blink_objs do
		if value.time > 0 then value.time = value.time - time_step end
		ObjectSetLit( value.obj, value.time > 0 )
	end

	-- Keep the switch turned off
	ObjectAddTorque( obj_switch, 800 )

	-- Keep the start hatch closed
	ObjectAddTorque( obj_start_hatch, 250 )

	-- Slow down the objects
	for key,value in objects do
		if value.vel_mul ~= 1.0 then
			local vel = ObjectGetVelocity( value.obj )
			ObjectSetVelocity( value.obj, vel * value.vel_mul )
		end
		if value.torque_mul ~= 1.0 then
			local torque = ObjectGetTorque( value.obj )
			ObjectSetTorque( value.obj, torque * value.torque_mul )
		end
	end

	-- Remove all scenes that need to be removed
	for k,v in remove_scenes do
		table.remove_value( balls, v )
		table.remove_value( active_balls, v )
		SceneRemove( v )
	end
	remove_scenes = {}

	-- Tilt counter
	if scene_tilt_counter > 0 then
		scene_tilt_counter = scene_tilt_counter - time_step
	end
end

-- Pushes the "table" world
function push_world()
	if scene_launching then return end
	print( "Pushing table" )

	for key,player_scene in balls do
		for key,value in {SceneGetObjects(player_scene)} do
			ObjectAddImpulse( value, Vec2( 10000, -14000 ) )
		end
	end

	if not scene_tilt then
		scene_tilt_counter = scene_tilt_counter + 2
		if scene_tilt_counter > 6 then
			SoundPlay( "12_tilt.wav" )
			HudShowText( "TILT!", 999999 )

			scene_tilt = true
		elseif scene_tilt_counter > 3 then
			HudShowText( "Warning!", 3, 0.1 )
		end
	end
end

-- Blinks a given object
function do_blink( obj, time )
	local val = blink_objs[ obj ]
	if val == nil then return end

	val.time = time
end

-- Applies force to a scene away from the given point
function apply_away_force( scene, from, power )
	local pos
	for key,value in {SceneGetObjects(scene)} do
		pos = ObjectGetPos( value )
		dir = pos - from
		dir:Normalize()
		ObjectAddImpulse( value, dir * power )
	end
end

-- Returns the objects for all the ids in the list
function get_objects_from_ids( scene, id_list )
	local ret = {}
	local idx = 1
	for key,value in id_list do
		for key2,value2 in {SceneGetObjectsById(scene,value)} do
			ret[idx] = value2
			idx = idx + 1
		end
	end
	return ret
end

-- Vounts how many of the objects are lit
function objs_count_lit( objs )
	local count = 0
	for key,value in objs do
		if ObjectIsLit( value ) then count = count + 1 end
	end
	return count
end

-- Tests if all the objects are lit
function objs_are_lit( objs )
	for key,value in objs do
		if not ObjectIsLit( value ) then return false  end
	end
	return true
end

-- Clears the lit status from the objects
function objs_set_lit( objs, val )
	for key,value in objs do
		ObjectSetLit( value, val )
	end
end

-- Lits x first objects in the list, clears the rest
function objs_set_lit_amt( objs, amt )
	local idx = 1
	for key,value in objs do
		ObjectSetLit( value, amt >= idx )
		idx = idx + 1
	end
end

-- Tests if the given scene is a ball scene
function is_ball_scene( scene )
	return table.contains_value( balls, scene )
end

-- Launches the player ball
function launch_ball( scene )
	if scene == nil then
		print( "WARNING: Invalid scene (nil) for launch_ball" )
		return
	end

	for key,value in {SceneGetObjects(scene)} do
		ObjectSetVelocity( value, Vec2( 0, -1200 ) )
	end

	SoundPlay( "03_palloliikkeelle.wav" )
end

-- Marks a ball to be removed (removed on next update)
function remove_ball( scene )
	table.insert_unique( remove_scenes, scene )
end

-- Marks that the ball has hit the "top" of the launch chute
function ball_launch_top( scene )
	if table.contains_value( remove_scenes, scene ) then return end
	if table.contains_value( active_balls, scene ) then return end

	table.insert_unique( active_balls, scene )
end

-- Marks that the ball has hit the "bottom" of the launch chute
function ball_launch_bottom( scene )
	if table.contains_value( remove_scenes, scene ) then return end
	if not table.contains_value( active_balls, scene ) then return end

	launch_ball( scene )
end


-- Spawns a new ball (returns the scene)
function spawn_ball( ball_scene_name )
	if ball_scene_name == "" then
		print( "WARNING: Invalid ball scene name for spawn_ball" )
		return
	end

	local scene = SceneSpawn( ball_scene_name, ball_spawn_pos )
	table.insert_unique( balls, scene )
	return scene
end

-- Resets the game callback functions
function reset_callbacks()
	update = function() end
	trigger_object_enter = function() end
	trigger_object_exit = function() end
	trigger_scene_enter = function() end
	trigger_scene_exit = function() end
	object_rotated = function() end
end

-- Resets the world variables
function reset_world()
	-- Remove all the balls
	for k,v in balls do
		SceneRemove( v )
	end
	balls = {}
	active_balls = {}

	-- Clear all the triggers and lit items
	table.map( SceneGetObjectsList(main_scene), function(x) ObjectSetLit(x,false) end )

	-- Set the variables
	scene_next_player = false
	scene_wheel_accel = 0
	scene_launching = true
	scene_respawn = false
	scene_tilt = false
	scene_tilt_counter = 0
end

-- Respawns the world
function spawn_world()
	WorldClear()

	main_scene = SceneSpawn( "level_01" )
	balls = {}
	active_balls = {}
	
	-- Get the objects
	obj_lpad = SceneGetObjectsById( main_scene, "PaddleLeft" )
	obj_lmpad = SceneGetObjectsById( main_scene, "PaddleMini" )
	obj_rpad = SceneGetObjectsById( main_scene, "PaddleRight" )

	obj_launch_top = SceneGetObjectsById( main_scene, "StartTriggerTop" )
	obj_launch_bottom = SceneGetObjectsById( main_scene, "StartTriggerBottom" )

	obj_switch = SceneGetObjectsById( main_scene, "Switch" )
	obj_start_hatch = SceneGetObjectsById( main_scene, "StartHatch" )

	obj_red_button = SceneGetObjectsById( main_scene, "BigRedButton" )

	for key,value in objects do
		value.obj = (SceneGetObjectsById( main_scene, value.id ))
	end

	hazard_objs = get_objects_from_ids( main_scene, hazard_ids )
	factory_objs = get_objects_from_ids( main_scene, factory_ids )
	accident_objs = get_objects_from_ids( main_scene, accident_ids )
	swlamp_objs = get_objects_from_ids( main_scene, swlamp_ids )
	rollpad_objs = get_objects_from_ids( main_scene, rollpad_ids )
	flame_objs = get_objects_from_ids( main_scene, flame_ids )
	arrow_objs = get_objects_from_ids( main_scene, arrow_ids )

	blink_objs =
	{
	[(SceneGetObjectsById( main_scene, "bouncer01_trigger" ))] = {obj = (SceneGetObjectsById( main_scene, "bouncer01" )), time = 0};
	[(SceneGetObjectsById( main_scene, "bouncer02_trigger" ))] = {obj = (SceneGetObjectsById( main_scene, "bouncer02" )), time = 0};
	[(SceneGetObjectsById( main_scene, "bouncer03_trigger" ))] = {obj = (SceneGetObjectsById( main_scene, "bouncer03" )), time = 0};
	[(SceneGetObjectsById( main_scene, "BigRedButton" ))] = {obj = (SceneGetObjectsById( main_scene, "BigRedButton" )), time = 0};
	[(SceneGetObjectByName( main_scene, "chain01_box_trigger" ))] = {obj = (SceneGetObjectByName( main_scene, "chain01_box" )), time = 0};
	}

	ball_spawn_pos = SceneGetSpecialPos( main_scene, "BallLaunchPosition" )

	-- Reset
	reset_world()
end



-- Object ids
ball_scene_ids = { "Ball", "Ball2", "Ball3" }
hazard_ids = { "hazard_H", "hazard_A1", "hazard_Z", "hazard_A2", "hazard_R", "hazard_D" }
factory_ids = { "factory_F", "factory_A", "factory_C", "factory_T", "factory_O", "factory_R", "factory_Y" }
accident_ids = { "accident_A", "accident_C1", "accident_C2", "accident_I", "accident_D", "accident_E", "accident_N", "accident_T" }
swlamp_ids = { "SwitchLamp01", "SwitchLamp02", "SwitchLamp03" }
rollpad_ids = { "RollpadLeft", "RollpadRight", "RollpadTop", "RollpadBottom" }
flame_ids = { "LeftFlame", "RightFlame", "LeftFlameTop", "RightFlameTop" }
arrow_ids = { "ArrowLeft", "ArrowRight" }

objects =
{
	{ id = "left_wheel", torque_mul = 0.995, vel_mul = 1.0 },
	{ id = "center_wheel", torque_mul = 0.995, vel_mul = 1.0 },
	{ id = "right_wheel", torque_mul = 0.995, vel_mul = 1.0 },
	{ id = "RollingPad", torque_mul = 0.995, vel_mul = 1.0 },
	{ id = "crate", torque_mul = 1.0, vel_mul = 0.998 },
}

remove_scenes = {}
