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

# $Log: not supported by cvs2svn $
# Revision 1.3  2001/04/20 21:12:54  emery
# removed restore choice #1 <--> #2.
#
# Revision 1.2  2001/04/20 18:53:58  emery
# Added commandline arguments to disable restoring one or the other
# controller to simplify the interface.
#
# Revision 1.1  2001/04/19 20:44:54  emery
# First installation.
#

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 "\$Author: borland $"

APSApplication . -name SRRestoreXrayTranslation \
  -overview "SRRestoreXrayTranslation reads a XrayTranslation SCR file and restores
specific Xray translation PVs with possible renaming of PV names."


proc MakeInputFrame {widget args} {
    global initialSCRSystem system oagDataDir
    global outputFileDir outputFileRoot outputFile 
    global beamline searchString daysPast

    set parent ""

    set arrayName ""
    set daysPast 7
# SCRFiles is an array, but the variable SCRFile will be
# a regular variable for the procedure KnLValues
    set arrayName SCRFiles
    set searchString *
    APSStrictParseArguments {parent}

    APSFrame $widget -parent $parent -label "Input parameters"
    set w $parent$widget.frame

    APSFrame .file  -parent $w -label "Choose SCR File"
    set w $parent$widget.frame.file.frame

    global $arrayName
    global apsSCRConfigStartYear apsSCRConfigStartMonth apsSCRConfigStartDay
    global apsSCRConfigEndYear apsSCRConfigEndMonth apsSCRConfigEndDay 
    APSSCRDateTimeEntryWidget .dtew -parent $w 
    APSSCRDefineVariables
    set system $initialSCRSystem
    APSDateBreakDown -dayVariable apsSCRConfigStartDay \
        -yearVariable apsSCRConfigStartYear -monthVariable apsSCRConfigStartMonth \
        -twoDigitYear 0 -leadingZeros 0
    APSDateBreakDown -dayVariable apsSCRConfigEndDay \
        -yearVariable apsSCRConfigEndYear -monthVariable apsSCRConfigEndMonth \
        -twoDigitYear 0 -leadingZeros 0
    if $daysPast {
        APSIncrementDateVariables -offset [expr -1*abs($daysPast)] -unit day \
          -dayVariable apsSCRConfigStartDay -yearVariable apsSCRConfigStartYear \
          -monthVariable apsSCRConfigStartMonth 
    }
    APSLabeledEntry .descript -parent $w.dtew.frame \
      -label "Description search string: " \
      -textVariable searchString  -packOption "-side top" -width 40 \
      -contextHelp "Enter a string to use in searching for files by matching the description given by the operator who saved the snapshot."
    APSFrame .choice -parent $w -label "Snapshot choice" 
    set w1 $w.choice.frame
    set ${arrayName}(ShortFilename) ""
    set ${arrayName}(Description) ""
    APSLabeledOutput .filename -parent $w1 -label "Filename" \
      -textVariable ${arrayName}(ShortFilename) -width 100
    APSLabeledOutput .description -parent $w1 -label "Description" \
      -textVariable ${arrayName}(Description) -width 100

    APSButton .refresh -parent $w -text Refresh \
      -command \
      "APSListSCRMatchSetArray1 -machine \$system -height 8 \
      -startYear \$apsSCRConfigStartYear -startMonth \$apsSCRConfigStartMonth \
      -startDay \$apsSCRConfigStartDay \
      -endYear \$apsSCRConfigEndYear -endMonth \$apsSCRConfigEndMonth \
      -endDay \$apsSCRConfigEndDay \
      -descriptionFragment \$searchString -parent $w \
      -statusCallback SetStatus \
      -callback APSAddSCRDialogCallback \
      -arrayName $arrayName -routine 0"
    APSListSCRMatchSetArray1 -machine $system -height 8 \
      -startYear $apsSCRConfigStartYear -startMonth $apsSCRConfigStartMonth \
      -startDay $apsSCRConfigStartDay \
      -endYear $apsSCRConfigEndYear -endMonth $apsSCRConfigEndMonth \
      -endDay $apsSCRConfigEndDay \
      -descriptionFragment $searchString -parent $w  \
      -statusCallback SetStatus \
      -callback APSAddSCRDialogCallback \
      -arrayName $arrayName -routine 0

    set w $parent$widget.frame

    return
}

