class_name AnimatedSprite_StateReceiver
extends AnimatedSprite

export var callable_state_machine :NodePath

onready var current_state = StateAnimatedActor.new()

var modifier: StateModifierAnimatedActor

var request_state_change: FuncRef
var add_state_modifier: FuncRef

var animation_index: int = 0
var current_animation_sequence: int = 0
var animation_suffix: String = '';

var mod_animation_sequence = [PoolStringArray()]

var previous_animation_name : String
var previous_state_frame_number : int
var previous_state_name: String
var previous_speed_multiplier: float

var _frame_switch_tracker := -1
var _index_tracker := -1

# Called when the node enters the scene tree for the first time.
func _ready():
	request_state_change = funcref(get_node(callable_state_machine), 'change_to_known_state')
	add_state_modifier = funcref(get_node(callable_state_machine),'push_state_modifier')

	get_node(callable_state_machine).connect("state_changed", self,"_on_state_change")
	get_node(callable_state_machine).connect("modifiers_updated",self,"_on_modifiers_updated")
	self.connect("animation_finished",self,"_on_animation_finished")
	
	#set current state since State machine might have set state before this
	# processed
	current_state = get_node(callable_state_machine).current_state
	#state_machine_modifiers = get_node(callable_state_machine).state_modifiers
	modifier = get_node(callable_state_machine).merged_animation_state_modifiers

# Sprites should only have a process function
# but if I have this will the sprite still animate?
func _process(delta):
	current_state.animation_frame = frame
	##TODO: Put in to try to buffer animation switches on frame change
	if _frame_switch_tracker != -1 and frame == _frame_switch_tracker:
		print ("time to switch", _frame_switch_tracker)
		change_animation(_frame_switch_tracker, _index_tracker)
	# Not sure what should be called first here.
	if has_method('_state_process_' + current_state.name):
		call('_state_process_' + current_state.name)

func _on_animation_finished():
	if frames.get_animation_loop(animation) == false:
		#print("Stop!!!!!", current_state.animation_sequence.size(), " - ", current_state.animation_index)
		if current_state.animation_sequence.size() > 0:
			#print("<-- next anim.")
			animation_index += 1
			if animation_index >= current_state.animation_sequence.size():
				#print("Stop!!!!!")
				current_state.animation_finished = true
	# TODO: Allow a way to stop animation even if in a looped sequence

# If called, this will attempt to make the most appropriate animation change
# would likely be triggered from an animation sequence finishing or a 
# modifier being applied/removed outside of enter/exit transitions. 
func change_animation(enter_frame := 0, index := 0, suffix := ''):
	## TODO: 
	# Need to find a way to attempt to keep and transfer the Index or frame
	if modifier:
		#print("hey you got one! -> ", modifier.animation_name)
		match modifier.modifier_type:
			StateModifier.TYPE.ANIMATION_SUFFIX:
				print("hey you got one! -> ", modifier.animation_suffix)
	_frame_switch_tracker = -1
	_index_tracker = -1
	
	# By Default, we build an animation sequence off of this state's before checking
	# for modifiers
	var animation_sequence = current_state.animation_sequence
	#var animations = current_state
	mod_animation_sequence.clear()
	mod_animation_sequence.append_array(animation_sequence)
	# Reset animation suffix in case there isn't one
	animation_suffix = suffix
	animation_index = index
	current_animation_sequence = animation_index
	
	if modifier:
		#TODO: Apply the animation starting frame
		#modifier.animation_starting_frame
		match modifier.modifier_type:
			modifier.TYPE.ANIMATION_SUFFIX:
				# Check that this animation actually exists
				if frames.has_animation(mod_animation_sequence[animation_index] + '-' + modifier.animation_suffix):
					animation_suffix = modifier.animation_suffix
				else:
					push_warning("Modifier attempting to apply suffix that doesn't exist" + 
						(mod_animation_sequence[animation_index] + '-' + modifier.animation_suffix))
			modifier.TYPE.REPLACE_ANIMATION:
				if frames.has_animation(modifier.animation_name):
					mod_animation_sequence.clear()
					mod_animation_sequence.push_back(modifier.animation_name)
					enter_frame = modifier.animation_starting_frame
	#var enter_animation = ''
	#var enter_frame = 0
