<?php
	session_start();
	require_once('../../private/depot_element.inc.php');
	require_once('../../private/qetcustomelement.inc.php');
	include_once('../../private/connexion_db.inc.php');
	
	// exprime la taille maximum des fichiers uploades en Ko
	$max_upload_size = floor(ElementsRepositoryConfiguration::ElementMaxSize / 1024.0);
	
	// texte pour le nombre d'elements possible
	if (ElementsRepositoryConfiguration::UploadMaxFile > 1) {
		$element_files_text = sprintf('%u', ElementsRepositoryConfiguration::UploadMaxFile);
	} else {
		$element_files_text = 'Fichier *.elmt&nbsp;:';
	}
	
	/**
		Verifie differents points du formulaire
		@return le nombre de fichiers uploades
		@throws Exception En cas de probleme, une exception avec une description exploitable est levee
	*/
	function checkForm() {
		// on verifie que la base de donnees est accessible
		global $qet_mysql_ok;
		if (!$qet_mysql_ok) {
			throw new Exception('la base de donn&eacute;es n\'est pas accessible');
		}
		
		// on verifie la presence d'un pseudo
		if (isEmpty(@$_POST['upload_pseudo'])) {
			throw new Exception('vous devez sp&eacute;cifier un pseudonyme, un nom et/ou un pr&eacute;nom');
		}
		
		// on verifie la presence d'une adresse email valide
		if (isEmpty(@$_POST['upload_email'])) {
			throw new Exception('vous devez sp&eacute;cifier une adresse email');
		}
		
		if (!checkEmailAddress(trim($_POST['upload_email']))) {
			throw new Exception('vous devez sp&eacute;cifier une adresse email valide');
		}
		
		// on verifie la presence d'au moins un fichier uploade
		if (!isset($_FILES['element'])) {
			throw new Exception('fichier non upload&eacute;');
		}
		
		// on determine le nombre de fichiers uploades
		$uploaded_files_count = 0;
		for ($i = 0 ; $i < count($_FILES['element']['name']) ; ++ $i) {
			if ($_FILES['element']['name'][$i] == '') break;
			++ $uploaded_files_count;
		}
		
		// on verifie que le nombre de fichiers uploades est autorise
		if ($uploaded_files_count > ElementsRepositoryConfiguration::UploadMaxFile) {
			throw new Exception('l\'upload est limite a '.ElementsRepositoryConfiguration::UploadMaxFile.' fichiers');
		}
		
		// on verifie les fichiers uploades
		for ($i = 0 ; $i < $uploaded_files_count ; ++ $i) {
			
			// on verifie que le fichier a bien ete uploade
			if ($_FILES['element']['error'][$i] != 0) {
				throw new Exception('l\'upload de l\'un des fichiers a echoue');
			}
			
			// on verifie la taille du fichier
			if ($_FILES['element']['size'][$i] > ElementsRepositoryConfiguration::ElementMaxSize) {
				throw new Exception('un des fichiers exc&egrave;de la taille maximale autoris&eacute;e ('.$max_upload_size.' Ko)');
			}
			
			// on exige que le fichier soit en *.elmt
			if (!preg_match('/[0-9a-z-_]+\.elmt$/', $_FILES['element']['name'][$i])) {
				throw new Exception('chaque fichier doit avoir un nom en *.elmt sans espace ni caract&egrave;re accentu&eacute; ni majuscule');
			}
		}
		
		return($uploaded_files_count);
	}
	
	/**
		Verifie qu'un fichier est un element.
		@param $element_path Chemin du fichier a valider
		@throws Exception En cas de probleme, une exception est levee
	*/
	function checkElement($element_path) {
		try {
			$element = new QETCustomElement($element_path);
		} catch(Exception $e) {
			throw new Exception('l\'&eacute;l&eacute;ment envoy&eacute; est invalide');
		}
	}
	
	/**
		Deplace un element
		@param $source_path Chemin source
		@param $target_path Chemin cible
		@throws Exception En cas de probleme, une exception avec une description exploitable est levee
	*/
	function moveUploadedElement($source_path, $target_path) {
		// empecher l'ecrasement d'un fichier existant evite tout vandalisme
		if (file_exists($target_path)) {
			throw new Exception('le fichier existe d&eacute;j&agrave; - veuillez choisir un autre nom de fichier');
		}
		
		// deplacement lui-meme
		$move_file = @move_uploaded_file($source_path, $target_path);
		if (!$move_file) {
			throw new Exception('erreur lors du d&eacute;placement du fichier temporaire (impossible de deplacer le fichier)');
		}
		
		$chmod_file = @chmod($target_path, ElementsRepositoryConfiguration::RepositoryPermissions);
		if (!$chmod_file) {
			throw new Exception('erreur lors du d&eacute;placement du fichier temporaire (impossible de changer les droits du fichier)');
		}
	}
	
	/**
		Enregistre un upload dans la base de donnees
		@param $pseudo  Pseudonyme de la personne uploadant les elements
		@param $email   Adresse email de la personne uploadant les elements
		@param $comment Commentaire rattache a l'upload
		@return l'id de l'upload enregistre dans la base de donnees
		@throws Exception En cas de probleme, une exception est levee
	*/
	function registerUploadedData($pseudo, $email, $comment) {
		// chaine d'erreur commune
		$error_string = 'probl&egrave;me lors de l\'insertion des donn&eacute;es compl&eacute;mentaires dans la base - le fichier a tout de m&ecirc;me &eacute;t&eacute; upload&eacute;';
		
		// insertion de l'upload dans la base
		$upload_query = sprintf(
			'INSERT INTO `elements_upload` (`pseudo`, `email`, `commentaire`) VALUES (\'%s\', \'%s\', \'%s\');',
			mysql_real_escape_string($pseudo ),
			mysql_real_escape_string($email  ),
			mysql_real_escape_string($comment)
		);
		$upload_result = mysql_query($upload_query);
		if (!$upload_result) {
			throw new Exception($error_string.' (1)');
		}
		
		// recupere et retourne l'id de l'upload ainsi enregistre
		$upload_row_id = mysql_insert_id();
		if (!$upload_row_id) {
			throw new Exception($error_string.' (2)');
		}
		return($upload_row_id);
	}
	
	/**
		@param $elements_array   Tableau contenant les chemin relatifs des elements ajoutes au depot
		@param $upload_id        Id de l'upload auquel est rattache cet element
		@throws Exception En cas de probleme, une exception avec une description exploitable est levee
	*/
	function registerUploadedFiles($elements_array, $upload_id) {
		$file_query = 'INSERT INTO `elements_files` (`file`, `upload_id`) VALUES ';
		foreach($elements_array as $ind => $element_rel_path) {
			$file_query .= sprintf('(\'%s\', %u)', mysql_real_escape_string($element_rel_path), $upload_id);
			if ($ind < count($elements_array) - 1) $file_query .= ', ';
		}
		
		$file_insertion = mysql_query($file_query);
		if (!$file_insertion) {
			throw new Exception('probl&egrave;me lors de l\'insertion d\'un fichier dans la base - le fichier a tout de m&ecirc;me &eacute;t&eacute; upload&eacute;');
		}
	}
	
	/**
		Memorise en session l'id d'un upload que l'utilisateur courant peut encore annuler
		@param $upload_id Id d'un upload
	*/
	function addUploadIdToSession($upload_id) {
		if (!isset($_SESSION['upload_ids'])) $_SESSION['upload_ids'] = array();
		$_SESSION['upload_ids'][] = $upload_id;
	}
	
	/**
		Memorise en session l'id d'un upload que l'utilisateur courant peut encore annuler
		@param $upload_id Id d'un upload
	*/
	function removeUploadIdFromSession($upload_id) {
		if (!isset($_SESSION['upload_ids'])) return;
		$ind_upload = array_search($upload_id, $_SESSION['upload_ids']);
		unset($_SESSION['upload_ids'][$ind_upload]);
		
		// ferme eventuellement la session
		if (empty($_SESSION['upload_ids'])) {
			$_SESSION = array();
			session_destroy();
		}
	}
	
	/**
		Verifie que l'utilisateur courant peut encore annuler l'upload dont l'id est passe en parametre
		@param $upload_id Id d'un upload
		@return l'id de l'upload
		@throws Exception En cas de probleme, une exception avec une description exploitable est levee
	*/
	function checkSubmittedUploadId($upload_id) {
		// si le fichier dont l'utilisateur confirme ou non le depot ne lui appartient pas, on leve une exception
		$ind_upload = array_search($upload_id, $_SESSION['upload_ids']);
		if ($ind_upload === false) {
			throw new Exception('cet &eacute;l&eacute;ment ne vous appartient pas');
		}
		return($upload_id);
	}
	
	/**
		Rapatrie les donnees relatives a un upload
		@param $upload_id Id d'un upload
		@return un tableau associatif contenant les donnees rapatriees
		@throws Exception En cas de probleme, une exception avec une description exploitable est levee
	*/
	function fetchUploadData($upload_id) {
		$metadata_query = sprintf(
			'SELECT id, date, pseudo, email, commentaire '.
			'FROM `elements_upload` '.
			'WHERE id = %u;',
			$upload_id
		);
		
		$files_query = sprintf(
			'SELECT file FROM `elements_files` WHERE upload_id = %u;',
			$upload_id
		);
		
		$metadata_result = mysql_query($metadata_query);
		if (!$metadata_result || !mysql_num_rows($metadata_result)) {
			throw new Exception('erreur lors de la lecture des donnees de l\'upload');
		}
		$result = mysql_fetch_assoc($metadata_result);
		
		$files_result = mysql_query($files_query);
		if (!$files_result) {
			throw new Exception('erreur lors de la lecture des fichiers de l\'upload');
		}
		for ($i = 1 ; $file_row = mysql_fetch_assoc($files_result) ; ++ $i) {
			$result['file'.$i] = $file_row['file'];
		}
		
		return($result);
	}
	
	/**
		Genere le corps du mail relatant un nouvel upload
		@param $data tableau associatif contenant les donnees relatives a l'upload
	*/
	function generateUploadMailBody($data) {
		$email_body = sprintf(
			"Date : %s\n".
			"Auteur : %s <%s>\n".
			"Commentaire : %s\n\n".
			"Fichiers envoyes :\n",
			$data['date'],
			$data['pseudo'],
			$data['email'],
			$data['commentaire']
		);
		for ($i = 1 ; isset($data['file'.$i]) ; ++ $i) {
			$email_body .= sprintf("  * %s\n", $data['file'.$i]);
		}
		return($email_body);
	}
	
	/**
		Supprime les fichiers rattaches a un upload
		@param $upload_id Id de l'upload dont il faut supprimer les fichier
		@return le nombre de fichiers supprimes
		@throws Exception En cas de probleme, une exception avec une description exploitable est levee
	*/
	function deleteUploadFiles($upload_id) {
		// on recupere les informations de l'upload a supprimer
		$data = fetchUploadData($upload_id);
		
		$unlink_failures = 0;
		$unlink_ok = 0;
		for ($i = 1 ; isset($data['file'.$i]) ; ++ $i) {
			$element_abs_path = concatPaths(ElementsRepositoryConfiguration::RepositoryContentRoot, $data['file'.$i]);
			if (@unlink($element_abs_path)) {
				++ $unlink_ok;
			} else {
				++ $unlink_failures;
			}
		}
		
		if ($unlink_failures) {
			throw new Exception(sprintf('la suppression %s a &eacute;chou&eacute;', $unlink_failures > 1 ? 'de '.$unlink_failures.' fichiers' : 'd\'un fichier'));
		}
		return($unlink_ok);
	}
	
	/**
		Supprime un upload en base
		@param $upload_id Id de l'upload dont il faut supprimer les fichier
		@throws Exception En cas de probleme, une exception avec une description exploitable est levee
	*/
	function deleteUpload($upload_id) {
		$delete_upload_query = sprintf('DELETE FROM elements_upload WHERE id = %u;', $upload_id);
		if (!mysql_query($delete_upload_query)) {
			throw new Exception('la suppression des donn&eacute;es compl&eacute;mentaires a &eacute;chou&eacute;');
		}
	}
	
	/* TRAITEMENT */
	$form = true;
	$error = '';
	try {
		// le formulaire est envoye
		if (isset($_POST['submit'])) {
			
			// premier envoi
			if ($_POST['submit'] == 'Envoyer') {
				// verification du formulaire soumis
				$uploaded_files_count = checkForm();
				
				// a ce stade, l'upload est techniquement reussi
				// on tente maintenant d'instancier un objet QETCustomElement a partir du fichier recu
				for ($i = 0 ; $i < $uploaded_files_count ; ++ $i) {
					checkElement($_FILES['element']['tmp_name'][$i]);
				}
				
				// a ce stade, les fichiers uploades sont bien des elements - on les deplace en categorie "moderation"
				$elements_rel_paths = array();
				$elements_abs_paths = array();
				for ($i = 0 ; $i < $uploaded_files_count ; ++ $i) {
					$element_rel_path = $elements_rel_paths[] = concatPaths(ElementsRepositoryConfiguration::RepositoryUploadCategory, $_FILES['element']['name'][$i]);
					$element_abs_path = $elements_abs_paths[] = concatPaths(ElementsRepositoryConfiguration::RepositoryContentRoot,    $element_rel_path);
					moveUploadedElement($_FILES['element']['tmp_name'][$i], $element_abs_path);
				}
				
				// enregistre les donnees complementaires dans la base de donnees
				$upload_id = registerUploadedData($_POST['upload_pseudo'], $_POST['upload_email'], $_POST['upload_comment']);
				registerUploadedFiles($elements_rel_paths, $upload_id);
				
				// memorise en session le fait que cet utilisateur peut encore supprimer cet upload
				addUploadIdToSession($upload_id);
				
				// pour afficher les elements fraichement uploades
				$show_elements = $elements_abs_paths;
				$preview = true;
				$form = false;
			} else if ($_POST['submit'] == 'Oui' || $_POST['submit'] == 'Non') {
				// 2eme envoi : confirme ou non l'upload
				$upload_asked = checkSubmittedUploadId($_POST['upload_id']);
				
				// si l'utilisateur confirme, ...
				if ($_POST['submit'] == 'Oui') {
					// il faut potentiellement signaler l'upload par mail
					if (ElementsRepositoryConfiguration::MailAfterUpload) {
						$data = fetchUploadData($upload_asked);
						mail(
							ElementsRepositoryConfiguration::UploadEmail,
							'Soumission d\'element sur le depot',
							generateUploadMailBody($data),
							'Reply-To: '.ElementsRepositoryConfiguration::UploadEmail
						);
						
					}
					
					// rediriger sur le formulaire de remerciement
					$form = false;
					$preview = false;
					$thanks = true;
				} else {
					$form = false;
					$preview = true;
					$thanks = false;
					$abort = false;
					
					// l'utilisateur veut annuler son upload : on supprime les fichiers...
					deleteUploadFiles($upload_asked);
					
					// puis les donnees complementaires en base
					deleteUpload($upload_asked);
					
					// enleve la permission pour cet utilisateur de revoquer ce fichier
					removeUploadIdFromSession($upload_asked);
					
					$preview = false;
					$abort = true;
				}
			}
		}
	} catch(Exception $e) {
		$error = $e -> getMessage();
	}
	
	// formulaire de 
	if (@$preview) {
		echo "\t\t\t".'<p>Voici les &eacute;l&eacute;ments que vous avez d&eacute;pos&eacute;s : </p>'."\n";
		foreach ($show_elements as $show_element) {
			include('private/showelement.inc.php');
		}
?>
			<div class="news_top">
				Soumettre des &eacute;l&eacute;ments : confirmation
			</div>
			<div class="news_middle">
				<form action="<?=$_SERVER['PHP_SELF']?>" method="post" enctype="multipart/form-data">
					Si vos &eacute;l&eacute;ments ne vous satisfont pas, vous pouvez encore annuler leur d&eacute;p&ocirc;t.
					Voulez-vous vraiment soumettre ces &eacute;l&eacute;ments ?
					<br />
					<div style="text-align:center;">
						<input type="submit" name="submit" value="Oui" />
						<input type="submit" name="submit" value="Non" />
					</div>
					<input type="hidden" name="upload_id" value="<?=$upload_id?>" />
				</form>
			</div>
<?php
	}
	if (@$form) {
?>
				<form action="<?=$_SERVER['PHP_SELF']?>" method="post" enctype="multipart/form-data">
					Your name:<br />
					<input style="width:100%;margin-bottom:10px;border:1px solid;border-color:#999999;background-color:white;" type="text" name="upload_pseudo" value="<?=@$_POST['upload_pseudo']?>" /><br />
					Your e-mail address:<br />
					<input style="width:100%;margin-bottom:10px;border:1px solid;border-color:#999999;background-color:white;" type="text" name="upload_email" value="<?=@$_POST['upload_email']?>" /><br />
					Comment/message (optional):<br />
					<textarea rows="5" type="text" name="upload_comment" style="width:100%;max-width:100%" /><?=@$_POST['upload_comment']?></textarea><br />

					<p>Select the elements you want to upload (the size of each file is limited to <?=$max_upload_size?> KB).<br />
                       If you want to upload more than <?=$element_files_text?> files, fill the form again.</p>
					<ol style="padding-left:30px;">
<?php
	for ($i = 1 ; $i <= ElementsRepositoryConfiguration::UploadMaxFile ; ++ $i) {
?>
						<li><input type="file" name="element[]" style="border:none" /></li>
<?php
	}
?>
					</ol>
					<div class="w3-center"><input type="submit" name="submit" value="Send your contribution" class="w3-card-2 w3-btn w3-large qet-white qet-hover-dark-gray"/></div>
				</form>
<?php
	}
	if (@$thanks) {
?>
			<div class="news_top">
				Merci pour votre contribution
			</div>
			<div class="news_middle">
				<p>
					L'&eacute;quipe de QElectroTech vous remercie pour votre contribution.
				</p>
				<ul>
					<li><a href="showcategory.php?cat=<?=ElementsRepositoryConfiguration::RepositoryUploadCategory?>">Voir la cat&eacute;gorie Mod&eacute;ration</a></li>
					<li><a href="showcategory.php">Retour au d&eacute;p&ocirc;t d'&eacute;l&eacute;ments</a></li>
				</ul>
			</div>
<?php
	}
	if (@$abort) {
?>
			<div class="news_top">
				Annulation du d&eacute;p&ocirc;t
			</div>
			<div class="news_middle">
				<p>
					Votre d&eacute;p&ocirc;t a bien &eacute;t&eacute; annul&eacute;.
				</p>
			</div>
<?php
	}
	
	// Affichage des erreurs
	if (trim(@$error) != '') {
?>
			<div class="news_bottom" style="color:red;">
				Erreur&nbsp;: <?=ucfirst($error).".\n";?>
			</div>
<?php
	}

?>
