#!/bin/bash
CONF=`dirname $0`/.nedap_ # chemin de configuration

now() {  # heure en format texte (décalage de l'horloge PC) pour "date" et "touch"
  if [ -f "$CONF"heure ]; then 
    echo now+`cat "$CONF"heure`seconds 
  else echo now
  fi
}

lit() {  # (comme read): demande une valeur numérique, sans rien faire si valeur incorrecte
  read lit_temp
  if [ "x$lit_temp" != "x" ]; then
    let $1=$lit_temp >/dev/null
  fi
}

chut() {  # (comme echo): affiche en rouge les messages normalement gardés secrets
  echo -n -e "\033[91m" # 31=rouge 91=rouge clair
  echo -n -e "\033[1m" # 1=gras 7=inverse 4=souligné
  echo "$@"
  echo -n -e "\033[0m"
}

entree() {  # message "Tapez ENTREE pour continuer"
  echo ""
  echo -n "Appuyez sur ENTREE pour continuer"
  read a
}
  
affiche_heure() {  # affiche la date et l'heure de la machine à voter
  date -d `now` +"%d/%m/%Y %H:%M:%S"
}

reglage_heure() {  # menu pour règler la date et l'heure
  clear
  echo "REGLAGE DE LA DATE ET DE L'HEURE"
  echo ""
  echo -n "Date et heure actuelle: "; affiche_heure
  echo ""
  echo -n "Entrez la nouvelle date et heure (mm/jj/aaaa hh:mm:ss) : "
  read date
  if [ "x$date" == "x" ] ; then return; fi # touche ENTREE => ne rien faire
  if (date -d "$date" > /dev/null); then  # format correct
    let diff=`date -d "$date" +%s`-`date +%s`;
    echo $diff > "$CONF"heure
    echo "Nouvelle date et heure prise en compte:"; affiche_heure
  else  # format incorrect
    echo "Format incorrect! Date et heure non modifiée"
  fi
  sleep 1
}

affiche_etat() {  # affiche l'état du vote (en cours ou non, heures début fin, votants)
  if [ -f "$CONF"fin -a -f "$CONF"debut ]; then
    echo "ELECTION TERMINEE:"
    echo -n "Début:   "; date -r "$CONF"debut +"%d/%m/%Y %H:%M:%S"
    echo -n "Fin:     "; date -r "$CONF"fin +"%d/%m/%Y %H:%M:%S"
    echo -n "Votants: "; (cat "$CONF"result* 2>/dev/null) | wc -c
  elif [ -f "$CONF"debut ]; then
    echo "ELECTION EN COURS"
    echo -n "Début:   "; date -r "$CONF"debut +"%d/%m/%Y %H:%M:%S"
    echo -n "Votants: "; (cat "$CONF"result* 2>/dev/null) | wc -c
  else
    echo "PAS D'ELECTION EN COURS"
  fi 
  if [ -f "$CONF"liste ]; then
    let nb=`cat "$CONF"liste | wc -l`-1
    echo "Il y a $nb candidats"
  else
    echo "La liste des candidats n'a pas été rentrée"
  fi
  if [ ! -f "$CONF"triche ]; then
    chut "Mode triche désactivé"
  else
    l=`cat "$CONF"triche | head -1`
    nmin=`echo $l|sed -n 's/\([^ ]*\) \([^ ]*\).*/\1/p'`
    tmin=`echo $l|sed -n 's/\([^ ]*\) \([^ ]*\).*/\2/p'`
    chut -n "Mode triche activé si au moins $nmin votants et durée minimale "
    chut `date -d "1/1/1970 +$tmin"seconds +%H:%M:%S`
  fi
}

