#f file.tcl - gestion des fonctionnalites liees au fichier (menu file)
#f sauvegarde, lecture, insertion de fichier ou de resultat de commande,
#f generation de fichiers temporaires.
# 
# $Id:  $

package provide stead 2.0

## stead:write w filename - write out a file
# 
proc stead:write {w filename} {
    global stead
    global EDITPREFS
    
    if {[info procs stead:write_pre_hook] != {}} {
        stead:write_pre_hook $filename $w
    }
    
    if {[info procs stead:write_inside_hook] != {}} {
    
        stead:write_inside_hook $filename $w
      
    } else {
    
        # should do error checking
        ####################################################################
        # DEBUT ENCOURS
        set ENCOURS {
        if {$EDITPREFS(saveoldfile)} {
             # création éventuelle du répertoire de sauvegarde :
             file mkdir $EDITPREFS(saveoldfiledir)
             
             # calcul du nom du fichier de sauvegarde :
             set bakName ${filename}[random 1000000000][random 1000000000]
             
             # write_file "$EDITPREFS(saveoldfiledir)/${filename}" \
             #    "*** FILENAME: ${filename}\n[read_file ${filename}]
             file_write "$EDITPREFS(saveoldfiledir)/${filename}" \
                "*** FILENAME: ${filename}\n[file_read ${filename}]
                
             catch {eval [list file copy -- ${filename} ${filename}~]}
        }
        }
        # FIN ENCOURS
        ####################################################################
        
        if {$EDITPREFS(saveoldfile)} {
             file copy -force ${filename} ${filename}~
        }
        set file [open $filename {w}]
        if {"x$EDITPREFS(encoding)" != "xauto"} {
             fconfigure $file -encoding $EDITPREFS(encoding)
        }
        
        # modif diam 21/08/00 (suppression du dernier caractere et cleanup)
        # puts $file [$w get 1.0 end] nonewline
        puts -nonewline $file [$w get 1.0 end-1c] 
        
        stead:updateFileLabel 
        flush $file
        # diam 08/07/04 flush pour assurer la syncronisation sur les FS 
        # journalisés §macOSX)
        close $file
        # si la préférence  est positionnée, on sauve aussi l'état du fichier
        set state ""
        
        set msg "[lindex [split [.main.t index end] .] 0] lines, \
                [file size $filename] characters $state"  
                
        stead:log -long 0  $msg
    }
    if {[info procs stead:write_post_hook] != {}} {
         stead:write_post_hook $filename $w
    }
}


## stead:save - write out a file, using $FILENAME if defined
# 
proc stead:save {{w .main.t}} {
    global stead
    global EDITPREFS

    # Si stead(readonly) à 1 : on ne doit pas modifier le fichier original
    if {$stead(readonly)} then {
        return [stead:saveas]
    } 
    
    if {![string length $stead(file)]}  {
        return [stead:saveas]
    }

    
    # # set stead(file) [file:normalName $prompt_result]
    stead:write $w $stead(file) 
    if {$EDITPREFS(clearUndoOnSave)} {
        xtext_undoInit
    }
    xtext_markClean $w
}

## stead:saveas - write out a file, prompting for a filename 
# 
proc stead:saveas {{w .main.t}} {
    global stead
    global EDITPREFS

    set prompt_result [xtk_fsBox -prompt "Save as:"]
    
    if { ![string length $prompt_result]} {
        # Opération annulée par l'utilisateur
        return 0
    }
    
    if {[file exists $prompt_result]} {
        set reply [stead:messageBox   \
                -message  "File \"$prompt_result\" exists, replace it?" \
                -type okcancel \
                -default cancel \
                -title  "Save dialog !"
        ]
        if {$reply == "cancel"} {
            # L'utilisateur ne veut pas remplacer le fichier préexistant
            return 0
        }
    }
    
    # OK : on peut sauvegarder dans un nouveau fichier
    set stead(file) [file:normalName $prompt_result]
    
    # Cette variable à pu être positionnée pour forcer le "save as"
    # on peut la remettre à 0 : 
    set stead(readonly) 0
    
    
    # On peut fair appel à la procédure "Save" standard !
    stead:save $w
    
    
}

