extends RigidBody

onready var camera = $Head/Camera
onready var camera_base = $Head
onready var ground_ray_cast = $GroundRayCast
onready var state_label = $Head/Camera/StateLabel
onready var ocean = get_node("/root/Ocean")

var camera_x_rotation = 0

const mouse_sensitivity = 0.2
const SPEED = 1
const SPRINT_MOD = 1
var jump_impulse = 5

var paused = false

enum STATE {
	FLOATING,
	DIVING,
	WALKING,
	SAILING
}

var bound_object = null
var bound_offset = Vector2()

var state = STATE.WALKING

# Called when the node enters the scene tree for the first time.
func _ready():
	Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)

func _input(event):
	# Mouse movement
	if not paused:
		if event is InputEventMouseMotion:
			camera_base.rotate_y(deg2rad(-event.relative.x * mouse_sensitivity))

			var x_delta = event.relative.y * mouse_sensitivity
			if camera_x_rotation + x_delta > -90 and camera_x_rotation + x_delta < 90:
				camera.rotate_x(deg2rad(-x_delta))
				camera_x_rotation += x_delta

func grounded():
	return ground_ray_cast.is_colliding()

func _integrate_forces(physics_state):
	# State machine
	state = swap_state()

	if not paused:
		var acc = Vector3()
		var direction = Vector3()
		var camera_base_basis = camera.get_global_transform().basis
		var mod = SPRINT_MOD if Input.is_action_pressed("sprint") else 1

		if Input.is_action_pressed("move_forward"):
			direction -= camera_base_basis.z #forward is negative in Godot
		if Input.is_action_pressed("move_backward"):
			direction += camera_base_basis.z

		# Strafe
		if Input.is_action_pressed("move_left"):
			direction -= camera_base_basis.x
		if Input.is_action_pressed("move_right"):
			direction += camera_base_basis.x

		match state:
			STATE.WALKING:
				if Input.is_action_just_pressed("jump") and grounded():
					physics_state.apply_central_impulse(Vector3.UP * jump_impulse)
				else:
					# Process inputs (only in the xz plane
					acc.x = direction.x * SPEED * mod
					acc.z = direction.z * SPEED * mod
				if not grounded():
					acc.y = -weight
			STATE.DIVING:
				# Process inputs in all directions
				acc = direction * SPEED * mod
			STATE.FLOATING:
				physics_state.add_central_force(Vector3.DOWN * 9.8)

				var wave = ocean.get_wave(translation.x, translation.z)
				var wave_height = wave.y
				var height = translation.y

				acc = direction * SPEED * mod

				if height < wave_height:
					var buoyancy = clamp((wave_height - height) / 0.001, 0, 1) * 5
					physics_state.add_central_force(Vector3(0, 9.8 * buoyancy, 0))
					#physics_state.add_central_force(buoyancy * -physics_state.linear_velocity * 0.5)
					#physics_state.add_torque(buoyancy * -physics_state.angular_velocity * 0.5)
			STATE.SAILING:
				self.transform = bound_object.transform
				self.translate(bound_offset)

		physics_state.add_central_force(acc * mass)

		# emit signal - playerinfo_updated
		Events.emit_signal("player_transform_updated", $Head/Camera.get_global_translation(), $Head.global_rotation.y)



func swap_state():
	var wave_height = ocean.get_wave(translation.x, translation.z).y
	var new_state = state
	match state:
		STATE.WALKING:
			# Are we in water
			if translation.y < wave_height:
				if linear_velocity.y < -5:
					new_state = STATE.DIVING
				else:
					new_state = STATE.FLOATING
		STATE.DIVING:
			# Are we on or above water
			if translation.y >= wave_height:
				new_state = STATE.FLOATING
		STATE.FLOATING:
			if grounded():
				new_state = STATE.WALKING
			if translation.y < wave_height - 0.1:
				new_state = STATE.DIVING

	return new_state

func _process(delta):
	if Input.is_action_just_pressed("toggle_mouse"):
		toggle_pause()
	state_label.text = "%s" % STATE.keys()[state]

func toggle_pause():
	paused = !paused
	if paused:
		Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
	else:
		Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
