extends Movement_StateReceiver

var parent_request_state_change :FuncRef

var player_number: int = 1

onready var pew_machine = $"%PewMachine"

func _ready():
	var state_ref :State
	var state_name :String
	state_name = 'jump'
	state_ref = get_node(callable_state_machine).get_state_reference(state_name)
	#TODO Should probably assert here or something.
	state_ref.connect("state_entered", self, "_on_state_entered_" + state_name)
	parent_request_state_change = funcref(get_node(callable_state_machine), 'check_parent_before_state_change')
	# Lets see if this nutty thing works
#	var state_ref :State = get_node(callable_state_machine).get_state_reference('idle')
#	state_ref.connect("state_entered", self, "_on_state_entered_idle")
	# It works but node order really mattered.
	# State machine needed to be processed first probably for ready function.
	# good to know!
	player_number = parent.player_number


func get_movement_direction() -> float:
	#return Input.get_axis('move_left', 'move_right')
	desired_movement_vector.x = Input.get_axis("move_left_" + str(player_number), "move_right_" + str(player_number))
	return Input.get_axis("move_left_" + str(player_number), "move_right_" + str(player_number))

var _wants_jump :bool
func wants_jump() -> bool:	
	if Input.is_action_just_pressed("jump_" + str(player_number)):
		desired_movement_vector.y = UP
		_wants_jump = true
		return true
	else:
		_wants_jump = false
		return false

var _wants_crouch :bool
func wants_crouch() -> bool:	
	if Input.is_action_pressed("crouch_" + str(player_number)):
		_wants_crouch = true
		return true
	else:
		_wants_crouch = false
		return false

var _wants_attack_primary :bool
func wants_attack_primary() -> bool:	
	if Input.is_action_just_pressed("attack_" + str(player_number)):
		_wants_attack_primary = true
		return true
	else:
		_wants_attack_primary = false
		return false

var _wants_attack_secondary :bool
func wants_attack_secondary() -> bool:	
	if Input.is_action_just_pressed("attack_secondary_" + str(player_number)):
		_wants_attack_secondary = true
		return true
	else:
		_wants_attack_secondary = false
		return false

var _wants_dash :bool
func wants_dash() -> bool:	
	if Input.is_action_just_pressed("dash_" + str(player_number)):
		_wants_dash = true
		return true
	else:
		_wants_dash = false
		return false

var _wants_roll :bool
func wants_roll() -> bool:
	if Input.is_action_just_pressed("dash_" + str(player_number)) and Input.is_action_pressed("move_up_" + str(player_number)):
		_wants_roll = true
		return true
	else:
		_wants_roll = false
		return false

var _wants_climb :bool
func wants_climb() -> bool:
	if Input.is_action_pressed("move_up_" + str(player_number)):
		_wants_climb = true
		return true
	else:
		_wants_climb = false
		return false
	
#TODO: This is probably not a good way to do this.
# we want to check input once and make decisions based on
# velocity and desired movement.
#func _state_process_physics_input_idle():
#	get_movement_direction()
#
#func _state_process_physics_input_move():
#	get_movement_direction()

# Probably better to do it this way then allocating individual
# state functions that all do the same thing.
func process_physics_input(delta):
	# call the parent, Which would call the individuals
	.process_physics_input(delta)
	# then process movement controls
	physics_delta = delta
	get_movement_direction()
	wants_jump()
	wants_crouch()
	wants_attack_primary()
	wants_attack_secondary()
	wants_dash()
	wants_roll()
	wants_climb()

func flip_sprite_to_movement_direction():
	if desired_movement_vector.x != 0.0:
		parent.transform.x.x = desired_movement_vector.x

func _state_process_physics_idle():
	if desired_movement_vector.y == UP:
		request_state_change.call_func('jump')
		
	if _wants_crouch == true:
		request_state_change.call_func('crouch')
	#TODO: May need that 'bump' logic to make velocity work.
	if desired_movement_vector.x != 0: # and velocity.x != 0:
		request_state_change.call_func('move')

	if !parent.is_on_floor():
		#return fall_state
		request_state_change.call_func('fall')

	if _wants_roll == true:
		request_state_change.call_func('roll')

	if _wants_attack_primary == true:
		#request_state_change.call_func('attack_shoot')
		attack_primary()
	
	if _wants_attack_secondary == true:
		#parent_request_state_change.call_func('attack_sword')
		attack_secondary()
	
	if $"../LadderDetector".is_colliding() and _wants_climb == true:
		request_state_change.call_func('climb')