affiche_liste() {  # affiche la liste des candidats, sauf le vote nul si argument fourni
  n=1;
  nb=`cat "$CONF"liste | wc -l`
  while [ $n -le $nb ] ; do
    if [ $n -eq $nb -a $# -gt 0 ]; then break; fi  # argument? s'arrêter juste avant le dernier
    nom=`cat "$CONF"liste | head -$n | tail -1`
    echo "$n. $nom"
    let n=n+1
  done
}

liste_candidats() {  # menu d'affichage et de modification de la liste des candidats
  clear
  echo "LISTE DES CANDIDATS"
  echo ""
  if [ -f "$CONF"liste ] ; then
    echo "Liste déjà entrée:"
    affiche_liste sans
    echo ""
  fi
  if [ -f "$CONF"debut -a ! -f "$CONF"fin ]; then
    echo "Impossible de changer la liste d'une élection en cours!"
    entree
    return
  fi
  echo "Voulez-vous vraiment rentrer une nouvelle liste de candidats? (O/N)"
  read -sn1 a; if [ "x$a" != "xo" -a "x$a" != "xO" ]; then return; fi
  echo ""
  echo "Entrez le nom de chaque candidat, suivi de la touche ENTREE"
  echo "Pour terminer, tapez ENTREE"
  rm -f "$CONF"liste "$CONF"debut "$CONF"fin "$CONF"triche "$CONF"result*
  while true; do
    read nom
    if [ "x$nom" == "x" ] ; then break; fi
    echo "$nom" >> "$CONF"liste
  done
  echo "Vote nul" >> "$CONF"liste
  echo "Merci, vous venez d'entrer la liste suivante:"
  affiche_liste sans
  echo ""
  echo "Appuyez sur une touche pour continuer"
  read -sn1 a
} 

debut_election(){  # vérifie élection non en cours et candidats présents => débute élection
  clear
  echo "DEBUTER L'ELECTION"
  echo ""
  if [ ! -f "$CONF"liste ]; then
    echo "Impossible: liste des candidats non rentrée!"; sleep 1; return;
  fi
  if [ -f "$CONF"debut -a ! -f "$CONF"fin ]; then
    echo "Impossible: élection déjà commencée et non terminée!"; sleep 1; return
  fi
  if (ls "$CONF"result* >/dev/null 2>&1); then
    echo "Voulez-vous vraiment effacer les résultats de l'élection précédente? (O/N)"
    read -sn1 a; if [ "x$a" != "xo" -a "x$a" != "xO" ]; then return; fi
    rm -f "$CONF"result*
  fi
  touch -d `now` "$CONF"debut
  rm -f "$CONF"fin
  echo ""
  echo -n "Election débutée: "; affiche_heure;
  entree
} 

clore_election(){  # vérifie élection en cours et demande confirmation => termine élection
  clear
  echo "CLORE L'ELECTION"
  echo ""
  if [ -f "$CONF"fin ]; then
    echo "Impossible: élection déjà close!"; sleep 1; return
  fi
  if [ ! -f "$CONF"debut ]; then
    echo "Impossible: élection pas encore commencée!"; sleep 1; return
  fi
  echo "Voulez-vous vraiment clore l'élection? (O/N)"
  read -sn1 a; if [ "x$a" != "xo" -a "x$a" != "xO" ]; then return; fi
  touch -d `now` "$CONF"fin  
  echo ""
  echo -n "Election terminée: "; affiche_heure;
  entree
} 

triche() {  # calculs modifiant les résultats si le mode "triche" est applicable
  if [ ! -f "$CONF"triche ]; then 
    chut "Mode triche non configuré: pas de triche"
    return; 
  fi
  l=`cat "$CONF"triche | head -1`
  nmin=`echo $l|sed -n 's/\([^ ]*\) \([^ ]*\).*/\1/p'`
  tmin=`echo $l|sed -n 's/\([^ ]*\) \([^ ]*\).*/\2/p'`
  let t=`date -r "$CONF"fin +%s`-`date -r "$CONF"debut +%s`
  if [ ${result[0]} -lt $n ]; then
    chut "${result[0]} votants, moins que le minimum $nmin: pas de triche"
    return
  fi
  if [ $t -lt $tmin ]; then
    chut -n "durée "`date -d "1/1/1970 $t"seconds +%H:%M:%S`
    chut -n " moins que le minimum "`date -d "1/1/1970 $tmin"seconds +%H:%M:%S`": pas de triche"
    return
  fi
  chut -n "Mode triche activé: ${result[0]} votants (> $nmin)"
  chut -n " et durée "`date -d "1/1/1970 $t"seconds +%H:%M:%S`
  chut " (> "`date -d "1/1/1970 $tmin"seconds +%H:%M:%S`")"
  nb=`cat "$CONF"liste | wc -l`
  n=1;
  while [ $n -le $nb ]; do
    tconf[$n]=0
    let n=$n+1
  done
  nb=`(cat "$CONF"triche 2>/dev/null)| wc -l`
  n=1;
  restant=${result[0]}
  while [ $n -lt $nb ]; do
    let n=n+1
    l=`cat "$CONF"triche | head -$n | tail -1`
    c=`echo $l|sed -n 's/\([^ ]*\) \([^ ]*\) \([^ ]*\).*/\1/p'`
    min=`echo $l|sed -n 's/\([^ ]*\) \([^ ]*\) \([^ ]*\).*/\2/p'`
    max=`echo $l|sed -n 's/\([^ ]*\) \([^ ]*\) \([^ ]*\).*/\3/p'`
    nom=`cat "$CONF"liste | head -$c | tail -1`
    if [ ${tconf[$c]} -gt 0 ]; then continue; fi
    voix=${result[c]}
    let p100=$voix*100/${result[0]}
    if [ $min -le $p100 -a $p100 -le $max ]; then
      chut "N°$c ($nom): $voix (${p100}%) entre ${min}% et ${max}%: score conservé"
    elif [ $p100 -lt $min ]; then
      chut -n "N°$c ($nom): $voix (${p100}%) < ${min}%: "
      let result[$c]=$min*${result[0]}/100+1;
      let p100=${result[$c]}*100/${result[0]}
      chut "remonté à ${result[$c]} (${p100}%)"
    elif [ $p100 -gt $max ]; then
      chut -n "N°$c ($nom): $voix (${p100}%) > ${max}%: "
      let result[$c]=$max*${result[0]}/100;
      let p100=${result[$c]}*100/${result[0]}
      chut "ramené à ${result[$c]} (${p100}%)"
    fi
    if [ ${result[$c]} -gt $restant ]; then result[$c]=$restant; fi
    let restant=$restant-${result[$c]}
    tconf[$c]=1
  done
  tot=0;
  nb=`cat "$CONF"liste | wc -l`
  n=1;
  while [ $n -le $nb ]; do
    let tot=$tot+${result[$n]}
    let n=$n+1
  done
  if [ $tot -ne ${result[0]} ]; then
    let p100=$tot*100/${result[0]}
    chut "Corrections à faire car le total fait ${p100}%"
    tot1=0
    tot2=0
    n=1;
    nconf=0;
    while [ $n -le $nb ]; do
     if [ ${tconf[$n]} -gt 0 ]; then
      let tot2=$tot2+${result[$n]}
      let nconf=$nconf+1
     else
      let tot1=$tot1+${result[$n]}
     fi
     let n=$n+1
    done
    n=1;
    let restant=${result[0]}-$tot2
    while [ $n -le $nb ]; do
     if [ ${tconf[$n]} -eq 0 ]; then
      let nconf=$nconf+1
      nom=`cat "$CONF"liste | head -$n | tail -1`
      if [ $nconf -eq $nb ]; then
        let voix=$restant
      else
        let voix="${result[$n]}*(${result[0]}-$tot2)/$tot1"
        if [ $voix -gt $restant ]; then voix=$restant; fi
        let restant=$restant-$voix
      fi
      let p100a=${result[$n]}*100/${result[0]}
      let p100b=$voix*100/${result[0]}
      if [ $voix -ne ${result[$n]} ]; then
        chut "N°$n ($nom): $voix (${p100b}%) au lieu de ${result[$n]} (${p100a}%)"
        result[$n]=$voix
      fi
     fi
     let n=$n+1
    done
  fi
}

affiche_resultats() {  # affiche le résultat de l'élection, en trichant si nécessaire
  clear
  echo "AFFICHER LES RESULTATS"
  echo ""
  if [ -f "$CONF"fin -a -f "$CONF"debut ]; then
    echo -n "Début:  "; date -r "$CONF"debut +"%d/%m/%Y %H:%M:%S"
    echo -n "Fin:    "; date -r "$CONF"fin +"%d/%m/%Y %H:%M:%S"
    echo -n "Votants:"; ( cat "$CONF"result* 2>/dev/null ) | wc -c
    echo ""
    # récupération des résultats
    nb=`cat "$CONF"liste | wc -l`;
    n=1;
    tot=0;
    while [ $n -le $nb ]; do
      result[$n]=`(cat "$CONF"result"$n" 2>/dev/null) | wc -c`;
      let tot=$tot+${result[$n]}
      let n=n+1
    done
    result[0]=$tot
    # triche
    triche    
    echo ""
    # affichage des résultats
    n=1;
    while [ $n -le $nb ]; do
      nom=`cat "$CONF"liste | head -$n | tail -1`
      if [ ${result[0]} -gt 0 ]; then
        let p10000=${result[$n]}*10000/${result[0]}
        let p100=$p10000/100
        let p100f=$p10000-100*$p100
      else
        p100=0; p100f=0;
      fi
      echo -n "Choix n°$n ($nom): "
      printf "%d votes (%d.%02d%% des votants)\n" ${result[$n]} $p100 $p100f
      let n=n+1
    done
  else
    echo "Impossible d'afficher les résultats: il faut voter puis clore l'élection"
  fi
  entree
}

ajoute_triche() {  # ajoute une règle de triche
  clear
  echo "AJOUTER UNE REGLE DE TRICHE"
  echo ""
  if [ ! -f "$CONF"triche ]; then
    echo "CONFIGURATION GENERALE DE LA TRICHE"
    echo ""
    echo "A partir de combien de votants active-t-on la triche?"
    echo -n "Entrez la valeur: "; 
    nmin=0; lit nmin
    echo "D'accord, à partir de $nmin votants"
    echo ""
    echo "A partir de quelle durée de vote active-t-on la triche?"
    echo -n "Entrez la durée (hh:mm:ss): "; read a
    tmin=0;
    if (date -d "1/1/1970 $tmin" 1>/dev/null 2>&1); then
      let tmin=`date -d "1/1/1970 $a" +%s`-`date -d "1/1/1970 0seconds" +%s`
    fi
    echo -n "D'accord, à partir de "; date -d "1/1/1970 $tmin"seconds +%H:%M:%S
    echo "$nmin $tmin" > "$CONF"triche
  fi
  echo ""
  affiche_liste
  echo -n "Choisissez le candidat (ENTREE sinon): "
  n=0; lit n
  if [ $n -lt 1 ]; then return; fi
  echo -n "Choisissez le pourcentage mini (ENTREE = 0%): "
  min=0; lit min
  echo -n "Choisissez le pourcentage maxi (ENTREE = 100%): "
  max=100; lit max
  echo "$n $min $max" >> "$CONF"triche
}

ecran_secret() {  # menu caché: affiche les règles de triche applicables
while true; do
  clear
  echo "MENU SECRET"
  echo ""
  echo "Règles de triche actuelles:"
  if [ ! -f "$CONF"liste ] ; then
    echo "Rentrez d'abord la liste des candidats!"
    entree
    return
  fi
  nb=`(cat "$CONF"triche 2>/dev/null)| wc -l`
  n=1;
  while [ $n -lt $nb ]; do
    echo -n " Règle $n: "
    let n=n+1
    l=`cat "$CONF"triche | head -$n | tail -1`
    c=`echo $l|sed -n 's/\([^ ]*\) \([^ ]*\) \([^ ]*\).*/\1/p'`
    min=`echo $l|sed -n 's/\([^ ]*\) \([^ ]*\) \([^ ]*\).*/\2/p'`
    max=`echo $l|sed -n 's/\([^ ]*\) \([^ ]*\) \([^ ]*\).*/\3/p'`
    nom=`cat "$CONF"liste | head -$c | tail -1`
    echo "n°$c ($nom) entre $min% et $max%"
  done
  if [ $nb -ge 1 ]; then
    l=`cat "$CONF"triche | head -1`
    nmin=`echo $l|sed -n 's/\([^ ]*\) \([^ ]*\).*/\1/p'`
    tmin=`echo $l|sed -n 's/\([^ ]*\) \([^ ]*\).*/\2/p'`
    echo "Seulement si au moins $nmin votants"
    echo -n "Seulement si le vote dure au moins "; date -d "1/1/1970 +$tmin"seconds +%H:%M:%S
  else
    echo "Aucune règle de triche n'a encore été rentrée"
  fi
  echo ""
  echo "1. Ajouter une nouvelle règle de triche"
  echo "2. Supprimer toutes les règles de triche"
  echo "0. Sortir"
  echo ""
  echo -n "Votre choix:"
  read -sn1 a
  case $a in
  2) rm -f "$CONF"triche;;
  1) ajoute_triche;;
  0) return;;
  esac