proc MakeControlWidgets {args} {
    global restoreButton
    APSParseArguments {parent controller}

    set controlWigetList [APSTabFrame .tabs -parent .userFrame -width 900 -height 150 \
                            -labelList "\"Restore\" \"Save\"" \
                            -label ""]
    set controlWidget .userFrame.tabs.frame.tn

    set windex 0
    set twidget [lindex $controlWigetList $windex]
    switch $controller {
        all {
            APSRadioButtonFrame .mode -parent $twidget -label "Select Mode" \
              -variable mode -limitPerRow 3 -valueList {asis 1only 2only 1to2 2to1} \
              -buttonList {"As is" "\#1 only" "\#2 only" "\#1 -> \#2" "\#2 -> \#1"} \
              -orientation vertical \
              -contextHelp "Select restore mode.\n\nAs is: Restores everthing without change.\n\n\#1 only: Restores all of translation stage \#1 PVs.\n\n\#2 only: Restores all of translation stage \#2 PVs.\n\n\#1 -> \#2: Takes translation stage \#1 PV values and restores translation stage \#2 with them.\n\n\#2 -> \#1: Takes translation stage \#2 PV values and restores translation stage \#1 with them.\n\n\#2 <--> \#1: Swaps values between translation stage \#1 and \#2 and restores everything."
        }
        1 {
            APSRadioButtonFrame .mode -parent $twidget -label "Select Mode" \
              -variable mode -limitPerRow 3 -valueList {1only 1to2} \
              -buttonList {"\#1 only" "\#1 -> \#2"} \
              -orientation vertical \
              -contextHelp "Select restore mode.\n\n\#1 only: Restores all of translation stage \#1 PVs.\n\n\#1 -> \#2: Takes translation stage \#1 PV values and restores translation stage \#2 with them."
        }
        2 {
            APSRadioButtonFrame .mode -parent $twidget -label "Select Mode" \
              -variable mode -limitPerRow 3 -valueList {2only 2to1} \
              -buttonList {"\#2 only" "\#2 -> \#1"} \
              -orientation vertical \
              -contextHelp "Select restore mode.\n\n\#2 only: Restores all of translation stage \#2 PVs.\n\n\#2 -> \#1: Takes translation stage \#2 PV values and restores translation stage \#1 with them."
        }
    }
    APSButton .restore -parent $twidget -text "Restore" \
      -command \
      { \
          catch {RestoreFile -SCRFile $SCRFiles(Filename) -mode $mode} status } \
      -contextHelp "Restores SCR file with specified mode."
    set restoreButton $twidget.restore.button
    APSDisableButton $twidget.restore.button 
    
    set windex 1
    set twidget [lindex $controlWigetList $windex]
    APSFrame .save -parent $twidget  -label "Save XrayTranslation configuration" \
     -contextHelp \
     "Use this frame to make a save of the XrayTranslation system."
    set w $twidget.save.frame
    $w configure -relief flat
    APSLabeledEntry .saveDescription -parent $w \
     -packOption "-side top -anchor w" \
     -label "Save description:" \
     -textVariable saveDescription -width 55
    APSFrame .savebuttons -parent $w  -label "" \
     -contextHelp \
     "Use this frame to make a save of the XrayTranslation system."
    set w $twidget.save.frame.savebuttons.frame
    $w configure -relief flat
    set saveConfig ""
    switch $controller {
        all {
            APSButton .saveMachine -parent $w \
              -packOption "-side left -anchor w" \
              -text "Save all" \
              -command {set saveConfig [SaveConfig -mode all -description $saveDescription -statusCallback "APSSetVarAndUpdate status"]} \
              -contextHelp "Saves the full XrayTranslation configuration, just like in SaveCompareRestore."
            APSButton .saveMachine1 -parent $w \
              -packOption "-side left -anchor w" \
              -text "Save controller \#1 only" \
              -command {set saveConfig [SaveConfig -mode 1only -description $saveDescription -statusCallback "APSSetVarAndUpdate status"]} \
              -contextHelp "Saves XrayTranslation configuration for controller \#1 only."
            APSButton .saveMachine2 -parent $w \
              -packOption "-side left -anchor w" \
              -text "Save controller \#2 only" \
              -command {set saveConfig [SaveConfig -mode 2only -description $saveDescription -statusCallback "APSSetVarAndUpdate status"]} \
              -contextHelp "Saves XrayTranslation configuration for controller \#2 only."
        }
        1 -
        2 {
            APSButton .saveMachine$controller -parent $w \
              -packOption "-side left -anchor w" \
              -text "Save controller \#${controller} only" \
              -command {set saveConfig [SaveConfig -mode ${controller}only -description $saveDescription -statusCallback "APSSetVarAndUpdate status"]} \
              -contextHelp "Saves XrayTranslation configuration for controller \#${controller} only."
        }
    }
}

