<?php

// myChess
// ```````

// ##########################################################
// Initialisation and constants
// ##########################################################


$page_create_time = microtime();
session_start();

require_once 'common.php';
require 'db.php';
require 'chess.php';

define('MODE_HOME',     0);
define('MODE_GAME',     1);
define('MODE_CREATE',   2);
define('MODE_MOVE',     3);
define('MODE_CHAT',     4);
define('MODE_OPTIONS',  5);
define('MODE_SETOPTS',  6);
define('MODE_AJAXHIST', 7);
define('MODE_DEFAULT', MODE_HOME);
$current_mode = MODE_DEFAULT;

$game = array(
	'id'        => 0,
	'whoami'    => PLAYER_S,
	'auth'      => '',
	'auth_spec' => '',
	'name1'     => '',
	'name2'     => '',
	'email1'    => '',
	'email2'    => '',
	'doEmail1'  => 0,
	'doEmail2'  => 0,
	'board'     => DEFAULT_BOARD,
	'turn'      => '',
	'move'      => ''
);


// ##########################################################
// Controller
// ##########################################################


$board = array();
if (! isset($_GET['p'])) redirect(HOME_ADDRESS);
switch( $_GET['p'] ) {
	case 'game': {
		$current_mode = MODE_GAME;
		
		// Validate request and load game
		if (! isset($_GET['id'])) dieWithError();
		$game['auth'] = $_GET['id'];
		validateGame();
		
	} break;
	
	// MODE_HOME
	case 'home': {
		$current_mode = MODE_HOME;
	} break;
	
	// MODE_OPTIONS
	case 'options': {
		$current_mode = MODE_OPTIONS;
	
		// Validate request and load game
		if (! isset($_GET['id'])) dieWithError();
		$game['auth'] = $_GET['id'];
		validateGame();
		
		// Require black/white
		if ($game['whoami'] == PLAYER_S) dieWithError();
	} break;
	
	// MODE_AJAXHIST
	case 'history': {
		$current_mode = MODE_AJAXHIST;
		
		// Validate request and load game (with plain errors)
		if (! isset($_GET['id'])) die('Invalid request!');
		$game['auth'] = $_GET['id'];
		list($game['id'], $game['whoami']) = DB\SearchHash($game['auth']);
		if (! $game['id']) die('Invalid request!');
		DB\GetGame();
		
		// Return entire history		
		viewHistory(1024);
		die();
		
	} break;
	
	// MODE_SETOPTS
	case 'setoptions': {
		$current_mode = MODE_SETOPTS;
				
		// Validate request and load game
		if (! checkPost(array('auth', 'email'))) dieWithError();
		$game['auth'] = $_POST['auth'];
		validateGame();
		
		// Require black/white
		if ($game['whoami'] == PLAYER_S) {
			$_SESSION['info'] = E_INVREQ;
			redirect('?p=options&id='.$game['auth']);
		}
		
		// Store changes
		DB\SetPlayerPreferences(
			$game['id'], $game['whoami'], $_POST['email'],
			isset($_POST['doEmail'])
		);
		
		$_SESSION['info'] = S_DETAILSOK;
		redirect('?p=options&id='.$game['auth']);
	} break;	
	
	// MODE_CREATE
	case 'create': {
		$current_mode = MODE_CREATE;
		
		// Validate request
		if (! checkPost(array('name1', 'name2'))) dieWithError();
		if (! strlen($_POST['name1']) || ! strlen($_POST['name2'])) dieWithError(E_NONAME);
		
		// Create the game
		$hashes = DB\NewGame($_POST['name1'], $_POST['name2']);
		$response_str = explode('|', S_GAMECREATED);		
		$_SESSION['info'] =
			$response_str[0] .
			'<a href="?p=game&id='.$hashes[PLAYER_B].'">'.$response_str[1].'</a>'.
			$response_str[2]
		;		
		redirect('?p=game&id='.$hashes[PLAYER_W]);
	} break;
	
	// MODE_MOVE
	case 'move': {
		$current_mode = MODE_MOVE;
	
		// Validate request and load game
		if (! checkPost(array('auth', 'move'))) dieWithError();
		$game['auth'] = $_POST['auth'];
		validateGame();
		
		// Check play order
		if ($game['whoami'] != $game['turn']) {
			$_SESSION['info'] = E_NOTURN;
			redirect('?p=game&id='.$game['auth']);
		}
		
		// Test and apply move
		$move = explode(' ', $_POST['move']);
		if ( (count($move) == 2) &&
			chess\canMoveStr($game['board'], $move[0], $move[1], $game['turn'])
		) {
			DB\Move(
				$game['id'],
				($game['turn'] == PLAYER_W ? PLAYER_B : PLAYER_W),
				$move[0].$move[1],
				chess\applyMoveStr($game['board'], $move[0], $move[1])
			);
			$_SESSION['info'] = S_PLAYED.' '.$move[0].$move[1];
			emailOpponent(S_PLAYED.' '.$move[0].$move[1]);
		} else {
			$_SESSION['info'] = E_INVMOVE;
		}
		
		// Send email notifications
		
		redirect('?p=game&id='.$game['auth']);
	} break;
	
	// MODE_CHAT
	case 'chat': {
		$current_mode = MODE_CHAT;
	
		// Validate request and load game
		if (! checkPost(array('auth', 'message'))) dieWithError(E_INVREQ);
		$game['auth'] = $_POST['auth'];
		validateGame();
		
		// Add to DB and notify opponent
		DB\Chat($game['id'], $game['whoami'], $_POST['message']);
		emailOpponent($_POST['message']);
		
		// Return
		$_SESSION['info'] = S_CHATOK;
		redirect('?p=game&id='.$game['auth']);
	} break;
	
	default:
		redirect(HOME_ADDRESS);
}


