extends Node

class_name Player

const MAX_SPEED:float = 0.2

const START_OFFSET = [1.70223, 1.20223, 0.702227, 0.202227 ]
const LANE_OFFSET = [-0.085, 0.085, -0.255, 0.255 ]

export var player_color:Color
var player_name:String

var thrust:int = 0
var current_speed:float = 0.0

export var speed_factor:float = 0.001
export var brake_factor:float = 2.0
export var friction_brake_factor:float = 0.8

onready var race_car = get_node("Path/PathFollow/raceCar")
onready var timer:Timer = get_node("ResetTimer")
onready var path:Path = get_node("Path")
onready var follow:PathFollow = get_node("Path/PathFollow")
onready var route:Route

var lane:int

var start_init:bool = true
var has_next:bool = false
var is_resetable:bool = false
var buffered_curve:Curve3D
var buffered_translate:Vector3 = Vector3(0,0,0)
var buffered_rotation:Vector3 = Vector3(0,0,0)
var last_rotation:Vector3 = Vector3(0,0,0)
var torque_penalty:Vector3
var force_penalty:Vector3
var path_penalty:float

var is_out:bool = false
var position:Vector2

puppet var slave_position:Vector2


func _ready():
	route = gamestate.game.route
	race_car.road_ray.set_collision_mask_bit(get_index(),1)
	path.curve = path.curve.duplicate()
	path.curve.set_bake_interval(0.05)


func _physics_process(delta):
	if is_network_master():
		if not is_out:
			var max_speed = MAX_SPEED
			
			if get_road() != null:
				var road = get_road()
				if is_in_group("first"):
					max_speed *= road.get_first_speed_factor()
				if road.get_creator() == get_index():
					max_speed *= road.get_creator_speed_factor()
				else:
					max_speed *= road.get_chasers_speed_factor()
					
			
			if thrust == 1:
				current_speed += speed_factor
			elif thrust == -1:
				current_speed -= speed_factor * brake_factor
			else:
				current_speed -= speed_factor * friction_brake_factor
				
			if current_speed >= max_speed:
				current_speed = max_speed
			elif current_speed < 0:
				current_speed = 0
			
			follow.set_offset(follow.get_offset() + current_speed)
			
			if follow.get_offset() < 0:
				follow.set_offset(0)
			
			if has_next && (path.curve.get_point_count() == 0 || follow.get_unit_offset() >= 1.0):
				has_next = false
				if path.curve.get_point_count() > 0:
					path.curve.clear_points()
				
				path.curve.set_bake_interval(0.05)
				for i in range(buffered_curve.get_point_count()):
					var _pos = buffered_curve.get_point_position(i)
					var _in = buffered_curve.get_point_in(i)
					var _out = buffered_curve.get_point_out(i)
					if buffered_rotation.length() != 0:
						_pos = _pos.rotated(buffered_rotation.normalized(), buffered_rotation.length())
						_in = _in.rotated(buffered_rotation.normalized(), buffered_rotation.length())
						_out = _out.rotated(buffered_rotation.normalized(), buffered_rotation.length())
					path.curve.add_point(buffered_translate + _pos, _in, _out)
					path.curve.set_point_tilt(i, buffered_curve.get_point_tilt(i))
				if not start_init:
					follow.set_offset(0.001)
				else:
					follow.set_offset(START_OFFSET[lane])
					start_init = false
			if get_road() != null:
				var road = get_road()
				var penalty_index = road.penalty_index(follow.get_offset(), current_speed)
				
				if penalty_index >= 0:
					torque_penalty = road.get_torque_penalty(penalty_index)
					force_penalty = road.get_force_penalty(penalty_index)
					path_penalty = road.get_path_penalty(penalty_index)
					is_out = true
					is_resetable = false
					timer.start()
			
			check_position()
		else:
			race_car.get_node("ray").set_enabled(false)
			if force_penalty.length() != 0:
				race_car.move_and_slide(force_penalty * current_speed + Vector3(0,-0.5,0))
			if torque_penalty.length() != 0:
				race_car.rotate_object_local(torque_penalty.normalized(), torque_penalty.length() * current_speed)
			if path_penalty > 0 && follow.get_offset() > 0.0:
				follow.set_offset(follow.get_offset() - 0.01)
				path_penalty -= 0.01
			current_speed -= 0.0002
			if current_speed < 0:
				current_speed = 0
	else:
		position = slave_position


func get_road():
	return race_car.road


func _on_raceCar_road_entered(road):
	
	var prev_road = route.get_road(road.get_index()-1)
	if prev_road != null:
		prev_road.body.set_collision_layer_bit(get_index(),0)
	
	buffered_curve = road.get_lane_curve(lane)
	
	buffered_rotation = last_rotation
							
	if path.curve.get_point_count() > 0:
		buffered_translate = Util.curve_get_last_point(path.curve)
		
	if road.get_end_rotation().length() != 0:
		last_rotation += road.get_end_rotation()
		
	has_next = true


func get_player_name():
	return player_name


func set_player_name(new_name):
	player_name = new_name


func get_player_color():
	return player_color


func set_player_color(new_color):
	player_color = new_color
	var material = SpatialMaterial.new()
	material.set_albedo(player_color)
	race_car.get_node("body").set_surface_material(1,material)


remotesync func set_first(is_first:bool):
	if is_first:
		add_to_group("first")
	else:
		remove_from_group("first")


master func check_position():
	position = Vector2(race_car.road_index, follow.get_offset())
	rset("slave_position", position)


master func reset():
	if is_resetable:
		has_next = false
		current_speed = 0
				
		var road = race_car.road
		road.body.set_collision_layer_bit(get_index(),1)
		
		while road.reset_index != 0:
			road = route.get_road(road.get_index() - road.reset_index)
			road.body.set_collision_layer_bit(get_index(),1)
			
		path.curve.clear_points()
		
		force_penalty = Vector3(0,0,0)
		torque_penalty = Vector3(0,0,0)
		
		buffered_translate = road.get_translation()
		last_rotation = road.get_rotation()
		
		race_car.road_index = road.get_index()
		race_car.road = null
		race_car.collider = null
		race_car.transform = Transform()
		race_car.get_node("ray").set_enabled(true)
		

		follow.set_transform(road.get_transform())
		
		is_out = false
		is_resetable = false
		return true
	else:
		return false


func set_start(new_lane:int):
	lane = new_lane
	follow.set_h_offset(LANE_OFFSET[lane])


func _on_ResetTimer_timeout():
	is_resetable = true