proc APSListSCRMatchSetArray1 {args} {
    global apsSCRRequestDir apsSCRSnapDir apsSCRSystem
    set machine ""
    set startYear 0
    set startDay 0
    set startMonth 0
    set endYear 0
    set endDay 0
    set endMonth 0
    set descriptionFragment "" 
    set statusCallback puts
    set parent ""
    set routine 0
    set callback ""
    set arrayName ""
    set height 10
    if [APSStrictParseArguments \
          {machine startYear startDay startMonth endYear endDay endMonth \
             descriptionFragment statusCallback height \
             parent routine callback arrayName}]==-1 {
        return -code error "APSListSCRMatch: bad arguments"
    }

    if $routine {
        set descriptionFragment "Routine save"
        set startYear 1990
        set endYear 2090
        set startDay 1
        set endDay 1
        set startMonth 1
        set endMonth 1
    }
    
    if {[string length $descriptionFragment] == 0} {
        $statusCallback "Supply a description search string (use * for everything)"
        return
    }
    if {[winfo exists ${parent}.apsSCRlist]} {destroy ${parent}.apsSCRlist}
    #    if {[winfo exists ${parent}.apsSCRcateg]} {destroy ${parent}.apsSCRcateg}
    $statusCallback "Searching for $machine..." 
    set oldDir [pwd]
    set snapDir $apsSCRSnapDir/$machine
    cd $snapDir
    set noMatches 0
    if {[file exists collapsed]} {
        set collapsedDirectoryFound 1
        cd collapsed
    } else {
        set collapsedDirectoryFound 0
    }
    set fileList \
      [APSFindFilesBetweenDates -directory . -rootname c$machine -tailsOnly 1 \
         -startDateList \
         [APSFormatDate -year $startYear -month $startMonth -day $startDay \
            -twoDigitYear 0 -dateFormat list] \
         -endDateList \
         [APSFormatDate -year $endYear -month $endMonth -day $endDay \
            -twoDigitYear 0 -dateFormat list] \
         -extensionList {""}
      ]
    if [llength $fileList]==0 {
        $statusCallback "No match found for dates given."
        set noMatches 1
#        cd $oldDir
#        return
    }
    set tmpID [APSUniqueName tmpID]
    if {!$noMatches} {
        set fileList [lsort $fileList]
        set listData /tmp/[APSTmpString]
        APSAddToTmpFileList -ID $tmpID -fileList $listData
        regsub -all {\[} ${descriptionFragment} {\[} descriptionFragment
        if [catch {eval exec sddscombine $fileList -pipe=out -merge \
                     | sddsprocess -pipe=in $listData \
                     \"-match=col,SnapshotDescription=+*${descriptionFragment}*\" -nowarnings} result] {
            $statusCallback "Error scanning descriptions of snapshots!"
            APSAlertBox [APSUniqueName .] -errorMessage "$result" 
            APSDeleteTmpFileList -ID $tmpID
            cd $oldDir
            return
        }
        if [catch {exec sdds2stream -rows $listData} result] {
            $statusCallback "Error reading list of matching snapshots"
            APSDeleteTmpFileList -ID $tmpID
            cd $oldDir
            return
        }
        set count [lindex [split $result] 0]
        $statusCallback "Count: $count"
        if {$count == 0} {
            $statusCallback "No match to search criteria"
            puts stderr "No match to search criteria"
            #        APSDeleteTmpFileList -ID $tmpID
            #        cd $oldDir
            #        return
        }
    }
    if {$collapsedDirectoryFound} {
        cd ..
    }
    APSFrame .apsSCRlist -parent $parent -label "" -relief flat 
    set w $parent.apsSCRlist.frame

    global apsSCRMakeLBoxTextLineMaxWidth apsSCRTopDirectory
    set apsSCRMakeLBoxTextLineMaxWidth 0
    global $arrayName
    set ${arrayName}(Filename) ""
    set ${arrayName}(ShortFilename) ""
    set ${arrayName}(Description) ""
    set ${arrayName}(IsPreferredFile) 0
    set apsSCRSystem $machine
    if {!$noMatches} {
        APSSDDSListbox .snaplist -parent $w -height $height \
          -widthLimit 120 -trim 1 \
          -fileName $listData -labelMaker APSSCRMakeLBoxTextLine -arrayName apsSCRMatchListArray \
          -page 0 -callback "APSListSCRMatchSetArrayCallback $callback 0 $arrayName " \
          -columnList {SnapshotFilename TimeStamp SnapshotDescription} \
          -contextHelp "Double-click to select a snapshot" -doneButton 0 \
          -label "Snapshot Choices"
    }
    if {!$routine && [file exists $apsSCRTopDirectory/preferredChoices/$machine.sdds]} {
        global apsSCRTopDirectory
        APSSDDSListbox .preflist -parent $w -height 4 \
          -widthLimit 120 -trim 1 -label "Preferred/Reference Choices" \
          -fileName $apsSCRTopDirectory/preferredChoices/$machine.sdds \
          -labelMaker APSSCRMakePrefLBoxTextLine -arrayName apsSCRMatchListPreferredArray \
          -page 0 -callback "APSListSCRMatchSetArrayCallback $callback 1 $arrayName "\
          -columnList {ChoiceName Suffix} \
          -contextHelp "Double-click to select a preferred file." -doneButton 0
    }

    $statusCallback "Pick a configuration to use."
    APSDeleteTmpFileList -ID $tmpID
    cd $oldDir
}

proc APSAddSCRDialogCallback {arrayName} {
    global $arrayName apsSCRSnapDir apsSCRSystem status
    global outputFileRoot
    if [set ${arrayName}(FileNotFound)] {
        set status "File not found!"
        update
        return
    }
    set name [set ${arrayName}(Filename)]
    set ${arrayName}(ShortFilename) $name
    set descrip [set ${arrayName}(Description)]
    set snapDir $apsSCRSnapDir/$apsSCRSystem
    if ![file exists $snapDir/$name] {
        if [file exists $snapDir/${name}.gz] {
            set name ${name}.gz
        } else {
            set status "File not found!"
            update
            return
        }
    }
    set ${arrayName}(Filename) $snapDir/$name
    set outputFileRoot [file root $name]
    EnableRestoreButton
}

proc EnableRestoreButton {} {
    global restoreButton
    APSEnableButton $restoreButton
}

proc RestoreFile {args} {
    set SCRFile ""
    set mode ""
    APSParseArguments {SCRFile mode}
    if ![string length $SCRFile] {
        return -code error "RestoreFile: No SCRFile given."
    }
    if ![string length $mode] {
        return -code error "RestoreFile: No mode given."
    }
    APSSetVarAndUpdate status "Setting up restore file"
    set tmpfile /tmp/[APSTmpString]
    switch $mode {
        asis {
            # do nothing
        }
        1only {
            exec sddsprocess $SCRFile $tmpfile -match=col,ControlName=SXDRV:1:* \
              -noWarning
        }
        2only {
            exec sddsprocess $SCRFile $tmpfile -match=col,ControlName=SXDRV:2:* \
              -noWarning
        }
        1to2 {
            exec sddsprocess $SCRFile $tmpfile -match=col,ControlName=SXDRV:1:* \
              -reedit=col,ControlName,%/SXDRV:1/SXDRV:2/ \
              -noWarning
        }
        2to1 {
            exec sddsprocess $SCRFile $tmpfile -match=col,ControlName=SXDRV:2:* \
              -reedit=col,ControlName,%/SXDRV:2/SXDRV:1/ \
              -noWarning
        }
        1exch2 {
            exec sddsprocess $SCRFile $tmpfile \
              -reedit=col,ControlName,%/SXDRV:2/SXDRV:X/ \
              -reedit=col,ControlName,%/SXDRV:1/SXDRV:2/ \
              -reedit=col,ControlName,%/SXDRV:X/SXDRV:1/ \
              -noWarning
        }
        default {
            return -code error "RestoreFile: Unknown mode $mode."
        }
    }
    exec sddscasr -restore $tmpfile
    APSSetVarAndUpdate status "Done."
    return
}

proc SaveConfig {args} {
    global apsSCRRequestDir
    set description ""
    set mode all
    APSParseArguments {mode description}
    if ![string length $description] {
        return -code error "SaveConfig: description has null value."
    }
    switch $mode {
        all {
            set saveConfig [APSSaveMachine -machine XrayTranslation -description $description]
        }
        1only {
            set tmpfile /tmp/[APSTmpString]
            exec sddsprocess ${apsSCRRequestDir}/XrayTranslation.req \
              $tmpfile.req -match=col,ControlName=SXDRV:1*
            set saveConfig [APSSaveMachine -machine XrayTranslation \
                              -requestFile $tmpfile.req \
                              -description $description]
        }
        2only {
            set tmpfile /tmp/[APSTmpString]
            exec sddsprocess $apsSCRRequestDir/XrayTranslation.req \
              $tmpfile.req -match=col,ControlName=SXDRV:2*
            set saveConfig [APSSaveMachine -machine XrayTranslation \
                              -requestFile $tmpfile.req \
                              -description $description]
        }
    }
    APSSetVarAndUpdate status "Save to $saveConfig Done."
    return -code ok $saveConfig
}

proc SetStatus {text} {
    global status
    set status $text
}

set args $argv
set controller all
set allowedControllers {1 2 all}
APSStrictParseArguments {controller}
if {-1==[lsearch $allowedControllers $controller]} {
    return -code error "$argv0: Controller number $controller not recognized."
}

if [string match $controller all] {
    set status "Working on both controllers."
    set mode asis
} else {
    set status "Working on controller $controller."
    set mode ${controller}only
}
APSScrolledStatus .status -parent .userFrame -textVariable status -width 90

set oagDataDir /home/helios/oagData/sr/magnetConditioning/lattices/default
set SCRFiles(Filename) ""
set initialSCRSystem XrayTranslation
set outputFileDir .
set outputFileRoot ""
set beamline SR
set statusCallback ""
set abortVariable ""
MakeInputFrame .input -parent .userFrame
MakeControlWidgets .controls -parent .userFrame -controller $controller
set status "Ready."
update

proc APSListSCRMatch {args} {
    global apsSCRRequestDir apsSCRSnapDir
    set machine ""
    set startYear 0
    set startDay 0
    set startMonth 0
    set endYear 0
    set endDay 0
    set endMonth 0
    set descriptionFragment "" 
    set statusCallback puts
    set parent ""
    set routine 0
    set callback ""
    set height 10
    if [APSStrictParseArguments \
          {machine startYear startDay startMonth endYear endDay endMonth \
             descriptionFragment statusCallback height \
             parent routine callback}]==-1 {
        return -code error "APSListSCRMatch: bad arguments"
    }
    if $routine {
        set descriptionFragment "Routine save"
        set startYear 1990
        set endYear 2090
        set startDay 1
        set endDay 1
        set startMonth 1
        set endMonth 1
    }
    
    if {[string length $descriptionFragment] == 0} {
        $statusCallback "Supply a description search string (use * for everything)"
        return
    }
    if {[winfo exists ${parent}.apsSCRlist]} {destroy ${parent}.apsSCRlist}
    #    if {[winfo exists ${parent}.apsSCRcateg]} {destroy ${parent}.apsSCRcateg}
    $statusCallback "Searching for $machine..." 
    set oldDir [pwd]
    set snapDir $apsSCRSnapDir/$machine
    cd $snapDir
    if {[file exists collapsed]} {
        set collapsedDirectoryFound 1
        cd collapsed
    } else {
        set collapsedDirectoryFound 0
    }
    set fileList \
      [APSFindFilesBetweenDates -directory . -rootname c$machine -tailsOnly 1 \
         -startDateList \
         [APSFormatDate -year $startYear -month $startMonth -day $startDay \
            -twoDigitYear 0 -dateFormat list] \
         -endDateList \
         [APSFormatDate -year $endYear -month $endMonth -day $endDay \
            -twoDigitYear 0 -dateFormat list] \
         -extensionList {""}
       ]
    if [llength $fileList]==0 {
        $statusCallback "No match found for dates given."
        cd $oldDir
        return
    }
    set fileList [lsort $fileList]
    set listData /tmp/[APSTmpString]
    set tmpID [APSUniqueName tmpID]
    APSAddToTmpFileList -ID $tmpID -fileList $listData
    regsub -all {\[} ${descriptionFragment} {\[} descriptionFragment
    if [catch {eval exec sddscombine $fileList -pipe=out -merge \
                | sddsprocess -pipe=in $listData \
                 \"-match=col,SnapshotDescription=+*${descriptionFragment}*\" -nowarnings} result] {
        $statusCallback "Error scanning descriptions of snapshots!"
        APSAlertBox [APSUniqueName .] -errorMessage "$result" 
        APSDeleteTmpFileList -ID $tmpID
        cd $oldDir
        return
    }
    if [catch {exec sdds2stream -rows $listData} result] {
        $statusCallback "Error reading list of matching snapshots"
        cd $oldDir
        APSDeleteTmpFileList -ID $tmpID
        return
    }
    set count [lindex [split $result] 0]
    if {$count == 0} {
        $statusCallback "No match to search criteria"
        cd $oldDir
        APSDeleteTmpFileList -ID $tmpID
        return
    }
    if {$collapsedDirectoryFound} {
        cd ..
    }
    global apsSCRMakeLBoxTextLineMaxWidth
    set apsSCRMakeLBoxTextLineMaxWidth 0
    APSSDDSListbox .apsSCRlist -parent ${parent} -height $height \
      -widthLimit 120 -trim 1 \
      -fileName $listData -labelMaker APSSCRMakeLBoxTextLine -arrayName descriptionArray \
      -page 0 -callback $callback -columnList {SnapshotFilename TimeStamp SnapshotDescription} \
      -contextHelp "Double-click to select a snapshot" -doneButton 0

    $statusCallback "Pick a configuration to use"
    cd $oldDir
    APSDeleteTmpFileList -ID $tmpID
}

proc APSListSCRMatchSetArray {args} {
    global apsSCRRequestDir apsSCRSnapDir apsSCRSystem
    set machine ""
    set startYear 0
    set startDay 0
    set startMonth 0
    set endYear 0
    set endDay 0
    set endMonth 0
    set descriptionFragment "" 
    set statusCallback puts
    set parent ""
    set routine 0
    set callback ""
    set arrayName ""
    set height 10
    if [APSStrictParseArguments \
          {machine startYear startDay startMonth endYear endDay endMonth \
             descriptionFragment statusCallback height \
             parent routine callback arrayName}]==-1 {
        return -code error "APSListSCRMatch: bad arguments"
    }

    if $routine {
        set descriptionFragment "Routine save"
        set startYear 1990
        set endYear 2090
        set startDay 1
        set endDay 1
        set startMonth 1
        set endMonth 1
    }
    
    if {[string length $descriptionFragment] == 0} {
        $statusCallback "Supply a description search string (use * for everything)"
        return
    }
    if {[winfo exists ${parent}.apsSCRlist]} {destroy ${parent}.apsSCRlist}
    #    if {[winfo exists ${parent}.apsSCRcateg]} {destroy ${parent}.apsSCRcateg}
    $statusCallback "Searching for $machine..." 
    set oldDir [pwd]
    set snapDir $apsSCRSnapDir/$machine
    cd $snapDir
    if {[file exists collapsed]} {
        set collapsedDirectoryFound 1
        cd collapsed
    } else {
        set collapsedDirectoryFound 0
    }
    set fileList \
      [APSFindFilesBetweenDates -directory . -rootname c$machine -tailsOnly 1 \
         -startDateList \
         [APSFormatDate -year $startYear -month $startMonth -day $startDay \
            -twoDigitYear 0 -dateFormat list] \
         -endDateList \
         [APSFormatDate -year $endYear -month $endMonth -day $endDay \
            -twoDigitYear 0 -dateFormat list] \
         -extensionList {""}
       ]
    if [llength $fileList]==0 {
        $statusCallback "No match found for dates given."
        cd $oldDir
        return
    }
    set fileList [lsort $fileList]
    set listData /tmp/[APSTmpString]
    set tmpID [APSUniqueName tmpID]
    APSAddToTmpFileList -ID $tmpID -fileList $listData
    regsub -all {\[} ${descriptionFragment} {\[} descriptionFragment
    if [catch {eval exec sddscombine $fileList -pipe=out -merge \
                | sddsprocess -pipe=in $listData \
                 \"-match=col,SnapshotDescription=+*${descriptionFragment}*\" -nowarnings} result] {
        $statusCallback "Error scanning descriptions of snapshots!"
        APSAlertBox [APSUniqueName .] -errorMessage "$result" 
        APSDeleteTmpFileList -ID $tmpID
        cd $oldDir
        return
    }
    if [catch {exec sdds2stream -rows $listData} result] {
        $statusCallback "Error reading list of matching snapshots"
        APSDeleteTmpFileList -ID $tmpID
        cd $oldDir
        return
    }
    set count [lindex [split $result] 0]
    if {$count == 0} {
        $statusCallback "No match to search criteria"
        APSDeleteTmpFileList -ID $tmpID
        cd $oldDir
        return
    }
    if {$collapsedDirectoryFound} {
        cd ..
    }

    APSFrame .apsSCRlist -parent $parent -label "" -relief flat 
    set w $parent.apsSCRlist.frame

    global apsSCRMakeLBoxTextLineMaxWidth apsSCRTopDirectory
    set apsSCRMakeLBoxTextLineMaxWidth 0
    global $arrayName
    set ${arrayName}(Filename) ""
    set ${arrayName}(ShortFilename) ""
    set ${arrayName}(Description) ""
    set ${arrayName}(IsPreferredFile) 0
    set apsSCRSystem $machine
    APSSDDSListbox .snaplist -parent $w -height $height \
      -widthLimit 120 -trim 1 \
      -fileName $listData -labelMaker APSSCRMakeLBoxTextLine -arrayName apsSCRMatchListArray \
      -page 0 -callback "APSListSCRMatchSetArrayCallback $callback 0 $arrayName " \
      -columnList {SnapshotFilename TimeStamp SnapshotDescription} \
      -contextHelp "Double-click to select a snapshot" -doneButton 0 \
      -label "Snapshot Choices"
    if {!$routine && [file exists [file join $apsSCRTopDirectory preferredChoices $machine.sdds]]} {
        global apsSCRTopDirectory
        APSSDDSListbox .preflist -parent $w -height 4 \
          -widthLimit 120 -trim 1 -label "Preferred/Reference Choices" \
          -fileName $apsSCRTopDirectory/preferredChoices/$machine.sdds \
          -labelMaker APSSCRMakePrefLBoxTextLine -arrayName apsSCRMatchListPreferredArray \
          -page 0 -callback "APSListSCRMatchSetArrayCallback $callback 1 $arrayName "\
          -columnList {ChoiceName Suffix} \
          -contextHelp "Double-click to select a preferred file." -doneButton 0
    }

    $statusCallback "Pick a configuration to use"
    APSDeleteTmpFileList -ID $tmpID
    cd $oldDir
}

proc APSListSCRMatchSetArrayCallback {callback mode arrayName index} {
    global $arrayName apsSCRMatchListArray apsSCRMatchListPreferredArray
    global apsSCRSystem apsSCRSnapDir apsSCRRestoreFilename apsSCRMatchListPreferredArray
    set ${arrayName}(FileNotFound) 1
    if $mode {
        # preferred file 
        set item [lindex $apsSCRMatchListPreferredArray(ChoiceName) $index]
        if {![catch {APSSCRResolvePreferredFileChoice -system $apsSCRSystem -choice $item} file] && \
		[file exists [file join $apsSCRSnapDir $apsSCRSystem $file]]} {
            set file [file readlink [file join $apsSCRSnapDir $apsSCRSystem $file]]
            set filename0 [file tail $file]
            set ${arrayName}(IsPreferredFile) $mode
            set ${arrayName}(Filename) [file rootname $filename0]
            set ${arrayName}(Description) \
              [join [APSGetSDDSColumn -page 0 -column SnapshotDescription \
                       -fileName $apsSCRSnapDir/$apsSCRSystem/c[file rootname $filename0]]]
            set ${arrayName}(FileNotFound) 0
        }
    } else {
        # normal file
        set ${arrayName}(IsPreferredFile) $mode
        set ${arrayName}(Filename) [lindex $apsSCRMatchListArray(SnapshotFilename)  $index]
        set ${arrayName}(Description) [lindex $apsSCRMatchListArray(SnapshotDescription) $index]
        set ${arrayName}(FileNotFound) 0
    }
    eval $callback ${arrayName}
}

proc APSSCRMakePrefLBoxTextLine {args} {
    global apsSCRMakeLBoxTextLineMaxWidth
    set dataList {}
    set widthList {}
    APSStrictParseArguments {dataList widthList}
    set choice [lindex $dataList 0]
    set wc [lindex $widthList 0]
    set sform [format "%%%lds" $apsSCRMakeLBoxTextLineMaxWidth]
    return [format $sform $choice]
}

