extends Node
export var grab_ik_curve: Curve
export var grab_ik_curve_multiplier: float = 0.14
export var cinematic_cam: PackedScene

# Declare member variables here. Examples:
# var a = 2
# var b = "text"


# Called when the node enters the scene tree for the first time.
var cinematic_camera

func _ready():
	pass # Replace with function body.

var active_states = []
var locked_actors = {}

class Grabbing:
	signal enable_cinematic_camera(where, look)
	signal update_cinematic_camera(where, look)
	signal disable_cinematic_camera
	signal end_stage
	var actor_master: KinematicBody
	var actor_slave: KinematicBody
	var slave_space: RID
	var master_space: RID
	var finished = false
	var follow_node
	var follow_node_full
	var state = 0
	var ik: SkeletonIK
	var ik_curve_pos = 0.0
	var grab_ik_curve: Curve
	var curve_delta_mul: float = 0.16
	func start(act_master: KinematicBody, act_slave: KinematicBody, curve: Curve, delta_mul: float):
		actor_master = act_master
		actor_slave = act_slave
		grab_ik_curve = curve
		curve_delta_mul = delta_mul
		var skel_master = actor_master.get_meta("skeleton")
		assert(skel_master is Skeleton)
		ik = SkeletonIK.new()
		ik.root_bone = "J_Bip_R_UpperArm"
		ik.tip_bone = "J_Bip_R_Hand"
		skel_master.add_child(ik)
		
#		actor_master.set_meta("orchestrated", true)
#		actor_slave.set_meta("orchestrated", true)
#		characters.animation_node_travel(actor_master, "grab")
#		characters.animation_node_travel(actor_slave, "grabbed")
		reset_character(actor_master)
		reset_character(actor_slave)
		var mx = actor_master.global_transform
		var sx = actor_slave.global_transform
		var m = mx.interpolate_with(sx, 0.5)
		var cam_where = m.origin + actor_master.global_transform.basis[0] * 1.1
		cam_where += Vector3.UP * 2.0
		var cam_to = m.origin + Vector3.UP * 1.4
		emit_signal("enable_cinematic_camera", cam_where, cam_to)
	func reset_character(b):
		assert(b)
		b.remove_meta("cmdqueue")
		b.remove_meta("cmdq_walk")
		b.remove_meta("climb")
		characters.animation_node_travel(b, "locomotion")
		characters.set_walk_speed(b, 0.0, 0)
		
	func update(delta):
		var mx = actor_master.global_transform
		var sx = actor_slave.global_transform
		var m = mx.interpolate_with(sx, 0.5)
		var cam_where = m.origin + actor_master.global_transform.basis[0] * 1.1
		cam_where += Vector3.UP * 2.0
		var cam_to = m.origin + Vector3.UP * 1.4
		emit_signal("update_cinematic_camera", cam_where, cam_to)
	func physics_update(delta):
		var offt = actor_slave.global_transform.origin - actor_slave.global_transform.basis[2] * 0.45
		match state:
			0:
				reset_character(actor_master)
				reset_character(actor_slave)
				actor_master.set_meta("orchestrated", true)
				actor_slave.set_meta("orchestrated", true)
				actor_master.add_collision_exception_with(actor_slave)
				actor_slave.add_collision_exception_with(actor_master)
				slave_space = PhysicsServer.body_get_space(actor_slave.get_rid())
				PhysicsServer.body_set_space(actor_slave.get_rid(), RID())
				master_space = PhysicsServer.body_get_space(actor_master.get_rid())
				PhysicsServer.body_set_space(actor_master.get_rid(), RID())
				state = 1
			1:
