<?php

include_once("internal/tracker.php");
include_once("internal/helpers.php");
include_once("internal/admin.php");
include_once("internal/log.php");

// --------------------------------------------

class TeamEliminationRoundHandler extends Tracker {
	protected $metagame = NULL;
	// introduce states into round handler:
	// ROUND_PRACTICE
	//  - initial state where the handler goes into
	//  - waits for enough players to join the server / for an admin signal to start 
	//  - once enough players on server, waits for a short time allowing people to choose sides
	//  - executes start_round
	// ROUND_RUNNING
	//  - start_round changes state to this
	//  - tracks for player kills and counts
	//  - calls on_faction_lost
	// ROUND_END
	//	- starts at on_faction_lost
	//  - announces the current score
	//  - waits for a short period of time so that people can catch up, use a timer
	//  - announce when the next round is about to start
	//  - then executes start_round

	const ROUND_WAITING = 0;
	const ROUND_RUNNING = 1;
	const ROUND_END = 2;
	protected $state;

	protected $state_timer = -1.0;
	protected $respawn_lock_timer = -1.0;

	protected $factions = array();
	protected $scores = array();
	protected $current_round = 0;

	protected $start_votes = array();

	// --------------------------------------------
	function __construct($metagame, $factions = array(0 => "Green", 1 => "Brown")) {
		$this->metagame = $metagame;
		$this->factions = $factions;

		// clear profiles now
		$this->metagame->comms->send("clear_profiles");

		$this->reset();

	}

	// ----------------------------------------------------
	protected function announce($text) {
		// using a direct console command here
		$this->metagame->comms->send("say " . $text);
	}

	// ----------------------------------------------------
	protected function reset() {
		$this->state = self::ROUND_WAITING;
		$this->state_timer = -1.0;
		$this->respawn_lock_timer = -1.0;
		$this->current_round = 0;
		$this->start_votes = array();

		$this->reset_scores();

		$this->set_respawn_lock(false);

		$this->announce("practice mode started");
	}

	// ----------------------------------------------------
	protected function reset_scores() {
		$this->scores = array();
		for ($i = 0; $i < count($this->factions); ++$i) {
			$this->scores[] = 0;
		}
	}

	// ----------------------------------------------------
	protected function announce_score() {
		$text = "";
		foreach ($this->factions as $i => $name) {
			$text .= $name . " " . $this->scores[$i];
			if ($i != count($this->factions) - 1) {
				$text .= ", ";
			}
		}
		$this->announce($text);
	}
	
	// ----------------------------------------------------
	protected function handle_chat_event($doc) {
		// player_id
		// player_name
		// message
		// global
		$event = $doc->firstChild;

		$message = $event->getAttribute("message");
		// for the most part, chat events aren't commands, so check that first 
		if (!starts_with($message, "/")) {
			return;
		}

		$sender = $event->getAttribute("player_name");
		$sender_id = $event->getAttribute("player_id");

		// TODO: handle any commands specific to this tracker 
		if ($this->state == self::ROUND_WAITING) {
			if (check_command($message, "start")) {
				$this->attempt_prepare_to_start($sender_id);
			}
		} 
		
		// admin only from here on
		if (!is_admin($sender)) {
			return;
		}

		if ($this->state == self::ROUND_WAITING) {
			if (check_command($message, "force_start")) {
				$this->prepare_to_start();
			}
		} else {
			if (check_command($message, "reset")) {
				// back to waiting
				$this->reset();
			}
		}
	}

	// --------------------------------------------
	function attempt_prepare_to_start($player_id) {
		$this->start_votes[$player_id] = true;

		// query current total player count 
		$total_player_count = $this->get_player_count();

		if ($total_player_count >= 2) {
			$diff = ceil($total_player_count / 2) - count($this->start_votes);

			if ($diff <= 0) {
				$this->prepare_to_start();
			} else {
				$this->announce($diff . " more vote(s) needed to start");
			}
		} else {
			$this->announce("need more players to start");
		}
	}

	// --------------------------------------------
	function prepare_to_start() {
		// waiting advances to match when timer runs out, so start the timer now from the signal
		$this->state_timer = 5.0;
		$this->announce("get ready, about to start");
	}

	// --------------------------------------------
	function has_ended() {
			// always on
			return false;
	}

	// --------------------------------------------
	function has_started() {
			// always on
			return true;
	}

    // ----------------------------------------------------
	public function update($time) {
		if ($this->state_timer >= 0.0) {
			$this->state_timer -= $time;
			if ($this->state_timer < 0.0) {
				$this->on_state_timer_end();
			}
		}

		if ($this->state == self::ROUND_RUNNING) {
			if ($this->respawn_lock_timer >= 0.0) {
				$this->respawn_lock_timer -= $time;
				if ($this->respawn_lock_timer < 0.0) {
					$this->set_respawn_lock(true);
				}
			}
		}
	}

	// --------------------------------------------
	// track for player death events
	// - check if there's anyone left in the team of the killed player
	// - if not, grant a score to the other team
	// - start next round
	function handle_player_die_event($doc) {
		if ($this->state == self::ROUND_RUNNING) {
			_log("handle_player_die_event");
			$event = $doc->firstChild;

			$elements = $event->getElementsByTagName("target");
			if ($elements->length > 0) {
				$element = $elements->item(0);
				$faction_id = $element->getAttribute("faction_id");
				_log("player killed: " . $element->getAttribute("name") . ", faction " . $faction_id);

				// query for faction status to check if there's anyone living anymore
				$faction = $this->get_faction_info($faction_id);
				if ($faction) {
					$soldiers = $faction->getAttribute("soldiers");
					_log("soldiers left: " . $soldiers);
					if ($soldiers <= 0) {
						$this->on_faction_lost($faction_id);
					}
				} else {
					_log("invalid faction?");
				}

			} else {
				_log("no player elements?");
			}
		}
	}