## stead:insertFileBox - read in a file and insert it at the insert mark
# 
# 14/08/02 ajout gestion encoding
# 
proc stead:insertFileBox {} {
    global stead 
    global EDITPREFS
    
    set w $stead(text)
    set prompt_result [xtk_fsBox -prompt "Insert:"]
    if {$prompt_result != ""} then {
        xtext_pushState
        
        set txt  [file_read \
                    -encoding $EDITPREFS(encoding) \
                    $prompt_result]

        $w insert insert $txt
        
        # # # commenté par diam le 14/08/02 et remis ç
        # # # # # # $w insert insert "\n"
        $w insert insert "\n"

        xtext_markDirty .main.t
    }
}


## stead:quitBox - quit the editor
# 
proc stead:quitBox {} {
    global stead
    if {[info procs stead:quit_pre_hook] != {}} {
        stead:quit_pre_hook .main.t
    }
    if {[stead:saveIfDirtyBox] != 0} {
        destroy .
    }
}

## stead:loadBox - read in a file
# 
proc stead:loadBox {{w .main.t}} {
    global stead
    
    if { [stead:saveIfDirtyBox] == 0 }  {
        stead:log "\"load\" operation canceled by user"
        return 
    }

    # set prompt_result [file:normalName [xtk_fsBox -prompt "Load:"]]
    set fileName [xtk_fsBox -prompt "Load:"]
    if {! [string length $fileName]} { 
        stead:log "\"load\" file operation canceled by user"
        return 
    } 
    set fileName [file:normalName $fileName]
    
    # Nettoyage du mode précédent
    stead:modeRemove $stead(mode)


    # $fileName contient à priori un nom de fichier.
    # Si ce fichier n'existe pas, c'est qu'on veut en créer un nouveau
    if { ![file isfile $fileName] || ![file readable $fileName] } {
        stead:log "load : new file to be create"
    }
    set stead(file) $fileName
    
    stead:read $stead(file)
    
    stead:modeApply  [stead:modeGuess $stead(file)]
    
    xtext_undoInit
    xtext_markClean $w

}

## stead:openBox - Open a file
# 
proc stead:openBox {} {
    global stead
    set fileName [xtk_fsBox -prompt "Open:"]
    if {$fileName != {}} then {
        stead:log -long 0 "Edit File [file tail $fileName]"
        stead $fileName 
    }
}


## stead:openSelectedFile - ouvre le fichier indiqué (sélectionné ou autre...) 
# 
proc stead:openSelectedFile {} {
    global stead
    upvar 0 stead(text) w
    
    set file [stead:guessSelectedFile]
    
    if {[string length $file]} {
        stead $file
        # Modi diam 16/06/03 
        # On impose l'affiche sur la ligne de status (sans lancer stead)
        stead:log -long 0  "Ouverture du fichier \"$file\""
        return 1
    } else {
        stead:log -error "Aucun fichier trouvé pour l'ouverture."
        return 0
    }
    
}

## stead:guessSelectedFile - retourne le nom d'un fichier indiqué
# 
# Retourne le nom d'un fichier "indiqué" ou vide
# - si la sélection correspond à un nom de fichier existant : retourne ce nom
# - si un des fichiers du répertoire courant est contenu dans la sélection :
#   retourne le nom de ce fichier
# - si un des fichiers du répertoire courant est contenu dans la ligne 
#   courante : retourne le nom de ce fichier
# - sinon retourn ""
# 
proc stead:guessSelectedFile {} {
    global stead
    upvar 0 stead(text) w
    set txt [xtext_getSel $w]
    if {[string length $txt] && [file isfile $txt]} {
        return $txt
    }
    
    # si non trouvé, on cherche si la sélection englobe un nom de fichier
    # existant dans le répertoire courant
    set files [glob -nocomplain *]
    foreach file $files {
        if {[regexp -- "(?q)$file" $txt]} {
            return $file
        }
    }
    
    # si non trouvé, on cherche si la ligne courant englobe un nom de fichier
    # existant dans le répertoire courant
    set txt [$w get "insert linestart" "insert lineend"]
    set files [glob -nocomplain *] ;# oui, je sais : c'était déja fait...
    foreach file $files {
        if {[regexp -- "(?q)$file" $txt]} {
            return $file
        }
    }
    return ""
}


