#
# The BackFire System administration tool ...
#!/usr/local/bin/wish8.4

package require BWidget 1.7

source GlobalDefaults
source System.TCL
source Database.TCL

proc init { } {
  # Open the database and cache the System Resources ...
  set ::N_Targets 0
  if [file exists $::DATABASE] {
    sql::openDBMS $::DATABASE
  } else {
    set msg [format "Unable to Find database %s.\n\
	Will attempt to create it." $::DATABASE]
    tk_messageBox -type ok -icon info -message $msg 
    sql::openDBMS $::DATABASE
    if [catch { db eval $::dbms_Schema } err] {
       set msg [format "Unable to Create database %s.\n%s" $::DATABASE $err]
       tk_messageBox -type error -icon error -message $msg 
    }
  }
  set N_Res [ sql::readResources ]
  create_Widgets
}

proc create_SplashPage { } {
  set ::logo [ label $::spl.l -bitmap @Logo.Q.xbm \
	-foreground black -background white ]
  pack $::logo -expand 1 -fill both
  return $::spl
}

proc scan_Devices { which } {
  set ix [ lsearch $::lst_devs $which ]
  if { $ix < 0 } {
    return
  }
  if [ winfo exists .mnu ] {
    destroy .mnu
  }
  if [string equal $which "dvd_burner"] {
     set widget .nb.fdev.f.v0
     set val [ tk_getOpenFile -initialdir /dev -title {Scan for DVD} ]
     $widget delete 0 end
     $widget insert 0 $val
  }
  if [string equal $which "network"] {
     set widget .nb.fdev.f.v1
     set ifcnfg [lindex [ sys::find_Prog ifconfig ] 0]
     if { [ string length $ifcnfg ] == 0 } {
       set msg "Unable to find a valid ifconfig program."
       tk_messageBox -type error -icon error -message $msg 
     }
     set cmd [format "%s -l" $ifcnfg ]
     if [ sys::do_SysCmd $cmd ] {
     }
     set lst $sys::sys_result
     if { [llength $lst ] > 1 } {
       set cmd "tk_optionMenu .mnu ::tmpval $lst"
       set mnu [ eval $cmd ]
       tk_popup $mnu [winfo pointerx .] [winfo pointery .]
       vwait ::tmpval
       destroy $mnu 
     } 
     $widget delete 0 end 
     $widget insert 0 $::tmpval
  }
}

proc scan_Prog { which } {
  set ix [ lsearch $::lst_progs $which ]
  if { $ix < 0 } {
    return
  } 
  if [ winfo exists .mnu ] {
    destroy .mnu
  }
  set widget .nb.fsys.f.v$ix
  set lst [ sys::find_Prog $which ]
  set ::tmpval [ lindex $lst 0 ]
  if { [llength $lst ] > 1 } {
    set cmd "tk_optionMenu .mnu ::tmpval $lst"
    set mnu [ eval $cmd ]
    tk_popup $mnu [winfo pointerx .] [winfo pointery .]
    vwait ::tmpval
    destroy $mnu 
  } 
  $widget delete 0 end 
  $widget insert 0 $::tmpval
}

proc create_ARC_Page { lst } {
  set lbl [ labelframe $::arc.f -text {Archives} ]
  pack $lbl -expand 1 -fill both
  make_Form $lbl $lst find_SystemDir
}

proc find_SystemDir { which } {
  set ix [ lsearch $::lst_dirs $which ]
  if { $ix < 0 } {
    return
  } 
  set widget .nb.farc.f.v$ix
  set ret [ tk_chooseDirectory -title {Find Directory Path} ]
  if { [ file exists $ret ] == 0 } {
    set msg [ format "%s does not exist\nOk to create." $ret ]
    set ans [ tk_messageBox -type okcancel -icon info -message $msg ]
    if [string equal $ans "ok" ] {
      if { [ catch { file mkdir $ret } err ] } {
       set msg [ format "Unable to create directory.\n%s" $err ]
       tk_messageBox -type ok -icon error -message $msg 
      }
    }
  }
  $widget delete 0 end 
  $widget insert 0 $ret
  return $ret
}

proc make_Form { parent lst cmd } {
  set i 0
  array set ::mod [ array get lst ]
  foreach v $lst {
    label $parent.l$i -text "$v"
    grid $parent.l$i -column 0 -row $i -sticky e
    set ::entry($v) [entry $parent.v$i -width 20 -textvariable ::mod($v)]
    grid $parent.v$i -column 1 -row $i
    button $parent.b$i -text {Browse} -command "$cmd $v"
    grid $parent.b$i -column 2 -row $i
    incr i
  }
  set lf [ labelframe $parent.lf -text Actions ]
  button $lf.do_Apply -text {Apply}  -command apply_Resources
  grid $lf.do_Apply -column 0 -row 0 
  button $lf.do_Cancel -text {Cancel}
  grid $lf.do_Cancel -column 1 -row 0 
  button $lf.do_Reset -text {Reset}
  grid $lf.do_Reset -column 2 -row 0 
  grid $lf -column 0 -row $i -columnspan 3 -sticky sew
}

