extends Node

var playing = false

onready var player_fab = preload('res://scenes/game1/Player.tscn')
var player : AnimatedSprite
var player_camera : Camera2D

onready var levels = [
	#'TestLogEntity',
	'Level1',
	'Level2',
	'Level3',
	'Level4',
	'Level5',
]

export var skipToLevel = ''

var current_level = -1
var spawn_pos = Vector2()
var exit_points = []

func _ready():
	if skipToLevel != '':
		$Opening1.queue_free()
		start_game()
		while levels[current_level] != skipToLevel:
			next_level()
		return
	
	$Opening1.play('default')
	yield($Opening1, 'animation_finished')
	$Opening1.queue_free()
	$Opening2/Player.sleep = false

func start_game():
	# Hide opening
	$Opening2.queue_free()
	next_level()

func next_level():
	if current_level >= 0:
		var level = $Game.get_node(levels[current_level])
		level.queue_free()
	
	current_level += 1
	
	if current_level >= levels.size():
		get_tree().change_scene("res://scenes/oil_tanker.tscn")
		return
	
	# Prepare level
	var level = load("res://scenes/game1/" + levels[current_level] + ".tscn").instance()
	$Game.add_child(level)
	spawn_entities(level)
	
	# Prepare player
	player = player_fab.instance()
	player_camera = player.get_node("Camera2D")
	level.add_child_below_node(level.get_node("Entities"), player)
	playing = true
	player_camera.make_current()
	player.connect('frame_changed', self, 'update_camera')
	
	# Spawn player
	player.position = spawn_pos * 16 + Vector2(8, 8)

func spawn_entities(level : Node):
	exit_points = []
	var entities = Node2D.new()
	entities.name = 'Entities'
	level.add_child_below_node(level.get_node('Props'), entities)
	
	for layer in level.get_children():
		if !(layer is TileMap): continue
		var tm  = layer as TileMap
		var tileset = tm.tile_set
		
		# Flatfish
		var fishes = []
		for tile in ['flatfish_s', 'flatfish_s_hidden', 'flatfish_t', 'flatfish_t_hidden']:
			fishes += tm.get_used_cells_by_id(tileset.find_tile_by_name(tile))
		
		for cell in fishes:
			var fish = Flatfish.new()
			fish.position = cell * 16 + Vector2(8, 8)
			var t = tm.is_cell_transposed(cell.x, cell.y)
			var x = tm.is_cell_x_flipped(cell.x, cell.y)
			var  y = tm.is_cell_y_flipped(cell.x, cell.y)
			if t && x:
				fish.rotation_degrees = 90
			elif x && y:
				fish.rotation_degrees = 180
			elif t && y:
				fish.rotation_degrees  = 270
			entities.add_child(fish)
			tm.set_cell(cell.x, cell.y, -1)
		
		# Spawn point
		for cell in tm.get_used_cells_by_id(tileset.find_tile_by_name('start')):
			spawn_pos = cell
			
		# Exit points
		for cell in tm.get_used_cells_by_id(tileset.find_tile_by_name('finish')):
			exit_points.append(cell)
		
		# Logs
		for d in ['horizontal', 'vertical']:
			for i in [1, 2, 3, 4]:
				for cell in tm.get_used_cells_by_id(tileset.find_tile_by_name('log_' + d + '_' + String(i))):
					var log_entity = LogEntity.new(LogEntity.Type.H if d == 'horizontal' else LogEntity.Type.V, i - 1)
					log_entity.spawn_at(cell * 16 + Vector2(16, 16))
					entities.add_child(log_entity)
					tm.set_cell(cell.x, cell.y, -1)

var go_right = false
var go_left = false
var do_interact = false

func _input(event):
	if playing:
		if event.is_action_pressed('right'):
			go_right = true
		if event.is_action_pressed('left'):
			go_left = true
		if event.is_action_pressed('interact'):
			do_interact = true
		
		if event.is_action_released('right'):
			go_right = false
		if event.is_action_released('left'):
			go_left = false
		if event.is_action_released('interact'):
			do_interact = false