## te:cmd:open_same_file - ouvre le meme fichier     
# 
proc te:cmd:open_same_file {} {
    global stead

    if [info exists stead(file)] {
        stead:log "Warning : Opening Same File !"
        stead $stead(file) 
    } else {
        stead:log "Save File First"
    }
}

## te:cmd:execute_sel - évalue la selection
# 
proc te:cmd:execute_sel {} {
    global stead
    set script [xtext_getSel $stead(text)  -ifnosel empty]
    if {[string length $script]} {
        set result [uplevel #0 $script]
        stead:log  "Évaluation de la sélection : $result"
    }
}

## te:cmd:execute_clip - evalue le presse-papier
# 
proc te:cmd:execute_clip {} {
    global xtext
    set script $xtext(buf,clip,data)
    if {[string length $script]} {
        set result [uplevel #0 $script]
        stead:log  "Évaluation du presse-papier : $result"
    }
}

## te:cmd:calculate_sel - calcule la selection (en tant que expression TCL)
# 
# à renommer en xtext_evalExprSel
# 
# Le texte sélectionné est tout d'abord évalué en tant qu'expression TCL.
# Si pas d'erreur : affichage du résultat 
# Si erreur : on essaie de calculer la somme de tous les nombres de la 
#   selection (pratique pour calculer la somme de la colonne sélectionnée !).
# 
# Exemple : 
#  la selection contient : 2 * 2e1 + sin (45)   => affiche : 40.8509
#  la selection contient : 2 * 2z1 + sin (45)   => affiche : 50
#  la selection contient : 1000 200 50 <LineBreak> -7   => affiche : 1243
# 
proc te:cmd:calculate_sel {} {
    global stead
    set sel [xtext_getSel $stead(text)]
    if {[string length $sel]} {
        if {![catch {expr $sel} result]} {
            stead:log "Calcul de la sélection: $result"
        } else {
            te:cmd:addition_sel
        }
    }
}

## te:cmd:addition_sel - calcule le somme des nombres contenus dans la selection
#    
proc te:cmd:addition_sel {} {
    global stead
    set sel [xtext_getSel $stead(text)]
    set msg "Sum of all numbers in selection result: [stringSum $sel]"
    stead:log $msg
}


## te:cmd:reset_To_last_save - recharge le fichier
# 
proc te:cmd:reset_to_last_save {{w .main.t}} {
    global stead

    if { ![info exist stead(file)] } {
        stead:log "No file to reload!"
        return
    }
    if {[xtext_isDirty $w]} {
        set msg "All Edits will be discarded!\
                 \nContinue?"
        set reply [stead:messageBox                   \
                -type okcancel                        \
                -default ok                       \
                -message $msg                         \
                -title  "Reset to Last Save"          \
        ]
        if {$reply == "cancel"} {
            return
        } else {
            xtext_markClean $w
            xtext_undoInit
        }
    }
    # On essaie de restituer le point d'insertion (appriximativement
    # en fonction des modification faite !
    set idx [$w index insert]
    stead:read $stead(file)
    $w mark set insert $idx
    $w see insert
}

proc te:cmd:save_sel_as {{w .main.t}} {

    global stead
    global EDITPREFS
    if { ![xtext_hasSel $w] } {
        stead:log "There is no selection to save!"
    } else {
        set selection [xtext_getSel $w]
        set prompt_result [xtk_fsBox -prompt "Save Selection as:"]
        
        if {![string length $prompt_result]} {
            stead:log "\"Save sel as\" canceled by user!"
            return
        }
        
        if {[file exists $prompt_result]} {
            set reply [stead:messageBox   \
                    -message  "File \"$prompt_result\" exists, replace it?" \
                    -type okcancel \
                    -default cancel \
                    -title  "Save dialog !"
            ]
            if {$reply == "cancel"} {
                # L'utilisateur ne veut pas remplacer le fichier préexistant
                return
            }
        }

        set filename [file:normalName $prompt_result]
        stead:log "Writing File..."
        
        # should do error checking
        set file [open $filename {w}]
        if {"x$EDITPREFS(encoding)" != "xauto"} {
             fconfigure $file -encoding $EDITPREFS(encoding)
        }
        
        puts $file $selection
        close $file
        
        stead:log -long 0  "Written in File $filename." 
    }
}
 
##  te:cmd:show_file_info - display informations on file
# 
# A REFONDRE MULTIPLATEFORM !
# 
proc te:cmd:show_file_info {} {

    global stead
  
    if {"x$stead(file)" == "x"} {
        stead:log "File Does Not Exist"
    } else {
        file stat $stead(file) infos
        
        append result "File name:                             "
        append result " [file type $stead(file)]\n"
        
        append result "Inode file number:                     " 
        append result "$infos(ino)\n" 
        
        append result "File Type :                            "
        append result "[file type $stead(file)]\n"

        # append result "File Owned by:                         "  
        # append result "[te:sys_file_owner $stead(file)]\n"  
          
        # append result "Time of Last Modification:             "
        # append result "[te:sys_last_modif $stead(file)]\n"  
        
        # append result "Mode Bits for File:                    "
        # append result "[te:sys_mode_bits $stead(file)] ($infos(mode))\n"  
        
        append result "Number of Links to File:               "  
        append result "$infos(nlink)\n"  
        
        append result "Size of File in Bytes:                 "  
        append result "$infos(size)\n"  
        
        append result "Time of Last Access:                   "  
        append result "$infos(atime)\n"  
        
        append result "Time of Last Status Change:            "  
        append result "$infos(ctime)\n"  
        
        append result "Identifier for Device Containing File: "  
        append result "$infos(dev)\n"  
        
        append result "Identifier for the file's group:       "  
        append result "$infos(gid)\n"  
        
        append result "User id: "  
        append result "$infos(uid)\n"  
        
        stead:log -title "$stead(file) : File Informations" \
                  -text $result
    }
}

## stead:saveIfDirtyBox - demande pour sauvegarder si nécessaire
# 
# A renommer en stead:saveIfDirtyBox
# qui retourne 
#   0 : si l'opération a été annulée par l'opérateur
#   1 : si pas voulu sauvegarder, mais on veut continuer l'opération
#   2 : si on veut sauvegarder, puis on veut continuer l'opération
# 
proc stead:saveIfDirtyBox {{w .main.t}} {

    global stead

    if { ![xtext_isDirty $w]} {
        # rien a faire : on peut quitter le texte est conforme au disque
        return 1
    }
    
    if {[string length $stead(file)] == 0} then {   
        set fname "Untitled"
        # # unset stead(file)
    } else {
        set fname $stead(file) 
    }
    set msg "$fname has been modified.\nDo you want to save it first?" 
    set choice [tk_dialog  .conf "Save Dialog" $msg question 2 \
            "Cancel"\
            "Don't Save"\
            "Save" \
    ]
    
    if {$choice == 2} {
        stead:save $w
    }
    return $choice
    
}


## stead:insertUnixResult - prompt for a Unix command to insert
# 
# modif :
#    diam 22/10/98 
#    diam 30/11/99 refonte 
# 
# Les commandes suivantes passent correctement :
# 
#     ls -al *log
#     ls -al *2b* *7b*
#     grep "    maxbuy = "  *.log
#     grep {  *.log
#     grep " [mM][cC][aA][pP]=" *.log
# 
proc stead:insertUnixResult {} {
    global stead
    global errorCode
                       
    set result [stead:getUnixResult]
    
    if {[string length $result]} {
        append result "\n"
        
        # save undo information
        xtext_pushState
        
        .main.t insert insert $result
        
        # text modified
        xtext_markDirty .main.t
    }
}

## stead:editUnixResult - prompt for a Unix command to edit
# 
# création diam 30/11/99
# 
# Les commandes suivantes passent correctement :
#     ls -al *log
#     ls -al *2b* *7b*
#     grep "    maxbuy = "  *.log
#     grep {  *.log
#     grep " [mM][cC][aA][pP]=" *.log
# 
# A FAIRE :
#   - Compléter la boite de dialogue
#   - options  
#       -dir <fromDirectory>
#       -defaultcommand <cmd>
#       -dowithresult  tofile ? edit ? ignore ? insert 
# 
proc stead:editUnixResult { {cmd ""} } {
    global stead
    global errorCode
    
    set result [stead:getUnixResult $cmd]
    
    if {[string length $result]} {
        stead -text $result
    } else {
        stead:log -text "No output from edit."
    }
}


## stead:getUnixResult -- 
# 
# création diam 08/12/99
# 
# Exécute une commande unix (via le bourne shell), et retourne le 
# résultat (sans rien en faire).
# 
# parametre :
# 
# cmd (optionnelle) : commande à exécuter
#     en cas d'absence : une commande est demandée
# subst (optionnelle) : 
#    si 1 (défaut) alors on fait une substutution par tcl
#    si 0 : pas de substutution
# 
# En cas d'erreur, le résultat fourni commence par "ERREUR : "
# 
# A FAIRE : options supplémentaires :
#   -dir <fromDirectory>
# 
proc stead:getUnixResult { {cmd ""} {subst 1} } {
    global stead
    global errorCode
    
    if {![string length $cmd]} {
        set cmd [te:prompt -text "Unix Command:" \
                           -default $stead(unixCommand)]
    }
    
    set result ""
    if {[string length $cmd]} then {
    
        set stead(unixCommand) $cmd
        
        if {!$subst} {
            # On cache les caracteres speciaux pour TCL
            regsub -all {([][$\\"])} $cmd {\\\1} cmd
        }
        
        # on forcera le passage par un shell (qui pourra intrepreter les "*"...)
        set shellCmd "/bin/sh -c \"$cmd\" "
        
        # # # if {[catch {eval exec $shellCmd} result]} { xxx}
        if {[catch {uplevel #0 exec $shellCmd} result]} {
           set result "ERREUR : $shellCmd\n$errorCode\n$result"
        }
    }
    return $result
}


## stead:tmpFile - retourne un nom de fichier temporaire
# 
# Construit un nom de fichier temporaire en conservant le suffixe (lié au mode)
# et en se basant sur le nom du fichier courant.
# 
# tryName : le nom de base du fichier à créer (e.g. : myTmp.tex)
#         le suffix est conserver dans le vrai nom final (e.g. ".tex") 
#         pratique pour l'impression...
# dir: le répertoire destinataire (e.g. : /tmp)
# 
# modif diam le 07/10/2005
#   gestion des répertoire par défaut suite à des pb sous windows (et cygwin)
#   Les variable d'environnement TMP et TEMP était positionnées sur un 
#   répertoire inexistant !
# 
# Version initiale de tkMail
# 
proc stead:tmpFile { {tryName tmp} {dir ""} } {
    global env

    set rootName   [file rootname  $tryName]
    set suffix     [file extension $tryName]
    
    # les répertoires temporaires candidats
    set dirs [list]
    
    # le parametre dir sera le répertoire de choix prioritaire
    if {"x$dir" != "x"} {
        lappend dirs $dir
    }
    catch {lappend dirs $env(TMPDIR)}
    
    switch -exact -- $::tcl_platform(platform) {
      unix {
        lappend dirs /tmp
      } 
      macintosh {
        lappend dirs $env(TRASH_FOLDER)
      } 
      windows -
      default {
        # Ces variables n'existent pas nécessairement !
        catch {lappend dirs $env(TMP)}
        catch {lappend dirs $env(TEMP)}
      } 
    } 
    foreach dir $dirs {
        catch {file mkdir $dir}
        if {[file isdir $dir] && [file writable $dir]} {
            # on adopte ce répertoire
            break
        }
    }
    
    # On peut ne rien avoir trouvé comme répertoire !
    if {![file writable $dir]} {
        error "$dir is not a writable directory"
    }

    set cnt 0
    # on commence par un nom de fichier sans numéro
    set fileName [file join $dir $rootName$suffix]
    while {[file exists $fileName]} {
        incr cnt
        if {$cnt > 9999} {
            return {}
        }
        set fileName [file join $dir $rootName-[format "%04d" $cnt]$suffix]
    }
    return $fileName
}
# # proc stead:tmpFile { {tryName tmp} {dir ""} } {
# #     global env
# # 
# #     # TODO : Renommer complétement les variables
# #     # 
# #     # set rootName [file rootname $tryName]
# #     # set suffix   [file extension $tryName]
# #     set str   [file rootname $tryName]
# #     set suf   [file extension $tryName]
# # 
# #     if {$dir == "" || ![file isdirectory $dir]} {
# #         if {[info exists env(TMPDIR)]} {
# #             set dir $env(TMPDIR)
# #         } else {
# #             global tcl_platform
# #             switch -exact -- $tcl_platform(platform) {
# #               unix {
# #                 set dir /tmp
# #               } 
# #               macintosh {
# #                 set dir $env(TRASH_FOLDER)
# #               } 
# #               windows -
# #               default {
# #                 # set dir /tmp
# #                 set dir [pwd]
# #                 catch {set dir $env(TMP)}
# #                 catch {set dir $env(TEMP)}
# #               } 
# #             } 
# #         }
# #     }
# # 
# #     if {![file writable $dir]} {
# #         error "$dir is not a writable directory"
# #     }
# # 
# #     set cnt 0
# #     # One begin without the suffix number
# #     set tfile [format "%s" $str] 
# #     while {[file exists [file join $dir $tfile$suf] ]} {
# #         incr cnt
# #         if {$cnt > 9999} {
# #             return {}
# #         }
# #         set tfile [format "%s%04d" $str $cnt]
# #     }
# #     return [file join $dir $tfile$suf]
# # }

## stead:cutToFile - cut selection and put it in the stead clipFile A TESTER
# 
proc stead:cutToFile {} {
    global stead 
    global EDITPREFS
    upvar #0 stead(text) w
    
    if {[xtext_hasSel $w]} {
        xtext_cut $w
        # file_write $stead(clipFile) [xtext_getClip $w]
        file_write -encoding $EDITPREFS(encoding) \
                $stead(clipFile) [xtext_getClip $w]
        return 1
    } else {
        return 0
    }
}
## stead:copyToFile - copy selection and put it in the stead clipFile A TESTER
# 
proc stead:copyToFile {} {
    global stead
    global EDITPREFS
    upvar #0 stead(text) w
    
    if {[xtext_hasSel $w]} {
        xtext_copy $w
        # file_write $stead(clipFile) [xtext_getClip $w]
        file_write -encoding $EDITPREFS(encoding) \
                $stead(clipFile) [xtext_getClip $w]
        return 1
    } else {
        return 0
    }
}

## stead:pastFromFile - copy selection and put it in the stead clipFile A TESTER
# 
proc stead:pastFromFile {} {
    global stead
    global EDITPREFS
    upvar #0 stead(text) w
    
    if {[file isfile $stead(clipFile)]} {
        # set text [file_read $stead(clipFile)]
        set text [file_read -encoding $EDITPREFS(encoding) \
                    $stead(clipFile)]
        xtext_insert $w $text
        return 1
    } else {
        return 0
    }
}

#./
