#
# Module for file I/O for Misc. widgets
#

# Returns pathname p with . and .. expressions evaluated
proc th_dedot_file {p} {
# First eliminate .
  while {[string match {\./*} $p]} {set p [string range $p 2 end]}
  while {[string match {*/\.} $p]} {set p [string range $p 0 [expr [string length $p] - 2]]}
  while {[regsub -- {/\./} $p {/} q]} {set p $q}

# Now eliminate ..
  while {[regsub -- {[^/]*/\.\.} $p {} q]} {regsub -- {//} $q {/} p}
  return $p
}

# Prompts user for a file to write to, before saving file.
proc th_save_file_prompt {w} {
  th_file_prompt $w "th_write_file $w" "File to Save:"
}

# Saves file w/o prompting, prompts user only if necessary
proc th_save_file {w} {
  global TH
  if {[catch "set TH(File,Last,$w)"]} {set TH(File,Last,$w) ""}
  if {([catch "set TH(File,$w)"] || ($TH(File,$w) == ""))} {
    th_save_file_prompt $w
  } elseif {([string first "|" $TH(File,$w)] >= 0) && ($TH(File,Last,$w) != "w")} {
    th_save_file_prompt $w
  } elseif {!([string first "|" $TH(File,$w)] >= 0) &&
      (![file exists $TH(File,$w)] || ![file writable $TH(File,$w)])} {
    th_save_file_prompt $w
  } else {
    set TH(File,New,$w) $TH(File,$w)
    th_write_file $w
}}

# Writes contents of w out to TH(File,%W)
proc th_write_file {w} {
  global TH auto_index
  if {[catch "set TH(Pipe,Enabled)"]} {set TH(Pipe,Enabled) 0}
  if {($TH(Pipe) || ([string first "|" $TH(File,New,$w)] >= 0)) && !$TH(Pipe,Enabled)} {
    error "Pipe writing (to $TH(File,New,$w)) is not allowed in this application."
  }
  set pwd [pwd]
  if {([set index [string first "|" $TH(File,New,$w)]] >= 0)} {
    cd [string range $TH(File,New,$w) 0 [expr $index - 2]]
    set file [open [string range $TH(File,New,$w) $index end] w]
  } elseif $TH(Pipe) {
    cd [th_file_dirname $TH(File,New,$w)]
    set file [open [th_file_tail $TH(File,New,$w)] w]
  } else {  set file [open $TH(File,New,$w) w]}

  th_file_update_widgets $w $TH(File,New,$w)
  th_[winfo class $w]_write_file $w $file
  close $file
  catch {set TH(Mtime,$w) [file mtime $TH(File,New,$w)]}
  set TH(Modified,$w) 0
  if {([info procs th_kill_undos] != "") || \
     ([lsearch [array names auto_index] th_kill_undos] >= 0)} {
    th_kill_undos $w}
  set TH(File,Last,$w) "w"
  set TH(File,$w) [th_dedot_file $TH(File,New,$w)]
  cd $pwd
  th_file_update_widgets $w
}


# Prompts user for a new file to read.
proc th_read_file_prompt {w} {
  th_confirm_save $w "th_file_prompt $w \"th_load_file $w\" {File to Read:}"
}

# Reads (reverts to) current file w/o prompt, unless necessary.
proc th_read_file {w} {
  global TH
  if {[catch "set TH(File,Last,$w)"]} {set TH(File,Last,$w) ""}
  if {([catch "set TH(File,$w)"] || ($TH(File,$w) == ""))} {
    th_read_file_prompt $w
  } elseif {([string first "|" $TH(File,$w)] >= 0) && ($TH(File,Last,$w) != "r")} {
    th_read_file_prompt $w
  } elseif {!([string first "|" $TH(File,$w)] >= 0) &&
      (![file exists $TH(File,$w)] || ![file readable $TH(File,$w)])} {
    th_read_file_prompt $w
  } else {
    set TH(File,New,$w) $TH(File,$w)
    global auto_index
    if {([info procs th_[winfo class $w]_save_view] != "") || \
       ([lsearch [array names auto_index] th_[winfo class $w]] >= 0)} {
      th_confirm_save $w "th_[winfo class $w]_save_view $w \"th_load_file $w\""
    } else {
      th_confirm_save $w "th_load_file $w"
}}}

# Inserts contents of prompted file into w, in usual editing fashion.
proc th_insert_file {w} {
  th_file_prompt $w "th_load_file $w 1" {File to Insert:}
}

# Loads w with contents of TH(File,$w) if insert_flag is 1, then insert,
# otherwise load.
proc th_load_file {w {insert_flag 0}} {
  global TH auto_index
  if {[catch "set TH(Pipe)"]} {set TH(Pipe) 0}
  if {[catch "set TH(Pipe,Enabled)"]} {set TH(Pipe,Enabled) 0}
  if {($TH(Pipe) || ([string first "|" $TH(File,New,$w)] >= 0)) && !$TH(Pipe,Enabled)} {
    error "Pipe reading (from $TH(File,New,$w)) is not allowed in this application."
  }

  set pwd [pwd]
  if {([set index [string first "|" $TH(File,New,$w)]] >= 0)} {
    cd [string range $TH(File,New,$w) 0 [expr $index - 2]]
    set name [string range $TH(File,New,$w) $index end]
    set pipe 1
  } elseif $TH(Pipe) {
    cd [th_file_dirname $TH(File,New,$w)]
    set name [th_file_tail $TH(File,New,$w)]
    set pipe 1
  } else {  set name $TH(File,New,$w) ; set pipe 0}
  if $pipe {
    if {[set comp [lindex [th_string_complete_multiple $name \
		{{th_substring_replace th_string_glob_files { }}}] 0]] != ""} {
      set name $comp
  }}
  set file [open $name r]

  if {![file writable $TH(File,New,$w)] && [file exists $TH(File,New,$w)]} {
    th_flash_label $w -text "File is not writable!"
  }

  if $insert_flag {
    if {![catch "set TH(File,New,Old,$w)"]} {set TH(File,New,$w) $TH(File,New,Old,$w)
    } else {unset TH(File,New,$w)}
    th_[winfo class $w]_insert_file $w $file $pipe
    set TH(Modified,$w) 1
  } else {
    th_file_update_widgets $w $TH(File,New,$w)
    th_[winfo class $w]_read_file $w $file $pipe
    catch {set TH(Mtime,$w) [file mtime $TH(File,New,$w)]}
    set TH(Modified,$w) 0
    if {([info procs th_kill_undos] != "") || \
       ([lsearch [array names auto_index] th_kill_undos] >= 0)} {
      th_kill_undos $w}
    set TH(File,New,Last,$w) "r"
    set TH(File,$w) [th_dedot_file $TH(File,New,$w)]
    th_file_update_widgets $w
    }
  cd $pwd
  close $file
}

# Prompts user for a file, doing cmd if OK.
proc th_file_prompt {w cmd {msg "File:"}} {
  global TH
  if {[set f [th_show_entry $w file]] == ""} {bell ; return}
  set TH(Completions,$f.e) [list {th_line_complete th_filter_glob none}]
  if {![catch "set TH(Completions,File,Commands)"]} {
    lappend TH(Completions,$f.e) [list th_substring_complete [list th_list_completions $TH(Completions,File,Commands)] {|}]
  }
  $f.l configure -text $msg
  $f.e delete 0 end
  if {([catch "set TH(File,$w)"] || ($TH(File,$w) == ""))} {
    $f.e insert 0 "[pwd]/"
    set index [$f.e index end]
    set padding [$f.e cget -width]
  } else {
    $f.e insert 0 $TH(File,$w)
    if {[set index [string first "|" $TH(File,$w)]] < 0} {
      set index [string last "/" $TH(File,$w)] ; incr index
    }
    set padding [expr [$f.e cget -width] - [string length [string range $TH(File,$w) $index end]]]
  }
  if {[catch "set TH(File,Pad)"]} {set TH(File,Pad) 0}
  if $TH(File,Pad) {for {set c 0} {$c < $padding} {incr c} {$f.e insert end " "}}
  $f.e icursor $index
  $f.e xview $index
  th_bind $f.e OK "th_file_prompt_aux $w \[string trimright \[$f.e get\]\]; $cmd"
  return $f
}

proc th_file_prompt_aux {w file} {
  global TH
  if {[catch "set TH(Pipe)"]} {set TH(Pipe) 0}
  th_hide_entry $w file
  if {$TH(Pipe) && ([string first "|" $file] < 0)} {
    set TH(File,New,$w) "[th_file_dirname $file]/| [th_file_tail $file]"
  } elseif {([string first [string index $file 0] {~/}] < 0)} {
    set TH(File,New,$w) "[pwd]/$file"
  } else {set TH(File,New,$w) $file}
}

# If w's contents differ from TH(File,$w), prompt user to save contents.
# Executes cmd if user does not cancel.
proc th_confirm_save {w cmd} {
  global TH
  if {![catch "set TH(Modified,$w)"] && $TH(Modified,$w)} {
    if {([catch "set TH(File,$w)"] || ($TH(File,$w) == ""))} {set name "This"
    } else {set name [th_file_tail $TH(File,$w)]}
    set message "$name has been modified. Do you want to save it first?"
    set choice [tk_dialog .conf "Save Dialog" $message question 0 "Save" "Don't Save" "Cancel"]
    if {$choice == 2} {return}
    if {$choice == 0} {
      th_save_file $w
      if $TH(Modified,$w) { tkwait variable TH(Modified,$w)}
  }}
  uplevel #0 $cmd
}

# Set mmodified flag if file has been modified since we last read/saved it.
proc th_check_mtime {w} {
  global TH
  if {[catch "set TH(Mtime,$w)"]} {return}
  if {([string first "|" $TH(File,$w)] >= 0)} {return}
  if {[catch "file mtime $TH(File,$w)"]} {set TH(Modified,$w) 1 ; return}
  if {([file mtime $TH(File,$w)] > $TH(Mtime,$w))} {set TH(Modified,$w) 1 ; return}
}


# Updates any widgets that contain the file patn/name (usually window title)
proc th_file_update_widgets {w {filename ""}} {
  global TH
  if {$filename == ""} {
    if {([catch "set TH(File,$w)"] || ($TH(File,$w) == ""))} {return}
    set filename $TH(File,$w)
  }
  if {[string first [string index $filename 0] {~/}] >= 0} {
    set path [th_file_dirname $filename] ; set name [th_file_tail $filename]
  } else {set path [pwd] ; set name $filename}
  set f [th_frame $w]
  if {[winfo exists $f.fpl]} {
   $f.fpl configure -onvalue $path
   if {$TH(File,fpl,$w) != "-"} {set TH(File,fpl,$w) $path}}
  if {[winfo exists $f.fnl]} {
    $f.fnl configure -onvalue $name 
    if {$TH(File,fnl,$w) != "-"} {set TH(File,fnl,$w) $name}}
  if {[info procs th_file_update_titles] != ""} {
    th_file_update_titles $w $filename}
}

# Returns the dirname of f (even if it is a pipe)
proc th_file_dirname {f} {
  if {[set pipe [string first "|" $f]] >= 0} {
    return [string range $f 0 [expr $pipe - 2]]
  } else {return [file dirname $f]}
}

# Returns the tail of f.
proc th_file_tail {f} {
  if {[set pipe [string first "|" $f]] >= 0} {
    return [string range $f $pipe end]
  } else {return [file tail $f]}
}