func attack_primary():
	##Another thing I wish I could avoid the funcref or string call
	if get_parent().has_method("primary_item"):
		var _item_state_name :String = get_parent().primary_item()
		if _item_state_name != '':
			request_state_change.call_func(_item_state_name)


func attack_secondary():
	if get_parent().has_method("secondary_item"):
		var _item_state_name :String = get_parent().secondary_item()
		if _item_state_name != '':
			request_state_change.call_func(_item_state_name)


func _state_process_physics_attack_shoot():

	if pew_machine.timer.time_left == 0:
		pew_machine.shoot()
	
	if current_state.animation_finished == true:
		request_state_change.call_func('idle')

	if !parent.is_on_floor():
		#return fall_state
		request_state_change.call_func('fall')

func _state_process_physics_attack_punch():
	if current_state.animation_finished == true:
		request_state_change.call_func('idle')

	if !parent.is_on_floor():
		#return fall_state
		request_state_change.call_func('fall')

func _state_process_physics_attack_sword():
	if current_state.animation_finished == true:
		request_state_change.call_func('idle')

	if !parent.is_on_floor():
		#return fall_state
		request_state_change.call_func('fall')

func _state_process_physics_roll():
	if current_state.animation_finished == true:
		request_state_change.call_func('idle')

	# Force role in facing direction 
	#	instead of movement direction
	move_actor_as_desired(parent.transform.x.x)

	if !parent.is_on_floor():
		#return fall_state
		request_state_change.call_func('fall')

var level_transition_latch: bool
var level_enter_dir: float
func _on_state_change_enter_right():
	#desired_movement_vector.x = RIGHT
	## Trying to do this in actor now.
	#parent.transform.x.x = RIGHT
	level_enter_dir = parent.transform.x.x
	level_transition_latch = false

func _state_process_physics_enter_right():
	#flip_sprite_to_movement_direction()
	
	if current_state.state_timeout.time_left == 0 and level_transition_latch == false:
		##TODO: Optionally flip direction
		#parent.transform.x.x = LEFT
		## Reset global position.
		parent.global_position = LevelInfo.player_start_position
		current_state.state_timeout.start()
		level_transition_latch = true
	elif current_state.state_timeout.time_left == 0 and level_transition_latch == true:
		request_state_change.call_func('idle')

	# Force role in facing direction 
	#	instead of movement direction
	move_actor_as_desired(parent.transform.x.x)

func _state_process_physics_land():
	$"../LedgeDetector".set_enabled(true)
	if current_state.animation_finished == true:
		request_state_change.call_func('idle')

	if !parent.is_on_floor():
		#return fall_state
		request_state_change.call_func('fall')
	move_actor_as_desired()

func _state_process_physics_hurt():
	if current_state.state_timeout.time_left == 0:
		request_state_change.call_func('idle')

#	if !parent.is_on_floor():
#		#return fall_state
#		request_state_change.call_func('fall')
	velocity.y += current_state.gravity * physics_delta
	#parent.velocity = parent.move_and_slide(parent.velocity, Vector2(0, -1))
	velocity.x = parent.transform.x.x * -1 * current_state.horizontal_speed
#	if (parent.direction.x > 0):
#		parent.velocity.x = 1 * move_speed
#	else:
#		parent.velocity.x = -1 * move_speed
	velocity = parent.move_and_slide(velocity, Vector2(0, -1))

	
func _state_process_physics_fall():
	flip_sprite_to_movement_direction()

	if $"../LedgeDetector".is_colliding() and !$"../WallDetector".is_colliding():
		#print("it touched me!")
		UiManager.debug_text = (str($"../LedgeDetector".get_collision_point()))
		request_state_change.call_func('ledge_grab')
		
	if parent.is_on_floor():
		#modifier.reference()
		#idle_state.modifier = landing_modifier
		request_state_change.call_func('land')
	
	move_actor_as_desired()

func _state_process_physics_jump():
	#UiManager.debug_text = (str(velocity))
	
	flip_sprite_to_movement_direction()
	
	#Apparently we're instantly landing
#	if parent.is_on_floor():
#		#modifier.reference()
#		#idle_state.modifier = landing_modifier
#		request_state_change.call_func('idle')
	if velocity.y > 0:
		request_state_change.call_func('fall')
	move_actor_as_desired()

func _state_process_physics_move():
	# flip sprite in direction
	flip_sprite_to_movement_direction()
	
	if desired_movement_vector.y == UP:
		request_state_change.call_func('jump')
	
	if desired_movement_vector.x == 0:
		request_state_change.call_func('idle')

	if !parent.is_on_floor():
		request_state_change.call_func('fall')
	
	move_actor_as_desired()

