extends Camera

export var enabled = true setget set_enabled
export(int, "Visible", "Hidden", "Captured, Confined") var mouse_mode = 2

# Freelook settings
export var freelook = true
export (float, 0.0, 1.0) var sensitivity = 0.5
export (float, 0.0, 0.999, 0.001) var smoothness = 0.5 setget set_smoothness
export (int, 0, 360) var yaw_limit = 360
export (int, 0, 360) var pitch_limit = 360

# Pivot Settings
export(NodePath) var privot setget set_privot
export var rotate_privot = false
var distance =25.0
var distance_smooth
export var distance_min = 10
export var distance_max = 100
export var distance_step: float = 2.0

# Movement settings
export (float, 0.0, 1.0) var acceleration = 0.1
export (float, 0.0, 0.0, 1.0) var deceleration = 0.1
export var max_speed = Vector3(1.0, 1.0, 1.0)
export var local = true

# Intern variables.
var _mouse_offset = Vector2()
var _rotation_offset = Vector2()
var _yaw = 0.0
var _pitch = 0.0
var _total_yaw = 0.0
var _total_pitch = 0.0

var _direction = Vector3(0.0, 0.0, 0.0)
var _speed = Vector3(0.0, 0.0, 0.0)

const ROTATION_MULTIPLIER = 500
func _ready():
	Input.set_mouse_mode(Input.MOUSE_MODE_CONFINED)

func _unhandled_input(event):
	if freelook:
		if Input.get_action_strength("right_click"):
			Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
			if event is InputEventMouseMotion:
				_mouse_offset = event.relative
		else:
			Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)

func _input(event):
	if privot:
		if event.is_action_pressed("wheel_down"):
			distance-=distance_step
		if event.is_action_pressed("wheel_up"):
			distance += distance_step
		distance += (Input.get_action_strength("ui_down") - Input.get_action_strength("ui_up")) * distance_step * 0.5
		distance = clamp(distance,distance_min,distance_max)
	else:
		_direction.x = Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
		_direction.y = Input.get_action_strength("ui_page_up") - Input.get_action_strength("ui_page_down")
		_direction.z = Input.get_action_strength("ui_down") - Input.get_action_strength("ui_up")
		

func _physics_process(delta):
	collide()
	if privot:
		distance_smooth =lerp(distance_smooth,distance,0.05)
		set_translation(privot.get_translation())
		translate_object_local(Vector3(0.0, 0.0, distance_smooth))
	else:
		_update_movement(delta)
	if freelook:
		_update_rotation(delta)
			
func collide():
	if privot:
		if $down.is_colliding():
			_mouse_offset.y = 1
		if $up.is_colliding():
			_mouse_offset.y = -1
		if $left.is_colliding():
			_mouse_offset.x = 1
		if $right.is_colliding():
			_mouse_offset.x = -1
		if $forward.is_colliding():
			distance +=distance_step 
		if $back.is_colliding():
			distance -=distance_step 
	else:
		if $down.is_colliding():
			_direction.y = 2
		if $up.is_colliding():
			_direction.y = -2
		if $left.is_colliding():
			_direction.x = 2
		if $right.is_colliding():
			_direction.x = -2
		if $forward.is_colliding():
			_direction.z =2 
		if $back.is_colliding():
			_direction.z =-2 
			
func _update_movement(delta):
	var offset = max_speed * acceleration * _direction

	_speed.x = clamp(_speed.x + offset.x, -max_speed.x, max_speed.x)
	_speed.y = clamp(_speed.y + offset.y, -max_speed.y, max_speed.y)
	_speed.z = clamp(_speed.z + offset.z, -max_speed.z, max_speed.z)

	# Apply deceleration if no input
	if _direction.x == 0:
		_speed.x *= (1.0 - deceleration)
	if _direction.y == 0:
		_speed.y *= (1.0 - deceleration)
	if _direction.z == 0:
		_speed.z *= (1.0 - deceleration)

	if local:
		translate_object_local(_speed * delta)
	else:
		global_translate(_speed * delta)

func _update_rotation(delta):
	var offset = Vector2();
	
	offset += _mouse_offset * sensitivity
		
	_mouse_offset = Vector2()

	_yaw = _yaw * smoothness + offset.x * (1.0 - smoothness)
	_pitch = _pitch * smoothness + offset.y * (1.0 - smoothness)

	if yaw_limit < 360:
		_yaw = clamp(_yaw, -yaw_limit - _total_yaw, yaw_limit - _total_yaw)
	if pitch_limit < 360:
		_pitch = clamp(_pitch, -pitch_limit - _total_pitch, pitch_limit - _total_pitch)
	_total_yaw += _yaw
	_total_pitch += _pitch
	
	rotate_y(deg2rad(-_yaw))
	rotate_object_local(Vector3(1,0,0), deg2rad(-_pitch))

func set_privot(value):
	privot = value
	if privot:
		distance = 25
	else:
		distance = 0
	distance_smooth = distance

func set_enabled(value):
	enabled = value
	#Input.set_mouse_mode(mouse_mode)
	set_process_input(enabled)
	set_physics_process(enabled)

func set_smoothness(value):
	smoothness = clamp(value, 0.001, 0.999)
