extends Node

signal player_disconnected
signal server_disconnected

export var SERVER_IP: String = "127.0.0.1"
export var SERVER_PORT: int = 55055
export var MAX_PLAYERS: int = 10
export var BASE_PATH: String = "/root/Node2D";

onready var gui_username: TextEdit = get_node(BASE_PATH + "/GUI/Control/Username")
onready var gui_lusername: Label = get_node(BASE_PATH + "/GUI/Control/LUsername")
onready var gui_create: Button = get_node(BASE_PATH + "/GUI/Control/Create")
onready var gui_join: Button = get_node(BASE_PATH + "/GUI/Control/Join")
onready var gui_waiting: Label = get_node(BASE_PATH + "/GUI/Control/Waiting")
onready var gui_lip: Label = get_node(BASE_PATH + "/GUI/Control/LIP")
onready var gui_ip: TextEdit = get_node(BASE_PATH + "/GUI/Control/IP")
onready var gui_chat: VBoxContainer = get_node(BASE_PATH + "/GUI/Control/Chat")

onready var spawn: Node2D = get_node(BASE_PATH + "/Game/Spawn") as Node2D

var players = {}

# If true, the player can't move. Accessed by tasks.
var move = true

var self_data = { name = '', position = Vector2(66, 175) }

func _ready():
	get_tree().connect('network_peer_disconnected', self, '_on_player_disconnected')
	get_tree().connect('network_peer_connected', self, '_on_player_connected')

#######################
### SERVER CODE
#######################
# Called when the node enters the scene tree for the first time.
func start_server():
	var admin_name = gui_username.text
	self_data.name = admin_name
	self_data.position = spawn.position
	players[1] = self_data	# ID of server is always 1
	var peer = NetworkedMultiplayerENet.new()
	peer.create_server(SERVER_PORT, MAX_PLAYERS)
	get_tree().network_peer = peer
	add_to_chat("Server is now running!", Color(0, 100, 0, 1))
	gui_create.text = "Cancel"
	gui_join.visible = false
	gui_waiting.visible = true
	
	# Create admin player
	create_new_player(1, players[1])	
	hideLobby()

func _on_player_connected(connected_player_id):
	print("Client connected!")
	add_to_chat("User " + String(connected_player_id) + " joined the game!")
	rpc_id(1, '_request_players')

func _on_player_disconnected(id):
	var player = get_node("/root/Node2D/Game/" + str(id))
	player.get_parent().remove_child(player)
	add_to_chat("User " + String(id) + " left the game!")
	players.erase(id)

# This function get's called by each client on join.
# It will loop though all players (except the requester) and will force the client
# to execute _send_player_info to create the local player objects
remote func _request_players():
	var request_from_id = get_tree().get_rpc_sender_id()
	if get_tree().is_network_server():
		for peer_id in players:
			#if( peer_id != request_from_id):
			rpc_id(request_from_id, '_send_player_info', peer_id, players[peer_id])

remote func _request_player_info(request_from_id, player_id):
	if get_tree().is_network_server():
		rpc_id(request_from_id, '_send_player_info', player_id, players[player_id])

remote func _send_player_info(id, info):
	print("Create player ", id, "with: ", info)
	players[id] = info
	
	create_new_player(id, info)

func update_position(id, position):
	#print("Update position of", id, ":", position)
	
	players[id].position = position

#######################
### CLIENT CODE
#######################
func connect_to_server():
	var player_name = gui_username.text
	self_data.name = player_name
	get_tree().connect("connected_to_server", self, '_connected_to_server')
	var peer = NetworkedMultiplayerENet.new()
	peer.create_client(SERVER_IP, SERVER_PORT)
	get_tree().network_peer = peer

func _connected_to_server():
	var id = get_tree().get_network_unique_id()
	print("Connected to server with id ", id)
	players[get_tree().get_network_unique_id()] = self_data
	rpc_id(1, '_send_player_info', get_tree().get_network_unique_id(), self_data)
	rpc_id(1, '_request_players')
	
	print("==== END CONNECT ====")
	
	hideLobby()

###
### HELPER
###
func hideLobby():
	(get_node(BASE_PATH + "/Game")).visible = true
	gui_username.visible = false
	gui_lusername.visible = false
	gui_create.visible = false
	gui_join.visible = false
	gui_lip.visible = false
	gui_ip.visible = false
	gui_waiting.visible = false

func add_to_chat(message: String, color = Color(100, 100, 100, 1)):
	var label: Label = Label.new()
	label.text = message
	if color != null:
		label.add_color_override("font_color", color)
		
	gui_chat.add_child(label)

func get_player_node(name: int):
	return get_node("/root/Node2D/Game/" + String(name))

func create_new_player(id: int, info):
	if get_node(BASE_PATH + "/Game/" + str(id)) != null:
		return	# Do not create a new player (duplicate)
		
	var new_player = (load('res://Characters/Player/Player.tscn').instance() as KinematicBody2D)
	new_player.position = info.position
	new_player.name = str(id)
	new_player.z_index = 10
	
	new_player.set_network_master(id)
	if get_tree().get_network_unique_id() != id:
		(new_player.get_node("./Light2D") as Light2D).enabled = false
		(new_player.get_node("./Darken") as Light2D).enabled = false
	
	new_player.get_node("Label").text = info.name
	
	get_node(BASE_PATH + "/Game").add_child(new_player)
	
	print("New player with master:", new_player.get_network_master())
