extends Node

signal tower_constructed

export (PackedScene) var MobFactory
export (PackedScene) var Mob
export (PackedScene) var Tower

export var Radius = 40

var path_polygon
var mob_factory

# class member variables go here, for example:
# var a = 2
# var b = "textvar"

func _ready():
	get_tree().connect("constructed", self, "_tower_constructed")
	
	mob_factory = MobFactory.instance()
	calculate_path()
	$DebugDrawer.update()

func _process(delta):
	pass
#	if Input.is_action_just_pressed("ui_up"):
#		if get_tree().is_network_server():
#			build_tower()

func start():
	print("Starting game")
	$MobSpawner.start()

func stop():
	$MobSpawner.stop()

func build_tower():
	if get_tree().is_network_server():
		rpc("_build_tower")
	
sync func _build_tower():
	var tower = Tower.instance()
	add_child(tower)

func calculate_path():
	var collision_points_over = []
	var collision_points_under = []
	for i in range(0, $Path2D.curve.get_baked_length(), $Path2D.curve.get_bake_interval()):
		$Path2D/PathFollow2D.offset = i
		$Path2D/PathFollow2D.v_offset = Radius
		collision_points_over.push_back($Path2D/PathFollow2D.position)
		$Path2D/PathFollow2D.v_offset = -Radius
		collision_points_under.push_front($Path2D/PathFollow2D.position)
	
	path_polygon = simplify_polygon(collision_points_over + collision_points_under)
	$Area2D/PathCollision.polygon = path_polygon
	$PathBackground.polygon = path_polygon
	
	# Reset tracing of path
	$Path2D/PathFollow2D.offset = 0
	$Path2D/PathFollow2D.v_offset = 0

func simplify_polygon(complex_polygon):
	var simple_polygon = reduce_points(complex_polygon)
	var intersections = find_intersections(simple_polygon)  # Point before, point after, point at
	for intersection in intersections:
		var before_index = simple_polygon.find(intersection[0])
		var after_index = simple_polygon.find(intersection[1])
		if before_index > 0 and after_index > 0:
			for i in range(after_index, before_index, -1):
				simple_polygon.remove(i)
	return simple_polygon
	
func reduce_points(complex_polygon):
	var simple_polygon = []
	simple_polygon.push_back(complex_polygon.front())
	for i in range(1, len(complex_polygon)):
		var distance = simple_polygon.back().distance_to(complex_polygon[i])
		if distance > 5:
			simple_polygon.push_back(complex_polygon[i])
	return simple_polygon

# Stolen (and adapted) from https://godotengine.org/qa/24004/efficient-way-of-detecting-if-a-line-touched-itself?show=24014#a24014
func find_intersections(points): # Returns an Array[3] with point before intersection, point after intersection, and point of intersection
	var intersections = []

	# Iterate all segments to see if they intersect another.
	# (Start at 1 because it's easier to iterate pairs of points)
	for i in range(1, len(points)):

		# Note: the +1 makes sure we don't get two results per segment pairs
		# (intersection of A into B and intersection of B into A, which are the same anyways)
		for j in range(1 + i, len(points)):

			if abs(j - i) < 2:
				# Ignore self and neighbors
				continue

			var begin0 = points[i - 1]
			var end0 = points[i]

			var begin1 = points[j - 1]
			var end1 = points[j]

			# Calculate intersection of the two segments
			var intersection = get_segment_intersection(begin0, end0, begin1, end1)
			if intersection != null:
				intersections.append([begin0, end1, intersection])

	return intersections


static func get_segment_intersection(a, b, c, d):
    # http://paulbourke.net/geometry/pointlineplane/ <-- Good stuff
    var cd = d - c
    var ab = b - a
    var div = cd.y * ab.x - cd.x * ab.y

    if abs(div) > 0.001:
        var ua = (cd.x * (a.y - c.y) - cd.y * (a.x - c.x)) / div
        var ub = (ab.x * (a.y - c.y) - ab.y * (a.x - c.x)) / div
        var intersection = a + ua * ab
        if ua >= 0.0 and ua <= 1.0 and ub >= 0.0 and ub <= 1.0:
            return intersection
        return null

    # Segments are parallel!
    return null

func _on_MobSpawner_timeout():
	if get_tree().is_network_server():
		var type = randi() % 3
		rpc("spawn_specific_mob", type)

func spawn_random_mob():
	var mob = mob_factory.create_random_mob()
	add_child(mob)
	mob.position = $Path2D/PathFollow2D.position
	mob.setPath($Path2D/PathFollow2D)

sync func spawn_specific_mob(type):
	var mob = mob_factory.create_specific_mob(type)
	mob.position = $Path2D/PathFollow2D.position
	mob.setPath($Path2D/PathFollow2D)
	add_child(mob)


func _tower_constructed():
	print("Map got constructed signal")
	emit_signal("tower_constructed")

func _on_DebugDrawer_draw():
	pass
