<?php

/**
 * La classe ErrorHandler définit les codes d'erreur, le traitement à leur apporter
 * et le message à présenter à l'utilisateur. Il effectue l'internationalisation
 * de ce dernier.
 */

 define ("SUCCESS",									   0);
 
 /** Erreurs annulant un login ou provoquant une déconnexion immédiate de l'utilisateur */
 define ("FATAL_UNKNOWN_ERROR",						1000);
 define ("FATAL_UNABLE_TO_CONNECT",					1001);
 define ("FATAL_UNKNOWN_USER",						1002);
 define ("FATAL_DUPLICATE_USER_ON_SIGNUP",			1003);
 define ("FATAL_INCORRECT_USER_DATABASE_CONTENTS",	1004);
 define ("FATAL_MISSING_USERNAME",					1005);
 define ("FATAL_MISSING_ADDRESS",					1006);
 define ("FATAL_MISSING_PASSWORD",					1007);
 define ("FATAL_PASSWORD_MISMATCH",					1008);
 define ("FATAL_USERNAME_TOO_SHORT",				1009);
 define ("FATAL_USERNAME_TOO_LONG",					1010);
 define ("FATAL_PASSWORD_TOO_SHORT",				1011);
 define ("FATAL_FORBIDDEN_CHARACTER",				1012);
 define ("FATAL_SIGNUP_ABORTED",					1013);
 define ("FATAL_LOGIN_FAILED",						1014);
 define ("FATAL_ACCOUNT_NOT_ACTIVATED",				1015); 
 define ("FATAL_ACCOUNT_LOCKED",					1016); 
 define ("FATAL_LOGIN_ABORTED",						1017);
 define ("FATAL_MISSING_TOKEN",						1018);
 define ("FATAL_DUPLICATE_USER_ON_LOGIN",			1019);
 define ("FATAL_SESSION_CHECK_FAILED",				1020);
 define ("FATAL_NOT_LOGGED",						1021);
 define ("FATAL_INVALID_EMAIL_ADDRESS",				1022);
 define ("FATAL_UNABLE_TO_INSERT_IN_CAREER",		1023);
 
 /** Erreurs empêchant une fonction / l'accès à une page mais conservant le login */
 define ("ERROR_UNKNOWN_ERROR",						2000);
 define ("ERROR_SIGNUP_DISABLED",					2001);
 define ("ERROR_RACE_MISMATCH",						2002);