#				actor_slave.get_parent().remove_child(actor_slave)
#				actor_master.add_child(actor_slave)
				var skel_master = actor_master.get_meta("skeleton")
				assert(skel_master is Skeleton)
				var skel_slave = actor_slave.get_meta("skeleton")
				assert(skel_slave is Skeleton)
				follow_node_full = skel_slave.get_node("neck/marker_neck_grab")
				follow_node = Position3D.new()
				skel_master.add_child(follow_node)
				follow_node.global_transform = follow_node_full.global_transform
				ik.target_node = ik.get_path_to(follow_node)
				ik.override_tip_basis = true
				ik.interpolation = 0.0
				ik_curve_pos = 0.0
				
				actor_master.global_transform = Transform(actor_slave.global_transform.basis.rotated(Vector3.UP, PI), offt)
				var master_xform = actor_master.global_transform.looking_at(actor_slave.global_transform.origin, Vector3.UP)
				var slave_xform = actor_slave.global_transform.looking_at(actor_master.global_transform.origin, Vector3.UP)
				var orientation = Transform(actor_slave.global_transform.basis, Vector3())
				actor_slave.set_meta("orientation", orientation)
				var master_orientation = Transform(actor_master.global_transform.basis, Vector3())
				actor_master.set_meta("orientation", master_orientation)
				characters.animation_node_travel(actor_master, "grab")
				characters.animation_node_travel(actor_slave, "grabbed")
				ik.start(true)
				state = 3
			3:
				ik.interpolation = grab_ik_curve.interpolate_baked(ik_curve_pos)
				ik_curve_pos += delta * curve_delta_mul
				follow_node.global_transform = follow_node_full.global_transform
				ik.start(true)
				if ik.interpolation >= 1.0:
					state = 4
			4:
				var m_anim: AnimationTree = actor_master.get_meta("animation_tree")
				var m_state: AnimationNodeStateMachinePlayback = m_anim["parameters/state/playback"]
				var m_l = m_state.get_current_length()
				var m_p = m_state.get_current_play_position()
				var s_anim: AnimationTree = actor_slave.get_meta("animation_tree")
				var s_state: AnimationNodeStateMachinePlayback = s_anim["parameters/state/playback"]
				var s_l = m_state.get_current_length()
				var s_p = m_state.get_current_play_position()
				if m_p >= m_l && s_p >= s_l:
					state = 5
					
#			2:
#				actor_slave.global_transform = Transform(actor_master.global_transform.basis.rotated(Vector3.UP, PI), offt)
#				var orientation = Transform(actor_slave.global_transform.basis, Vector3())
#				actor_slave.set_meta("orientation", orientation)
#				state = 3
#			3:
#				actor_slave.global_transform = Transform(actor_master.global_transform.basis.rotated(Vector3.UP, PI), offt)
#				var orientation = Transform(actor_slave.global_transform.basis, Vector3())
#				actor_slave.set_meta("orientation", orientation)
#				state = 4
	func finish():
		pass

func enable_camera(where, to):
	var current_cam = get_viewport().get_camera()
	var player = current_cam.get_meta("player")
	if !cinematic_camera:
		cinematic_camera = cinematic_cam.instance()
		var cam: Camera = cinematic_camera.get_node("rot_y/rot_x/SpringArm/camera_offset/Camera")
		var cam_offset = cinematic_camera.get_node("rot_y/rot_x/SpringArm/camera_offset")
		cam.set_meta("player", player)
		cam.set_meta("current_cam", current_cam)
		cinematic_camera.set_meta("cam", cam)
		cinematic_camera.set_meta("offset", cam_offset)
		get_viewport().add_child(cinematic_camera)
		cinematic_camera.global_transform.origin = where
#		cam_offset.global_transform.origin = where
		cam.current = true
		cam.look_at(to, Vector3.UP)
func update_camera(where, to):
	var cam = cinematic_camera.get_meta("cam")
	var cam_offset = cinematic_camera.get_meta("offset")
	cam_offset.global_transform.origin = where
	cam.look_at(to, Vector3.UP)
	

func grab(actor_master, actor_slave):
	var gr = Grabbing.new()
	gr.connect("enable_cinematic_camera", self, "enable_camera")
	gr.connect("update_cinematic_camera", self, "update_camera")
	gr.start(actor_master, actor_slave, grab_ik_curve, grab_ik_curve_multiplier)
	active_states.push_back(gr)

func _physics_process(delta):
	var completed = []
	for e in active_states:
		e.physics_update(delta)
		if e.finished:
			completed.push_back(e)
	for d in completed:
		active_states.erase(d)
func _process(delta):
	var completed = []
	for e in active_states:
		e.update(delta)
		if e.finished:
			completed.push_back(e)
	for d in completed:
		active_states.erase(d)
