(* Initialisations diverses *)

let mac = true ;;

let nom_du_journal = 
 if mac then "disque_dur:TeX:OptionInfo:TP-Spé:Accès:journal.txt" 
        else "c:\util\journal.txt" ;;

let utilisateurs = ["anne";"bernard";"bertrand";"bruno";"christian";"claire"; 
 "jean-marc";"johann";"michel";"noelle";"tadiou"] ;;

let date_initiale = 0 ;;

let nb_transactions = 1000 ;;

(* Déclarations de types *)

type obj = Connexion | Deconnexion ;;

type date = {jour : int ; mois : int ; annee : int ; heure : int ; minutes : int ; secondes : int } ;;

type transaction = {instant:date ; objet : obj ; demandeur : string } ;;

(* Convertisseur int -> date *)

let date_of_int d = 
 let se = d mod 60 and d = d/60 in 
 let mi = d mod 60 and d = d/60 in 
 let he = d mod 24 and d = d/24 in 
 let jo = d mod 30 and d = d/30 in 
 let mo = d mod 12 and d = d/12 in 
 {jour = jo+1 ; mois = mo+1 ; annee = d+2000; heure = he ; minutes = mi ; secondes = se} ;;

(* Fonctions de conversion en chaînes de caractères *)

let eol = if mac then "\013" else "\013\010" ;;

let string_of_obj = function 
 | Connexion -> "Connexion" 
 | Deconnexion -> "Deconnexion" 
;;

let string_of_date d = 
 "{ jour = " ^ (string_of_int d.jour) ^ " ; " 
 ^ "mois = " ^ (string_of_int d.mois) ^ " ; " 
 ^ "annee = " ^ (string_of_int d.annee) ^ " ; " 
 ^ "heure = " ^ (string_of_int d.heure) ^ " ; " 
 ^ "minutes = " ^ (string_of_int d.minutes) ^ " ; " 
 ^ "secondes = " ^ (string_of_int d.secondes) ^ " }" 
;;

let string_of_transaction t = 
 "{instant = " ^ string_of_date(t.instant) ^ " ; " ^ eol 
 ^ " objet = " ^ (string_of_obj t.objet) ^ " ; " 
 ^ " demandeur = " ^ "\"" ^ t.demandeur ^ "\"} ; " ^ eol 
;;

(* Petits outils *)

let rec nth_of_list n = function 
 | [] -> failwith "n trop grand" 
 | t::q when n=0 -> (t,q) 
 | t::q -> let (x,q') = nth_of_list (n-1) q in (x,t::q') 
;;

let choisit l = 
 let n = random__int (list_length l) in 
  nth_of_list n l 
;;

let rec itere f n x = 
 if n = 0 then x else itere f (n-1) (f x) 
;;

(* La fonction de mise à jour *)

let action (bran,debr,d,j) = 
 let delai = 10 + random__int 20 in 
 let d' = d + delai in 
 match random__int 4 with 
  | 0 when debr <> [] -> let (t,debr') = choisit debr in 
     let bran' = t::bran in 
     let tr = {instant = date_of_int(d'); objet = Connexion ; demandeur = t} in 
     (bran',debr',d',tr::j)
  | 1 when bran <> [] -> let (t,bran') = choisit bran in 
     let debr' = t::debr in 
     let tr = {instant = date_of_int(d'); objet = Deconnexion ; demandeur = t} in 
     (bran',debr',d',tr::j)
  | _ -> (bran,debr,d',j) ;;

let fabrique_journal liste_ut date_ini nb_trans = 
 let (_,_,_,j) = itere action nb_trans (liste_ut,[],date_ini,[]) in rev j ;;

let rec écrire_journal f = function 
  | [] -> () 
  | t::q -> output_string f (string_of_transaction t) ; écrire_journal f q ;;

let journal = fabrique_journal utilisateurs date_initiale nb_transactions in 
 let f = open_out nom_du_journal in 
  écrire_journal f journal; 
  close_out f ;;