#
# <20240518.1934.53>
#
# This routine presents the password locker passwords and options.
# It also allows editing of the entry.
#
proc editPasswords {} {
  
  package require elastictabs
 
  if {[info exists ::pwLocker::window]} {
    destroy $::pwLocker::window
  }
  # Lets use 'viewString' to show this...
  set whatToDo [list {Add a new Password} {addNewPw %w {}}\
		    {edit selected}   {editSelectedPass %w}\
		    {delete selected} {deleteSelectedPass %w}\
                    {merge passwords from} {mergePassWords %w}]
  set lines {}
  set w [ViewString "Passwords" lines utf16 $whatToDo spellOps 0 undo 0]
  # Set window up to select by line
  bind $w <1> {
    set tk::Priv(selectMode) line
    catch {tk::TextSelectTo %W %x %y}
    catch {%W mark set insert sel.first}
  }
  set ::pwLocker::window $w
  frputs "[wm geo $w] "
  populatePwEditWindow $w
}

proc populatePwEditWindow {w} {
  global glob config
  append line  "\n Mouse <3> gives a menu which allows adding, editing "
  append line  "or deleting a password. Mouse <1> selects line.\n\n"
  append line  " Note: If editing leaves the original password you will be asked if you want to delete it.\n\n"
  
  realWaitForIdle
  set widthOverhead [expr {[winfo width $w] - [winfo width $w.text] + 8}]
  frputs "[wm geo $w] "
  $w.text tag configure el -elide 1
  # append line
  $w.text configure -state normal
  $w.text delete 0.0 end
  $w.text insert insert $line
  set line {}
  # set fon $glob(gui,ListBoxFont)
  set curPws [::pwLocker::patternGet *]
  
  set line  "     URL\tUSER\tPASSWORD\tCOMMENTS\n"
  foreach ent $curPws {
    set arg [list {*}[lassign $ent id pw]]
    if {$arg == {{}} } {
      set arg ""
    }
    # set pw [eval [list {*}$::pwLocker::decryptRoutine $password]]
    set failsafe 0
    while {[lindex $pw end] == {} && $pw != {} && [incr failsafe] < 4} {
      set pw [lrange $pw 0 end-1]
    }
    lassign [URLsplit $id] type user add port path
    if {$type == {}} {
      set user $id
    } else {
      append line  $type://$add
    }
    if {$port != {}} {
      append line :$port
    }
    if {$path != {} && [string equal -nocase $type "cifs"]} {
      append line / $path
    }
    # lappend sz1 [font measure $fon "$line "]
    append line \t$user
     if {$pw != {} || $arg != {}} {   
      append line \t[list {*}$pw]
    }
    if {$arg != {}} {
      append line \t[list {*}$arg]
    } 
    append line \n
    # tag each entry with the location in the list from patternGet
  }
  # Figure the max width
  
  lassign [ElasticTabStops $line $w.text width 5000 ret 1] line withW
  set lineList [split $line \n]
  set lineList [lassign $lineList headLine]
  set lineIndes [lsort -indices $lineList]
  $w.text insert insert $headLine\n
  foreach ent $lineIndes {
    $w.text insert insert "[lindex $curPws $ent] " el
    $w.text insert insert [lindex $lineList $ent]\n
  }
  $w.text mark set insert 0.0
  $w.text edit reset
  $w.text edit modified 0
  intelWinSize $::config(geometry,textviewer) $w.text
  ::autoscroll::autoscroll $w.scroll
  realWaitForIdle
  #bind $w.text <<UndoStack>> [list doReadOnly $w.text]
  #bind $w.text <<Modified>> [list doReadOnly $w.text]
  $w.text configure -state disabled
  lassign [split [wm geo .] +x] wd h
  # The 15 accounts for a border (2) and a scroll bar (11)
  wm geo $w [expr {$widthOverhead + $withW}]x$h
  frputs withW widthOverhead "[wm geo $w] "
}

proc addNewPw {w id  args} {
  # We ask the getpw routine to provide the password and unless we are way
  # wrong, it will pop up a dialog to fill in the details...
  # We are going to refresh the window after the return. If there are changes
  # let the user save those first.
  set id [regsub {([^:]:+//[^/]+)(.*)} $id {\1}]
  
  set newpass [::pwLocker::getPw $id \
		   newuser 1 \
		   full 1 \
		   returnall 1 \
                   prompt [list ""]\
		   {*}$args]

  if {$newpass in {0 -1 -2}} {return 0}
  frputs newpass
  array set newpw $newpass
  
  frputs "[array get newpw] " newpass li
  ::pwLocker::putPw $newpw(id)\
      [list $newpw(password)\
           $newpw(disk) \
           $newpw(passphrase)]\
      {*}$newpw(comment)
  
  if {$id != {} &&\
          ![string equal -nocase $id \
                [regsub {([^:]:+//[^/]+)(.*)} $newpw(id) {\1}]] &&\
          [::pwLocker::getPw $id noprompt 1] != -1} {
    set r [smart_dialog .apop[incr ::uni] . "!" \
               [list {} "Id \"$id\" is not \"$newpw(id)\"\nDelete $id?"]\
               0 2 \
               [list [_ "Yes"] [_ "No"]]]
    if {$r == 0} {
      
      if {[set entries [::pwLocker::delete $id case 1]] != 1} {
        # Something bad going on. We should always get 1
        PopError "Delete of ID \"$id\" returned 'deleted $entries', should be exactly 1."
      }
    }
  }
  
  if {$args == {}} {
    populatePwEditWindow $w
  }
  return 1
}

  
proc deleteSelectedPass {w} {
  if {[catch {$w.text get sel.first sel.last} lines] != 0} {
    if {[string match "*tagged with \"sel\"" $lines]} {
      set lines "Nothing selected."
    }
    PopError "$lines"
    return
  }
  set deleted 0
  frputs lines
  foreach line [split $lines \n] {
    # first toss the title line...
    if {$line == {} || [string index $line 0] == " "} {continue}
    incr deleted
    frputs line
    if {[set entries [::pwLocker::delete [lindex $line 0] case 1]] != 1} {
      # Something bad going on. We should always get 1
      PopError "Delete of ID \"$id\" deleted $entries, should be exactly 1."
      break
    }
  }
  if {$deleted == 0} {
    PopError "No password entries selected"
  }
  populatePwEditWindow $w
}


proc editSelectedPass {w} {
  if {[catch {$w.text get sel.first sel.last} lines] != 0} {
    if {[string match "*tagged with \"sel\" " $lines]} {
      set lines "Nothing selected."
    }
    PopError "$lines"
    return
  }
  frputs lines
  set doneCount 0
  foreach line [split $lines \n] {
    # first toss the title line...
    if {$line == {} || [string index $line 0] == " "} {continue}
    lassign $line id pw comment

    incr doneCount
    
    if {[addNewPw $w $id startwith $pw]} {continue}
    # Some sort of problem. If this is the first call, do nothing
    # otherwise repopulate the window to show what has been done
  }
  if {$doneCount == 0} {
    PopError "No password entries selected"
    return
  }
  
  populatePwEditWindow $w
}

proc mergePassWords {w} {
  PopError "not yet, but soon"
}
