<?php

// Database for myChess
// ````````````````````

namespace {
	require_once 'common.php';
}

namespace DB {

	// Load and create/validate the database
	$db = new \PDO('sqlite:'.DB_PATH);	
	ValidateSchema();

	// [] --> null
	function ValidateSchema() {
		global $db;
		$db->query('
			CREATE TABLE IF NOT EXISTS boards (
				id    INTEGER PRIMARY KEY,
				game  INTEGER,
				time  INTEGER,
				turn  INTEGER,
				move  TEXT,
				board TEXT
			);
		');
		$db->query('
			CREATE TABLE IF NOT EXISTS chat (
				id      INTEGER PRIMARY KEY,
				game    INTEGER,
				time    INTEGER,
				player  INTEGER,
				message TEXT
			);
		');
		$db->query('
			CREATE TABLE IF NOT EXISTS games (
				id       INTEGER PRIMARY KEY,
				player1  INTEGER,
				player2  INTEGER
			);
		');
		$db->query('
			CREATE TABLE IF NOT EXISTS players (
				id       INTEGER PRIMARY KEY,
				name     TEXT,
				email    TEXT,
				doEmail  INTEGER,
				timezone TEXT,
				theme    INTEGER
			);
		');
		$db->query('
			CREATE TABLE IF NOT EXISTS auth (
				id      INTEGER PRIMARY KEY,
				hash    VARCHAR(40),
				game	INTEGER,
				player  INTEGER
			);
		');
	}

	// [] --> null (side effects: game);
	function GetGame() {
		global $db, $game;
		
		// Get player IDs
		$stmt = $db->prepare('SELECT * FROM games WHERE id=?');
		$stmt->execute(array($game['id']));
		$result = $stmt->fetchAll();
		if (! count($result)) dieWithError(E_NOGAME);
		$player_1_id = $result[0]['player1'];
		$player_2_id = $result[0]['player2'];
				
		// Get player details
		$stmt = $db->prepare('SELECT * FROM players WHERE id=?');		
		
		$stmt->execute(array($player_1_id));
		$result = $stmt->fetchAll();
		if (! count($result)) dieWithError(E_NOPLAYER);
		$game['player1'] = $result[0];
		
		$stmt->execute(array($player_2_id));
		$result = $stmt->fetchAll();
		if (! count($result)) dieWithError(E_NOPLAYER);
		$game['player2'] = $result[0];
		
		// Get current board and turn
		$stmt = $db->prepare('SELECT * FROM boards WHERE game=? ORDER BY id DESC LIMIT 1');
		$stmt->execute(array($game['id']));
		$result = $stmt->fetchAll();
		if (! count($result)) dieWithError(E_NOBOARD);
		$game['board'] = $result[0]['board'];
		$game['turn']  = $result[0]['turn'];
		
		// Get spectate url
		$stmt = $db->prepare('SELECT hash FROM auth WHERE game=? AND player=?');
		$stmt->execute(array($game['id'], PLAYER_S));
		$result = $stmt->fetchAll();
		if (! count($result)) dieWithError(E_NOBOARD);
		$game['auth_spec'] = $result[0]['hash'];
	}

	// [game_id] --> {'key', 'val', 'time', 'type'}
	function GetHistory($game, $limit = 5) {
		global $db;
		
		// SQLite doesn't support FULL OUTER JOIN
		$stmt = $db->prepare('
			SELECT * FROM (
				SELECT
					player key, message val, time, 2 type
				FROM chat WHERE game = ?
				UNION ALL
				SELECT
					turn key, move val, time, 1 type
				FROM boards WHERE game = ?
			) ORDER BY time DESC LIMIT ?
		');
		$stmt->execute(array($game, $game, $limit));
		$results = $stmt->fetchAll();
		
		return $results;
	}
	
	// [name1_str, name2_str] --> [PLAYER_* => hash_str]
	function NewGame($name1, $name2) {
		global $db;

		// Create new players
		$stmt = $db->prepare('
			INSERT INTO players (name, email, doEmail, timezone, theme)
			VALUES( ?, ?, ?, ?, ?);
		');
		$stmt->execute(array($name1, '', 0, DEFAULT_TZONE, DEFAULT_THEME));
		$player_1_id = $db->lastInsertID();
		$stmt->execute(array($name2, '', 0, DEFAULT_TZONE, DEFAULT_THEME));
		$player_2_id = $db->lastInsertID();
		
		// Create new game
		$stmt = $db->prepare('INSERT INTO games (player1, player2) VALUES(?, ?);');
		$stmt->execute(array($player_1_id, $player_2_id));
		$game_id = $db->lastInsertID();
		
		// Create default board
		Move($game_id, PLAYER_W, '', DEFAULT_BOARD);
		
		// Create authentication hash keys
		$stmt = $db->prepare('INSERT INTO auth (hash, game, player) VALUES (?, ?, ?);');
		$stmt->execute(array(($hash_w = RandomHash()), $game_id, PLAYER_W));
		$stmt->execute(array(($hash_b = RandomHash()), $game_id, PLAYER_B));
		$stmt->execute(array(($hash_s = RandomHash()), $game_id, PLAYER_S));
		
		// Return keys
		return array(PLAYER_W => $hash_w, PLAYER_B => $hash_b, PLAYER_S => $hash_s);
	}
	
	// [] --> null
	function SetPlayerPreferences($player_id, $email, $doEmails, $timezone_str, $theme) {
		global $db;		
		$stmt = $db->prepare('UPDATE players SET email=?, doEmail=?, timezone=?, theme=? WHERE id=?');
		$stmt->execute(array($email, ($doEmails)?1:0 , $timezone_str, $theme, $player_id));
	}
	
	// [game_id, PLAYER_TO_MOVE, move_str, board_str] --> null
	function Move($game_id, $turn, $move_str, $board_str) {
		global $db;		
		$stmt = $db->prepare('
			INSERT INTO boards (game, turn, move, board, time)
			VALUES( ?, ?, ?, ?, ?);
		');
		$stmt->execute(array($game_id, $turn, $move_str, $board_str, time()));
	}

	// [game_id, PLAYER_*, message_str] --> null
	function Chat($game_id, $player, $message) {
		global $db;
		$stmt = $db->prepare('
			INSERT INTO chat (game, player, message, time)
			VALUES (?, ?, ?, ?);
		');
		$stmt->execute(array($game_id, $player, $message, time()));
	}
	
	// --> int
	function CountGames() {
		global $db;
		$stmt = $db->query('SELECT MAX(id) m FROM games');
		$response = $stmt->fetchAll();
		return intval($response[0]['m']);
	}

	// --> hash
	function RandomHash() {
		return sha1(APP_NAME.time(NULL).(rand() % 1000));
	}

	// hash --> [game_id, PLAYER_*]
	function SearchHash($hash) {
		global $db;
		$stmt = $db->prepare('SELECT * FROM auth WHERE hash = ?');
		$stmt->execute(array($hash));
		$result = $stmt->fetchAll();
		
		if (! count($result)) {
			return array(0, PLAYER_S);
		} else {
			return array($result[0]['game'], $result[0]['player']);
		}
	}
	
	// [game_id, PLAYER_*] --> hash
	function RetrieveHash($game, $player) {
		global $db;
		$stmt = $db->prepare('SELECT hash FROM auth WHERE game = ? AND player = ?');
		$stmt->execute(array($game, $player));
		$results = $stmt->fetchAll();
		return $results[0]['hash'];
	}
	
}
