extends Node

const MAX_PEERS = 4
const LOBBY_READY_WAIT_TIME = 3
const EMPTY_WAIT_TIME = 30

var port:int = -1
var dedicated_server:bool = false
var server_secret:String = ""
var server_id:String = "[GAME:-1] "

var timer:Timer

signal server_error(type, data)


func _ready():
	for argument in OS.get_cmdline_args():
		if argument.split("=")[0] == "--port":
			dedicated_server = true
			port = int(argument.split("=")[1])
		if argument.split("=")[0] == "--server-id":
			server_id = "[GAME:" + str(argument.split("=")[1]) + "] "
		if argument.split("=")[0] == "--secret":
			server_secret=argument.split("=")[1]
		if argument.split("=")[0] == "--bots":
			gamestate.set_bots(bool(int(argument.split("=")[1])))
			
	if dedicated_server:
		var err = host_game(port)
		if err == OK:
			print(server_id + "New game hosted: port=" + str(port) + " secret=" + str(server_secret) + " bots=" + str(gamestate.bots))
		else:
			print(server_id + "Could not create Server! (port=" + str(port) + " secret=" + str(server_secret) + ")")
			quit_server()


func host_game(port:int, set_bots:bool = false):
	var host = NetworkedMultiplayerENet.new()
	var err = host.create_server(port, MAX_PEERS)
	get_tree().set_network_peer(host)
		
	get_tree().connect("network_peer_connected", self, "_client_connected")
	get_tree().connect("network_peer_disconnected", self,"_client_disconnected")
	
	gamestate.connect("players_changed",self,"_players_changed")
	gamestate.connect("game_ready",self,"_game_ready")
	gamestate.connect("game_ended",self,"_game_ended")
	
	if set_bots:
		gamestate.bots = true
	
	if timer == null:
		timer = Timer.new()
		timer.set_name("timer")
		timer.set_timer_process_mode(Timer.TIMER_PROCESS_PHYSICS)
		timer.set_one_shot(true)
		timer.set_autostart(false)
		add_child(timer)
	
	if err != OK:		
		emit_signal("server_error", "HOST", err)
		
	return err


func local_game(name:String, color:Color, bots:bool):
	var localhost = NetworkedMultiplayerENet.new()
	localhost.create_server(0, 0)
	get_tree().set_network_peer(localhost)
	gamestate.bots = bots
	gamestate.set_player(get_tree().get_network_unique_id(), name, color)
	gamestate.prepare_game()
	gamestate.post_start_game()


func update_server_data():
	var req = game_server.http()
	req.put_request("game",to_json({'secret' : server_secret, 'player_count' : gamestate.players.size(), 'running' : gamestate.game_running}))
	
func _client_connected(id):
	if get_tree().is_network_server():
		if dedicated_server:
			print(server_id + "peer connected: " + str(id))
		gamestate.rpc_id(id, "set_bots" ,gamestate.bots)
		if not timer.is_stopped():
			timer.disconnect("timeout",self,"quit_server")
			timer.stop()


func _client_disconnected(id):
	if get_tree().is_network_server():
		if dedicated_server:
			print(server_id + "peer disconnected: " + str(id))
		if gamestate.game_running:
			emit_signal("server_error", "DISCONNECTED", [id])
			gamestate.rpc("remove_player" ,id)
		else: 
			gamestate.rpc("remove_player" ,id)


func _players_changed(players):	
	if get_tree().is_network_server():
		if dedicated_server:
			update_server_data()
			if players.empty():
				if gamestate.game_running:
					print(server_id + "All players disconnected, close server.")
					quit_server()
				else:
					print(server_id + "All players disconnected, wait for closing...")
					timer.set_wait_time(EMPTY_WAIT_TIME)
					timer.connect("timeout",self,"quit_server",[true])
					timer.start()


func quit_server(triggered:bool = false):
	if dedicated_server && triggered:
		print(server_id + "Closing time over...quit")
	var req = game_server.http()
	req.connect_http(self,"_on_delete_server")
	req.delete_request("game",to_json({'secret' : server_secret}))


func _on_delete_server(result, response_code, headers, body):
	if result != OK || response_code != HTTPClient.RESPONSE_OK:
		print(server_id + "ERROR: _on_delete_server, server might be in undefined state!")
		get_tree().quit()


func _start_game():
	if get_tree().is_network_server():
		get_tree().set_refuse_new_network_connections(true)
		gamestate.rpc("prepare_game")


func _game_ready(all_ready):
	if get_tree().is_network_server():
		if all_ready:
			timer.set_wait_time(LOBBY_READY_WAIT_TIME)
			timer.connect("timeout",self,"_start_game")
			timer.start()
		else:
			timer.disconnect("timeout",self,"_start_game")
			timer.stop()


func _game_ended():
	get_tree().disconnect("network_peer_connected", self, "_client_connected")
	get_tree().disconnect("network_peer_disconnected", self,"_client_disconnected")
	
	gamestate.disconnect("players_changed",self,"_players_changed")
	gamestate.disconnect("game_ready",self,"_game_ready")
	gamestate.disconnect("game_ended",self,"_game_ended")
	
	get_tree().set_refuse_new_network_connections(false)
	get_tree().set_network_peer(null)