// ##########################################################
// Controller helper functions
// ##########################################################


function emailOpponent($content) {
	global $game;
	
	// Retrieve and validate opponent's parameters
	if ($game['whoami'] == PLAYER_W) {
		if (! $game['doEmail2']) return;
		$email = $game['email2'];
		$opponent = PLAYER_B;		
	} else {
		if (! $game['doEmail1']) return;
		$email = $game['email1'];
		$opponent = PLAYER_W;
	}
	if (! filter_var($email, FILTER_VALIDATE_EMAIL)) return;
	
	// Search for opponent's hash
	$hash = DB\RetrieveHash($game['id'], $opponent);
	
	// Determine message content
	$content .= "\n\n
___________________________
View game: http://".main_url()."?p=game&id={$hash}
Powered by ".APP_NAME."
	";
	
	// Send message
	mail(
		$email,
		APP_NAME.' update',
		$content,
		'From: '.APP_NAME.' <'.FROM_EMAIL.'>'
	);
}

function dieWithError($message = E_INVREQ) {
	$_SESSION['info'] = $message;
	redirect(HOME_ADDRESS);
}

function validateGame() {
	global $game;
	list($game['id'], $game['whoami']) = DB\SearchHash($game['auth']);
	if (! $game['id']) dieWithError();
	DB\GetGame();
}

function checkPost($args) {
	foreach ($args as $arg) if (! isset($_POST[$arg])) return false;
	return true;
}


// ##########################################################
// HTML Helper views
// ##########################################################


function formatPiece($type) {
	static $types = array(
		'K' => 12, 'Q' => 13, 'R' => 14, 'B' => 15, 'N' => 16, 'P' => 17,
		'k' => 18, 'q' => 19, 'r' => 20, 'b' => 21, 'n' => 22, 'p' => 23
	);
	return (isset($types[$type])) ? '&#98'.$types[$type].';' : '&nbsp;';
}

function formatBoard($board) {
	global $game;
	
	$colnames = array('&nbsp;','a','b','c','d','e','f','g','h','&nbsp;');
	if ($game['whoami'] == PLAYER_B) {
		$colnames = array_reverse($colnames);
		$bounds = array(7, -1, -1, 1);
	} else {
		$bounds = array(0,  8, 1,  0);		
	}
	
	$colnames = '<tr><td>'.implode('</td><td>',$colnames).'</td></tr>';
	
	$response = '<table id="board" class="board" cellpadding="0" cellspacing="0">';
	$response .= $colnames;
	for($i = $bounds[0]; $i != $bounds[1]; $i += $bounds[2]) {
		$response .= '<tr><td>'.(8 - $i).'</td>';
		for ($j = $bounds[0]; $j != $bounds[1]; $j += $bounds[2]) {
			$response .= '<td class="'.
				((($i + $j)%2 == $bounds[3]) ? 'bw' : 'bb').
				'">'.formatPiece($board[($i * 8)+$j]).'</td>'
			;
		}
		$response .= '<td>'.(8 - $i).'</td></tr>';
	}
	$response .= $colnames;
	$response .= '</table>';
	return $response;
}