// define ("ERROR_TIME_NOT_IMPROVED",					2003);
 define ("ERROR_INCORRECT_GHOST",					2004);
 define ("ERROR_RECORD_UPDATE_FAILED",				2005);
 define ("ERROR_INVALID_CAR",						2006);
 define ("ERROR_INVALID_LEVEL",						2007);
 define ("ERROR_LOCKED_ITEM",						2008);
 define ("ERROR_INVALID_MODE",						2009);
 define ("ERROR_GENERIC_DB_ERROR",					2010);
 define ("ERROR_GHOST_DUPLICATION",					2011);
 
 /** Avertissements sur l'exécution d'un traitement, mais non bloquants */
 define ("WARN_UNKNOWN_WARNING",					3000);
 define ("WARN_NO_OPERATION",						3001);
 define ("WARN_TIME_NOT_IMPROVED",					3002);
 
 /** Information sur l'exécution d'un traitement */
 define ("INFO_ALREADY_UNLOCKED",					4001);
 define ("INFO_NOT_LOGGED",							4002);
 define ("INFO_ACCOUNT_CREATED",					4003);
 
 
 class ErrorHandler
 {
	private $userErrorMessages = array (
		"FR" => array (
			FATAL_UNKNOWN_ERROR						=> "",
			FATAL_UNABLE_TO_CONNECT					=> "",
			FATAL_UNKNOWN_USER						=> "",
			FATAL_DUPLICATE_USER_ON_SIGNUP			=> "Impossible de créer un compte avec ce nom d'utilisateur. Veuillez réessayer avec un nom différent.",
			FATAL_INCORRECT_USER_DATABASE_CONTENTS	=> "",
			FATAL_MISSING_USERNAME					=> "Veuillez rentrer un nom d'utilisateur pour vous inscrire.",
			FATAL_MISSING_ADDRESS					=> "Veuillez rentrer une adresse mail valide.",
			FATAL_MISSING_PASSWORD					=> "Veuillez choisir un mot de passe valide.",
			FATAL_PASSWORD_MISMATCH					=> "Les deux champs du mot de passe diffèrent.",
			FATAL_USERNAME_TOO_SHORT				=> "Le nom d'utilisateur doit faire au minimum 3 caractères.",
			FATAL_USERNAME_TOO_LONG					=> "Le nom d'utilisateur doit faire au maximum 30 caractères.",
			FATAL_PASSWORD_TOO_SHORT				=> "Le mot de passe doit faire au minimum 6 caractères.",
			FATAL_FORBIDDEN_CHARACTER				=> "Le nom d'utilisateur ne peut pas contenir le caractère {0}",
			FATAL_SIGNUP_ABORTED					=> "Erreur à la création du compte. Les administrateurs ont été informés. Veuillez réessayer ultérieurement.",
			FATAL_LOGIN_FAILED						=> "Connexion refusée. L'identifiant utilisateur ou le mot de passe est incorrect.",
			FATAL_ACCOUNT_NOT_ACTIVATED				=> "Votre compte n'a pas encore été activé. Veuillez rentrer le code d'activation qui vous a été envoyé par mail.",
			FATAL_ACCOUNT_LOCKED					=> "Ce compte a été verrouillé par les administrateurs.",
			FATAL_LOGIN_ABORTED						=> "Accès à votre compte impossible pour le moment. Les administrateurs ont été notifiés du problème. Merci de réessayer ultérieurement.",
			FATAL_MISSING_TOKEN						=> "",
			FATAL_DUPLICATE_USER_ON_LOGIN			=> "Accès à votre compte impossible pour le moment. Les administrateurs ont été notifiés du problème. Merci de réessayer ultérieurement.",
			FATAL_SESSION_CHECK_FAILED				=> "",
			FATAL_NOT_LOGGED						=> "Vous devez vous identifier avant de jouer.",
			FATAL_INVALID_EMAIL_ADDRESS				=> "Veuillez rentrer une adresse mail valide.",
			FATAL_UNABLE_TO_INSERT_IN_CAREER		=> "",
			ERROR_SIGNUP_DISABLED					=> "Le site n'accepte plus de nouvelles inscriptions pour le moment. Veuillez réessayer ultérieurement.",
			ERROR_RACE_MISMATCH						=> "",
			ERROR_INCORRECT_GHOST					=> "",
			ERROR_RECORD_UPDATE_FAILED				=> "",
			ERROR_INVALID_CAR						=> "",
			ERROR_INVALID_LEVEL						=> "",
			ERROR_LOCKED_ITEM						=> "",
			ERROR_INVALID_MODE						=> "",
			ERROR_GENERIC_DB_ERROR					=> "",
			ERROR_GHOST_DUPLICATION					=> "",
			WARN_UNKNOWN_WARNING					=> "",
			WARN_NO_OPERATION						=> "",
			WARN_TIME_NOT_IMPROVED					=> "",
			INFO_ALREADY_UNLOCKED					=> "",
			INFO_NOT_LOGGED							=> "",
			INFO_ACCOUNT_CREATED					=> "Inscription effectée. Vous recevrez prochainement un lien pour activer votre compte."
		),
		"EN" => array () 
	);

	private $adminErrorMessages = array (
			FATAL_UNKNOWN_ERROR						=> "Erreur inconnue de niveau fatal",
			FATAL_UNABLE_TO_CONNECT					=> "Impossible d'obtenir une instance PDO qui se connecte à la base. Erreur DB : {0}",
			FATAL_UNKNOWN_USER						=> "Tentative de login avec l'utilisateur /{0}/ inconnu de la base.",
			FATAL_DUPLICATE_USER_ON_SIGNUP			=> "Tentative d'inscription sous le nom /{0}/ déja enregistré.",
			FATAL_INCORRECT_USER_DATABASE_CONTENTS	=> "Champ STATUS irrégulier pour l'utilisateur /{0}/",
			FATAL_MISSING_USERNAME					=> "Tentative d'inscription avec un nom d'utilisateur vide (Utilisation de Firebug ou équivalent).",
			FATAL_MISSING_ADDRESS					=> "Tentative d'inscription avec une adresse vide (Utilisation de Firebug ou équivalent).",
			FATAL_MISSING_PASSWORD					=> "Tentative d'inscription avec un mot de passe vide (Utilisation de Firebug ou équivalent).",
			FATAL_PASSWORD_MISMATCH					=> "Les deux champs du mot de passe diffèrent.",
			FATAL_USERNAME_TOO_SHORT				=> "Tentative d'inscription avec un nom d'utilisateur < 3 caractères.",
			FATAL_USERNAME_TOO_LONG					=> "Tentative d'inscription avec un nom d'utilisateur > 30 caractères.",
			FATAL_PASSWORD_TOO_SHORT				=> "Tentative d'inscription avec un mot de passe trop court (Utilisation de Firebug ou équivalent).",
			FATAL_FORBIDDEN_CHARACTER				=> "Tentative d'inscription avec un nom d'utilisateur non conforme : caractère /{0}/",
			FATAL_SIGNUP_ABORTED					=> "Erreur d'inscription qui devrait être plus détaillée. Pb dans le code pour avoir renvoyé cette valeur.",
			FATAL_LOGIN_FAILED						=> "Tentative de connexion avec un mot de passe incorrect pour le compte /{0}/.",
			FATAL_ACCOUNT_NOT_ACTIVATED				=> "Tentative de connexion sur le compte /{0}/ qui n'a pas été activé.",
			FATAL_ACCOUNT_LOCKED					=> "Tentative de connexion sur le compte /{0}/ verrouillé.",
			FATAL_LOGIN_ABORTED						=> "Erreur de login qui devrait être plus détaillée. Pb dans le code pour avoir renvoyé cette valeur.",
			FATAL_MISSING_TOKEN						=> "Utilisation d'un formulaire du site depuis une source externe.",
			FATAL_DUPLICATE_USER_ON_LOGIN			=> "Utilisateur /{0}/ présent deux fois (ou plus) dans la base.",
			FATAL_SESSION_CHECK_FAILED				=> "Echec de la validation de session, code fourni : /{0}/",
			FATAL_NOT_LOGGED						=> "Tentative d'accès à un circuit ou envoi de ghost sans être logué.",
			FATAL_INVALID_EMAIL_ADDRESS				=> "Tentative d'inscription avec une adresse non conforme.",
			FATAL_UNABLE_TO_INSERT_IN_CAREER		=> "Impossible d'ajouter l'utilisateur dans la table career.",
			ERROR_UNKNOWN_ERROR						=> "Erreur de nature non précisée",
			ERROR_SIGNUP_DISABLED					=> "Tentative d'inscription, alors que celles-ci sont verrouillées.",
			ERROR_RACE_MISMATCH						=> "Record envoyé sur un autre mode/circuit que ceux initialement demandés. (HACK JS).",
			ERROR_INCORRECT_GHOST					=> "Télémétrie renvoyée non-conforme : {0}.",
			ERROR_RECORD_UPDATE_FAILED				=> "Echec de la mise à jour du record",
			ERROR_INVALID_CAR						=> "Voiture inconnue : /{0}/",
			ERROR_INVALID_LEVEL						=> "Circuit inconnu : /{0}/",
			ERROR_LOCKED_ITEM						=> "Demande de circuit/mode/voiture non débloqué par le joueur (HACK JS).",
			ERROR_INVALID_MODE						=> "Mode inconnu : /{0}/",
			ERROR_GENERIC_DB_ERROR					=> "Erreur renvoyée par la BDD : /{0}/",
			ERROR_GHOST_DUPLICATION					=> "Télémétrie envoyée identique à celle du joueur /{0}/ (HACK JS)",
			WARN_UNKNOWN_WARNING					=> "Avertissement de nature non précisée",
			WARN_NO_OPERATION						=> "Opération sans effet : /{0}/",
			WARN_TIME_NOT_IMPROVED					=> "Record envoyé sans amélioration du temps.",
			INFO_ALREADY_UNLOCKED					=> "Voiture, circuit ou mode déja déverrouillé",
			INFO_NOT_LOGGED							=> "Session anonyme",
			INFO_ACCOUNT_CREATED					=> "Compte créé"
	);

	
	private static $instance = null;
	
	private $errorParameters = null;
	
	/**
	 * Renvoie l'instance du singleton
	 */
	public static function getInstance()
	{
		if (self::$instance == null) {
			self::$instance = new ErrorHandler();
		}
		return self::$instance;
	}
	
	
	/**
	 * Renvoie le message d'erreur correspondant au code fourni, dans la langue demandée.
	 */
	function getErrorMessage($errorCode, $language)
	{
		$prefix = "";
		if (! array_key_exists($language, $this->userErrorMessages)) {
			$prefix = "Unknown language ".preg_replace('/[^\w]/', '_', $language).", reverting to english. ";
			$language = "EN";
		}
		if (! array_key_exists($errorCode, $this->userErrorMessages[$language])) {
			$errorCode = ERROR_UNKNOWN_ERROR;
		}
		$message = $prefix.$this->userErrorMessages[$language][$errorCode];
		$paramCount = count($this->errorParameters);
		for ($index=0; $index<$paramCount; ++$index)
		{
			$searchPattern = '/\{'.$index.'\}/';
			$message = preg_replace($searchPattern, $this->errorParameters[$index], $message);
		}
		// Le message utilisateur est destiné à être affiché via le navigateur
		return htmlentities($message);
	}
	
	/**
	 * Renvoie le message d'erreur administrateur (i.e. non visible du joueur) correspondant au code fourni
	 * Il n'y a pas d'internationalisation sur le message admin
	 */
	function getAdminErrorMessage($errorCode)
	{
		if (! array_key_exists($errorCode, $this->adminErrorMessages)) {
			$errorCode = ERROR_UNKNOWN_ERROR;
		}
		$message = $this->adminErrorMessages[$errorCode];
		$paramCount = count($this->errorParameters);
		for ($index=0; $index<$paramCount; ++$index)
		{
			$searchPattern = '/\{'.$index.'\}/';
			$message = preg_replace($searchPattern, $this->errorParameters[$index], $message);
		}
		// On ne transforme pas le message admin via htmlentities(), il doit être stocké en base, pas affiché
		return $message;
	}
	
	/**
	 * Définit les paramètres de l'erreur en cours, pour remplacement dans la
	 * chaîne de caractères
	 */
	function setParameters($value)
	{
		$this->errorParameters = array( $value );
	}
	
 }
 
?>