#!/bin/sh  
# \
exec oagwish "$0" "$@"

#
# $Log: not supported by cvs2svn $
# Revision 1.13  1998/07/16 18:25:25  borland
# Per D. Blachowicz: fixed bug with delete/save/create sequence.
# Now creating columns with proper data types (not all strings).
#
# Revision 1.12  1997/08/11 16:48:31  borland
# Now trims \012 and space from to-do descriptions.  For some reason, old
# items had many \012's appended to them.
#
# Revision 1.11  1997/06/27 18:41:02  borland
# Fixed logic in save routine so that it behaves properly for blank
# dataFileName.
#
# Revision 1.10  1997/06/27 18:36:24  borland
# Set initial value for dataFileName to avoid tcl error when no file is
# defined.  No longer backup the autosave file.
#
# Revision 1.9  1997/06/24 16:11:53  borland
# Fixed problem with -silent option to SaveToDoFile
#
# Revision 1.8  1997/06/24 16:09:40  borland
# Added autosaving of data.
#
# Revision 1.7  1997/06/24 15:42:58  borland
# Now gives control over whether deleted and/or completed items are included
# in searches.
#
# Revision 1.6  1997/06/24 14:38:06  borland
# Now deletes items that are marked for deletion when the data is written out.
#
# Revision 1.5  1997/06/20 22:52:56  borland
# No longer considers deleted items when doing search.
#
# Revision 1.4  1997/06/20 22:49:35  borland
# Now makes a backup copy of eisting fiel before saving.
#
# Revision 1.3  1997/06/20 22:47:25  borland
# Fixed type (DataColumnTypesList vs DataColumnTypeList).
#
# Revision 1.2  1997/06/20 22:38:14  borland
# Now accepts -fileName commandline argument.
#
# Revision 1.1  1997/06/20 22:04:10  borland
# First version.
#
#

set auto_path [linsert $auto_path 0 /usr/local/oag/apps/lib/$env(HOST_ARCH)]
set auto_path [linsert $auto_path 0  /usr/local/oag/lib_patch/$env(HOST_ARCH)]
APSDebugPath

set CVSRevisionAuthor "\$Revision: 1.14 $ \$Author: borland $"

set indexShown 0
set numberOfItems 0
set workingDir [pwd]
set blockAutoSave 0
set dataFileName ""

set fileName ""
set args $argv
APSStrictParseArguments {fileName}

set DataColumnList {EntryTimeStamp CompletionTimeStamp ToDoStatus EntryTime CompletionTime ToDoText Priority}
set DataColumnTypeList {STRING STRING STRING LONG LONG STRING LONG}

proc SetStatus {text} {
    global statusText
    set statusText "$text"
    update
}

proc SetUpToDoFrame {widget args} {
    set parent ""
    APSStrictParseArguments {parent}
    if ![winfo exists $parent$widget] {
        APSFrame $widget -parent $parent -label "" 
        # create a frame-within-a-frame to allow deleting all
        # the guts without losing the position in the parent
        frame $parent$widget.frame.frame
        pack $parent$widget.frame.frame
    } else {
        if [winfo exists $parent$widget.frame.frame] {
            # destroy all the guts of the widget
            destroy $parent$widget.frame.frame
        }
        # make a new container for the guts
        frame $parent$widget.frame.frame
        pack $parent$widget.frame.frame
    }
    return $parent$widget.frame.frame
}

proc ReadToDoFile {widget args} {
    set fileName ""
    set parent ""
    set new 0
    APSStrictParseArguments {parent fileName new}

    global itemParent numberOfItems disableAutoSave

    if !$new {
        global workingDir dataFileName
        if ![string length $fileName] {
            set fileName \
              [APSFileSelectDialog .openDialog -listDir $workingDir \
                 -contextHelp "Select a file to edit." \
                 -title "Select file to edit."]
            update idletasks
            if ![string length $fileName] return
        }
        set disableAutoSave 0
        if [file exists $fileName.autosave] {
            if [APSMultipleChoice [APSUniqueName .] \
                  -question "An autosave file exists.  Use it?" \
                  -labelList "Yes No" -returnList "1 0"] {
                set fileName $fileName.autosave
                set disableAutoSave 1
                SetStatus "Autosaving disabled until this file saved manually using Save or Save as..."
            }
        }
        if [catch {sdds open $fileName r} fid] {
            SetStatus $fid
            return
        }
        if $disableAutoSave {
            # get rid of the .autosave extension for use in later saves
            set fileName [file rootname $fileName]
        }
        global DataColumnList 
        foreach column $DataColumnList {
            global ${column}
            if [catch {sdds getColumn $fid $column} ${column}] {
                SetStatus "[subst \$${column}]"
                return
            }
        }
        if [catch {sdds close $fid} result] {
            SetStatus $result
        }
        set workingDir [file dirname $fileName]
        set dataFileName [file tail $fileName]
        set numberOfItems 0
    } else {
        global DataColumnList
        set disableAutoSave 0
        foreach column $DataColumnList {
            global ${column}
            set ${column} ""
        }
        set numberOfItems 0
    }

    set w [SetUpToDoFrame $widget -parent $parent]
    set itemParent $w
    set index 0
    set parent $parent$widget.frame
    if !$new {
        foreach item $EntryTimeStamp {
            AddToDoEntry -parent $w -blank 0
            incr index
        } 
    } else {
        set index 0
        AddToDoEntry -parent $w -blank 1
        incr index
    }
    ShowToDoEntry -index [expr $numberOfItems-1]
}