function viewMessage() {
	if (! isset($_SESSION['info'])) return;
	echo
	'<div class="info" id="info">'.
		'<h2>'.$_SESSION['info'].'</h2>'.
		'<span class="closer">'.
			'<a href="javascript:;" onClick="hideInfo();">X</a>'.
		'</span>'.
	'</div>';
	unset($_SESSION['info']);
}

function viewMenu() {
	global $game;
	if ($game['whoami'] != PLAYER_S) {
		echo '<a href="?p=options&id='.$game['auth'].'">Options</a> | ';
		echo '<a href="?p=game&id='.$game['auth_spec'].'">Spectate</a> | ';			
	}
	if (strlen($game['auth'])) {		
		echo '<a href="rss.php?id='.$game['auth'].'">RSS</a> | ';
		echo '<a href="?p=game&id='.$game['auth'].'">Board</a> | ';
		echo '<a href="?p=home">Log out</a>';
	} else {
		echo '<a href="?p=home">Home</a>';
	}	
}

function viewFooter() {
	global $page_create_time;
	echo '<div class="footer">';
	echo '-- '.APP_NAME . ' :: Page generated in '.
		number_format((microtime() - $page_create_time)*1000, 1).
	'ms --';
	echo '</div>';
}

function viewHistory($count = HISTORY_COUNT) {
	global $game;
	
	// Load history
	$history = DB\GetHistory($game['id'], $count);
	
	foreach( $history as $hitem) {		
		if ($hitem['type'] == 1) {
			$h_content = 'Action: '.$hitem['val'];
			$h_player = ($hitem['key'] == PLAYER_W) ? PLAYER_B : PLAYER_W;
			if (strlen($hitem['val']) > 6) $h_player = PLAYER_W;
		} else {
			$h_content = nl2br(htmlspecialchars($hitem['val']));
			$h_player = $hitem['key'];
		}
		$h_author = ($h_player == PLAYER_W) ? $game['name1'] : $game['name2'];
		
?>
		<div class="hist_<?php echo $h_player; ?>">
			<?php echo $h_content; ?> 
			<br />
			<span class="hist_author">
				-- <?php echo htmlspecialchars($h_author).', '.date(S_DATEFMT, $hitem['time']); ?> 
			</span>
		</div>
<?php 
	}
}

// ##########################################################
// HTML main views
// ##########################################################


function viewHome() {
?>
	<h2>About:</h2>
	<p><?php echo S_ABOUT; ?></p>
	<p>
		<?php echo APP_NAME; ?> is currently hosting
		<?php echo DB\CountGames(); ?> game(s).
	</p>

	<h2>New game:</h2>
	<p>
		<form method="POST" action="?p=create" class="p_creategame">
			<input type="text" name="name1" title="White's name" />
			&nbsp;v&nbsp;
			<input type="text" name="name2" title="Black's name" />
			<input type="submit" value="Create &gt; &gt;" />			
		</form>
	</p>

<?php
}

function viewOptions() {
	global $game;
	
	switch ($game['whoami']) {
		case PLAYER_W: {
			$checked = ($game['doEmail1'] == 1) ? 'checked' : '';
			$email_str = $game['email1'];
		} break;
		case PLAYER_B: {
			$checked = ($game['doEmail2'] == 1) ? 'checked' : '';
			$email_str = $game['email2'];
		} break;
		default: return;
	}
	$email_str = htmlspecialchars($email_str);
?>
	<h2>Email notifications:</h2>
	<p>
		<form method="POST" action="?p=setoptions">
			<input type="hidden" name="auth" value="<?php echo $game['auth']; ?>" />
			<table>
				<tr>
					<td>Email Address:</td>
					<td><input type="email" name="email" title="Email address (optional)" value="<?php echo $email_str; ?>"/></td>
				</tr>
				<tr>
					<td>Enable notifications:</td>
					<td><input type="checkbox" name="doEmail" <?php echo $checked; ?> /></td>
				</tr>
				<tr>
					<td>&nbsp;</td>
					<td><input type="submit" value="Update &gt; &gt;" /></td>
				</tr>
			</table>
		</form>
	</p>
<?php
}