proc apply_Resources { } {
  foreach element [ array names ::mod ] {
    if [ string length $::mod($element) ] {
      set cmd [format "insert or replace into resource values( '%s', '%s' ) ;"\
        $element $::mod($element) ]
      if [catch { db eval $cmd } err] {
        set msg [ format "Error in dbms access.\n%s." $err ]
        tk_messageBox -type ok -icon error -message $msg
      }
    }
  }
  set nch [ db total_changes ]
  set msg [ format "%d rows updated in Database" $nch ]
  tk_messageBox -type ok -icon info -message $msg
  sql::closeDBMS 
  sql::openDBMS $::DATABASE
}

proc create_SysPage { lst } {
  set lbl [ labelframe $::sys.f -text {Program Configuration} ]
  pack $lbl -expand 1 -fill both
  make_Form $lbl $lst scan_Prog
}

proc target_Names { } {
  set ret {}
  set ::N_Targets [ sql::cache_tbl_Data target ]
  for { set i 0 } { $i < $::N_Targets } { incr i } {
    array set t [ sql::get_tbl_Row $i ]
    lappend ret $t(name)
  }
  return $ret
}
proc refresh_Targets { } {
  set ::tgts [ target_Names ]
}
proc target_Form { parent } {

  refresh_Targets
  set lf [ labelframe $parent.lf -text {Select Target} ]
  set lb [ listbox $lf.list -height 10 -width 20 -listvariable ::tgts \
		-yscrollcommand [list $lf.sy set] ]
  set ys [ scrollbar $lf.sy -command [list $lf.list yview ]]
  grid $lb -sticky ns -row 0 -column 0
  grid $ys -sticky ns -row 0 -column 1
  grid $lf -column 0

  set lf [ labelframe $parent.act -text Actions ]
  button $lf.do_New -text {New} -command [list do_New $lb ]
  grid $lf.do_New -column 0 -row 0 
  button $lf.do_Edit -text {Edit} -command [list create_tgtForm $lb ]
  grid $lf.do_Edit -column 1 -row 0 
  button $lf.do_Delete -text {Delete} -command [list create_tgtForm $lb ]
  grid $lf.do_Delete -column 2 -row 0 
  grid $lf -column 0 -row 1 -columnspan 3 -sticky sew
}

proc next_ID { } {
    set ret -1
    if [ catch {db eval "select max(id) from target ;" } max ] {
      set msg "Problem querying target table of database"
      tk_messageBox -type ok -icon error -message $msg 
    }
    if [string is integer $max] {
      set ret $max
    }
    incr ret
    return $ret
}
proc pick_Type { widget } {
  if [ winfo exists .mnu ] {
    destroy .mnu
  }
  set cmd "tk_optionMenu .mnu ::t(type) [list Samba Unix NFS]"
  set mnu [ eval $cmd ]
  tk_popup $mnu [winfo pointerx .] [winfo pointery .]
  vwait ::t(type)
  destroy $mnu 
  $widget configure -text $::t(type)
}
proc do_New { lbx } {
  $lbx selection clear 0 end
  create_tgtForm $lbx
}
proc create_tgtForm { lbx } {

  set ix [ $lbx curselection ]
  if [winfo exists .tgt_form] {
    destroy .tgt_form
  }
  set tl [ toplevel .tgt_form ]
  wm title $tl {Edit Target}
  set lf [ labelframe $tl.f -text {Fields}]
  if { $ix < 0 } {
    set ix [ next_ID ]
    foreach fld [ sql::tbl_Vars target ] {
      set ::t($fld) {}
    }
    set ::t(id) $ix
  } else {
    array set ::t [sql::get_tbl_Row $ix]
  }
  set r 0

  #
  #  id ...
  set lbl [label $lf.lid -text {Identifier}]
  set fld [entry $lf.eid -width 20 -state disabled -textvariable ::t(id) ]
  $fld delete 0 end
  $fld insert 0 $ix
  grid $lbl -column 0 -row $r -sticky e
  grid $fld -column 1 -row $r
  incr r

  #
  # name ...
  set lbl [label $lf.lname -text {Target Name}]
  set fld [entry $lf.ename -width 20 -textvariable ::t(name) ]
  grid $lbl -column 0 -row $r -sticky e
  grid $fld -column 1 -row $r
  incr r

  #
  # type ...
  set lbl [label $lf.ltype -text {Target Type}]
  set fld [button $lf.btn -text $::t(type) -command [list pick_Type $lf.btn]]
  grid $lbl -column 0 -row $r -sticky e
  grid $fld -column 1 -row $r -sticky w
  incr r

  #
  # host ...
  set lbl [label $lf.lhost -text {Host Name}]
  set fld [entry $lf.ehost -width 20 -textvariable ::t(host) ]
  grid $lbl -column 0 -row $r -sticky e
  grid $fld -column 1 -row $r
  incr r

  #
  # share ...
  set lbl [label $lf.lshare -text {Share or Mount point}]
  set fld [entry $lf.eshare -width 20 -textvariable ::t(share) ]
  grid $lbl -column 0 -row $r -sticky e
  grid $fld -column 1 -row $r
  incr r

  #
  # path ...
  set lbl [label $lf.lpath -text {Path}]
  set fld [entry $lf.epath -width 20 -textvariable ::t(path) ]
  grid $lbl -column 0 -row $r -sticky e
  grid $fld -column 1 -row $r
  incr r

  #
  # user ...
  set lbl [label $lf.luser -text {User Name}]
  set fld [entry $lf.euser -width 20 -textvariable ::t(user) ]
  grid $lbl -column 0 -row $r -sticky e
  grid $fld -column 1 -row $r
  incr r

  #
  # passwd ...
  set lbl [label $lf.lpasswd -text {User Password}]
  set fld [entry $lf.epasswd -width 20 -textvariable ::t(passwd) -show *]
  grid $lbl -column 0 -row $r -sticky e
  grid $fld -column 1 -row $r
  incr r

  pack $lf
  set lf [ labelframe $tl.act -text {Actions}]
  set cmd [button $lf.apply -command [list update_Row .tgt_form] -text Apply]
  grid $cmd -column 0 -row 0
  set cmd [button $lf.cancel -command [list delete_Row .tgt_form] -text Delete]
  grid $cmd -column 1 -row 0
  set cmd [button $lf.reset -command [list close_Window .tgt_form] -text Cancel]
  grid $cmd -column 2 -row 0
  pack $lf
}