#	var modifier :StateModifier = current_state.modifier
#	if modifier != null:
##		if modifier.modifier_type == modifier.TYPE.EXIT_ANIMATION:
##			#print("OHHH Modifier Applies! ", modifier.animation_name)
##			mod_animation_sequence.push_front(modifier.animation_name)
##			enter_frame = modifier.starting_frame
#		match modifier.modifier_type:
#			modifier.TYPE.EXIT_ANIMATION:
#				mod_animation_sequence.push_front(modifier.animation_name)
#				enter_frame = modifier.starting_frame
#
#			modifier.TYPE.ANIMATION_SUFFIX:
#				if frames.has_animation(mod_animation_sequence[animation_index] + modifier.animation_name):
#					animation_suffix = modifier.animation_name
#				else:
#					print("Warning!: Modifier attempting to apply suffix that doesn't exist ", 
#												mod_animation_sequence[animation_index] + modifier.animation_name)
#
#			modifier.TYPE.REPLACE_ANIMATION:
#				#animations.play(modifier_stack_ref[i].animation_name)
#				#animations.frame = modifier_stack_ref[i].starting_frame
#				mod_animation_sequence.clear()
#				mod_animation_sequence.push_back(modifier.animation_name)
#				enter_frame = modifier.starting_frame

	# Some safety checks with supplied update parameters
	if animation_index != 0:
		if mod_animation_sequence.size() < animation_index + 1:
			if current_state.debug_state:
				print("Warning!: attempting to set to non-existant index ")
			animation_index  = 0
			current_animation_sequence = animation_index

	if frames.has_animation(mod_animation_sequence[animation_index] + animation_suffix) == false:
		if current_state.debug_state:
			print("Warning!: Animation doesn't exist! ")
		
	if enter_frame != 0:
		if frames.get_frame_count(animation) != frames.get_frame_count(mod_animation_sequence[animation_index] + animation_suffix):
			if current_state.debug_state:
				print("Warning!: attempting to set a mismatched frame ")
			enter_frame = 0

	if mod_animation_sequence.size() > 0:
		if current_state.debug_state:
			print("Starting Animation: " , mod_animation_sequence[animation_index] + animation_suffix)
		if animation_suffix != '':
			play(mod_animation_sequence[animation_index] + '-' + animation_suffix)
		else:
			play(mod_animation_sequence[animation_index])
		#TODO: maybe check current animatio has this frame
		if enter_frame != 0:
			print ("alternate starting frame:", enter_frame)
			frame = enter_frame
	else:
		print("Error! Resolved to empty animation sequence!?")
	return

#func process_state_modifier():
#	var modifier :StateModifier = current_state.modifier
#	if modifier != null:
#		if modifier.state_timeout and modifier.state_timeout.time_left == 0:
#			print("Expired Modifier, updating animation.")
#			#modifier = null
#			match modifier.modifier_type:
#
#				modifier.TYPE.ANIMATION_SUFFIX:
#					# Attempt to seemlessly transition animations.
#					modifier = null
#					change_animation(frame,animation_index)
#
#				modifier.TYPE.REPLACE_ANIMATION:
#					if current_state.debug_state:
#						print("I don't have anything for replacements yet.")
#					modifier = null
#					change_animation()
#				_:
#					modifier = null
#			return

	
	# We have no more sequence animations and the current one doesn't loop
	# we do this to prevent the default idle animation from playing.
	##TODO: between this and the signal based iterator I get some really strange behavior
	if animation_index >= mod_animation_sequence.size() and frames.get_animation_loop(
			animation) == false:
		#print(animations.animation, " Animation Stopped")
		stop()
		#animation_finished = true
	elif mod_animation_sequence.size() > animation_index and current_animation_sequence != animation_index:
		#TODO: why was I doing this
#		if animation_index >= mod_animation_sequence.size():
#			animation_index = 0
		##TODO: Add a safety check here. 
		play(mod_animation_sequence[animation_index] + animation_suffix)
		if current_state.debug_state:
			print("An animation sequence: ", mod_animation_sequence[animation_index - 1], " -> ", 
				animation , " (", animation_index, ")")
		current_animation_sequence = animation_index

	##TODO: Could probably add some more checks here.
	# Singal based frame call.
	#TODO: reimplement this later. 
#	if emitter_frame_subscriptions.has(animations.frame):
#		if emitter_frame_subscriptions[animations.frame] == animations.animation:
#			if frame_signal_emitted == false:
#				emit_signal("frame_reached", self.name, animations.animation, animations.frame)
#				# Try to only so this once.
#				frame_signal_emitted = true
#	else:
#		frame_signal_emitted = false

# Handle state change from subscribed state machine.
#From signal state_changed(old_state_name, new_state)
func _on_state_change(old_state_name:String, new_state :State):
	#print ("1? got the state change signal ", new_state.name)
	# set current state to new_state
	previous_state_name = old_state_name
	#TODO: Confirm that this is a reference to the state in the
	###### State machine
	if new_state is StateAnimatedActor: #Testing this. Update: It works
		current_state = new_state
		if has_method('_on_state_change_' + current_state.name):
			call('_on_state_change_' + current_state.name)
		else:
			change_animation()
		#print("It's an animated Actor state!")
	else:
		push_warning("Received non animated Actor state.")

func _on_modifiers_updated(_modifier_type :int, _modifier_action :int):
	##TODO: There's so many things I could maybe do here but lets target the 
	## current use case. 
	if _modifier_type == StateModifierAnimatedActor.TYPE.ANIMATION_SUFFIX:
		print("A: ", animation, " F: ", frame, " -Modifier Changed Signal")
		# Wait for frame to finish before doing anything.
		#yield(self, "frame_changed")
	if _modifier_action == StateModifierAnimatedActor.EVENT_ID.DEACTIVATED:
		if frame != 0 and frame != frames.get_frame_count(animation):
			print ("lets change the animation suffix frame:", frame)
			var current_frame = frame
			#yield(self, "frame_changed")
			#while current_frame == frame:
			#	print("waiting...")
			#change_animation(frame + 1 ,animation_index)
			_frame_switch_tracker = frame  + 1
			_index_tracker = animation_index