function viewGame() {
	global $game;
	
	// Format game title
	$player1 = htmlspecialchars($game['name1']);
	$player2 = htmlspecialchars($game['name2']);
	if (strlen($game['email1'])) {
		$player1 = '<a href="mailto:'.htmlspecialchars($game['email1']).'">'.$player1.'</a>';
	}
	if (strlen($game['email2'])) {
		$player2 = '<a href="mailto:'.htmlspecialchars($game['email2']).'">'.$player2.'</a>';
	}
	
	// Format authorisation
	$authtext = '';
	switch ($game['whoami']) {
		case PLAYER_W: $authtext = '(playing as white)'; break;
		case PLAYER_B: $authtext = '(playing as black)'; break;
		case PLAYER_S: $authtext = '(spectating)'; break;
	}
	
	// Move texts
	$col_to_move = ($game['turn'] == PLAYER_W) ? 'white' : 'black';
	$to_play = ($game['turn'] == PLAYER_W) ? $game['name1'] : $game['name2'];
	$formal_description = htmlspecialchars($to_play).'\'s turn to play '.$col_to_move.'.';
	
?>
	
	<h2>Game in Progress:</h2>
	<p>
		<?php echo $player1.' v '.$player2; ?><br/>
		<?php echo $authtext; ?> 
	</p>
	
	<h2>Board:</h2>
	<p>
		<?php echo formatBoard(explode('|', $game['board'])); ?> 
	</p>
	
	<h2>Move:</h2>
	<p>
<?php if ($game['turn'] == $game['whoami']) { ?> 
		<form method="POST" action="?p=move">
			<input type="hidden" name="auth" value="<?php echo $game['auth']; ?>" />
			<input type="text" maxlength=5 id="moveEntry" name="move"/>
			<input type="submit" value="Move &gt; &gt;" title="Your turn to play <?php echo $col_to_move; ?>" />
		</form>
<?php } else { ?>
		<?php echo $formal_description; ?> 
<?php } ?>
	</p>
	
<?php if ($game['whoami'] != PLAYER_S) { ?> 
	<h2>Chat:</h2>
	<p>		
		<form method="POST" action="?p=chat">
			<input type="hidden" name="auth" value="<?php echo $game['auth']; ?>" />
			<textarea name="message"></textarea>
			<br/>
			<input type="submit" value="Say &gt; &gt;" />
		</form>
	</p>
<?php } ?> 
	
	<h2>History: <a href="javascript:;" id="moreHistory">more</a></h2>
	<p>
		<div id="history">
<?php viewHistory(); ?>
		</div>
	</p>
<?php
}


// ##########################################################
// HTML Template
// ##########################################################


?>
<!DOCTYPE html>
<html>
	<head>
		<title><?php echo APP_NAME; ?></title>
	
		<link rel="shortcut icon" href="favicon.ico" />
		<link rel="stylesheet" type="text/css" href="style.css" />
<?php if (strlen($game['auth'])) { ?>
		<link rel="alternate" type="application/rss+xml" href="rss.php?id=<?php echo $game['auth']; ?>" />
		<script language="javascript">
var myAuth = "<?php echo $game['auth']; ?>";
var board_reverse = <?php echo ($game['whoami'] == PLAYER_B) ? 'true' : 'false'; ?>;
		</script>
<?php } ?>
		
		
		<script language="javascript" src="scripts.js"></script>
	</head>
	<body>
		<div class="content">
			<div class="menu">
				<div class="logo">&#9822;<?php echo APP_NAME; ?></div>
				<?php viewMenu(); ?> 
			</div>
		
			<?php viewMessage(); ?>
			
			<div class="padder">
<?php
switch ($current_mode) {
	case MODE_HOME: {
		viewHome();
	} break;
	case MODE_GAME: {
		viewGame();
	} break;
	case MODE_OPTIONS: {
		viewOptions();
	} break;
}
viewFooter();
?>
			</div>
		</div>
	</body>
</html>
