###
### Tree part of the obex tool implamentation
###
### Main functions for mataging the folder tree (left part of the gui)
### and the interface to the list part (right part of the gui)
###
### Interface components:
### ObexList::lb_entries - array with file detail information with 
###                        names as indices
### ObexTree::dir_list   - list of names in current folder
### 
### History:
###   20050610: Implementation of an 8-bit clean character 
###             mapping (just hex code) -ger
###

package provide obextree 0.4

namespace eval ObexTree {
  variable tree_font [getObexCfg tree font]
  variable list_frame 
  variable dblclick
  variable dir_list
  variable dir_path
  variable ObxMap
  variable ObxUnm
  variable tree

 # Let's make a bit-clean charmapping (hex)
  for {set i 0} {$i <= 255} {incr i} {
    set c [format %c $i]
    set enc [format %.2x $i]
    set ObxMap($c) $enc
    set ObxUnm($enc) $c
  }

  proc path2node { str } {
    variable ObxMap
    debug_out "path2node $str" 3
    set str [string map [array get ObxMap] $str]
    return $str
  }

  proc node2path { str } {
    variable ObxUnm
    if [string_equal $str "home"] {return /}
    set str [string map [array get ObxUnm] $str]
    return $str
  }

  proc create { frame } {
    variable tree
    variable list_frame 
    debug_out "create $frame" 3

    set lineheight [getObexCfg tree height]
    set pw [PanedWindow $frame.pw -side top]
    
  ############################################################
  # Left window setup
  #
    set pane [$pw add -weight 2]
    set tfr  [TitleFrame $pane.lf -text [get_text "Folder tree"]]
    set sw   [ScrolledWindow [$tfr getframe].sw -relief sunken -borderwidth 2]
    set tree [Tree $sw.tree -background white -deltay $lineheight -redraw 0\
                   -relief flat -borderwidth 0 -width 25 -highlightthickness 0\
                   -opencmd   "ObexTree::moddir 1" \
                   -closecmd  "ObexTree::moddir 0"]
    $sw setwidget $tree
    pack $sw $tfr -side top -expand yes -fill both
  #
  ############################################################

  ############################################################
  # Right window setup
  #
    set pane [$pw add -weight 8]
    set list_frame [TitleFrame $pane.lf]
    set sw   [ScrolledWindow [$list_frame getframe].sw \
              -auto both -borderwidth 2]
    pack $sw $list_frame -fill both -expand yes
    pack $pw -fill both -expand yes
  #
  ############################################################
    set left [getObexCfg mouse_button left]

    $tree bindText <ButtonPress-$left>        "ObexTree::select 1"
    $tree bindText <Double-ButtonPress-$left> "ObexTree::select 2"

    return $sw
  }

  proc init {} {
    variable tree
    variable tree_font
  debug_out " ObexTree::init" 3

    $tree insert end root home \
          -text / -data / -drawcross allways \
          -font $tree_font -open 0 -image [Bitmap::get openfold_icon]
     getdir home /
  #### select 1 home
     select_node home

    $tree configure -redraw 1
  }

  proc drop { tree  lbox  ttnode  op  type  snode } {
    debug_out "ObexTree::drop $tree $lbox $ttnode $op $type $snode"
  }

  proc find_file {} {
    variable found_list {}
    variable filsiz 0
    variable dircnt 0
    variable filcnt 0
    global prg_msg bail vinc
   
    set dir [curr_dir]
    if [string_empty $dir] {set dir /}
    set h1 [get_text "Use *, ? and \[ \] for wildcard matching"]
    set h2 [get_text "Example: *pic\[a-z\]?\[0-9\].bm\[px\]"]
    set h3 [format [get_text "Current directory is: %s"] $dir]
    set pat [filename_dlg [get_text "File pattern to find:"] "*" $h1 $h2 $h3]
    if [string_empty $pat] return
    set start [clock seconds]
    set bail 0
    set vinc 1
    ProgressDlg .prg -command {set bail 1;destroy .prg} \
      -variable vinc -textvariable prg_msg \
      -type infinite -stop [get_text "Stop"] -width 50 -maximum 20 \
      -title [format [get_text "Searching '%s'..."] $pat]
    scan_dir $pat $dir
    if [winfo exists .prg] {destroy .prg}
    set end [clock seconds]
    set secs [expr $end-$start]
    set numf [llength $found_list]
    set txt ""
    if $bail { set txt [get_text "    *** Interrupted ***\n"] }
    append txt [format [get_text "Checked %d folders and %d files"] $dircnt $filcnt]
    append txt [format [get_text "\nSearch time was %d seconds"] $secs]
    append txt [format [get_text "\nSearch pattern was: '%s'"] $pat]
    append txt [format [get_text "\nStart folder was: %s"] $dir]
    append txt [format [get_text "\nNumber of results: %d"] $numf]
    append txt [format [get_text "\nTotally used bytes: %d"] $filsiz]
    append txt         [get_text "\n==========================\n"]
    append txt [join $found_list "\n"]
    ObexTool::text_view [get_text "Search results:"] $txt
  }

