#########################################################################
# COPYRIGHT (C) 2003         EDF R&D              WWW.CODE-ASTER.ORG    #
#                                                                       #
# THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR         #
# MODIFY IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS        #
# PUBLISHED BY THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE    #
# LICENSE, OR (AT YOUR OPTION) ANY LATER VERSION.                       #
# THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,       #
# BUT WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF        #
# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU      #
# GENERAL PUBLIC LICENSE FOR MORE DETAILS.                              #
#                                                                       #
# YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE     #
# ALONG WITH THIS PROGRAM; IF NOT, WRITE TO : EDF R&D CODE_ASTER,       #
#    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.        #
#########################################################################
#$Id: asjob_main.tcl 1154 2006-04-05 16:52:32Z mcourtoi $
# Environnement graphique de suivi des exécutions
#
#### ==========
proc asjob_main {{root .}} {
#### ==========
#   on est normalement sous ASTK/ASTK_CLIENT/lib/ASJOB
#
   init_asjob
   set asjob::fen_root $root
   set asjob::popup .asjob_popup
   wm title    $asjob::fen_root [ashare::mess ihm 137 $astk::astk_version]
   wm iconname $asjob::fen_root [ashare::mess ihm 137 $astk::astk_version]
   wm protocol $asjob::fen_root WM_DELETE_WINDOW { set asjob::actu(indic) 0;destroy $asjob::fen_root }
   if { $asjob::fen_root == "." } {
      set main .main
   } else {
      set main $asjob::fen_root.main
   }
   eval destroy [winfo child $asjob::fen_root]
   affiche_main $main
}
#### =========
proc ajout_job { args } {
#### =========
#
# verif que asjob est lancé si appel par astk
   show_fen $astk::ihm(asjob)
#
   set iret 4
   lire_job asjob::TextJobs $asjob::NomSuivi
   set retour [eval insert_job asjob::TextJobs $args]
   if { $retour > 0 } {
      sauv_job asjob::TextJobs $asjob::NomSuivi
      lbxLoadFile $asjob::actu(f_actu) $asjob::NomSuivi
      $asjob::actu(f_actu) yview end
      set iret 0
   }
   return $iret
}
#### ============
proc loadStateJob {w {bysel 0}} {
#### ============
#
#  Examine l'ensemble des travaux affichés dans le suivi, sélectionne ceux dans l'état different de
#  "ENDED" et envoie la commande d'actualisation sur chacun d'eux
#
   global loadStateJob_lock
   if { $loadStateJob_lock } {
         ashare::mess info 38
   } else {
      set loadStateJob_lock 1
      set asjob::status ""
      lire_job asjob::TextJobs $asjob::NomSuivi
      set nb_jobs [array size asjob::TextJobs]
      if { $nb_jobs > 0 } {
         set id [array startsearch asjob::TextJobs]
         for {set i 0} {$i < $nb_jobs} {incr i} {
            set elt [array nextelement asjob::TextJobs $id]
            set valjob [lindex [array get asjob::TextJobs $elt] 1]
            set etajob [lindex $valjob [lindex $asjob::paraJob(etat) 0]]
            set num      [lindex $valjob [lindex $asjob::paraJob(numero) 0]]
            set iactu 1
            if { $etajob == "ENDED" } {
               set iactu 0
            }
            if { $iactu && $bysel } {
               set indsel [lsort -integer [$w curselection]]
               set itrouv 0
               for {set is 0} {$is < [llength $indsel]} {incr is} {
                  set sel  [lindex $asjob::Jobs [lindex $indsel $is]]
                  set nums [lindex $sel [lindex $asjob::paraJob(numero) 0]]
                  if { $nums == $num } {
                     set itrouv 1
                     break
                  }
               }
               if { $itrouv == 0 } {
                  set iactu 0
               }
            }
            if { $iactu } {
               set machexe  [lindex $valjob [lindex $asjob::paraJob(machine) 0]]
               set user     [lindex $valjob [lindex $asjob::paraJob(user) 0]]
               set nom      [lindex $valjob [lindex $asjob::paraJob(nom) 0]]
               set mode     [lindex $valjob [lindex $asjob::paraJob(mode) 0]]
               set tcpu_av  [lindex $valjob [lindex $asjob::paraJob(tcpu) 0]]
               set noeud_av [lindex $valjob [lindex $asjob::paraJob(noeud) 0]]
               set classe_av [lindex $valjob [lindex $asjob::paraJob(classe) 0]]

            #  On envoie la commande sur le serveur permettant de récupérer l'état du job et on actualise les paramètres
               set retour -1
               set is [valid_serveur $machexe $user nom_complet]
               set out ""
               if { $is == -888 } {
                  set out "Serveur dans l'état off"
               } elseif { $is != -999 } {
                  # etat du serveur
                  set lcmd ""
                  append lcmd [file join $astk::config($astk::inv(cmpl,$machexe,$user),rep_serv) as_serv]
                  append lcmd " as_actu"
                  append lcmd " --remote_shell_protocol $astk::config(-1,remote_shell_protocol)"
                  append lcmd " --remote_copy_protocol $astk::config(-1,remote_copy_protocol)"
                  set argu "$num $nom $mode"
                  set retour [ashare::rexec_cmd $astk::inv(cmpl,$machexe,$user) astk::config $lcmd $argu 0 out $asjob::fen_root]
               } else {
                  set out [ashare::mess ihm 360]
                  ashare::mess erreur 47 $machexe $user
               }
               if { $retour == 0 } {
                  if { [regexp {DIAG[ ]*=[ ]*([-a-z_A-Z0-9<>?*+=]+)} $out match diag] == 0 } { set diag "_" }
                  if { [regexp {TCPU[ ]*=[ ]*([0-9_]+)} $out match tcpu] == 0 } { set tcpu "_" }
                  if { $tcpu == "_" }  {set tcpu $tcpu_av}
                  if { [regexp {ETAT[ ]*=[ ]*([a-z_A-Z]+)}  $out match etat] == 0 } { set etat "_" }
                  if { [regexp {QUEUE[ ]*=[ ]*([a-z_A-Z\.0-9]+)}  $out match classe] == 0 } { set classe "_" }
                  if { $classe == "_" }  { set classe $classe_av }
                  if { [regexp {EXEC[ ]*=[ ]*([a-z_A-Z\.0-9]+)} $out match noeud] == 0 } { set noeud "_" }
                  if { $noeud == "_" }  { set noeud $noeud_av }
                  set j1 [lindex $asjob::paraJob(diagnostic) 0]
                  set valjob [lreplace $valjob $j1 $j1 $diag]
                  set j1 [lindex $asjob::paraJob(etat) 0]
                  set valjob [lreplace $valjob $j1 $j1 $etat]
                  set j1 [lindex $asjob::paraJob(classe) 0]
                  set valjob [lreplace $valjob $j1 $j1 $classe]
                  set j1 [lindex $asjob::paraJob(tcpu) 0]
                  set valjob [lreplace $valjob $j1 $j1 $tcpu]
                  set j1 [lindex $asjob::paraJob(noeud) 0]
                  set valjob [lreplace $valjob $j1 $j1 $noeud]
                  array set asjob::TextJobs [list $num $valjob]
                  if { $etat == "ENDED" && $astk::config(-1,bip)==1 } {
                     bell ; after 100 ; bell
                  }
               } else {
                  set asjob::status "<ERREUR> accès $num $nom impossible, Code retour : $retour"
               }
            }
         }
         array donesearch asjob::TextJobs $id
         sauv_job asjob::TextJobs $asjob::NomSuivi
         lbxLoadFile $w $asjob::NomSuivi
         $w yview end
      }
      set loadStateJob_lock 0
   }
}
#### =========
proc suppr_job { w } {
#### =========
   if { [$w curselection] == "" } {
      set asjob::status "<ALARME> Sélectionner tout d'abord un job !"
   } else {
      # tabj : tableau temporaire qui regroupe les jobs par serveur
      # tabj(num_serv,nbj)
      # tabj(num_serv,indice=1...nbfic) = indice de la sélection
      for {set nsrv -1} {$nsrv < $astk::config(nb_serv)} {incr nsrv} {
         set tabj($nsrv,nbj) 0
      }
      set indsel [lsort -decreasing -integer [$w curselection]]
   # regroupe les jobs par serveur
      for {set i 0} {$i < [llength $indsel]} {incr i} {
         set nsel [lindex $indsel $i]
         set sel  [lindex $asjob::Jobs $nsel]
         set machexe [lindex $sel [lindex $asjob::paraJob(machine) 0]]
         set user    [lindex $sel [lindex $asjob::paraJob(user) 0]]
         if { [valid_serveur $machexe $user nom_complet] <= -888 } {
            ashare::mess erreur 47 $machexe $user
            set tabj($nsrv,nbj) 0
            # effacer le job de la liste
            set num     [lindex $sel [lindex $asjob::paraJob(numero) 0]]
            lire_job asjob::TextJobs $asjob::NomSuivi
            delete_job asjob::TextJobs $num
            sauv_job asjob::TextJobs $asjob::NomSuivi
            lbxLoadFile $w $asjob::NomSuivi
            $w yview end
         } else {
            set nsrv $astk::inv(cmpl,$machexe,$user)
            incr tabj($nsrv,nbj)
            set tabj($nsrv,$tabj($nsrv,nbj)) $sel
         }
      }
   # interrogation de chaque serveur
      for {set nsrv -1} {$nsrv < $astk::config(nb_serv)} {incr nsrv} {
         if { $tabj($nsrv,nbj) > 0 } {
            set NN 10
            set ilast 0
         # pour éviter les lignes de commandes trop longues, on passe par paquet de NN
            while { $ilast < $tabj($nsrv,nbj) } {
               set ideb [expr $ilast + 1]
               set ilast [expr $ideb + $NN - 1]
               if { $ilast > $tabj($nsrv,nbj) } {
                  set ilast $tabj($nsrv,nbj)
               }
               #
               set cmd "/bin/sh -c \""
               # liste des jobs confirmés pour suppression
               set ljconf [list]
               for {set nf $ideb} {$nf <= $ilast} {incr nf} {
                  set sel $tabj($nsrv,$nf)
                  set nom     [lindex $sel [lindex $asjob::paraJob(nom) 0]]
                  set num     [lindex $sel [lindex $asjob::paraJob(numero) 0]]
                  set etajob  [lindex $sel [lindex $asjob::paraJob(etat) 0]]
                  set machexe [lindex $sel [lindex $asjob::paraJob(machine) 0]]
                  set noeud   [lindex $sel [lindex $asjob::paraJob(noeud) 0]]
                  set user    [lindex $sel [lindex $asjob::paraJob(user) 0]]
                  set mode    [lindex $sel [lindex $asjob::paraJob(mode) 0]]
               # on appelle le service permettant d'interrompre le job as_del
                  if { $etajob != "ENDED" } {
                     set confirm [tk_messageBox -title [ashare::mess ihm 143] -message [ashare::mess ihm 249 $num] -type yesno -icon question -parent $asjob::fen_root]
                  } else {
                     set confirm "yes"
                  }
                  if { $confirm == "yes" } {
                     set retour -1
                     lappend ljconf $sel
                     append cmd [file join $astk::config($nsrv,rep_serv) as_serv]
                     append cmd " as_del"
                     append cmd " --remote_shell_protocol $astk::config(-1,remote_shell_protocol)"
                     append cmd " --remote_copy_protocol $astk::config(-1,remote_copy_protocol)"
                     append cmd " --signal=KILL"
                     append cmd " $num $nom $mode $noeud ; "
                  }
               }
               append cmd "\""
               # nbre de jobs confirmés
               set inc [llength $ljconf]
               set retour [list]
            # execution si plus d'un job à supprimer
               set out ""
               if { $inc > 0 } {
                  set retour [ashare::rexec_cmd $nsrv astk::config $cmd "" 0 out $asjob::fen_root]
               }
               # nbre de code retour
               set nret [llength $retour]
               if { $nret != $inc } {
                  tk_messageBox -title "$ashare::msg($ashare::lang,erreur,txt)" \
                     -message [ashare::mess erreur 33] -type ok -parent $asjob::fen_root
               } else {
                  for {set nf 0} {$nf < $inc} {incr nf} {
                     set sel [lindex $ljconf $nf]
                     set nom     [lindex $sel [lindex $asjob::paraJob(nom) 0]]
                     set num     [lindex $sel [lindex $asjob::paraJob(numero) 0]]
                     set ireti [lindex $retour $nf]
                     if { $ireti != 0 && $ireti != -1 } {
                        set asjob::status "<ERREUR> Suppression $num $nom impossible, Code retour : $ireti"
                     } else {
                        lire_job asjob::TextJobs $asjob::NomSuivi
                        eval delete_job asjob::TextJobs $num
                        sauv_job asjob::TextJobs $asjob::NomSuivi
                        lbxLoadFile $w $asjob::NomSuivi
                        $w yview end
                     }
                  }
               }
            }
         }
      }
      $w selection set $nsel
   }
}
#### ============
proc purge_job { } {
#### ============
#  Envoie à chaque serveur la liste des jobs "connus" pour que les autres fichiers
#  soient supprimés du flasheur.
#
   set asjob::status ""
   lire_job asjob::TextJobs $asjob::NomSuivi
   set nb_jobs [array size asjob::TextJobs]
   # interrogation de chaque serveur
   for {set nsrv 0} {$nsrv < $astk::config(nb_serv)} {incr nsrv} {
      set nbj 0
      set cmd [file join $astk::config($nsrv,rep_serv) as_serv]
      append cmd " as_run"
      append cmd " --remote_shell_protocol $astk::config(-1,remote_shell_protocol)"
      append cmd " --remote_copy_protocol $astk::config(-1,remote_copy_protocol)"
      append cmd " --purge_flash"
      set id [array startsearch asjob::TextJobs]
      for {set i 0} {$i < $nb_jobs} {incr i} {
         set elt    [array nextelement asjob::TextJobs $id]
         set valjob [lindex [array get asjob::TextJobs $elt] 1]
         
         set num     [lindex $valjob [lindex $asjob::paraJob(numero) 0]]
         set machexe [lindex $valjob [lindex $asjob::paraJob(machine) 0]]
         set user    [lindex $valjob [lindex $asjob::paraJob(user) 0]]
         if { [valid_serveur $machexe $user nom_complet] <= -888 } {
            ashare::mess erreur 47 $machexe $user
         } else {
            set nsrvJ $astk::inv(cmpl,$machexe,$user)
            if { $nsrvJ == $nsrv } {
               append cmd " $num"
               incr nbj
            }
         }
      }
      array donesearch asjob::TextJobs $id
      # execution si plus d'un job sur ce serveur
      if { $nbj > 0 } {
         set iret [ashare::rexec_cmd $nsrv astk::config $cmd "" 0 out $asjob::fen_root]
         if { $iret != 0 } {
            set asjob::status "<ERREUR> Purge sur $machexe, Code retour : $iret"
         }
      }
   }
}
#### =========
proc susp_job { w } {
#### =========
   if { [$w curselection] == "" } {
      set asjob::status "<ALARME> Sélectionner tout d'abord un job !"
   } else {
      set indsel [$w curselection]
      for {set i 0} {$i < [llength $indsel]} {incr i} {
         set nsel [lindex $indsel $i]
         set sel  [lindex $asjob::Jobs $nsel]
      # on appelle le service as_edit
         set num     [lindex $sel [lindex $asjob::paraJob(numero) 0]]
         set nom     [lindex $sel [lindex $asjob::paraJob(nom) 0]]
         set mode    [lindex $sel [lindex $asjob::paraJob(mode) 0]]
         set machexe [lindex $sel [lindex $asjob::paraJob(machine) 0]]
         set noeud   [lindex $sel [lindex $asjob::paraJob(noeud) 0]]
         set user    [lindex $sel [lindex $asjob::paraJob(user) 0]]
         set etat    [lindex $sel [lindex $asjob::paraJob(etat) 0]]
         if { $etat != "ENDED" } {
            set retour -1
            set is [valid_serveur $machexe $user nom_complet]
            if { $is == -888 } {
               set out "Serveur dans l'état off"
            } elseif { $is != -999 } {
               set lcmd ""
               append lcmd [file join $astk::config($astk::inv(cmpl,$machexe,$user),rep_serv) as_serv]
               append lcmd " as_del"
               append lcmd " --remote_shell_protocol $astk::config(-1,remote_shell_protocol)"
               append lcmd " --remote_copy_protocol $astk::config(-1,remote_copy_protocol)"
               append lcmd " --signal=USR1"
               set argu "$num $nom $mode $noeud"
               set retour [ashare::rexec_cmd $astk::inv(cmpl,$machexe,$user) astk::config $lcmd $argu 1 out $asjob::fen_root]
            } else {
               set out [ashare::mess ihm 360]
               ashare::mess erreur 47 $machexe $user
            }
         } else {
            set asjob::status "<ALARME> état du job = $etat"
         }
      }
   }
}