done
}

ecran_configuration() {  # écran de configuration (accessible par la clé)
mot=""
while true; do
  clear
  echo "MENU DE CONFIGURATION"
  affiche_heure
  echo ""
  affiche_etat
  echo ""
  echo ""
  echo "1. Débuter l'élection"
  echo "2. Clore l'élection"
  echo "3. Afficher les résultats"
  echo "4. Liste des candidats"
  echo "5. Règler l'heure"
  echo "0. Sortir"
  echo ""
  echo -n "Votre choix "
  chut -n "(tapez \"secret\" pour le mode triche)"
  echo -n ": "
  read -sn1 a
  echo "";
  ok=0;
  case $a in
  1) debut_election;ok=1;;
  2) clore_election;ok=1;;
  3) affiche_resultats;ok=1;;
  4) liste_candidats;ok=1;;
  5) reglage_heure;ok=1;;
  0) return;
  esac
  if [ $ok -eq 1 ]; then return; fi
  mot=`echo "$mot$a" | tr a-z A-Z`
  ncar=`echo -n "$mot" | wc -c`
  if [ X$mot != X`echo SECRET|head -c$ncar` ]; then mot=""; ncar=0; fi
  if [ X"$mot" == X"SECRET" ]; then
    ecran_secret
    mot=""
  fi