  proc list_directory { path } {
  debug_out "list_directory $path"
    set_cursor on
    if [getObexCfg config dir_slash] {
      set dlist [ObexFile::list_dir "$path/"] 
    } else {
      set dlist [ObexFile::list_dir $path] 
    }
    set_cursor 
    return $dlist
  }

  proc scan_dir { pattern path } {
    variable found_list 
    variable filsiz 
    variable dircnt 
    variable filcnt
    global prg_msg bail vinc
  debug_out "scan_dir $pattern $path" 3

    if $bail return

    set path [make_path $path ""]
    set prg_msg [format [get_text "Searching '%s'..."] $path]

    foreach ent [list_directory $path] {
      set name [lindex $ent 0]
      set ftyp [lindex $ent 1]
      set size [lindex $ent 2]
      set vinc 1

      if [string match -nocase $pattern $name] {
        lappend found_list $path$name
        if ![string_empty $size] {incr filsiz $size}
      }

      if [string_equal $ftyp "folder"] {
        incr dircnt
        scan_dir $pattern $path$name
      } else {
        incr filcnt
      }
    }
  }

  proc show_props {} {
  debug_out "ObexTree::show_props"
    set path [curr_dir]
    if [string_empty $path] {
      warning [get_text "No file or folder selected!"]
      return
    }
    set ents [list_directory $path]
    set size 0
    set acnt 0
    set fcnt 0
    set dcnt 0
    foreach ent $ents {
      set typ [lindex $ent 1]
      incr acnt
      if [string_equal $typ "folder"] {
        incr dcnt 
      } else {
        incr fcnt 
        set fsiz [lindex $ent 2]
        if ![string_empty $fsiz] {incr size $fsiz}
      }
    }
    set    txt [format [get_text "%d entries with\n"  ] $acnt]
    append txt [format [get_text "%d subfolders and\n"] $dcnt]
    append txt [format [get_text "%d files use\n"     ] $fcnt]
    append txt [format [get_text "%d bytes of memory" ] $size]
    status_msg [format [get_text "Properties for folder '%s'..."] $path]
    ObexTool::text_view [format [get_text "Folder properties: %s"] $path] $txt
  }

  proc getdir { node path } {
    variable tree
    variable dir_list
    variable dir_path $path
    variable tree_font
  debug_out "ObexTree::getdir $node $path" 3

    set lfiles {}
    set d_list {}
    set f_list {}
    set ents [list_directory $path]
    set path [make_path $path ""]

    set sub [$tree nodes $node]
    if ![string_empty $sub] {$tree delete $sub}

    foreach ent $ents {
      set name [lindex $ent 0]
      set ftyp [lindex $ent 1]
      set ent [lreplace $ent 0 0 $path$name]
      set ::ObexList::lb_entries($name) $ent
  debug_out "::ObexList::lb_entries($name)->$ent" 8

      if ![string_equal $ftyp "folder"] {
        lappend lfiles $name
        lappend f_list $path$name
        continue
      } else {
        lappend d_list $path$name
      }

  ### zeeze are folders
      set icon [ObexTool::filetype_icon $ftyp]
      set nnode [path2node $path$name]
      if [$tree exists $nnode] {$tree delete $nnode}
      $tree insert end $node $nnode \
            -text      $name \
            -font      $tree_font \
            -image     [Bitmap::get $icon] \
            -drawcross allways \
            -data      $path$name
    }

    $tree itemconfigure $node -drawcross allways \
                              -data $lfiles -open 1 \
                              -image [Bitmap::get openfold_icon]
    set dir_list {}
    if [llength $d_list] {eval "lappend dir_list [lsort $d_list]"}
    if [llength $f_list] {eval "lappend dir_list [lsort $f_list]"}
    set msg [get_text "%d entries in folder '%s'"]
    status_msg [format $msg [llength $ents] $path]
  }


