### Copyright (C) 1995-1997 Jesper K. Pedersen
### 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 the Free Software
### Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.


######################################################################
### This is the function, which save a file. If no current save
### file exists, the function saveOrExport will be invoked
######################################################################
proc save {} {
  global __editInfo module
  if {$__editInfo(loadFile) != ""} {
    ### call pageEnd
    if {[checkPage] == 0} return
    saveFile [myGlob ~/].dotfile/$module(name)/save-files/$__editInfo(loadFile)
  } else {
    saveOrExport user-save
  }
}

######################################################################
### This function ask the user for a name for a save file, a
### description of the savefile and then save into this file
######################################################################
proc saveOrExport {type {fileName {}}} {
  global module __system argv __fileName __content
  if {$fileName == ""} {
    ### call pageEnd
    if {[checkPage] == 0} return
  }
  regexp {^user-(.*)$} $type all dir
  
  if {![file exists ~/.dotfile]} {
    eval "exec $__system(mkdir) [myGlob ~/].dotfile"
  }
  if {![file exists ~/.dotfile/$module(name)]} {
    eval "exec $__system(mkdir) [myGlob ~/].dotfile/$module(name)"
  }
  if {![file exists ~/.dotfile/$module(name)/$dir-files]} {
    eval "exec $__system(mkdir) [myGlob ~/].dotfile/$module(name)/$dir-files"
  }

  ### ask the user for a description and a header
  set w [makeTempWindow "$dir - Description"]

  frame $w.filename
  label $w.filename.label -text "Relative file name:"
  entry $w.filename.entry -textvariable __fileName
  button $w.filename.button \
      -bitmap @[lindex $argv 0]/bitmaps/folder_center.xbm \
      -command "
        set __fileName \
            \[lindex \[FileBrowser -dir ~/.dotfile/$module(name)/${dir}-files \
                                      -file \$__fileName -pattern *.$dir \] 0\]
        testIfElmExist $w $type
      "
  bind $w.filename.entry <Return> "testIfElmExist $w $type"
  label $w.filename.after \
      -text "(files will be placed in ~/.dotfile/$module(name)/${dir}-files/)"
  pack $w.filename
  pack $w.filename.label $w.filename.entry $w.filename.button $w.filename.after\
      -side left
  label $w.title -text "Title:"
  text $w.titleText -width 50 -height 4 -wrap word
  label $w.desc -text "Description:"
  text $w.descText -width 50 -height 7 -wrap word
  label $w.command -text \
      "Tcl Command to give more information about $dir file:"
  text $w.commandText -width 50 -height 7
  pack $w.title
  pack $w.titleText -fill both -expand 1
  pack $w.desc
  pack $w.descText -fill both -expand 1
  pack $w.command
  pack $w.commandText -fill both -expand 1

  label $w.help -wraplength 500 -justify left -text "You have to give the $dir file a title and a description. This information is shown in the load page, which comes up when you start the Dotfile Generator, or when you press the \"Reload\" button."
  pack $w.help

  if {$fileName != ""} {
    set edit 1
    set __fileName $fileName
  } else {
    set __fileName ""
    set edit 0
  }
  button $w.ok -text OK -command "saveAsEnd $w $dir ok \$__fileName $edit"
  button $w.cancel -text Cancel \
      -command "saveAsEnd $w $dir cancel \$__fileName 0"
  pack $w.cancel $w.ok -side right

  ### if a file is specified read the elements
  if {$fileName != ""} {
    set __fileName $fileName
    set header [lindex $__content($type,$fileName) 0]
    set function [lindex $__content($type,$fileName) 1]
    set desc [lindex $__content($type,$fileName) 2]
    $w.titleText insert insert $header
    $w.descText insert insert $desc
    $w.commandText insert insert $function
  }
  
  ### wait until the user is finished
  tkwait window $w
}

