tool
extends Area2D

class_name Player

export var speed : float = 1
export var speed_dash : float = 3
export var rest : float = 1
export var reservoir : int  = 1

var level
onready var footsteps = $FootSteps
onready var deny = $Deny

var tile_position := Vector2(0,0)
var last_move_time := 0.0
var step_count := 0
var stepped := false
var dashing := false

class Movement:
	var action: String
	var direction: Vector2
	var animation: String
	
	func _init(_action, _direction, _animation):
		action = _action
		direction = _direction
		animation = _animation
	
var movements = [
	Movement.new("ui_right", Vector2.RIGHT, "right"),
	Movement.new("ui_left",  Vector2.LEFT,  "left"),
	Movement.new("ui_up",    Vector2.UP,    "back"),
	Movement.new("ui_down",  Vector2.DOWN,  "front")
]

class Sweep:
	var action: String
	var tile_limit
	var waste_limit
	var cost: int
	var sound: AudioStreamPlayer
	
	func _init(_action, _tlimit, _wlimit, _cost, _sound):
		action = _action
		tile_limit = _tlimit
		waste_limit = _wlimit
		cost = _cost
		sound = _sound
	
onready var sweeps = [
	Sweep.new("dash", INF, INF, 3, $Hoover),
	Sweep.new("whoosh", INF, 1, 2, null)
]

var movement_queue = []
var current_target = null
var current_direction : Movement = movements.back()
onready var sprite = $AnimatedSprite as AnimatedSprite

func _process(delta):

	if Engine.editor_hint:
		return 

	if Input.is_action_pressed("reset"):
		level.reset()

	if (last_move_time + rest) * 1000 < OS.get_ticks_msec():
		for movement in movements:
			if Input.is_action_pressed(movement.action):
				current_direction = movement
				if not Input.is_action_pressed("lock_move"):
					var target = level.get_tile_v(tile_position + movement.direction)
					if target.can_walk(movement.direction) or target.can_push(movement.direction):
						movement_queue.push_back(movement)
						
				
	update_animation()
	
	if not movement_queue.empty():
					
		var current_movement : Movement = movement_queue.front()
					
		if current_target == null:
			current_target = tile_position + current_movement.direction
			var tile = level.get_tile_v(current_target)
			if not tile.can_walk(current_movement.direction) and not tile.can_push(current_movement.direction):
				current_target = null
				movement_queue.pop_front()
			else:
				tile.push(current_movement.direction)
				footsteps.play()
		
		if current_target != null:
			tile_position += current_movement.direction * delta * (speed_dash if dashing else speed)
			
			var remaining : Vector2 = current_target - tile_position
			
			if remaining.dot(current_movement.direction) <= 0:
				tile_position = current_target
				current_target = null
				movement_queue.pop_front()
				stepped = false
				dashing = false
				if level.get_tile_v(tile_position).is_stairs_entrance():
					level.end_of_level()
			elif remaining.length() < 0.5 and not stepped:
				step_count += 1
				stepped = true
			
			update_position()
			last_move_time = OS.get_ticks_msec() / 1000.0
	
	for sweep in sweeps:
		
		if Input.is_action_just_pressed(sweep.action):
			
			if reservoir >= sweep.cost:
		
				if not current_target == null:
					tile_position = current_target
				
				var current = level.get_tile_v(tile_position)
				var end = current.dash(current_direction.direction, sweep.tile_limit, sweep.waste_limit)
				if current != end:
					movement_queue = [current_direction]
					current_target = Vector2 (end.x, end.y)
					dashing = true
					reservoir = reservoir - sweep.cost
					level.update_reservoir()
					if sweep.sound != null:
						sweep.sound.play()
					break
				else:
					deny.play()
			
			else:
				
				deny.play()
			

func update_position():
	position = level._floor.cell_custom_transform * (tile_position + Vector2.ONE / 2 )
	
func update_animation():
	sprite.animation = current_direction.animation
	sprite.frame = step_count % 2 + (0 if reservoir > 0 else 2)