  proc moddir { open node } {
    variable tree
    debug_out "ObexTree::moddir $node" 3
    if $open {
      getdir $node [node2path $node]
    } else {
      $tree closetree $node
      $tree itemconfigure $node -image [Bitmap::get folder_icon]
    }
  }

  proc curr_dir {} {
    variable tree

    set node [$tree selection get]
    if [string_empty $node] {
      return ""
    } else {
      return [node2path $node]
    }
  }

  proc select { num node } {
    variable tree
    variable dblclick
  debug_out "ObexTree::select $num $node" 3

    set dblclick 1
     if { $num == 1 } {
       if  { [lsearch [$tree selection get] $node] != -1 } {
         unset dblclick
         return
       }
       select_node $node
     } 

    if { $num == 2 } {
      if { [lsearch [$tree selection get] $node] != -1 } {
        $tree itemconfigure "$node" -open 1
        moddir 1 $node
      }
    }

  }

  proc select_node { node } {
  debug_out "ObexTree::select_node $node" 3
    variable tree
    variable dir_path 
    variable list_frame 

    set path [node2path $node]
    $tree selection set "$node"
    set sub [$tree itemcget $node -data]
    debug_var sub 5
    if ![string_equal $node $sub] { $tree delete $sub }

    $tree itemconfigure "$node" -drawcross allways

    getdir $node $path
    set sub [$tree itemcget $node -data]
    debug_out "tree nodes $node=[$tree nodes $node]" 5
    foreach subnode [$tree nodes "$node"] {
      set name [$tree itemcget "$subnode" -text]
    }
    $tree itemconfigure $node -open 1

    ObexList::update_list $ObexList::list_mode
    set ftr [format [get_text "List of folder %s"] $dir_path]
    $list_frame configure -text $ftr
  }

  proc refresh_list { msg } {
    variable tree

    set node [$tree selection get]
    if ![string_empty $node] { select_node $node }
    if [string_empty $msg] { set msg [get_text "Folder contents reloaded"] }
    status_msg $msg
    ObexTool::file_status 0
  }

  proc new_folder {} {
    set dir [curr_dir]
    set new_dir [filename_dlg [get_text "Name of new folder:"] ""]
    if [string_empty $new_dir] return

    set path [make_path $dir $new_dir]
    set_cursor on
    if [ObexFile::path_exists any $path] {
      set_cursor 
      set msg [format [get_text "Cannot create folder '%s'!"] $path]
      if [ObexFile::path_exists dir $path] {
        append msg [get_text "\nA folder with that name already exists."]
      } else {
        append msg [get_text "\nA file with that name already exists."]
      }
      warning $msg
      return
    }

    ObexFile::obexftp md $path
    if [ObexFile::path_exists dir $path] {
      refresh_list [format [get_text "Folder '%s' created"] $path]
    } else {
      no_permission [format [get_text "Could not create folder '%s'!"] $path]
    }
    set_cursor 
  }

  proc up_level {} {
    variable tree
    debug_out "up_level" 3

    set node [$tree selection get]
    if [string_empty "$node"] return
    debug_var node

    set pnode [$tree parent "$node"]
    if [string_empty "pnode" ] return
    if [string_equal $pnode root] {
      warning [get_text "Already at upper most folder level!"]
      return
    }
    debug_var pnode
    select_node "$pnode"
  }

  proc expand { but } {
    variable tree
    debug_out "ObexTree::expand $tree $but" 3

    set cur [$tree selection get]
    if [string_empty $cur] {
      if { $but == 0 } {
        $tree opentree $cur
      } else {
        $tree closetree $cur
      }
    }
  }
}