func get_climb_shape_location() -> Vector2:
	if $"../LadderDetector".is_colliding():
		var point: Vector2 = $"../LadderDetector".get_collision_point()
		var shape_id = $"../LadderDetector".get_collider_shape()
		var object = $"../LadderDetector".get_collider()

		# This appears to get the shapes location!
		var area = Physics2DServer.area_get_transform(object)
		var areashape = Physics2DServer.area_get_shape_transform(object, shape_id)
		
		var y_dir = Input.get_axis("ui_up" , "ui_down")
		var global_origin = areashape.origin + area.origin
		return Vector2(global_origin.x, y_dir)
	else:
		return Vector2(-1,-1)


func _state_process_physics_climb():
	#$"../LadderDetector".set_enabled(false)

	var ladder_location = get_climb_shape_location()
	if ladder_location != Vector2(-1,-1):
		#UiManager.debug_text =  str(ladder_location) + '\n' + str(ladder_location - parent.global_position) #+ '\n' + str(parent.global_position.distance_to(ladder_location)) 
		# An attempt to snap to the ladder location 
		if parent.global_position.x != round(ladder_location.x):
			parent.global_translate(Vector2(round((ladder_location.x - parent.global_position.x)),(ladder_location.y * current_state.horizontal_speed) * physics_delta))
		if ladder_location.y != 0:
			#print("singal that I'm climbing?")
			current_state.movement_stopped = false
		else:
			#print("singal that I'm not climbing?")
			current_state.movement_stopped = true
			# Make sure we hopped the step index
#			if animation_index > 0:
#				animations.stop()
	else: 
		return request_state_change.call_func('idle')

	if _wants_crouch:
		request_state_change.call_func('fall')

func _state_process_physics_ledge_grab():
	UiManager.debug_text = (str(velocity))
	$"../LedgeDetector".set_enabled(false)

	if _wants_jump:
		request_state_change.call_func('ledge_climb')
		
	if _wants_crouch:
		request_state_change.call_func('fall')

func _state_process_physics_ledge_climb():
#	UiManager.debug_text = (str(velocity))
#	$"../LedgeDetector".set_enabled(false)

	UiManager.debug_text = (str(parent.is_on_floor()) + 
		str(parent.is_on_wall()) + ")\nV:" + str(velocity))
	
	if current_state.animation_finished == true:
		request_state_change.call_func('land')
		return

	if parent.is_on_wall() == true:
		#velocity = parent.move_and_slide(Vector2(10.0,-60.0),Vector2.UP)
		parent.move_and_slide(Vector2(sign(parent.transform.x.x) * 10.0,-100.0),Vector2.UP)
	else: #parent.is_on_floor() == true:
		#velocity = parent.move_and_slide(Vector2(10.0,10.0),Vector2.UP)
		parent.move_and_slide(Vector2(sign(parent.transform.x.x) * 60.0,10.0),Vector2.UP)

	#velocity = parent.move_and_slide(Vector2(60.0,-60.0),Vector2.UP)
#	if parent.is_on_wall() != true:
#		#modifier.reference()
#		#idle_state.modifier = landing_modifier
#		request_state_change.call_func('land')
#		return


func _state_process_physics_crouch():
	# flip sprite in direction
	flip_sprite_to_movement_direction()
	
	if _wants_crouch != true:
		request_state_change.call_func('idle')
	
	if !parent.is_on_floor():
		request_state_change.call_func('fall')

	if _wants_crouch == true and desired_movement_vector.x != 0:
		request_state_change.call_func('crouch_move')
	elif desired_movement_vector.x != 0: # and velocity.x != 0:
		request_state_change.call_func('move')

func _state_process_physics_crouch_move():
	# flip sprite in direction
	flip_sprite_to_movement_direction()
	
	if _wants_crouch != true:
		request_state_change.call_func('idle')
	
	if !parent.is_on_floor():
		request_state_change.call_func('fall')

	if _wants_crouch == true and desired_movement_vector.x == 0:
		request_state_change.call_func('crouch')
	elif _wants_crouch != true and desired_movement_vector.x != 0:
		request_state_change.call_func('move')

	move_actor_as_desired()

#func _on_state_entered_idle():
#	print("Movement State Idle State Entered!")

func _on_state_entered_jump():
	#TODO: Make this a state variable
	# I used to call it 'jump_force' like an idiot.
	velocity.y = -200