proc AddToDoEntry {args} {
    global numberOfItems
    set parent ""
    set blank 0
    set scrollAdjust 0
    set scrollParent ""
    APSStrictParseArguments {parent blank scrollAdjust scrollParent}
    set index $numberOfItems
    set widget .item$index
    global DataColumnList
    eval global $DataColumnList
    if $blank {
        lappend EntryTime [expr int([exec timeconvert -break=now])]
        lappend EntryTimeStamp [exec timeconvert -sec=[lindex $EntryTime $index] -text]
        lappend ToDoStatus pending
        lappend CompletionTimeStamp ""
        lappend CompletionTime 0
        lappend ToDoText ""
        lappend Priority 1
    }
    foreach var $DataColumnList {
        global $var$index
        set $var$index [lindex [subst \$$var] $index]
    }
    if [winfo exists $parent$widget] {
        destroy $parent$widget
    }
    APSFrame $widget -parent $parent -relief flat -label "" -noPack 1
    APSFrameGrid .fg -parent $parent$widget.frame -yList {top mid bot} 
    set p1 $parent$widget.frame.fg
    APSLabeledOutput .status -parent $p1.top \
      -label "Item $numberOfItems     Status: " -width 10 -packOption "-side left" \
      -textVariable ToDoStatus$index 
    APSLabeledEntry .priority -parent $p1.top \
      -label "Priority: " -width 4 -packOption "-side left" \
      -textVariable Priority$index
    APSLabeledOutputFrame .time -parent $p1.mid \
      -label "Entry, completion times: " -width 26 \
      -variableList [list EntryTimeStamp$index CompletionTimeStamp$index] \
      -orientation horizontal 
    APSFrame .buttons -parent $p1.bot -label "" -packOption "-side left"
    set bframe $p1.bot.buttons.frame
    APSButton .complete -parent $bframe -size small -text "Complete" \
      -command "MarkAsComplete -index $index -state 1" -packOption "-side top"
    APSButton .incomplete -parent $bframe -size small -text "Pending" \
      -command "MarkAsComplete -index $index -state 0" -packOption "-side top"
    APSButton .delete -parent $bframe -size small -text "Delete" \
      -command "MarkAsDeleted -index $index -state 1" -packOption "-side top"
    APSButton .undelete -parent $bframe -size small -text "Undelete" \
      -command "MarkAsDeleted -index $index -state 0" -packOption "-side top"
    APSScrolledText .text -parent $p1.bot -name "" -width 80 -height 1
    global ToDoTextWidget$index ToDoWidget$index
    set ToDoTextWidget$index $p1.bot.text.text
    set ToDoWidget$index $parent$widget
    $p1.bot.text.text insert end [subst \$ToDoText$index]
    incr numberOfItems
    update
}

proc AddToDoEntryForUser {args} {
    set scrollParent ""
    APSParseArguments {scrollParent}
    eval AddToDoEntry $args -blank 1
    global numberOfItems
    ShowToDoEntry -index [expr $numberOfItems-1]
}

proc ShowToDoEntry {args} {
    set index 0
    APSStrictParseArguments {index}
    global indexShown numberOfItems

    if $numberOfItems<=$index {
       set index [expr $numberOfItems-1]
    }
    if $index<0 {
        set index 0
    }
    global ToDoWidget$index ToDoWidget$indexShown
    pack forget [subst \$ToDoWidget$indexShown]
    pack [subst \$ToDoWidget$index]
    set indexShown $index
}

proc DoAutoSave {} {
    global dataFileName workingDir numberOfItems disableAutoSave 
    if {!$numberOfItems || $disableAutoSave} return
    if [string length $dataFileName] {
        SaveToDoFile -saveTo $workingDir/$dataFileName.autosave -silent 1 -isAutoSave 1 -saveAs 0
    } else {
        SaveToDoFile -saveTo $workingDir/ToDoList.[pid].autosave -silent 1 -isAutoSave 1 -saveAs 0
    }
    after 60000 DoAutoSave
}