proc close_Window { top } {
  if [ winfo exists $top ] {
    destroy $top
  }
}

proc delete_Row { top } {
  set cmd [format "delete from target where id = %d" $::t(id)]
  if [modify_Target $cmd] {
    close_Window $top
  }
  refresh_Targets
}

proc update_Row { top } {
  set cmd [format "insert or replace into target values ( %d" $::t(id)]
  foreach v [list name type host share path user] {
    set val [ format ",'%s'" $::t($v)]
    set cmd [ format "%s%s" $cmd $val]
  }
  set pwd [sys::encrypt $::t(passwd)]
  set cmd [ format "%s, '%s' ) ;" $cmd $pwd ]
  if [modify_Target $cmd] {
    close_Window $top
  }
  refresh_Targets
}

proc modify_Target { cmd } {
  if [ catch { db eval $cmd } err ] {
       set msg [format "Unable to modify database %s.\n%s\n%s" $::DATABASE $err $cmd]
       tk_messageBox -type ok -icon error -message $msg 
       return 0
  }
  set nch [ db total_changes ]
  set msg [ format "%d rows updated in Database" $nch ]
  tk_messageBox -type ok -icon info -message $msg
  sql::closeDBMS 
  sql::openDBMS $::DATABASE
  return 1
}

proc create_TgtPage { } {
  set lbl [ labelframe $::tgt.f -text {Target Configuration} ]
  pack $lbl -expand 1 -fill both
  target_Form $lbl 
}

proc create_RetPage { lst } {
  set lbl [ labelframe $::ret.f -text {Retension Policy} ]
  pack $lbl -expand 1 -fill both
  make_Form $lbl $lst scan_Devices
}

proc create_DevPage { lst } {
  set lbl [ labelframe $::dev.f -text {Devices} ]
  pack $lbl -expand 1 -fill both
  make_Form $lbl $lst scan_Devices
}

proc shutdown { } {
  sql::closeDBMS 
  exit
}

proc create_Widgets { } {
  wm title . {BackFire Configuration Tool}
  set ::nbk [ NoteBook .nb ]
  set ::spl [ $::nbk insert end splash -text {} ]
  set ::tgt [ $::nbk insert end tgt -text Targets -raisecmd [list refresh_Targets]]
  set ::arc [ $::nbk insert end arc -text Archives ]
  set ::sys [ $::nbk insert end sys -text Programs ]
  set ::dev [ $::nbk insert end dev -text Devices ]
  set ::ret [ $::nbk insert end ret -text Retention ]

  create_SplashPage
  create_TgtPage 
  create_ARC_Page $::lst_dirs
  create_SysPage $::lst_progs
  create_DevPage $::lst_devs
  create_RetPage $::lst_ret
  button .exit -command shutdown -text "Exit"

  $::nbk raise splash
  pack $::nbk
  pack .exit
}

init