#### ============
proc textLoadFile {w file} {
#### ============
# Cette procédure permet de charger le contenu du fichier "file" dans un
# widget de type Text.
#
# Arguments:
# w    : Nom d'une fenetre de type text
# file : Nom du fichier à charger
   if [file exist $file] {
      set f [open $file]
      $w delete 1.0 end
      while {![eof $f]} {
         $w insert end [read $f 10000]
      }
      close $f
   }
}
#### ===========
proc lbxLoadFile {w file} {
#### ===========
# Cette procédure permet de charger le contenu du fichier "file" dans un
# widget de type Listbox.
#
# Arguments:
# w    : Nom d'une Listbox
# file : Nom du fichier à charger
   if [file exist $file] {
      set f [open $file]
      $w delete 0 end
      while {![eof $f]} {
         set line ""
         if { [gets $f line] > 0 } {
            if { [llength $line] != $asjob::maxarg } {
               ashare::mess erreur 11
               for {set j [llength $line]} {$j < $asjob::maxarg} {incr j} {
                  append line " UNKNOWN"
               }
            }
            $w insert end $line
         }
      }
      close $f
   }
}
#### ==========
proc editJobSel {w type} {
#### ==========
# edition du job selectionne
# Arguments:
# w : widget listbox
# type      output/error
#
   global env

   if { [$w curselection] == "" } {
      set asjob::status "<ALARME> Sélectionner tout d'abord un job !"
   } else {
      set indsel [$w curselection]
      for {set i 0} {$i < [llength $indsel]} {incr i} {
         set nsel [lindex $indsel $i]
         set sel  [lindex $asjob::Jobs $nsel]
      # on appelle le service as_edit
         set num     [lindex $sel [lindex $asjob::paraJob(numero) 0]]
         set nom     [lindex $sel [lindex $asjob::paraJob(nom) 0]]
         set mode    [lindex $sel [lindex $asjob::paraJob(mode) 0]]
         set machexe [lindex $sel [lindex $asjob::paraJob(machine) 0]]
         set user    [lindex $sel [lindex $asjob::paraJob(user) 0]]
         set etat    [lindex $sel [lindex $asjob::paraJob(etat) 0]]
         if { $etat == "ENDED" } {
            set retour -1
            set is [valid_serveur $machexe $user nom_complet]
            set out ""
            if { $is == -888 } {
               set out "Serveur dans l'état off"
            } elseif { $is != -999 } {
               set lcmd ""
               append lcmd [file join $astk::config($astk::inv(cmpl,$machexe,$user),rep_serv) as_serv]
               append lcmd " as_edit"
               append lcmd " --remote_shell_protocol $astk::config(-1,remote_shell_protocol)"
               append lcmd " --remote_copy_protocol $astk::config(-1,remote_copy_protocol)"
               set displ $ashare::DISPLAY
               set argu "$num $nom $mode $type $displ"
               set retour [ashare::rexec_cmd $astk::inv(cmpl,$machexe,$user) astk::config $lcmd $argu 1 out $asjob::fen_root]
            } else {
               set out [ashare::mess ihm 360]
               ashare::mess erreur 47 $machexe $user
            }
            # rem : en background, le code retour vaut toujours 0
            if { $retour == 4 } {
               set asjob::status "<ERREUR> Edition $num $nom : Fichier non trouvé"
            } elseif { $retour != 0 } {
               set asjob::status "<ERREUR> Edition $num $nom Code retour : $retour"
            } else {
               set asjob::status "<INFO> Edition $num $nom"
            }
         } else {
            set asjob::status "<ALARME> état du job = $etat"
         }
      }
   }
}
#### ==========
proc tailJobSel { w } {
#### ==========
# edition du job selectionne
# Arguments:
# w : widget listbox
   global expr_tail
#
   if { [$w curselection] == "" } {
      set asjob::status "<ALARME> Sélectionner tout d'abord un job !"
   } else {
      lire_job asjob::TextJobs $asjob::NomSuivi
      set indsel [$w curselection]
      set nsel   [lindex $indsel 0]
      $w selection clear 0 end
      $w selection set $nsel
      set sel  [lindex $asjob::Jobs $nsel]
  #
  # on appelle le service as_tail
  #
      set num     [lindex $sel [lindex $asjob::paraJob(numero) 0]]
      set nom     [lindex $sel [lindex $asjob::paraJob(nom) 0]]
      set mode    [lindex $sel [lindex $asjob::paraJob(mode) 0]]
      set machexe [lindex $sel [lindex $asjob::paraJob(machine) 0]]
      set user    [lindex $sel [lindex $asjob::paraJob(user) 0]]
      set etat    [lindex $sel [lindex $asjob::paraJob(etat) 0]]
      if { $etat == "RUN" } {
         set nb        $astk::config(-1,nb_ligne)
         set output    [file join $astk::tmpdir output]
         file delete -force $output
         if { [ashare::meme_machine $astk::config(-1,nom_complet) $machexe] 
           && $astk::config(-1,login) == $user } {
            set r_output  "$output"
         } else {
            set r_output  "$astk::config(-1,login)@$astk::config(-1,nom_complet):$output"
         }
         set retour -1
         set is [valid_serveur $machexe $user nom_complet]
         set out ""
         if { $is == -888 } {
            set out "Serveur dans l'état off"
         } elseif { $is != -999 } {
            set lcmd ""
            append lcmd [file join $astk::config($astk::inv(cmpl,$machexe,$user),rep_serv) as_serv]
            append lcmd " as_tail"
            append lcmd " --remote_shell_protocol $astk::config(-1,remote_shell_protocol)"
            append lcmd " --remote_copy_protocol $astk::config(-1,remote_copy_protocol)"
            set argu "$num $nom $mode $r_output $nb $expr_tail"
            set retour [ashare::rexec_cmd $astk::inv(cmpl,$machexe,$user) astk::config $lcmd $argu 0 out $asjob::fen_root]
         } else {
            set out [ashare::mess ihm 360]
            ashare::mess erreur 47 $machexe $user
         }
         if { $retour == 1 } {
            set asjob::status "<INFO> Consultation $num $nom : Echec, essayez 'Actualiser'"
         } elseif { $retour == 2 } {
            set asjob::status "<INFO> Consultation $num $nom : Fichier vide !"
         } elseif { $retour == 3 } {
            set asjob::status "<ERREUR> Consultation $num $nom : Problème de copie"
         } elseif { $retour == 4 } {
            if { [regexp {ETAT[ ]*=[ ]*([a-z_A-Z]+)} $out match etat] == 0 } { set etat "_" }
            set asjob::status "<INFO> Consultation $num $nom : état $etat"
            set j1 [lindex $asjob::paraJob(etat) 0]
            set sel [lreplace $sel $j1 $j1 $etat]
            array set asjob::TextJobs [list $num $sel]
            sauv_job asjob::TextJobs $asjob::NomSuivi
            lbxLoadFile $w $asjob::NomSuivi
         } else {
            set asjob::status "<INFO> Consultation  $num $nom"
            textLoadFile $asjob::actu(f_tail) $output
            $asjob::actu(f_tail) yview end
         }
      } else {
         $asjob::actu(f_tail) delete 1.0 end
         set asjob::status "<ALARME> état du job = $etat"
      }
   }
}
#### ============
proc reactu_jobs  { } {
#### ============
   if { $asjob::actu(indic) == 1 && $astk::config(-1,freq_actu) > 0 } {
      loadStateJob $asjob::actu(f_actu)
      set val_ms [expr $astk::config(-1,freq_actu) * 60 * 1000]
      set asjob::actu(id_after) [after $val_ms {reactu_jobs}]
   } else {
      if { $asjob::actu(id_after) > 0 } {
         after cancel $asjob::actu(id_after)
         set asjob::actu(id_after) 0
      }
   }
}
#### ============
proc affiche_main { w } {
#### ============
#
#  Affichage de la fenetre principale contenant :
#     1 - barre de status (widget label)
#     2 - SUPPRIME (menu)
#     3 - ensemble de boutons (widget button)
#     4 - zone d'affichage des jobs (widget listbox)
#     5 - ligne de texte de recherche (widget entry)
#     6 - zone d'affichage du contenu des fichiers (widget listbox)
#
   global tk_version
   global loadStateJob_lock
   set asjob::actu(id_after) 0

   set but_fnt  $astk::ihm(font,labbout)
   set lbx_fnt  $astk::ihm(font,txtfix)

   set asjob::window $w
   destroy $w
   pack [frame $w -bd 0] -expand yes -fill both
#
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Liste des frames
   set use_panedwindow 1
   if { $tk_version < 8.4 } {
      set use_panedwindow 0
   }

   set fensuiv $w.princ.suivi
   set ftail $w.princ.fen_tail
   set fstat $w.statusbar
#
   set asjob::actu(f_actu) $fensuiv.ftx1.lbx
   set asjob::actu(f_tail) $ftail.lbx2
#  Barre de status
   pack [frame $fstat] -side bottom -fill x -pady 2

   if { $use_panedwindow } {
   #  jobs et boutons
      pack [panedwindow $w.princ -orient vertical] -anchor nw -expand 1 -fill both
      $w.princ add [frame $fensuiv] -sticky nsew -minsize 75
         # Listbox utilisée pour afficher la liste des travaux
         grid [frame $fensuiv.ftx1] -row 0 -column 0 -sticky nsew
         # Liste des boutons situés à droite
         set fbout $fensuiv.bout
         grid [frame $fbout] -row 0 -column 1 -sticky ew -padx 5
         grid rowconfigure $fensuiv 0 -weight 1
         grid columnconfigure $fensuiv 0 -weight 1
   #  Zone d'affichage du fichier message
      $w.princ add [frame $ftail] -sticky nsew -minsize 35
   } else {
   #  jobs et boutons
      pack [frame $w.princ] -anchor nw -expand 1 -fill both
      grid [frame $fensuiv] -row 0 -column 0 -sticky nsew
         # Listbox utilisée pour afficher la liste des travaux
         grid [frame $fensuiv.ftx1] -row 0 -column 0 -sticky nsew
         # Liste des boutons situés à droite
         set fbout $fensuiv.bout
         grid [frame $fbout] -row 0 -column 1 -sticky ew -padx 5
         grid rowconfigure $fensuiv 0 -weight 1
         grid columnconfigure $fensuiv 0 -weight 1
   #  Zone d'affichage du fichier message
      grid [frame $ftail] -row 1 -column 0 -sticky nsew
      grid rowconfigure $w.princ 0 -weight 1
      grid rowconfigure $w.princ 1 -weight 2
      grid columnconfigure $w.princ 0 -weight 1
   }
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Liste des boutons situés à droite
#
   set m  $fbout.file.m
   menubutton $fbout.file -text "Editer" -font $but_fnt -menu $m -relief raised
   menu $m -tearoff 0
   $m add command -label "Fichier output" -underline 8 -font $but_fnt -command "editJobSel $fensuiv.ftx1.lbx output"
   $m add command -label "Fichier error"  -underline 8 -font $but_fnt -command "editJobSel $fensuiv.ftx1.lbx error"
   grid $fbout.file -row 0 -column 0 -sticky ew -pady 5

   button $fbout.su -text "Supprimer " -font $but_fnt -command "suppr_job $fensuiv.ftx1.lbx"
   grid $fbout.su   -row 1 -column 0 -sticky ew -pady 5

   # initialise le verrouillage
   set loadStateJob_lock 0
   button $fbout.ac -text "Actualiser " -font $but_fnt -command "loadStateJob $fensuiv.ftx1.lbx"
   grid $fbout.ac   -row 2 -column 0 -sticky ew -pady 5

   checkbutton $fbout.cb -variable asjob::actu(indic) -command "reactu_jobs"
   grid $fbout.cb   -row 2 -column 1 -sticky w -pady 5
   
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Listbox utilisée pour afficher la liste des travaux
#
   listbox $fensuiv.ftx1.lbx -xscrollcommand "$fensuiv.ftx1.scrollx set" -yscrollcommand "$fensuiv.ftx1.scrolly set" \
      -selectmode extended -height 10 -width 80 -font $lbx_fnt -bg white -setgrid true -listvar asjob::Jobs
   scrollbar $fensuiv.ftx1.scrolly -command "$fensuiv.ftx1.lbx yview"
   scrollbar $fensuiv.ftx1.scrollx -command "$fensuiv.ftx1.lbx xview" -orient h

   pack $fensuiv.ftx1.scrolly -side right  -fill y
   pack $fensuiv.ftx1.scrollx -side bottom -fill x
   pack $fensuiv.ftx1.lbx -expand yes -fill both

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Champ utilisé pour la recherche d'expressions régulières dans le fichier message
#
   frame  $ftail.filtre
   label  $ftail.filtre.label -text "Filtre :" -font $but_fnt -anchor w
   entry  $ftail.filtre.entry -width 40 -textvariable expr_tail
   button $ftail.filtre.button -text "Rechercher " -font $but_fnt -command "tailJobSel $fensuiv.ftx1.lbx"
   pack   $ftail.filtre.label -side left
   pack   $ftail.filtre.entry -side left -expand yes -fill x
   pack   $ftail.filtre.button -side left -pady 5 -padx 10
   focus  $ftail.filtre.entry
   pack   $ftail.filtre -expand no -fill x

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Zone de texte pour afficher le fichier message
#
   text $ftail.lbx2 -xscrollcommand "$ftail.scrollx set" -yscrollcommand "$ftail.scrolly set" \
      -height $asjob::size(h,f_tail) -width $asjob::size(w,f_tail) -font $lbx_fnt -bg white
   scrollbar $ftail.scrolly -command "$ftail.lbx2 yview"
   scrollbar $ftail.scrollx -command "$ftail.lbx2 xview" -orient h
   pack $ftail.scrolly -side right  -fill y
   pack $ftail.scrollx -side bottom -fill x
   pack $ftail.lbx2    -expand yes -fill both

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Barre de status : affichage des erreurs, alarmes et informations
#     status :  contient le message à afficher
   label $fstat.label -textvariable asjob::status -relief sunken -bd 1 -font $lbx_fnt -anchor w
   pack $fstat.label -side left -padx 2 -expand yes -fill both

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#  Affichage de la liste des jobs depuis le fichier stocké sur le client
#
   if { [file exists $asjob::NomSuivi] } {
      lbxLoadFile $fensuiv.ftx1.lbx $asjob::NomSuivi
      $fensuiv.ftx1.lbx yview end
   }

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#  récupération de la sélection par double clic
#
   bind $fensuiv.ftx1.lbx <Double-Button-1> {
      set ficsel [selection get]
      set asjob::status "<INFO> Job [lindex $ficsel [lindex $asjob::paraJob(numero) 0]]"
      editJobSel %W output
   }

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#  récupération de la sélection par simple clic
#
   bind $fensuiv.ftx1.lbx <<ListboxSelect>> {
      set list_ [%W curselection]
      if {[llength $list_] == 1 } {
         set asjob::status "<INFO> Job [lindex [lindex $asjob::Jobs $list_] 0]"
      } else {
         set asjob::status ""
      }
   }

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#  récupération de la sélection par clic droit
#
   bind $fensuiv.ftx1.lbx <3> {
      set id @%x,%y
      if { [%W selection includes $id] == 0 } {
         %W selection clear 0 end
      }
      %W selection set $id
      set ficsel [%W get $id]
      set asjob::status "<INFO> Job [lindex $ficsel [lindex $asjob::paraJob(numero) 0]]"
      tk_popup $asjob::popup %X %Y
   }

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#  ctrl+Q pour fermer
   bind $asjob::fen_root <Control-Key-Q> "set asjob::actu(indic) 0;destroy $asjob::fen_root"
   bind $asjob::fen_root <Control-Key-q> "set asjob::actu(indic) 0;destroy $asjob::fen_root"

   update
   wm geometry $asjob::fen_root $asjob::size(root)
# ne marche pas bien : la fenetre se maximise !?
#    ashare::trace_geom asjob $asjob::fen_root

   # initialisation du popup menu
   if { ! [winfo exists $asjob::popup] } {
      asjob_popup $w.princ.suivi $asjob::popup
   }
}

# construit le popup menu
#################################################################
proc asjob_popup { fensuiv m } {
   menu $m -tearoff 0 -bd 1
   $m add command -label "Editer output" -font $astk::ihm(font,labmenuB) -command "editJobSel $fensuiv.ftx1.lbx output"
   $m add command -label "Editer error" -font $astk::ihm(font,labmenu)  -command "editJobSel $fensuiv.ftx1.lbx error"
   $m add separator
   $m add command -label "Actualiser" -font $astk::ihm(font,labmenu) -command "loadStateJob $fensuiv.ftx1.lbx 1"
   $m add command -label "Actualiser tous" -font $astk::ihm(font,labmenu)  -command "$fensuiv.bout.ac invoke"
   $m add separator
   $m add command -label "Supprimer" -font $astk::ihm(font,labmenu)  -command "$fensuiv.bout.su invoke"
   $m add command -label "Interrompre USR1" -font $astk::ihm(font,labmenu)  -command "susp_job $fensuiv.ftx1.lbx"
   $m add command -label "Purger flasheur" -font $astk::ihm(font,labmenu)  -command "purge_job"
}