var trying_to_move = false
func move():
	if !playing || trying_to_move || is_interacting || is_camera_moving: return
	
	trying_to_move = true
	yield(get_tree(), "physics_frame")
	yield(get_tree(), "physics_frame")
	if go_right && !go_left && can_move_towards('Right'):
		move_right()
	elif go_left && !go_right && can_move_towards('Left'):
		move_left()
	trying_to_move = false

func _process(delta):
	interact()
	move()

func can_move_towards(sensorName : String) -> bool:
	var sensor = player.get_node("Sensors/" + sensorName) as Area2D
	var bodies = sensor.get_overlapping_bodies()
	var areas = sensor.get_overlapping_areas()
	
	# Check for pushables and push
	for body in bodies + areas:
		var p = body.get_parent()
		if p is LogEntity:
			var rot = int(floor(player.rotation_degrees / 90.0)) % 4
			var dir = 1 if (rot == 0 || rot == 1) && sensorName == 'Right' || (rot == 2 || rot == 3) && sensorName == 'Left' else -1
			
			# Push and fall
			if p.push((player.position / 16) - Vector2(0.5, 0.5), dir):
				var level = $Game.get_node(levels[current_level])
				var pos = (p.position / 16) - Vector2(1, 1)
				for layer in level.get_children():
					if !(layer is TileMap): continue
					var tm  = layer as TileMap
					var tileset = tm.tile_set
					
					var name = tileset.tile_get_name(tm.get_cellv(pos))
					if name != null && name.rfind('hole_') == 0:
						tm.set_cellv(pos, tileset.find_tile_by_name("log_in_" + name), tm.is_cell_x_flipped(pos.x, pos.y), tm.is_cell_y_flipped(pos.x, pos.y), tm.is_cell_transposed(pos.x, pos.y))
						p.queue_free()
					
	return bodies.size() == 0 && areas.size() == 0

func move_right():
	is_camera_moving = true
	player.play('moving')
	update_camera()
	
	yield(player, 'animation_finished')
	
	player.play('default')
	player.frame = 0
	offset_player(16)
	is_camera_moving = false
	if !check_exit(): move()

func move_left():
	is_camera_moving = true
	offset_player(-16)
	player.play('moving', true)
	update_camera()
	
	yield(player, 'animation_finished')
	
	player.play('default')
	player.frame = 0
	is_camera_moving = false
	if !check_exit(): move()

func check_exit() -> bool:
	var player_pos = (player.position - Vector2(8, 8)) / 16
	print(player_pos)
	for exit in exit_points:
		if player_pos == exit:
			print('exit')
			next_level()
			return true
	return false

func offset_player(offset):
	var r = int(ceil(player.rotation_degrees / 90.0)) % 4
	if r == 0: player.position.x += offset
	elif r == 1: player.position.y += offset
	elif r == 2: player.position.x -= offset
	elif r == 3: player.position.y -= offset

const animation_steps = [3, 6, 10, 13]
var is_camera_moving = false
func update_camera():
	if is_camera_moving && !is_interacting:
		player_camera.position = Vector2(animation_steps[player.frame], 0)
	else:
		player_camera.position = Vector2()

var is_interacting = false
func interact():
	if !playing || !do_interact || is_interacting || trying_to_move || is_camera_moving: return
	is_interacting = true
	
	var level = $Game.get_node(levels[current_level])
	var entities = level.get_node('Entities').get_children()
	
	var fish = null
	for e in entities:
		if e is Flatfish && e.position == player.position:
			fish = e
			break
	
	if fish != null:
		fish.appear()
		yield(get_tree().create_timer(0.2), "timeout")
		
		fish.do_rotation()
		player.rotation_degrees += 45
		yield(get_tree().create_timer(0.2), "timeout")
		
		fish.do_rotation()
		player.rotation_degrees += 45
		yield(get_tree().create_timer(0.2), "timeout")
		
		fish.disappear()
	
	is_interacting = false
	if fish != null: interact()