	// ----------------------------------------------------
	protected function handle_vehicle_destroyed_event($doc) {
		// don't process if not properly started
		if (!$this->has_started()) return;

		if ($this->state == self::ROUND_RUNNING) {
			// vehicle_id
			// character_id
			$event = $doc->firstChild;

			$vehicle_id = $event->getAttribute("vehicle_id");
			$query_doc = new DOMDocument();
			$command =
				"<command class='make_query' id='round_handler_" . $this->metagame->comms->get_query_uid() . "'>\n" .
				"	<data class='vehicle' id='" . $vehicle_id . "' />\n" .
				"</command>";
			$query_doc->loadXML($command);
			$doc = $this->metagame->comms->query($query_doc);

			if ($doc) {
				$results = $doc->getElementsByTagName("vehicle");
				if ($results->length > 0) {
					$vehicle = $results->item(0);
					$key = $vehicle->getAttribute("key");
					$owner_id = $vehicle->getAttribute("owner_id");
					_log(" vehicle destroyed, it's a " . $key . " owned by " . $owner_id);

					if ($key == "radar_truck.vehicle" && 
						$owner_id >= 0 && $owner_id < count($this->factions)) {
						$vehicle_name = $vehicle->getAttribute("name");
						$faction_name = $this->factions[$owner_id];
						$this->announce($faction_name . " " . $vehicle_name . " destroyed");
						$this->on_faction_lost($owner_id);
					}
				}
			}
		}
	}

	// --------------------------------------------
	function get_faction_info($faction_id) {
		$query_doc = new DOMDocument();
		$command =
			"<command class='make_query' id='round_handler_" . $this->metagame->comms->get_query_uid() . "'>\n" .
			"	<data class='faction' id='" . $faction_id . "' />\n" .
			"</command>";
		$query_doc->loadXML($command);

		$doc = $this->metagame->comms->query($query_doc);

		$faction = NULL;
		if ($doc) {
			$faction = $doc->getElementsByTagName("faction")->item(0);
		}

		return $faction;
	}

	// --------------------------------------------------------
	function get_player_count() {
		$query_doc = new DOMDocument();
		$command =
				"<command class='make_query' id='player_count_query_" . $this->metagame->comms->get_query_uid() . "'>\n" .
				"       <data class='players' />\n" .
				"</command>";
		$query_doc->loadXML($command);

		$players_doc = $this->metagame->comms->query($query_doc);

		$players_count = 0;
		if ($players_doc) {
				$players = $players_doc->getElementsByTagName("player");
				$players_count = $players->length;
		}

		return $players_count;
	}

	// --------------------------------------------
	// - give score to the other team
	// - ignite new round start
	function on_faction_lost($faction_id) {
		_log("on_faction_lost, faction " . $faction_id);
		// TODO: this still assumes faction count = 2
		$winner = $faction_id == 0 ? 1 : 0;
		$this->scores[$winner] += 1;
		$this->announce_score();
		$this->state = self::ROUND_END;
		// 5 seconds
		$this->state_timer = 5.0;
	}

	// --------------------------------------------
	// - when round starts, allow respawning
	// - a) call start_game / restart_server to get it going -> respawns players automatically
	//     - if this is used, server needs to be in persistent profiles mode so that match start won't clear stats (unless round specific stats are wanted)
	//     - with persistent profiles, the script should clear the profiles after the match ends, so that stats won't carry over to next match
	// - b) inform about next round & allow a period of time for respawning
	// - disable respawning
	function start_round() {
		_log("start_round");
		$this->current_round++;
		$this->state = self::ROUND_RUNNING;
		$this->state_timer = -1.0;
		// allow respawn and/or start match?
		$this->set_respawn_lock(false);

		$this->start_match();

		$this->announce("round " . $this->current_round . " started");
	}

	// --------------------------------------------
	function on_state_timer_end() {
		_log("on_state_timer_end, state " . $this->state);
		if ($this->state == self::ROUND_WAITING) {
			_log("waiting ended");
			// start first round
			$this->start_round();

		} else if ($this->state == self::ROUND_END) {
			_log("end ended");

			// check if there are any players in the game
			if ($this->get_player_count() == 0) {
				$this->reset();
			} else {
				// everything ok, start next round
				$this->start_round();
			}
		}
	}

	// --------------------------------------------
	function start_match() {
		$clear_profiles = 0;
		if ($this->current_round == 1) {
			// when starting the first round, clear profiles to clear practice results
			$clear_profiles = 1;
		}

		$command =
			"<command class='restart_game'\n" .
			"  clear_profiles_at_start='" . $clear_profiles . "' />\n";
		$this->metagame->comms->send($command);

		$this->respawn_lock_timer = 2.0;
	}

	// --------------------------------------------
	function set_respawn_lock($locked) {
		_log("set_respawn_lock " . $locked);
		for ($i = 0; $i < count($this->factions); $i++) {
			$command =
				"<command class='set_soldier_spawn'\n" .
				"  enabled='" . ($locked ? 0 : 1) . "'\n" .
				"  faction_id='" . $i . "'/>\n";

			$this->metagame->comms->send($command);
		}
	}

}


?>