proc testIfElmExist {w type} {
  global __fileName __content
  if {[info exists __content($type,$__fileName)]} {
    set header [lindex $__content($type,$__fileName) 0]
    set function [lindex $__content($type,$__fileName) 1]
    set desc [lindex $__content($type,$__fileName) 2]
    $w.titleText insert insert $header
    $w.descText insert insert $desc
    $w.commandText insert insert $function
  }
}

######################################################################
### This function is called when the user have inserted the
### information to the saveAs dialogbox
######################################################################
proc saveAsEnd {path type method fileName edit} {
  global __content module __editInfo __activeNivau

  if {$method == "ok"} {
    if {!$edit && [file dirname $fileName] != "."} {
      tk_dialog .error "Error" "The filename may not not be with a path!"\
          error 0 OK
      return
    }

    if {![regexp ".$type\$" $fileName]} {
      set fileName "$fileName.$type"
    }
    if {[file exists [myGlob ~/].dotfile/$module(name)/$type-files/$fileName] &&
      !$edit} {
      set answer [tk_dialog .warning "FILE EXISTS" "File \"$fileName\" allready exists, Do you want to owerwrite?!" questhead 0 No Yes]
      if {$answer == 0} return
    }
    set fun $__editInfo(name)
   
    set function [string trimright [$path.commandText get 1.0 end]]
    set header [string trimright [$path.titleText get 1.0 end]]
    set desc [string trimright [$path.descText get 1.0 end]]
    set __content(user-$type,$fileName) [list $header $function $desc]

    writeContentFile $type

    destroy $path
    if {!$edit} {
      if {$type == "save"} {
        saveFile [myGlob ~/].dotfile/$module(name)/save-files/$fileName
        set __editInfo(loadFile) $fileName
      } else {
        export [myGlob ~/].dotfile/$module(name)/export-files/$fileName
      }
      if {$fun != ""} {
        unlink $fun top ""
        catch "unset __activeNivau"
        linkVars $fun __$fun top
      }
    } 
  } else {
    destroy $path
  }
}
######################################################################
### This is the save function, which writes the internal
### state to a file
######################################################################
proc saveFile {fileName} {
  global module __progList __changed __saveInfo __children __widgetArgs 
  global __fillList __fillOutCounter setup __editInfo __state __hash __clean
  
  set saved {}

  ### creating the "please wait" window
  timeWindow [expr 6+[llength $__progList]] "Saving" "Saving...Please Wait"

  set FILE [open $fileName w]

  puts $FILE "$__hash\n\# Dotfile Generator version $__editInfo(version)\n\# $module(name) module version $module(version)\n$__hash\n"
  incrTimeWindow

  puts $FILE "timeWindow [expr 3+[llength $__progList]]  Loading \"Loading...please wait\""
  
  foreach function $__progList {
    puts $FILE "$__hash\n\# $function\n$__hash"
    foreach child $__children(${function}__top) {
      saveOptions $FILE $function __$function $child
    }
    incrTimeWindow
    puts $FILE incrTimeWindow
  }
  
  puts $FILE "$__hash\n\# setup\n$__hash"
  foreach elm [array names setup] {
    puts $FILE "set_setup $elm \{$setup($elm)\}"
  }
  incrTimeWindow

  puts $FILE "$__hash\n\# __saveInfo\n$__hash"
  foreach elm [array names __saveInfo] {
    puts $FILE "set__saveInfo $elm $__saveInfo($elm)"
  }
  incrTimeWindow
  puts $FILE incrTimeWindow
  
  puts $FILE "$__hash\n\# __state\n$__hash"
  foreach elm [array names __state] {
    if {$__state($elm) != "normal"} {
      puts $FILE "set__state $elm $__state($elm)"
    }
  }
  incrTimeWindow
  puts $FILE incrTimeWindow
  
  if {[info exists __fillList]} {
    puts $FILE "$__hash\n\# __fillList (fillouts)\n$__hash"
    foreach elm [array names __fillList] {
      puts $FILE "set__fillList $elm \{$__fillList($elm)\}"
    }
    puts $FILE "set__fillOutCounter $__fillOutCounter"
  }
  incrTimeWindow

  puts $FILE "$__hash\n\# __clean\n$__hash"
  foreach elm [array names __clean] {
    puts $FILE "set__clean $elm \{$__clean($elm)\}"
  }
  incrTimeWindow

  puts $FILE incrTimeWindow
  puts $FILE "after idle destroyTimeWindow"

  close $FILE
  set __changed 0
  destroyTimeWindow
}

