tool

extends Node2D

class_name ProbeArea

export(String) var area_name
export(NodePath) var wall_tilemap
export(NodePath) var base_tilemap

var debug_font = preload("res://Graphics/UI/uifont.tres")

const AREA_LAYER_ID = 16

onready var walls = get_node(wall_tilemap) as TileMap
onready var base = get_node(base_tilemap) as TileMap
onready var physics = get_world_2d().direct_space_state
onready var map = walls.get_parent() as GameMap

const TILE_SIZE = 32

var cells = {}
var bounds = {}

func _ready():
	scout()
	update()

func scout():
	# Reset lists
	cells = {}
	bounds = {}
	# Get origin and immediate neighbour of probe
	var origin = Vector2(floor(position.x / TILE_SIZE), floor(position.y / TILE_SIZE))
	cells[origin] = true
	var queue = get_neighbours(origin)
	# Use children probes for extra areas
	for child in get_children():
		var child_origin = Vector2(floor((position.x + child.position.x) / TILE_SIZE), floor((position.y + child.position.y) / TILE_SIZE))
		cells[child_origin] = true
		for neighbour in get_neighbours(child_origin):
			queue.push_front(neighbour)
	# Depth-first search
	while not queue.empty():
		var current = queue.pop_front()
		# Have we checked this already?
		if not is_valid(current):
			continue
		var wall_tile = walls.get_cellv(current)
		if wall_tile == -1:
			var objects = physics.intersect_point(current * TILE_SIZE + Vector2.ONE * TILE_SIZE / 2.0, 1, [], AREA_LAYER_ID)
			if objects.size() > 0:
				bounds[current] = true
			else:
				cells[current] = true
				for neighbour in get_neighbours(current):
					queue.push_front(neighbour)
		else:
			bounds[current] = true
	# Join walls
	var joined = []
	for cell in bounds:
		var sides = [
			[Vector2(cell.x, cell.y-1),Vector2(cell.x, cell.y+1)],
			[Vector2(cell.x-1, cell.y),Vector2(cell.x+1, cell.y)],
		]
		for side_pair in sides:
			if cells.has(side_pair[0]) and cells.has(side_pair[1]):
				# This bound is joined at one side, make it a cell and not a bound
				joined.push_back(cell)
	for wall in joined:
		bounds.erase(wall)
		cells[wall] = true

func is_valid(cell: Vector2) -> bool:
	# Have we checked this already?
	if cells.has(cell) or bounds.has(cell):
		return false
	# Is it a valid tile for an area
	return base.get_cellv(cell) != -1

func get_neighbours(cell: Vector2) -> Array:
	var neighbours = [
		Vector2(cell.x-1, cell.y-1), Vector2(cell.x, cell.y-1), Vector2(cell.x+1, cell.y-1),
		Vector2(cell.x-1, cell.y),                              Vector2(cell.x+1, cell.y),
		Vector2(cell.x-1, cell.y+1), Vector2(cell.x, cell.y+1), Vector2(cell.x+1, cell.y+1)
	]
	var out = []
	for neighbour in neighbours:
		# Have we checked this already?
		if not is_valid(neighbour):
			continue
		out.push_back(neighbour)
	return out

func _draw():
	if map == null or not map.debug_areas:
		return
	var origin = Vector2(floor(position.x / TILE_SIZE), floor(position.y / TILE_SIZE))
	var draw_origin = origin * TILE_SIZE - position
	var rect_size = Vector2.ONE * TILE_SIZE
	draw_rect(Rect2(draw_origin, rect_size), Color.red, false, 2)
	draw_string(debug_font, Vector2.ZERO, area_name, Color.blue)
	for child in get_children():
		var child_origin = Vector2(floor(child.position.x / TILE_SIZE), floor(child.position.y / TILE_SIZE))
		draw_rect(Rect2(draw_origin + child_origin * TILE_SIZE, rect_size), Color.orange, false, 2)
		draw_string(debug_font, child.position, area_name + "/" + child.name, Color.blue)
	for wall in bounds:
		draw_rect(Rect2(wall * TILE_SIZE - position + Vector2.ONE * (TILE_SIZE / 2.0 - TILE_SIZE / 4.0), rect_size/2.0), Color(0,0.5,1,0.5))

func _area_moved():
	scout()
	update()

func serialize():
	var subareas = {}
	for child in get_children():
		subareas[child.name] = {
			"transform": child.transform
		}
	return {
		"name": area_name,
		"wall_path": wall_tilemap,
		"base_path": base_tilemap,
		"subareas": subareas
	}

func deserialize(data):
	for subarea in data.subareas:
		var node = Node2D.new()
		node.name = subarea
		node.transform = data.subareas[subarea].transform
		add_child(node)
	area_name = data.name
	wall_tilemap = data.wall_path
	base_tilemap = data.base_path
