<?php
class Database {
	private $_handler;
 	public function __construct($host = "localhost", $username = "root", $password = "0308Martinez", $database = "ptut")
    {
    	//Connexion à la BDD
 		Try {
			$this->_handler = new PDO('mysql:host=' . $host . ';dbname=' . $database, $username, $password);
 			$this->_handler->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
 		}
 		Catch (Exception $e) {
			throw new Exception('Database connection error :' . $e->getMessage());
 		}
 	}
	
	//
    /**
     * Prepare et execute une requête de type SELECT et renvoie le résultat sous forme de tableau associatif
     * 
     * Affiche un message d'erreur en cas d'échec
     *
     * @param Chaine $sql Requête SQL formattée pour être préparée et exécutée
     * 
     * @param multitype $args Liste d'arguments utilisés pour exécuter la requête SQL
     *
     * @return Tableau associatif contenant le résultat de la requête
     */
 	private function query($sql, ...$args)
    {
		$request = $this->_handler->prepare($sql);
 		if($request ==! false) {
 			if($request->execute($args))
			{
 				$resultArray = $request->fetchAll(PDO::FETCH_ASSOC);
 				$request->closeCursor();
 				return $resultArray;
			}
			else {
				//Requête échouée
                echo 'Request failed :' . $sql;
 				return null;
			}
 		} else {
			//Requête fausse
            echo 'Wrong request :' . $sql;
 			return null;
 		}
 	}
    
    //
    /**
     * Prepare et execute une requête de type UPDATE, DELETE ou INSERT et renvoie vrai en cas de succès et faux en cas d'échec
     * 
     * Affiche un message d'erreur en cas d'échec
     *
     * @param Chaine $sql Requête SQL formattée pour être préparée et exécutée
     * 
     * @param multitype $args Liste d'arguments utilisés pour exécuter la requête SQL
     *
     * @return Booleen Vrai en cas de succès et Faux en cas d'échec
     */
 	private function execute($sql, ...$args)
 	{
 		$request = $this->_handler->prepare($sql);
 		if($request ==! false) {
 			if($request->execute($args))
			{
 				return true;
			}
			else {
				//Requête échouée
				echo 'Request failed :' . $sql;
 				return false;
			}
 		} else {
			//Requête fausse
            echo 'Wrong request :' . $sql;
 			return false;
 		}
 	}
    
    /**
     * Insert les données reçues retourne vrai en cas de succès et faux en cas d'échec
     *
     * @param Chaine $service URL du service qui a envoyé les données
     *
     * @param Tableau de chaines $values Tableau contenant les valeurs reçues
     * 
     * @param Entier $timestamp Date et heure à laquelle la Raspberry Pi a collectée les informations
     *
     * @return Booleen Vrai en cas de succès et Faux en cas d'échec
     */
    public function insertData($service, $values, $timestamp)
    {
        $success = true;
        //Démarrage de la transaction
        $this->_handler->beginTransaction();
        //Insertion des du service et de la date
        $success = $success && $this->execute('INSERT INTO data (service, date) VALUES (?, FROM_UNIXTIME(?))', $service, $timestamp);
        //Récupération du dernier id inséré
        $dataId = $this->_handler->lastInsertId();
        foreach($values as $value)
        {
            //Insertion des valeurs
            $success = $success && $this->execute('INSERT INTO dataValues (dataId, value) VALUES (?, ?)', $dataId, $value);
        }
        if($success)
        {
            //Aucune erreur -> commit
            $this->_handler->commit();
        }
        else
        {
            //Au moins une erreur -> rollBack
            $this->_handler->rollBack();
        }
        return $success;
    }
    
    /**
     * Récupère les données de tous les services et les retourne sous forme de tableau associatif
     *
     * @return Tableau associatif contenant toutes les données reçues par la Raspberry Pi
     */
    public function getAllServices()
    {
        return $this->query('SELECT d.id, UNIX_TIMESTAMP(d.date) timestamp, d.service, dv.value 
        					 FROM data d 
        					 INNER JOIN dataValues dv ON dv.dataId = d.id ORDER BY timestamp DESC');
    }
	
}