(** Projet Puzzle @author Lilian Besson <lilian.bessonATens-cachan.fr> *)


open Sys;;

(** Pour gérer le code de retour d'un processus Unix lancé par la commande "Sys.command" en ocaml. Ce n'est pas très très propre de faire comme ca, mais ca marche bien. *)

exception Error_Annule of int;;

(** Un peu de scripting en Ocaml. La fonction suivante execute la commande Unix contenue dans la chaine argument, en renvoyant une exception si la commande ne s'execute pas comme il faut (code d'erreur de retour unix non nul). *)

let faire0 cmd =
        match (Sys.command cmd) with
        | 0                        -> ();
        | n when (n <> 0)         -> raise (Error_Annule(n));;

(** Pour attendre. Lourd car consomme 100% CPU juste pour .... attendre ! *)

let wait_lourd s = 
   let tmps_init = Sys.time() in
   while (( (Sys.time ()) -. tmps_init) < s) do
    ();
   done;;

(** Plus intelligent. Utilise sleep ! Mais ne marche pas. *)

let wait s =
        faire0 ("sleep "^(string_of_float s));;

(** Représente un temps. *)

type temps = {
        heure        : int;
        minute        : int;
        seconde        : int;
        milisec        : int;
                };;

(** Convertit un nombre de secondes en temps. *)

let convertir_temps s =
        let si = ref (1000. *. s) in
        let heu = floor (!si /. 3600000.) in
        si := !si -. (3600000. *. heu);
        let min = floor (!si /. 60000.) in
        si := !si -. (60000. *. min);
        let sec = floor (!si /. 1000.) in
        si := !si -. (1000. *. sec);
        let msec = floor (!si) in
        { heure = int_of_float heu; minute = int_of_float min; seconde = int_of_float sec; milisec = int_of_float msec};;

(** Affiche un 'temps'. *)

let string_of_temps tmp =
        match (tmp.heure, tmp.minute, tmp.seconde) with
        | 0,0,0 -> ((string_of_int tmp.milisec)^"ms")
        | 0,0,_ -> ((string_of_int tmp.seconde)^"s:"^(string_of_int tmp.milisec)^"ms")
        | 0,_,_ -> ((string_of_int tmp.minute)^"m:"^(string_of_int tmp.seconde)^"s:"^(string_of_int tmp.milisec)^"ms")
        | _,_,_ -> ((string_of_int tmp.heure)^"H:"^(string_of_int tmp.minute)^"m:"^(string_of_int tmp.seconde)^"s:"^(string_of_int tmp.milisec)^"ms")
        
(** Donne une chaine représentant le temps courant. *)

let string_time () =
        string_of_temps (convertir_temps (time ()));;

(** Mixte. *)

type temps_full = {
        tmp : temps;
        se  : float};;

(** Référence globale pour le début du chronomètre . *)

let temps_debut_chrono = ref { tmp={heure = 0; minute = 0; seconde = 0; milisec = 0}; se=0.};;

(** Idem, pour savoir si un chrono est en cours. *)

let chronometre_est_actif = ref false;;

(** Lance le chrono. *)

let lancer_chrono () =
        chronometre_est_actif := true;
        temps_debut_chrono := { tmp=convertir_temps (time ()); se=(time ())};;

(** Si on demande le temps du chronomètre sans qu'il soit actif !*)

exception Chronometre_non_actif;;

(** Récupère une chaine donnant le temps écoulé depuis le dernier appel à lancer_chrono. *)

let temps_chrono () =
        (if not(!chronometre_est_actif) then raise Chronometre_non_actif);
        string_of_temps (convertir_temps ((time ()) -. !temps_debut_chrono.se ) );;

(** Stope le chrono. *)

let stopper_chrono () =
        chronometre_est_actif := false;
        temps_debut_chrono := { tmp={heure = 0; minute = 0; seconde = 0; milisec = 0}; se=0.};;