proc DeleteAutoSave {} {
    global dataFileName workingDir numberOfItems
    if [string length $dataFileName] {
        set filename $workingDir/$dataFileName.autosave 
    } else {
        set filename $workingDir/ToDoList.[pid].autosave
    }
    if [file exists $filename] {
        catch {file delete -force -- $filename}
    }
}
    
proc SaveToDoFile {args} {
    set saveAs 0
    set saveTo ""
    set silent 0
    set isAutoSave 0
    APSStrictParseArguments {saveAs saveTo silent isAutoSave}

    global blockAutoSave disableAutoSave workingDir dataFilename
    if !$isAutoSave {
        set blockAutoSave 1
    }
    if {($blockAutoSave || $disableAutoSave) && $isAutoSave} {
        return
    }
    
    global dataFileName workingDir
    if [string length $saveTo] {
        set outputFile $saveTo
    } elseif {$saveAs || ![string length $dataFileName]} {
        set outputFile \
          [APSInfoDialog [APSUniqueName .] -name "Output file dialog" \
             -width 40 -infoMessage "Output filename: " \
             -contextHelp "Enter the name of the file to which to write the data." \
             -default $workingDir/]
        if {![string length $outputFile] || \
            ([file exists $outputFile] && \
               ![APSMultipleChoice [APSUniqueName .] -question "$outputFile exists---overwrite?" \
                  -labelList "Yes No" -returnList "1 0" -name "File overwrite dialog"])} {
            set blockAutoSave 0
            SetStatus "Save cancelled."
            return
        }
    } else {
        set outputFile $workingDir/$dataFileName
    }
    if !$silent {
        SetStatus "Saving to $outputFile"
    }

    if {!$isAutoSave && [file exists $outputFile]} {
        if [catch {exec cp $outputFile ${outputFile}~} result] {
            SetStatus "Unable to make backup copy of $outputFile---not saved!"
            set blockAutoSave 0
            return
        }
    }

    if [catch {sdds open $outputFile w} fid] {
        SetStatus $fid
        set blockAutoSave 0
        return
    }
    global DataColumnList DataColumnTypeList
    foreach item $DataColumnList {
        set type [lindex $DataColumnTypeList [lsearch -exact $DataColumnList $item]]
        if [catch {sdds defineColumn $fid $item -type SDDS_$type} result] {
            SetStatus $result
            set blockAutoSave 0
            return
        }
    }
    global numberOfItems
    if [catch {sdds writeLayout $fid} result] {
        SetStatus $result
        set blockAutoSave 0
        return
    }

    for {set index 0} {$index<$numberOfItems} {incr index} {
        global ToDoText$index ToDoTextWidget$index
        set ToDoText$index [[subst \$ToDoTextWidget$index] get 1.0 end]
    }

    set rowCount 0
    for {set index 0} {$index<$numberOfItems} {incr index} {
        global ToDoStatus$index
        if [string compare [subst \$ToDoStatus$index] deleted] {
            foreach column $DataColumnList {
                global ${column}${index}
                lappend $column [string trim [subst \$${column}${index}] "\012 "]
            }
            incr rowCount
        }
    }

    if [catch {sdds startPage $fid $rowCount} result] {
        SetStatus $result
        set blockAutoSave 0
        return
    }

    foreach column $DataColumnList {
        if [catch {eval sdds setColumn $fid $column [subst \$$column]} result] {
            SetStatus $result
            set blockAutoSave 0
            return
        }
    }

    if {[catch {sdds writePage $fid} result] ||
       [catch {sdds close $fid} result]} {
        SetStatus $result
        set blockAutoSave 0
        return
    }
    set blockAutoSave 0
    set disableAutoSave 0
    if !$isAutoSave {
        set workingDir [file dirname $outputFile]
        set dataFileName [file tail $outputFile]
    }
    if !$silent {
        SetStatus Done.
    }
}

proc MarkAsComplete {args} {
    set index 0
    set state 1
    APSStrictParseArguments {index state}
    global CompletionTime$index CompletionTimeStamp$index
    if $state {
        set CompletionTime$index [expr int([exec timeconvert -break=now])]
        set CompletionTimeStamp$index [exec timeconvert -sec=[subst \$CompletionTime$index] -text]
    } else {
        set CompletionTime$index 0
        set CompletionTimeStamp$index ""
    }

    global ToDoStatus$index
    if $state {
        set ToDoStatus$index complete
    } else {
        set ToDoStatus$index pending
    }
}

proc MarkAsDeleted {args} {
    set index 0
    set state 1
    APSStrictParseArguments {index state}

    global ToDoStatus$index ToDoStatus${index}Last
    if $state {
        set ToDoStatus${index}Last [subst \$ToDoStatus$index]
        set ToDoStatus$index "deleted"
    } else {
        set ToDoStatus$index [subst \$ToDoStatus${index}Last]
    }
}