done
}

ecran_vote() {  # écran de vote: pour l'électeur après accord du président du bureau
  vote=0;
  nb=`cat "$CONF"liste | wc-l`
  while true; do
    clear
    echo "BIENVENUE SUR LA MACHINE A VOTER"
    echo "Choisir un candidat"
    affiche_heure
    echo -n "Votants:"; (cat "$CONF"result* 2>/dev/null) | wc -c
    echo ""
    affiche_liste
    echo ""
    echo -n "Votre vote: "
    vote=0; lit vote
    if [ $vote -gt 0 -a $vote -le $nb ]; then
      clear
      echo "CONFIRMATION DE VOTRE VOTE"
      echo ""
      nom=`cat "$CONF"liste | head -$vote | tail -1`
      echo "Vous êtes sur le point de voter: $nom"
      echo
      echo "Confirmer ce vote? (O/N)"
      read -sn1 a; if [ "x$a" == "xo" -o "x$a" == "xO" ]; then 
        echo -n "X" >> "$CONF"result"$vote"
        echo "Merci, votre vote a été enregistré"
        sleep 1;
        return
      fi
    fi
  done
}

ecran_accueil() {  # écran principal, visible à l'allumage de la machine
while true; do
  clear
  echo "BIENVENUE SUR LA MACHINE A VOTER"
  affiche_heure
  echo ""
  affiche_etat
  echo ""
  if [ -f "$CONF"debut -a ! -f "$CONF"fin ]; then
    echo "Le président du bureau de vote doit autoriser un électeur à voter"
    echo ""
    echo "Appuyez sur ESPACE pour autoriser un vote, ou entrez la clé (K)"
    IFS=""; read -sn1 c
    if [ X"$c" == "X " ] ; then
      ecran_vote
    elif [ X`echo "$c"|tr a-z A-Z` == XK ] ; then
      ecran_configuration
    fi
  else 
    echo "Insérez la clé (NB: c'est la touche K qui en tient lieu)"
    echo ""
    read -sn1 c
    if [ X`echo "$c"|tr a-z A-Z` == XK ] ; then
      ecran_configuration
    fi
  fi
done
}

# programme principal:
ecran_accueil