############################################################
# This function escapes every control chars for the
# save file
############################################################  
proc escape {string} {
  regsub -all {["#\${}]} $string \\\\\\0 result
  regsub -all {[[]} $result \\\\\\0 string
  regsub -all {[]]} $string \\\\\\0 result
  return $result
}

############################################################
# This function write every user configuration options
# to the save file.
############################################################
proc saveOptions {FILE function prefix name} {
  global __widgetArgs __children __scrollBar __fillList
  set type $__widgetArgs(${function}__${name}__type)
  switch $type {
    checkbox -
    entry -
    int -
    float -
    menu -
    radio -
    command -
    combobox -
    label  {
      puts $FILE "setVar $function $name ${prefix}_$name {[escape [uplevel \#0 set ${prefix}_$name]]}"
    }
    textbox -
    listbox {
      upvar \#0 ${prefix}_${name}_scroll scroll
      puts $FILE "setVar $function $name ${prefix}_$name {[escape [uplevel \#0 set ${prefix}_$name]]}"
      
      if {[info exists scroll]} {
        puts $FILE "setVar $function $name ${prefix}_${name}_scroll {$scroll}"
      }
    }
    extentry {
      puts $FILE "setVar $function $name __scrollBar(${prefix}_${name}) {$__scrollBar(${prefix}_${name})}"
      set count [lindex $__scrollBar(${prefix}_${name}) 1]
      for {set i 0} {$i < $count } {incr i} {
        foreach child $__children(${function}__$name) {
          saveOptions $FILE $function ${prefix}_$name$i $child
        }
      }
    }
    frame -
    window {
      foreach child $__children(${function}__$name) {
        saveOptions $FILE $function $prefix $child
      }
    }
    fillout {
      puts $FILE "setVar $function $name ${prefix}_$name {[escape [uplevel \#0 set ${prefix}_$name]]}"
      if {[info exists __fillList(${prefix}_$name)]} {
	foreach elm $__fillList(${prefix}_$name) {
	  set elmName [lindex $elm 2]
	  set counter [lindex $elm 3]
	  if {$counter == -1} continue
	  foreach child $__children(${function}__$elmName) {
	    saveOptions $FILE $function ${prefix}_${name}_$counter $child
	  }
	}
      }
    }
    header -
    line {}
    default {
      error "Unknow type: $type"
    }
  }
}

############################################################
#   This function is used in the savefile, to register
#   which variables are set.
############################################################
proc setVar {function child variable value} {
  global __loadPage
  if {$__loadPage($function)} {
    uplevel \#0 "set $variable \"$value\""
  }
}

######################################################################
### This function set the variable __saveInfo from the savefile.
### It is necesary this way, so it is possible to check wether a
### page, shall be loaded or not.
######################################################################
proc set__saveInfo {function value} {
  global __loadPage __saveInfo
  if {$__loadPage($function)} {
    set __saveInfo($function) $value
  }
}

######################################################################
### This function set the variable __fillList from the savefile.
### It is necesary this way, so it is possible to check wether a
### page, shall be loaded or not.
######################################################################
proc set__fillList {var value} {
  global __fillList __loadPage
  set id [array startsearch __loadPage]
  
  while {[array anymore __loadPage $id]} {
    set name [array nextelement __loadPage $id]
    if {$__loadPage($name) &&
        [regexp  "^__${name}_.*" $var]} {
      set __fillList($var) $value
    }
  }
}

######################################################################
### This function set the variable __state from the savefile.
### It is necesary this way, so it is possible to check wether a
### page, shall be loaded or not.
######################################################################
proc set__state {var value} {
  global __state __loadPage
  set id [array startsearch __loadPage]
  
  while {[array anymore __loadPage $id]} {
    set name [array nextelement __loadPage $id]
    if {$__loadPage($name) &&
        [regexp "^__${name}_.*" $var]} {
      set __state($var) $value
    }
  }
}

######################################################################
### This function set the variable __clean from the savefile.
### It is necesary this way, so it is possible to check wether a
### page, shall be loaded or not.
######################################################################
proc set__clean {var value} {
  global __clean __loadPage
  set id [array startsearch __loadPage]
  
  while {[array anymore __loadPage $id]} {
    set name [array nextelement __loadPage $id]
    if {$__loadPage($name) &&
        [regexp "^__${name}*" $var]} {
      set __clean($var) $value
    }
  }
}

######################################################################
### This functoin set the variable __fillOutCounter from the savefile
### It is necesary, so the counter will always be uniq.
######################################################################
proc set__fillOutCounter {val} {
  global __fillOutCounter
  if {$val > $__fillOutCounter} {
    set __fillOutCounter $val
  }
}

######################################################################
### This function set the variable setup from the save file, if the
### checkbox is selected on the details page
######################################################################
proc set_setup {var value} {
  global __loadSetup setup
  if {$__loadSetup} {
    set setup($var) $value
  }
}

######################################################################
### This function brings up the "manage save file" dialog
######################################################################
proc manageSaveFiles {} {
  global __content __fileToLoad
  set w [makeTempWindow "Manage Save File"]
  
  label $w.dummy
  set txt [frame $w.text]
  text $txt.text -yscrollcommand "$txt.scroll set" -wrap word \
      -font [$w.dummy cget -font]
  scrollbar $txt.scroll -command "$txt.text yview"
  button $w.cancel -text Cancel -command "destroy $w"

  button $w.configure -text "Configure" \
      -command "destroy $w;eval saveOrExport \$__fileToLoad"
  button $w.remove -text "Remove" -command "destroy $w;removeFile"

  pack $w.text -fill both -expand 1
  pack $w.cancel -side right -padx 2 -pady 5
  pack $w.configure -side right -padx 2 -pady 5
  pack $w.remove -side right -padx 2 -pady 5
  pack $txt.scroll -side right -fill y
  pack $txt.text -fill both -expand 1
  insertIntoTextBox $txt.text manage
  if {![existsLoadFiles]} {
    $w.configure configure -state disabled
    $w.remove configure -state disabled
  }
}

######################################################################
### This function ask the user wether he really want's to remove
### the save file.
######################################################################
proc removeFile {} {
  global __fileToLoad __system __content module
  set type [lindex $__fileToLoad 0]
  set fileName [lindex $__fileToLoad 1]
  regexp {^user-(.*)$} $type all dir
  
  set answer [tk_dialog .sure "Remove file" "Are you sure that you want to remove the $dir file called \"$fileName\". The file will be removed from disk too!" questhead 0 No Yes]

  if {$answer == 1} {
    eval exec $__system(rm) \
        [myGlob ~/].dotfile/$module(name)/$dir-files/$fileName
    unset __content($type,$fileName)
    writeContentFile $dir
  }
}

######################################################################
### This function write the information to the content file
######################################################################
proc writeContentFile {type} {
  global __content module
  set FILE [open ~/.dotfile/$module(name)/$type-files/contents w]
  foreach elm [array names __content "user-$type,*"] {
    regexp "^user-$type,(.*)\$" $elm all file
    set header [escape [lindex $__content($elm) 0]]
    set function [lindex $__content($elm) 1]
    set desc [escape [lindex $__content($elm) 2]]
    puts $FILE \
        "Content $file\\\n\t{$function}\\\n\t\"$header\"\\\n\t\"$desc\"\n\n"
  }
  close $FILE
}
