<?php
 include 'INCLUDE/MySQL_include_param_dbb.php';
 $ERR_TRAIT=false;
 // --- on affiche l'état des comptes AVANT la transaction ---
 $Tab_Tous_les_Comptes=Affiche_Etat_Comptes("Etat des comptes AVANT le virement");
 // --- on récupère la colonne des ID_Cpt ---
 if (!$ERR_TRAIT)
 {
  $Tab_Colonne_IDCpt=array_column($Tab_Tous_les_Comptes,'ID_Cpt');
  // --- initialisation des infos sur les comptes --- 
  $Infos_Cpt_Debit =array();
  $Infos_Cpt_Credit=array();
  // --- Saisie du numéro de compte à débiter ---
  $Num_Cpt_Debit=Saisie_Numero_Compte_Valide('Debit');
  // --- Saisie du numéro de compte à créditer ---
  $Num_Cpt_Credit=Saisie_Numero_Compte_Valide('Credit');
  // --- Saisie du montant du virement ---
  echo "Montant du débit            : ";
  fscanf(STDIN,"%s",$Montant_Virement_saisi)    ;
  // --- Post traitement du montant du virement ---
  $Montant_Virement_saisi=str_replace(",",".",$Montant_Virement_saisi);
  $Montant_Virement=floatval($Montant_Virement_saisi);
  $Montant_Virement_formate=number_format($Montant_Virement,2,","," ")." €";
  // --- affichage avant confirmation ---
  $Tab_deux_comptes[0]=$Infos_Cpt_Debit;
  $Tab_deux_comptes[1]=$Infos_Cpt_Credit;
  Affichage_Liste_Comptes("Résumé : Virement de $Montant_Virement_formate, du compte $Num_Cpt_Debit -> le compte $Num_Cpt_Credit",$Tab_deux_comptes);
  // --- Demande de confirmation ---
  echo "Confirmez le virement (o/n) : ";
  fscanf(STDIN,"%s",$ConfirmationVirement);
  if ($ConfirmationVirement == "o")
  {
   // === on gère le virement  dans une transaction SQL ===
   $virementOK=Virement($Num_Cpt_Debit,$Num_Cpt_Credit,$Montant_Virement);
   // -----------------------------------------------------
   if ($virementOK)
   {
    // --- on affiche le résultat du virement ---
    $Tab_deux_comptes[0]=Info_Compte($Num_Cpt_Debit);
    $Tab_deux_comptes[1]=Info_Compte($Num_Cpt_Credit);
    if (!$ERR_TRAIT)
      Affichage_Liste_Comptes("Résultat : Virement de $Montant_Virement_formate, du compte $Num_Cpt_Debit -> le compte $Num_Cpt_Credit",$Tab_deux_comptes);
   }
  }
 }
 // ************** Sous-programmes ****************** 
 // ==========================================================
 // --- Fonction d'affichage de l'état de tous les comptes ---
 // ==========================================================
 function Affiche_Etat_Comptes($texte)
 {
  global $ERR_TRAIT,$TYPE_DBB,$SERVEUR,$BASEDD,$TABLEPERSONNES,$LOGIN_ADM,$MDP_ADM;
  try
  {
   // -- contexte pour le message d'erreur ---
   $contexte="Connexion base de données";
   // --- connexion de la base de données ---
   $bdd = new PDO($TYPE_DBB.":host=".$SERVEUR.";dbname=".$BASEDD,$LOGIN_ADM,$MDP_ADM,
         array(PDO::ATTR_PERSISTENT => true));
   // --- définition du codage en UTF8 ---
   $bdd->exec("SET CHARACTER SET utf8");     
   // --- initialisation des Exceptions PDO pour prepare ---
   $bdd->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
   // --- limitation aux comptes de dépôt ---
   $type_compte="Compte_Dépôts";
   // --- on affiche tous les comptes courant Avant le virement ---
   // -- contexte pour le message d'erreur ---
   $contexte="Problème de requête";  
   // --- préparation de la requête ---
   $requete_sql='SELECT cb.ID_Cpt,cb.Agence,cb.Numero,cb.Type,cl.Nom,cl.Prenom,ROUND(cb.Solde,2) Solde_Compte FROM comptes_bancaires cb INNER JOIN clients_bancaires cl ON cb.ID_Clt=cl.ID_Clt WHERE Type=:type_compte';
   $RequetePreparee = $bdd->prepare($requete_sql);
   // --- liaison avec les paramètres ---
   $RequetePreparee->bindParam(':type_compte', $type_compte);
   // --- exécution de la requête ---
    $RequetePreparee->execute();
   // ---retourne un tableau associatif ---
   $RequetePreparee->setFetchMode(PDO::FETCH_ASSOC); 
   // --- boucle de traitement de chaque client --- 
   $Tab_Comptes=$RequetePreparee->fetchAll();
   // --- Conversion de la colonne solde au format français ---
   foreach ($Tab_Comptes as $Num => $un_cpt)
   {
     $un_cpt['Solde_Compte']=number_format($un_cpt['Solde_Compte'],2,","," ")." €";
     $Tab_Comptes[$Num]=$un_cpt;
   }
   // --- affichage des données retournées ---
   Affichage_Liste_Comptes($texte,$Tab_Comptes);
   // --- fermeture de la requête ---
   $RequetePreparee->closeCursor();
   return $Tab_Comptes;
  }
  catch(Exception $e)
  {
   echo $contexte.' : '.$e->getMessage().PHP_EOL;
   $ERR_TRAIT=true;
  }
 }
 // ================================================
 // --- Fonction de saisie d'un numéro de compte ---
 // ================================================
 function Saisie_Numero_Compte_Valide($type_saisie)
 {
  global $Infos_Cpt_Debit,$Infos_Cpt_Credit,$Tab_Colonne_IDCpt,$Tab_Tous_les_Comptes;
  $Infos_Cpt_xxx=array();
  if ($type_saisie == "Debit") $Texte_Action="à débiter ";
  else $Texte_Action="à créditer";
  // --- Boucle de saisie ---
  while (count($Infos_Cpt_xxx) == 0)
  {
   echo "Numéro du compte ".$Texte_Action." : ";
   fscanf(STDIN,"%d",$Num_Cpt) ;
   // --- on récupère l'indice numérique de la case --- 
   $numcase=array_search($Num_Cpt,$Tab_Colonne_IDCpt);
   // --- array_search() retourne le numéro de la case du tableau --- 
   // --- ou bien false en cas d'échec --- 
   // --- attention il faut utiliser le triple = afin de résoudre --- 
   // --- le problème de la donnée trouvée dans la case 0  --- 
   // --- valeur qui peut être interprétée comme false si le test  --- 
   // --- est noté : if (!$numcase) --- 
   if ($numcase === false)
     echo "Compte $Num_Cpt inexistant !".PHP_EOL;
   else
   {
     $Infos_Cpt_xxx=$Tab_Tous_les_Comptes[$numcase];
     if ($type_saisie == "Debit")
        $Infos_Cpt_Debit=$Infos_Cpt_xxx;
     else
        $Infos_Cpt_Credit=$Infos_Cpt_xxx;
   }
  }
  return $Num_Cpt;
 }
 // ============================
 // --- Fonction de virement ---
 // ============================
 function Virement($NumCptDebit,$NumCptCredit,$MtVirt)
 {
  global $TYPE_DBB,$SERVEUR,$BASEDD,$TABLEPERSONNES,$LOGIN_ADM,$MDP_ADM;
  $virement_effectue=true;
  $ConnexionBDD=false;
  $TransactionDemarree=false;
  try
  {
   // -- contexte pour le message d'erreur ---
   $contexte="Connexion base de données";
   // --- connexion de la base de données ---
   $bdd = new PDO($TYPE_DBB.":host=".$SERVEUR.";dbname=".$BASEDD,$LOGIN_ADM,$MDP_ADM,
          array(PDO::ATTR_PERSISTENT => true));
   $ConnexionBDD=true;
   // --- initialisation des Exceptions PDO pour prepare ---
   $bdd->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
   // --- définition du codage en UTF8 ---
   $bdd->exec("SET CHARACTER SET utf8");     
   // --- on gère le virement  dans une transaction SQL ---
   // ================================
   // === on débute la transaction ===
   // ================================
   // -- contexte pour le message d'erreur ---
   $contexte="Initialisation virement";  
   $bdd->beginTransaction();
   $TransactionDemarree=true;
   // ===========================
   // === on débite le compte ===
   // ===========================
   // -- contexte pour le message d'erreur ---
   $contexte="Débit du compte"     ;
   // --- préparation de la requête ---
   $requete_sql='UPDATE comptes_bancaires SET Solde=Solde+:MontantVir WHERE Id_Cpt=:NumCptOperation';
   $reponse = $bdd->prepare($requete_sql);
   // --- liaison avec les paramètres ---
   $reponse->bindParam(':MontantVir', $MontantVir);
   $reponse->bindParam(':NumCptOperation', $NumCptOperation, PDO::PARAM_INT);
   // --- affectation des valeurs pour les paramètres ---
   $MontantVir      = -$MtVirt     ;
   $NumCptOperation = $NumCptDebit ;
   // --- exécution de la requête ---
   $reponse->execute();
   // --- fermeture de la requête --- 
   $reponse->closeCursor();
   // ============================
   // === on crédite le compte ===
   // ============================
   // -- contexte pour le message d'erreur ---
   $contexte="Crédit du compte";  
   // --- La requête est déjà préparée, elle ne change pas ---
   // --- les paramètres sont déjà liés (bind) ils ne changent pas ---
   // --- affectation des valeurs pour les paramètres ---
   $MontantVir      = +$MtVirt      ;
   $NumCptOperation = $NumCptCredit ;
   // --- exécution de la requête ---
   $reponse->execute();
   // --- fermeture de la requête --- 
   $reponse->closeCursor();
   // ================================
   // === on valide la transaction ===
   // ================================
   // --- si aucune erreur, on valide la transaction ---
   $contexte="Validation virement";
   $reponse = $bdd->commit();
   // --- on confirme le viremet ---
   echo 'Virement effectué !'.PHP_EOL;
  }
  catch(Exception $e)
  {
   // ================================
   // === on annule la transaction ===
   // ================================
   if ($ConnexionBDD && $TransactionDemarree)
   {
    try
    {
       $bdd->rollback();
    }
    catch(Exception $er)
    {
     // --- on affiche un message d'erreur ---
     echo 'Problème sur le virement - Transaction annulée'.PHP_EOL;
     echo 'Annulation : '.$er->getMessage().PHP_EOL;
     $virement_effectue=false;
    }
   }
   // --- on affiche un message d'erreur ---
   echo 'Problème sur le virement - Transaction annulée'.PHP_EOL;
   echo $contexte.' : '.$e->getMessage().PHP_EOL;
   $virement_effectue=false;
  }
  return $virement_effectue;
 }
 // =========================================================
 // --- Fonction d'information de l'état d'un seul compte ---
 // =========================================================
 function Info_Compte($compte)
 {
  global $ERR_TRAIT,$TYPE_DBB,$SERVEUR,$BASEDD,$TABLEPERSONNES,$LOGIN_ADM,$MDP_ADM;
  try
  {
   // -- contexte pour le message d'erreur ---
   $contexte="Connexion base de données";
   // --- connexion de la base de données ---
   $bdd = new PDO($TYPE_DBB.":host=".$SERVEUR.";dbname=".$BASEDD,$LOGIN_ADM,$MDP_ADM,
          array(PDO::ATTR_PERSISTENT => true));
   // --- définition du codage en UTF8 ---
   $bdd->exec("SET CHARACTER SET utf8");     
   // --- initialisation des Exceptions PDO pour prepare ---
   $bdd->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
   $contexte="Problème de requête sur la table";
   // --- préparation de la requête ---
   $requete_sql='SELECT cb.ID_Cpt,cb.Agence,cb.Numero,cb.Type,cl.Nom,cl.Prenom,ROUND(cb.Solde,2) Solde_Compte FROM comptes_bancaires cb INNER JOIN clients_bancaires cl ON cb.ID_Clt=cl.ID_Clt WHERE ID_Cpt=:compte';
   $RequetePreparee = $bdd->prepare($requete_sql);
   // --- liaison avec les paramètres ---
   $RequetePreparee->bindParam(':compte', $compte, PDO::PARAM_INT);
   // --- exécution de la requête ---
   $RequetePreparee->execute();
   // ---retourne un tableau associatif ---
   $RequetePreparee->setFetchMode(PDO::FETCH_ASSOC); 
   // --- boucle de traitement de chaque client --- 
   $Tab_Infos_Cpt=$RequetePreparee->fetchAll();
   // --- Conversion de la colonne solde au format français ---
   foreach ($Tab_Infos_Cpt as $Num => $un_cpt)
   {
    $un_cpt['Solde_Compte']=number_format($un_cpt['Solde_Compte'],2,","," ")." €";
    $Tab_Infos_Cpt[$Num]=$un_cpt;
   }
   $Tab_Infos_Un_Cpt=$Tab_Infos_Cpt[0];
   return $Tab_Infos_Un_Cpt;
  }
  catch(Exception $e)
  {
   echo $contexte.' : '.$e->getMessage().PHP_EOL;
   $ERR_TRAIT=true;
  }   
 }
 // =======================================
 // --- fonction d'affichage du tableau ---
 // =======================================
 function Affichage_Liste_Comptes($texte,$tab_mixte)
 {
  if (count($tab_mixte)==0)
    echo 'Aucun élément à afficher.';
  else
  {
   // --- affichage entête du tableau ---
   reset($tab_mixte);
   $un_compte=current($tab_mixte);
   $liste_champs=array_keys($un_compte);
   echo "---------------------------------------------------------------------------------------".PHP_EOL;
   echo "               $texte".PHP_EOL;
   echo "---------------------------------------------------------------------------------------".PHP_EOL;
   foreach($liste_champs as $nom_champ)
   {
    if ($nom_champ == "ID_Cpt")
     fprintf(STDOUT,"%6s|",$nom_champ);
    else if ($nom_champ == "Agence")
     fprintf(STDOUT," %-6s|",$nom_champ);
    else if ($nom_champ == "Numero")
     fprintf(STDOUT," %-8s|",$nom_champ);
    else if ($nom_champ == "Type")
     fprintf(STDOUT," %-12s|",$nom_champ);
    else if ($nom_champ == "Nom")
     fprintf(STDOUT," %-15s|",$nom_champ);
    else if ($nom_champ == "Prenom")
     fprintf(STDOUT," %-16s|",$nom_champ);
    else if ($nom_champ == "Solde_Compte")
     fprintf(STDOUT,"%-11s|",$nom_champ);
    else
     echo "$nom_champ\t";
   }
   echo PHP_EOL;
   echo "---------------------------------------------------------------------------------------".PHP_EOL;
   // --- boucle de traitement de chaque compte --- 
   foreach ($tab_mixte as $un_compte)
   {
   // --- on affiche le contenu des champs ---
   foreach($liste_champs as $nom_champ)
   {
    if ($nom_champ == "ID_Cpt")
     fprintf(STDOUT,"%5s |",$un_compte[$nom_champ]);
    else if ($nom_champ == "Agence")
     fprintf(STDOUT," %-6s|",$un_compte[$nom_champ]);
    else if ($nom_champ == "Numero")
     fprintf(STDOUT," %-8s|",$un_compte[$nom_champ]);
    else if ($nom_champ == "Type")
     fprintf(STDOUT,"%-13s|",$un_compte[$nom_champ]);
    else if ($nom_champ == "Nom")
     fprintf(STDOUT," %-15s|",$un_compte[$nom_champ]);
    else if ($nom_champ == "Prenom")
     fprintf(STDOUT," %-16s|",$un_compte[$nom_champ]);
    else if ($nom_champ == "Solde_Compte")
     fprintf(STDOUT,"%13s |",$un_compte[$nom_champ]);
    else
     echo $un_compte[$nom_champ]."\t";
   }
   echo PHP_EOL; 
   }
   echo "---------------------------------------------------------------------------------------".PHP_EOL;
  }
 }
?>