proc SearchForToDoItem  {args} {
    set matchString *
    set direction forward
    set minimumPriority 5
    set excludeCompleted 1
    set excludeDeleted 1
    APSStrictParseArguments {matchString direction minimumPriority excludeCompleted excludeDeleted}

    SetStatus "Searching..."
    global indexShown numberOfItems
    set increment 1
    if [string compare $direction forward] {
        set increment -1
    }
    set index [expr $indexShown+$increment]
    while {[expr $index>=0 && $index<$numberOfItems]} {
        global Priority$index ToDoStatus$index
        if {(!$excludeDeleted || [string compare [subst \$ToDoStatus$index] deleted]) && \
              (!$excludeCompleted || [string compare [subst \$ToDoStatus$index] complete]) \
              && [subst \$Priority$index]<=$minimumPriority} {
            global ToDoTextWidget$index
            set ToDoText [[subst \$ToDoTextWidget$index] get 1.0 end]
            if [string match $matchString $ToDoText] {
                ShowToDoEntry -index $index
                SetStatus "Match found."
                return
            }
        }
        set index [expr $index+$increment]
    }
    SetStatus "No match found."
}

APSApplication . -name MaintainToDoList -version $CVSRevisionAuthor \
  -overview "Maintains and searches a to-do list.  Keeps track of items that are completed and allows finding items by priority."

set statusText Working...
APSScrolledStatus .status -parent .userFrame -textVariable statusText -width 80

set itemParent [SetUpToDoFrame .todo -parent .userFrame]

set textMatch *
APSLabeledEntry .match -parent .userFrame -label "Search string: " \
  -textVariable textMatch -width 20 -contextHelp \
  "A wildcard string to match to the text during a search."
set minimumPriority 5
APSLabeledEntry .priority -parent .userFrame -label "Minimum priority: " \
  -textVariable minimumPriority -width 4 -contextHelp \
  "An integer value giving the minimum priority of the item to find." 
set excludeDeletedFromSearch 1
set excludeCompleteFromSearch 1
APSCheckButtonFrame .exclude -parent .userFrame -label "Exclude: " \
    -buttonList {"Deleted items" "Completed items"} \
    -variableList "excludeDeletedFromSearch excludeCompleteFromSearch" \
    -orientation horizontal -allNone 1 -contextHelp \
    "Permits exclusion from searching of items that have been deleted and/or completed."

APSButton .bsearch -parent .userFrame -text "Search backward" \
  -contextHelp "Finds the next item matching the search string." \
  -command {SearchForToDoItem -matchString $textMatch -direction backward -minimumPriority $minimumPriority -excludeDeleted $excludeDeletedFromSearch -excludeCompleted $excludeCompleteFromSearch}
APSButton .fsearch -parent .userFrame -text "Search forward" \
  -contextHelp "Finds the next item matching the search string." \
  -command {SearchForToDoItem -matchString $textMatch -direction forward -minimumPriority $minimumPriority -excludeDeleted $excludeDeletedFromSearch -excludeCompleted $excludeCompleteFromSearch}
APSButton .minus1 -parent .userFrame -text "-1" \
    -contextHelp "Moves to the next item" -command \
    {ShowToDoEntry -index [expr $indexShown-1]}
APSButton .plus1 -parent .userFrame -text "+1" \
    -contextHelp "Moves to the next item" -command \
    {ShowToDoEntry -index [expr $indexShown+1]}
APSButton .minus10 -parent .userFrame -text "-10" \
    -contextHelp "Moves to the item 10 items before this one." -command \
    {ShowToDoEntry -index [expr $indexShown-10]}
APSButton .plus10 -parent .userFrame -text "+10" \
    -contextHelp "Moves to the item 10 items after this one." -command \
    {ShowToDoEntry -index [expr $indexShown+10]}
APSButton .add -parent .userFrame -text "Add entry" \
  -contextHelp "Adds a new item at the end of the list" \
  -command {AddToDoEntryForUser -parent $itemParent -scrollParent .userFrame.todo.frame.scroll -scrollAdjust 1}

.menu.file.menu insert 1 command -label "Read..." -command "ReadToDoFile .todo -parent .userFrame"
.menu.file.menu insert 1 command -label "New" -command "ReadToDoFile .todo -parent .userFrame -new 1"
.menu.file.menu insert 1 command -label "Save" -command SaveToDoFile
.menu.file.menu insert 1 command -label "Save as..." -command "SaveToDoFile -saveAs 1"

if [string length $fileName] {
    set workingDir [file dirname $fileName]
    SetStatus "Reading $fileName..."
    ReadToDoFile .todo -parent .userFrame -fileName $fileName
}

set disableAutoSave 0
after 60000 DoAutoSave
dp_atexit append DeleteAutoSave

SetStatus Ready.
