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


# *******************************************************
# setStatusText : puts message into status area
# clearAll : Runs all clear* procedures, destroys partial compare dialog,
#            resets pv name filter
# clearSort : resets the compare sort choice
# clearTolerances : resets the compare tolerance values
# clearSearchString : resets time range for search, resets description search string
# clearCompareFilenames : clears filenames and descriptions for compare
# clearRestoreFilename : clears filename, descriptions for restore; resets restore lock
# clearSearch : destroys scrolled lists of files from searches
# compareSnapnameCallback : callback from snapshot dialog list for compare
# setCompareFilterFlags : brings up dialog box allow selection of partial comparison
# compareFiles : runs file comparison, including partial and full comparisons.
# saveSnapshot : runs saving of snapshots
# saveSnapshotFullSet : does routine saves of all systems
# makeCompareFilenameDisplayFrame :  makes frame for displaying filename and description, plus
#       reference choice for comparison.
# setCompareReferenceFile : finds the reference file and installs it as one of the choices for
#       comparison
# makeCompareFrame : makes/packs frame for doing compare
# makeSaveFrame : makes/packs frame for doing saves
# removeSnapshot : removes a snapshot (part of restore)
# reviewSnapshot : reviews the snapshot (part of restore)
# restoreSnapshot : restores the snapshot
# restoreSnapnameCallback : callback from snapshot dialog list for restore
# setSnapname : used by restoreSnapnameCallback and setRestoreReferenceFile
#       to assert a snapshot for restore
# makeRestoreFilenameDisplayFrame : makes frame for displaying  filename and description, plus
#       reference choice for restore
# setRestoreReferenceFile : finds the reference file and installs it as one of the choices for
#       comparison
# installPreferredSnapshot : installs a snapshot as the new reference (part of restore)
# makeRestoreFrame : makes/packs frame for doing restore
# runAPSListSCRMatch : runs APSListSCRMatch for compare and restore, creating scrollable
#       list of available snapshots
# makeSCRChoices : makes widget for choosing among save, compare, and restore
# changeSCRMode : changes among save, compare, and restore
# *******************************************************

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 apsttk 1

APSStandardSetup

set statusText ""
proc setStatusText { text } {
    global statusText
    set statusText "$text ([exec date +%H:%M:%S])"
    update
}

proc clearAll {} {
    clearSort
    clearTolerances
    clearSearchString
    clearCompareFilenames
    clearRestoreFilename
    clearSearch
    if [winfo exists .selectbox] {
        destroy .selectbox
    }
    global apsSCRPVNameFilter apsSCRRestoreComboboxFrame apsSCRPVSetpointFilter
    global apsSCRCompareComboboxFrame1 apsSCRCompareComboboxFrame2 
    global apsSCRCompareComboboxMenu1 apsSCRCompareComboboxMenu2 apsSCRRestoreComboboxMenu
    set apsSCRPVNameFilter "*"
    set apsSCRPVSetpointFilter 0
    if [winfo exist $apsSCRRestoreComboboxFrame] {
        $apsSCRRestoreComboboxFrame configure -values {}
    }
    if [winfo exist $apsSCRCompareComboboxFrame1] {
        $apsSCRCompareComboboxFrame1 configure -values {}
    }
    if [winfo exist $apsSCRCompareComboboxFrame2] {
        $apsSCRCompareComboboxFrame2 configure -values {}
    }
    if [winfo exist $apsSCRRestoreComboboxMenu] {
        $apsSCRRestoreComboboxMenu.m delete 0 end
    }
    if [winfo exist $apsSCRCompareComboboxMenu1] {
        $apsSCRCompareComboboxMenu1.m delete 0 end
    }
    if [winfo exist $apsSCRCompareComboboxMenu2] {
        $apsSCRCompareComboboxMenu2.m delete 0 end
    }
}

proc clearSort {} {
    global sortChoice
    set sortChoice byError
}

proc clearTolerances {} {
    global percentTolerance absoluteTolerance showSimilarities
    set percentTolerance 0
    set absoluteTolerance 0
    set showSimilarities 0
}

proc clearSearchString {} {
    global apsSCRConfigStartYear apsSCRConfigStartDay apsSCRConfigStartMonth 
    global apsSCRConfigEndYear apsSCRConfigEndDay apsSCRConfigEndMonth 
    global searchString
    APSDateBreakDown -dayVariable apsSCRConfigStartDay \
      -yearVariable apsSCRConfigStartYear -monthVariable apsSCRConfigStartMonth \
      -twoDigitYear 0 -leadingZeros 0
    APSDateBreakDown -dayVariable apsSCRConfigEndDay \
      -yearVariable apsSCRConfigEndYear -monthVariable apsSCRConfigEndMonth \
      -twoDigitYear 0 -leadingZeros 0
    APSIncrementDateVariables -offset -7 -unit day \
      -dayVariable apsSCRConfigStartDay -yearVariable apsSCRConfigStartYear \
      -monthVariable apsSCRConfigStartMonth 
    set searchString "*"
}

proc clearCompareFilenames { } {
    global fillFirstCompareSlot apsSCRCompareFile1 apsSCRCompareFile2 apsSCRCompareDescrip1 apsSCRCompareDescrip2 
    global apsSCRUseRefForCompare1 apsSCRUseRefForCompare2
    global apsSCRCompareReference1 apsSCRCompareReference2
    set fillFirstCompareSlot 1
    set apsSCRCompareFile1 ""
    set apsSCRCompareFile2 ""
    set apsSCRCompareDescrip1 ""
    set apsSCRCompareDescrip2 ""
    set apsSCRUseRefForCompare1 0
    set apsSCRUseRefForCompare2 0
    set apsSCRCompareReference1 ""
    set apsSCRCompareReference2 ""
}

proc clearRestoreFilename {} {
    global apsSCRRestoreFilename apsSCRRestoreDescription restoreLock apsSCRPVNameFilter apsSCRUseRefForRestorev apsSCRRestoreReference
    global restoreFrame 
    set apsSCRRestoreFilename ""
    set apsSCRRestoreDescription ""
    set apsSCRRestoreReference ""
    set restoreLock 1
    set apsSCRUseRefForRestore 0
    if {[winfo exists $restoreFrame.apsSCRcateg]} {
        destroy $restoreFrame.apsSCRcateg
        update
    }
    APSClearSCRFilterFlags
}

proc clearSearch {} {
    global restoreSnapListWidget compareSnapListWidget
    foreach widget [list $restoreSnapListWidget $compareSnapListWidget] {
        if {[winfo exists $widget]} {
            destroy $widget
            update
        }
    }
}

proc compareSnapnameCallback {index} {
    global descriptionArray apsSCRCompareReference1 apsSCRCompareReference2
    global apsSCRCompareReference1 apsSCRCompareReference2

    set name [lindex $descriptionArray(SnapshotFilename) $index]
    set descrip [lindex $descriptionArray(SnapshotDescription) $index]

    global filename description apsSCRSystem 
    global apsSCRSnapDir apsSCRAtticDir apsSCRCompareAtticWidget
    if {!$apsSCRCompareAtticWidget} {
        set snapDir $apsSCRSnapDir/$apsSCRSystem
    } else {
        set snapDir $apsSCRAtticDir/$apsSCRSystem
    }
    if ![file exists $snapDir/$name] {
        if [file exists $snapDir/${name}.gz] {
            set name ${name}.gz
        } else {
            setStatusText "No file found! ($name)"
            return
        }
    }


    global fillFirstCompareSlot apsSCRCompareFile1 apsSCRCompareFile2 statusText apsSCRCompareDescrip1 apsSCRCompareDescrip2 apsSCRUseRefForCompare1 apsSCRUseRefForCompare2
    
    if {$apsSCRUseRefForCompare1 && $apsSCRUseRefForCompare2} {
        set apsSCRUseRefForCompare1 0
        set fillFirstCompareSlot 1
    }
    if $apsSCRUseRefForCompare1 {
        set fillFirstCompareSlot 0
    }
    if ($fillFirstCompareSlot) { 
        if !$apsSCRUseRefForCompare1 {
            set apsSCRCompareFile1 $name
            set apsSCRCompareDescrip1 $descrip
            set apsSCRCompareReference1 [FindPreferredRefChoice $name]
        }
        if !$apsSCRUseRefForCompare2 {
            set apsSCRCompareFile2 ""
            set apsSCRCompareDescrip2 ""
            setStatusText "Ready to compare to present configuration"
            set apsSCRCompareReference2 ""
        }
    }
    if (!$fillFirstCompareSlot) {
        set apsSCRCompareFile2 $name
        set apsSCRCompareDescrip2 $descrip
        setStatusText "Ready to compare two files"
        set apsSCRCompareReference2 [FindPreferredRefChoice $name]
    }
    set fillFirstCompareSlot !$fillFirstCompareSlot
    if $apsSCRUseRefForCompare2 {
        set fillFirstCompareSlot 1
    }
}

proc setCompareFilterFlags {args} {
    global matchOpt apsSCRSystem apsSCRFilterFileDir apsSCRFilterFileName apsSCRFilterFileDescription apsSCRAtticDir
    set matchOpt ""
    set apsSCRFilterFileName ""
    set apsSCRFilterFileDescription ""

    set name ""
    set snapDir ""
    APSStrictParseArguments {name snapDir}

    if [string length $snapDir] {
        set name [file join $snapDir $name]
    }
    if ![file exists $name] {
        if [file exists ${name}.gz] {
            set name ${name}.gz
        } else {
	    set name [file join $apsSCRAtticDir/$apsSCRSystem/ [file root [file tail $name]]]
	    if ![file exists $name] {
		set name ${name}.gz
		if ![file exist $name] {
		    setStatusText "No file found! ([file tail [file root $name]])"
		    return 0
		}
	    }
        }
    }
    
    # $filename is the actual name of the file, $name is the name without the .gz extension,
    # if any
    set filename $name
    set name [APSRemoveGzipExtension $name]
   
    global apsSCRFilterCategory apsSCRFilterBeamline apsSCRPVNameFilter apsSCRPVSetpointFilter
    set apsSCRPVNameFilter *
    set apsSCRPVSetpointFilter 0

    if [winfo exists .selectbox] {
        destroy .selectbox
    }
    APSDialogBox .selectbox -name "Category and beamline selection" \
      -contextHelp "This dialog box permits specifying partial comparisons of snapshots. There are three mechanisms for doing this.  First, you must select one or more categories and one or more beamlines (or systems).  Second, for some systems you may select a predefined colleciton of PVs; if you do, all categories and beamlines are automatically selected for you; you may unselect any that do not interest you.  Third, you may give a PV name filter to further restrict the selection."

    global cancelsetCompareFilterFlags 
    set cancelsetCompareFilterFlags 1
    .selectbox.buttonRow.cancel.button configure -command \
      {set cancelsetCompareFilterFlags 1; destroy .selectbox}
    .selectbox.buttonRow.ok.button configure -command \
      {set cancelsetCompareFilterFlags 0; destroy .selectbox}

    set w .selectbox.userFrame
    
    APSPVFilterWidget .apsSCRcateg -parent .selectbox.userFrame \
      -fileName [file tail $filename] -showSetpointFilter 1 \
      -snapDir [file dirname $filename] -rootname $apsSCRSystem    

    APSEnableButton .selectbox.buttonRow.ok.button

    tkwait window .selectbox

    if $cancelsetCompareFilterFlags {
        return -code ok 0
    }
    setStatusText "Doing comparison..."
    if {$apsSCRPVSetpointFilter} {
        set includeReadOnlys 0
    } else {
        set includeReadOnlys 1
    }
    if [catch {APSMakeSCRMatchOptions $filename -includeReadOnlys $includeReadOnlys \
                 -protectionLock 0 -pvNameFilter "$apsSCRPVNameFilter"} matchOpt] {
        setStatusText "$matchOpt"
        return -code error 
    }
    return -code ok 1
}


proc compareFiles {args} {
    global apsSCRCompareFile1 apsSCRCompareFile2 apsSCRSystem fillFirstCompareSlot statusText 
    global percentTolerance absoluteTolerance sortChoice matchOpt showSimilarities
    global apsSCRFilterFileDir apsSCRFilterFileName 
    global apsSCRSnapDir apsSCRCustomCompareList apsSCRAtticDir apsSCRCompareAtticWidget
    global apsSCRUseRefForCompare1 apsSCRUseRefForCompare2 env apsSCRPendIOTime apsSCRAtticDir apsUpgrade
    
    if ![info exist apsSCRPendIOTime($apsSCRSystem)] {
        set apsSCRPendIOTime($apsSCRSystem) 80
    }
    if $apsSCRCompareAtticWidget {
        set snapDir $apsSCRAtticDir/$apsSCRSystem
    } else {
        set snapDir $apsSCRSnapDir/$apsSCRSystem
    }
    set fillFirstCompareSlot 1
    set partial 0
    set custom 0
    if [APSStrictParseArguments {partial custom}]==-1 {
        setStatusText "Error: Bad argument to compareFiles"
        return
    }

    set compareFile1 $apsSCRCompareFile1
    set compareFile2 $apsSCRCompareFile2

    if {[string length $compareFile1] == 0} {
        setStatusText "Use the search facility to choose at least one snapshot"
        return
    }
    if {$apsSCRUseRefForCompare1} {
        if ![file exists $apsSCRSnapDir/$apsSCRSystem/$compareFile1] {
            set compareFile1 $apsSCRSnapDir/$apsSCRSystem/${compareFile1}.gz
        }
        set compareFile1 $apsSCRSnapDir/$apsSCRSystem/$compareFile1
    } else {
        if [file exists $snapDir/$compareFile1] {
            set compareFile1 $snapDir/$compareFile1
        } elseif [file exists $apsSCRSnapDir/$apsSCRSystem/$compareFile1] {
            set compareFile1 $apsSCRSnapDir/$apsSCRSystem/$compareFile1
        } elseif [file exists $apsSCRAtticDir/$apsSCRSystem/$compareFile1] {
            set compareFile1 $apsSCRAtticDir/$apsSCRSystem/$compareFile1
        } elseif [file exists $snapDir/${compareFile1}.gz] {
            set compareFile1 $snapDir/${compareFile1}.gz
        } elseif [file exists $apsSCRSnapDir/$apsSCRSystem/${compareFile1}.gz] {
            set compareFile1 $apsSCRSnapDir/$apsSCRSystem/${compareFile1}.gz
        } elseif [file exists $apsSCRAtticDir/$apsSCRSystem/${compareFile1}.gz] {
            set compareFile1 $apsSCRAtticDir/$apsSCRSystem/${compareFile1}.gz
        }
    }
    if ![file exist $compareFile1] {
	set compareFile1 $apsSCRAtticDir/$apsSCRSystem/[file root [file root [file tail $compareFile1]]]
	if ![file exist $compareFile1] {
	    set compareFile1 ${compareFile1}.gz
	    if ![file exist $compareFile1] {
		SetStatus "compareFile1 -- [file tail [file root [file root $compareFile1]]] not found."
		return
	    }
	}
    }

    set waveformFile1 [file root $compareFile1].waveform.gz
    set waveformFile2 ""
    set compareWaveform 1
    if [string length $compareFile2] {    
        if $apsSCRUseRefForCompare2 {
            if ![file exists $apsSCRSnapDir/$apsSCRSystem/$compareFile2] {
                set compareFile2 $apsSCRSnapDir/$apsSCRSystem/${compareFile2}.gz 
            }
            set compareFile2 $apsSCRSnapDir/$apsSCRSystem/$compareFile2
        } else {  
            if [file exists $snapDir/$compareFile2] {
                set compareFile2 $snapDir/$compareFile2
            } elseif [file exists $apsSCRSnapDir/$apsSCRSystem/$compareFile2] {
                set compareFile2 $apsSCRSnapDir/$apsSCRSystem/$compareFile2
            } elseif [file exists $apsSCRAtticDir/$apsSCRSystem/$compareFile2] {
                set compareFile2 $apsSCRAtticDir/$apsSCRSystem/$compareFile2
            } elseif [file exists $snapDir/${compareFile2}.gz] {
                set compareFile2 $snapDir/${compareFile2}.gz
            } elseif [file exists $apsSCRSnapDir/$apsSCRSystem/${compareFile2}.gz] {
                set compareFile2 $apsSCRSnapDir/$apsSCRSystem/${compareFile2}.gz
            } elseif [file exists $apsSCRAtticDir/$apsSCRSystem/${compareFile2}.gz] {
                set compareFile2 $apsSCRAtticDir/$apsSCRSystem/${compareFile2}.gz
            }
        }
	if ![file exist $compareFile2] {
	    set compareFile2 $apsSCRAtticDir/$apsSCRSystem/[file root [file root [file tail $compareFile2]]]
	    if ![file exist $compareFile2] {
		set compareFile2 ${compareFile2}.gz
		if ![file exist $compareFile2] {
		    SetStatus "compareFile2 -- [file tail [file root [file root $compareFile2]]] not found."
		    return
		}
	    }
	}
	
        set waveformFile2 [file root $compareFile2].waveform.gz
    }
    
    if $partial {
        global env
        APSClearSCRFilterFlags
        if [catch {setCompareFilterFlags -name $compareFile1} result] {
            global errorInfo
            setStatusText "Problem filtering file"
            APSAlertBox [APSUniqueName .] -errorMessage "$errorInfo"
            return
        }
        if {!$result} {
            return
        }
        set filename1a [APSTmpDir]/[APSTmpString]
        APSAddToTempFileList $filename1a
        if ![string length $apsSCRFilterFileName] {
            if {$apsUpgrade} {
                eval exec sddsprocess $compareFile1 $filename1a \
                    "$matchOpt" -nowarning
            } else {
                eval exec sddsprocess $compareFile1 $filename1a \
                    "$matchOpt" -match=column,ControlType=pv -nowarning
            }
        } else {
            set apsSCRFilterFile $apsSCRFilterFileDir/$apsSCRFilterFileName
            if {$apsUpgrade} {
                eval exec sddsprocess $compareFile1 -pipe=out \
                    "$matchOpt" -nowarning \
                    | sddsxref -nowarning -pipe $apsSCRFilterFileDir/$apsSCRFilterFileName -match=ControlName -take=Index   \
                    | sddssort -pipe=in $filename1a -column=Index
            } else {
                eval exec sddsprocess $compareFile1 -pipe=out \
                    "$matchOpt" -match=column,ControlType=pv -nowarning \
                    | sddsxref -nowarning -pipe $apsSCRFilterFileDir/$apsSCRFilterFileName -match=ControlName -take=Index   \
                    | sddssort -pipe=in $filename1a -column=Index
            }
        }
        
        if {[exec sdds2stream $filename1a -rows=bare] == 0} {
            setStatusText "Problem filtering file"
            APSAlertBox [APSUniqueName .] -errorMessage "Selected categories do not exist in selected beamlines"
            return
        }
        if [catch {exec sddsprocess $filename1a $filename1a.wave -match=col,ValueString=*.waveform* } result] {
            #no waveforms  found -- do not compare waveforms
            set waveformFile1 NonExistent
        } else {
            set waveforms [exec sdds2stream -col=ControlName $filename1a.wave]
            set opt1 "-match=par,WaveformPV=[lindex $waveforms 0]"
            for {set i 1} {$i<[llength $waveforms]} {incr i} {
                append opt1 ",WaveformPV=[lindex $waveforms $i],|"
            }
            if [catch {exec sddsprocess $waveformFile1 $filename1a.wave $opt1} result] {
                setStatusText "Problem filtering waveform file"
                APSAlertBox [APSUniqueName .] -errorMessage "Selected categories do not exist in selected beamlines"
                return
            }
            set waveformFile1 $filename1a.wave
        }
    } else {
        set filename1a $compareFile1
    }
    #these arguments are used for SRXrayBPMSystem
    global gapDiffTolerance posDiffTolerance minVoltage
    set gapDiffTolerance 0.1
    set posDiffTolerance 0.1
    set minVoltage 0.01
    #minVoltage is the minimum acceptable blade voltage
    if $custom {
        if ![llength $apsSCRCustomCompareList($apsSCRSystem)] {
            setStatusText "No custom comparisons for $apsSCRSystem"
            return
        }
        global apsSCRCustomCompareDescription
        if [catch {APSChooseItemFromList -name CustomCompareChoices:$apsSCRSystem \
                     -itemList $apsSCRCustomCompareDescription($apsSCRSystem) \
                     -returnList $apsSCRCustomCompareList($apsSCRSystem) \
                     -returnIndices 0 -multiItem 1} compareChoices] {
            setStatusText "Problem choosing custom comparisons: $compareChoices"
            return
        }
        if ![llength $compareChoices] {
            setStatusText "No custom comparisons chosen."
            return
        }
        if {$apsSCRSystem=="SRXrayBPM"} {
            #create dialog for chosing comparison tolerance
            global dialogBoxResponse
            set w [APSUniqueName .]
            APSDialogBox $w -cancelCommand "set dialogBoxResponse cancel" \
              -okCommand "set dialogBoxResponse ok"  -name "SRXrayBPM Comparison limits"
            APSLabeledEntry .gapTolerance -parent $w.userFrame \
              -label "Gap difference tolerance:" \
              -textVariable gapDiffTolerance \
              -contextHelp \
              "Enter tolerance for difference in gap between data sets. \
                   Data with gap differences that are greaters will not be \
                   shown in comparison."
            APSLabeledEntry .posTolerance -parent $w.userFrame \
              -label "Position difference tolerance:" \
              -textVariable posDiffTolerance \
              -contextHelp \
              "Enter tolerance for difference in position between data sets. "
            
            APSLabeledEntry .filterVoltage -parent $w.userFrame \
              -label "Minimal acceptable voltage:" \
              -textVariable minVoltage \
              -contextHelp \
              "Enter minimal acceptable voltage. \
              Data with smaller voltage  will not be shown."
            update
            tkwait variable dialogBoxResponse
            if [string compare $dialogBoxResponse cancel]==0 return
        }
    } else {
        set compareChoices ""
    }
    
    setStatusText "Working..."

    if [catch {APSCompareMachine -machine $apsSCRSystem -snapshot1 $filename1a \
                 -partial $partial \
                 -waveformFile1 $waveformFile1 -waveformFile2 $waveformFile2 \
                 -snap1Label $compareFile1 \
                 -sortChoice $sortChoice -statusCallback setStatusText \
                 -snapshot2 $compareFile2 -graphics 1 \
                 -absoluteTolerance $absoluteTolerance \
                 -percentTolerance $percentTolerance \
                 -showSimilarities $showSimilarities \
                 -gapDiffTolerance $gapDiffTolerance \
                 -posDiffTolerance $posDiffTolerance \
                 -minVoltage $minVoltage \
                 -pendIOTime [set apsSCRPendIOTime($apsSCRSystem)] \
                 -customComparisonList $compareChoices} result] {
        APSAlertBox [APSUniqueName .] -errorMessage "Error doing compare: $result"
        return
    }

    setStatusText "Comparison done."
}

proc saveSnapshot {args} {
    global apsSCRSystem errorInfo apsSCRUseCASRServer env apsScriptUser apsSCRSnapDir apsSCRPendIOTime
    set description ""
    set routine 0
    set poorPerformance 0
    set limited 0
    set shift 0
    APSStrictParseArguments {description routine poorPerformance limited shift}
    
    if {[string length $description] == 0} {
        setStatusText "you must give a description for the snapshot"
        return
    }
    if {$shift} {
        set description "Routine save (shift change): $description"
    } elseif $routine {
        set description "Routine save: $description"
    }
    if $poorPerformance  {
        set description "Poor performance: [clock format [clock seconds]] $apsScriptUser $description"
    }
    if {$limited} {
        set description "Limited save: $description"
        set random [expr rand()]
        global apsSCRRequestDir apsLimitedSaveReady$random 
        global apsLimitedSaveCategories apsLimitedSaveBeamlines
        if ![file exists [file join $apsSCRRequestDir $apsSCRSystem.req]] {
            setStatusText "Bad machine name $apsSCRSystem"
            return
        }
        if {[catch {exec sddssort [file join $apsSCRRequestDir $apsSCRSystem.req] -pipe=out -col=Category -unique | sdds2stream -pipe -col=Category} Categories]} {
            setStatusText "Error: $Categories"
            return
        }
        if {[catch {exec sddssort [file join $apsSCRRequestDir $apsSCRSystem.req] -pipe=out -col=Beamline -unique | sdds2stream -pipe -col=Beamline} Beamlines]} {
            setStatusText "Error: $Beamlines"
            return
        }
        foreach c $Categories {
            set apsLimitedSaveCategories($c) 0
            append categoryVarList "apsLimitedSaveCategories($c) "
        }
        foreach b $Beamlines {
            set apsLimitedSaveBeamlines($c) 0
            append beamlineVarList "apsLimitedSaveBeamlines($b) "
        }
        destroy .limitedsave
        set apsLimitedSaveReady$random -1
        APSDialogBox .limitedsave \
          -okCommand "set apsLimitedSaveReady$random 1" \
          -cancelCommand "set apsLimitedSaveReady$random 0"
        APSCheckButtonFrame .categories \
          -parent .limitedsave.userFrame \
          -label Categories \
          -orientation horizontal \
          -limitPerRow 10 \
          -allNone 1 \
          -buttonList $Categories \
          -variableList $categoryVarList
        APSCheckButtonFrame .beamlines \
          -parent .limitedsave.userFrame \
          -label Beamlines \
          -orientation horizontal \
          -limitPerRow 15 \
          -allNone 1 \
          -buttonList $Beamlines \
          -variableList $beamlineVarList
        if {$apsSCRSystem == "LPL"} {
            set setLinacBody {
                global apsLimitedSaveBeamlines
                set apsLimitedSaveBeamlines($var) 1
            }
            set setLinacCmd [list foreach var "L0 L1 L2 L3 L4 L5 L6 LINAC Laser PCGun1 PCgun1 PCgun2 rfGun rfGun1 rfGun2 LI Misc" $setLinacBody]

            set setParBody {
                global apsLimitedSaveBeamlines
                set apsLimitedSaveBeamlines($var) 1
            }
            set setParCmd [list foreach var "BTS LTP LTP1 LTP2 PAR PTB PTB1 PTB2 PTB3 Misc" $setLinacBody]

            set setLetBody {
                global apsLimitedSaveBeamlines
                set apsLimitedSaveBeamlines($var) 1
            }
            set setLetCmd [list foreach var "BTS LTP LTP1 LTP2 PTB PTB1 PTB2 PTB3 Misc" $setLinacBody]

            APSButton .linac \
              -parent .limitedsave.userFrame.beamlines.frame \
              -text LINAC \
              -size small \
              -command ".limitedsave.userFrame.beamlines.frame.none.button invoke ; $setLinacCmd"
            APSButton .par \
              -parent .limitedsave.userFrame.beamlines.frame \
              -text PAR \
              -size small \
              -command ".limitedsave.userFrame.beamlines.frame.none.button invoke ; $setParCmd"
            APSButton .let \
              -parent .limitedsave.userFrame.beamlines.frame \
              -text LET \
              -size small \
              -command ".limitedsave.userFrame.beamlines.frame.none.button invoke ; $setLetCmd"
        }
        tkwait variable apsLimitedSaveReady$random
        if {[set apsLimitedSaveReady$random] != 1} {
            return
        }
    }
    
    set pingTimeOut 80
    setStatusText "Doing save for $apsSCRSystem..."
    if ![info exist apsSCRPendIOTime($apsSCRSystem)] {
        set apsSCRPendIOTime($apsSCRSystem) 80
    }
    setStatusText "pend IO time=[set apsSCRPendIOTime($apsSCRSystem)]"
    
    if [catch {APSSaveMachine -machine $apsSCRSystem -description "$description" \
                   -routine $routine \
                   -pendIOTime [set apsSCRPendIOTime($apsSCRSystem)] -pingTimeOut $pingTimeOut \
                   -statusCallback setStatusText} result] {
        APSAlertBox [APSUniqueName .] -errorMessage "Error doing save: $result"
        return
    }
    if {[llength $result]==0} {
        setStatusText "Save failed!"
        bell
        return
    }
    set filename [lindex $result 0]

    if {$limited} {
        catch {exec chmod u+w $filename}
        set matchTestCategory ""
        set i 0
        foreach c $categoryVarList c2 $Categories {
            if {[set $c]} {
                if {$i == 0} {
                    append matchTestCategory "-match=column,Category=$c2"
                    incr i
                } else {
                    append matchTestCategory ",Category=$c2,|"
                }
            }
        }
        set matchTestBeamline ""
        set i 0
        foreach b $beamlineVarList b2 $Beamlines {
            if {[set $b]} {
                if {$i == 0} {
                    append matchTestBeamline " -match=column,Beamline=$b2"
                    incr i
                } else {
                    append matchTestBeamline ",Beamline=$b2,|"
                }
            }
        }
        set f1 [file join $apsSCRSnapDir $apsSCRSystem $filename]
        if {[catch {eval exec sddsprocess $f1 ${f1}.limited.gz -nowarn $matchTestCategory $matchTestBeamline} results]} {
            setStatusText "Error removing unwanted Categories and Beamlines: $results"
            bell
            catch {exec chmod a-w $f1}
            catch {file delete ${f1}.limited.gz}
            return
        }
        file rename -force ${f1}.limited.gz ${f1}
        catch {exec chmod a-w $f1}
        if {[file exists [file join [file dirname $f1] categories]]} {
            set f2 [file join [file dirname $f1] categories categ[file tail [file rootname $f1]]]
            if {[file exists $f2]} {
                if {[catch {eval exec sddsprocess $f2 -nowarn $matchTestCategory} results]} {
                    setStatusText "Error removing unwanted Categories and Beamlines: $results"
                    bell
                    catch {file delete ${f2}~}
                    return
                }
                catch {file delete ${f2}~}
            }
        } else {
            set f2 [file join [file dirname $f1] categ[file tail [file rootname $f1]]]
            if {[file exists $f2]} {
                if {[catch {eval exec sddsprocess $f2 -nowarn $matchTestCategory} results]} {
                    setStatusText "Error removing unwanted Categories and Beamlines: $results"
                    bell
                    catch {file delete ${f2}~}
                    return
                }
                catch {file delete ${f2}~}
            }
        }
        if {[file exists [file join [file dirname $f1] beamlines]]} {
            set f2 [file join [file dirname $f1] beamlines beam[file tail [file rootname $f1]]]
            if {[file exists $f2]} {
                if {[catch {eval exec sddsprocess $f2 -nowarn $matchTestBeamline} results]} {
                    setStatusText "Error removing unwanted Categories and Beamlines: $results"
                    bell
                    catch {file delete ${f2}~}
                    return
                }
                catch {file delete ${f2}~}
            }
        } else {
            set f2 [file join [file dirname $f1] beam[file tail [file rootname $f1]]]
            if {[file exists $f2]} {
                if {[catch {eval exec sddsprocess $f2 -nowarn $matchTestBeamline} results]} {
                    setStatusText "Error removing unwanted Categories and Beamlines: $results"
                    bell
                    catch {file delete ${f2}~}
                    return
                }
                catch {file delete ${f2}~}
            }
        }
    }

    if [llength $result]==2 {
        setStatusText "Save done, but some errors seen."
        APSFileDisplayWindow [APSUniqueName .] \
          -fileName [lindex $result 1] -deleteOnClose 1 -width 100 \
          -comment "Errors for $apsSCRSystem save [lindex $result 0]" \
          -printCommand "enscript -r"
    } else {
        setStatusText "Save done.  No errors detected."
    }
}

proc saveMultipleSystems {args} {
    global errorInfo apsSCRSystemList apsSCRSystem apsSCRGroupMenuOrder
    global apsSCRGroupMembers apsSCRGroupDescription apsSCRGroup
    set description ""
    set routine 1
    set poorPerformance 0
    set limited 0
    set shift 0
    APSStrictParseArguments {description routine poorPerformance limited shift}
    if {[string length $description] == 0} {
        setStatusText "You must give a description for the snapshot"
        return
    }

    set i 0
    set apsSCRSystem0 $apsSCRSystem
    foreach group $apsSCRGroupMenuOrder {
        if {$group == "Obsolete"} {continue}
        foreach member $apsSCRGroupMembers($group) {
            global mrsSave${member}
            set name mrsSave${member}
            set flag [set $name]
            set apsSCRSystem $member
            if $flag {
                saveSnapshot -description $description -routine $routine -poorPerformance $poorPerformance -limited $limited -shift $shift
                incr i
            }
        }
    }
    set apsSCRSystem $apsSCRSystem0

    if {$i == 0} {
        setStatusText "No SCR systems selected to save."
    } else {
        if $routine {
            if {$i > 1} {
                setStatusText "Multiple routine save done."
            } else {
                setStatusText "Routine save done."
            }
        } else {
            if {$i > 1} {
                setStatusText "Multiple save done."
            } else {
                setStatusText "Save done."
            }
        }
    }

    bell
}


proc makeCompareFilenameDisplayFrame {widget args} {
    set index 1
    set parent ""
    set refButton 0
    APSStrictParseArguments {index parent refButton}

    global apsSCRCompareFile$index apsSCRCompareDescrip$index apsSCRSystem apsSCRPreferredList apsSCRFilterList
    global apsSCRCompareComboboxFrame$index apsSCRCompareComboboxReference$index 
    global apsSCRCompareReference$index apsSCRCompareComboboxMenu$index
    
    ttk::frame $parent$widget -borderwidth 2
    pack $parent$widget -side top -anchor w

    set height 0
    set unfiltered ""
    foreach item $apsSCRPreferredList filter $apsSCRFilterList {
        if {[string range $item 0 4] == "Attic"} {
            break
        }
        incr height
        set i [string last "MeV" $item]
        set ii [string last "Mev" $item]
        if {$ii > $i} {set i $ii}
        if {$i != -1} {
            lappend preferred([string trim [string range $item [expr $i - 4] [expr $i - 1]]]) $item
        }
        if {$filter == 0} {
            lappend unfiltered $item
        }
    }
    if {[info exists preferred]} {
        foreach energy [lsort [array names preferred]] {
            foreach item $unfiltered {
                lappend preferred($energy) $item
            }
        }
    }
    ttk::label $parent$widget.cblabel -text "Reference $index:"
    if {$height < 5} {
        ttk::combobox $parent$widget.cb -textvariable apsSCRCompareReference$index -state readonly -values $apsSCRPreferredList -width 80
    } else {
        ttk::combobox $parent$widget.cb -textvariable apsSCRCompareReference$index -state readonly -values $apsSCRPreferredList -width 80 -height $height
    }
    grid $parent$widget.cblabel -row 0 -column 0 -sticky e
    grid $parent$widget.cb -row 0 -column 1 -sticky ew
    if {[info exists preferred]} {
        ttk::menubutton $parent$widget.energy -text MeV -underline 0 -menu $parent$widget.energy.m
        menu $parent$widget.energy.m -tearoff 0
        grid $parent$widget.energy -row 0 -column 2 -sticky ew
        $parent$widget.energy.m add command -label "" -command "energySelect -w $parent$widget.energy -cb $parent$widget.cb -energy 0"
        foreach energy [lsort [array names preferred]] {
            $parent$widget.energy.m add command -label "${energy}MeV" -command "energySelect -w $parent$widget.energy -cb $parent$widget.cb -energy $energy -preferred \"$preferred($energy)\""
        }
        set apsSCRCompareComboboxMenu$index $parent$widget.energy
    }
    set apsSCRCompareComboboxFrame$index $parent$widget.cb
    bind $parent$widget.cb <<ComboboxSelected>> "APSComboboxRunCallback %W -callback \"SetComparePreferredFile $index\" -textFont TkDefaultFont -editable 0 -textVariable apsSCRCompareReference$index"

    ttk::label $parent$widget.fileLabel -text "Filename $index:"
    ttk::entry $parent$widget.fileEntry -textvariable apsSCRCompareFile$index -state readonly -width 80
    grid $parent$widget.fileLabel -row 1 -column 0 -sticky e
    grid $parent$widget.fileEntry -row 1 -column 1 -sticky ew

    ttk::label $parent$widget.descripLabel -text "Description:"
    ttk::entry $parent$widget.descripEntry -textvariable apsSCRCompareDescrip$index -state readonly -width 80
    grid $parent$widget.descripLabel -row 2 -column 0 -sticky e
    grid $parent$widget.descripEntry -row 2 -column 1 -sticky ew

}

proc energySelect {args} {
    APSStrictParseArguments {cb w preferred energy}
    global apsSCRPreferredList

    if {$energy == 0} {
        $cb configure -values $apsSCRPreferredList
        $w configure -text "MeV"
    } else {
        $cb configure -values [concat <FromSearchList> $preferred]
        $w configure -text "$energy"
    }
}

proc SetComparePreferredFile {index itemIndex} {
    global apsSCRCompareFile$index apsSCRCompareDescrip$index apsSCRSystem apsSCRSnapDir 
    global apsSCRUseRefForCompare$index apsSCRCompareRefChoice$index 
    global apsSCRPreferredList apsSCRCompareReference$index

    #set item [lindex $apsSCRPreferredList $itemIndex]
    set item [set apsSCRCompareReference$index]

    set state [string compare $item <FromSearchList>]
    if !$state {
        if [subst \$apsSCRUseRefForCompare$index] {
            set apsSCRCompareFile$index ""
            set apsSCRCompareDescrip$index ""
            set apsSCRUseRefForCompare$index 0
        }
        return
    }
    set apsSCRCompareRefChoice$index $item
    if [catch {APSSCRResolvePreferredFileChoice -system $apsSCRSystem -choice $item} file] {
        setStatusText $file
        set apsSCRCompareFile$index ""
        set apsSCRCompareDescrip$index ""
        set apsSCRUseRefForCompare$index 0
        return
    }
    set apsSCRUseRefForCompare$index 1
    if ![file exists $apsSCRSnapDir/$apsSCRSystem/$file] {
        setStatusText "Preferred file $apsSCRSnapDir/$apsSCRSystem/$file not found for $apsSCRSystem"
        set apsSCRUseRefForCompare$index 0
        set apsSCRCompareFile$index ""
        set apsSCRCompareDescrip$index ""
        return 
    }
    set file [file readlink $apsSCRSnapDir/$apsSCRSystem/$file]
    #in case file is also a link
    if [catch {file readlink $apsSCRSnapDir/$apsSCRSystem/[file tail $file]} file1] {
    } else {
	set file $file1
    }
    set apsSCRCompareFile$index [file tail $file]
    update
    if {[file exists $apsSCRSnapDir/$apsSCRSystem/collapsed]} {
        set apsSCRCompareDescrip$index [join [APSGetSDDSColumn -page 0 -column SnapshotDescription \
                                                -fileName $apsSCRSnapDir/$apsSCRSystem/collapsed/c[file tail [file rootname $file]]]]
    } else {
        set apsSCRCompareDescrip$index [join [APSGetSDDSColumn -page 0 -column SnapshotDescription \
                                                -fileName $apsSCRSnapDir/$apsSCRSystem/c[file tail [file rootname $file]]]]
    }
    set apsSCRCompareRef$index 1
}

proc makeCompareFrame {widget args} {
    global apsSCRSystem apsSCRConfigStartYear apsSCRConfigStartMonth apsSCRConfigStartDay
    global apsSCRConfigEndYear apsSCRConfigEndMonth apsSCRConfigEndDay searchString 
    global percentTolerance absoluteTolerance showSimilarities

    set singleAccel ""
    set parent ""
    set noPack 0
    set label ""
    APSStrictParseArguments {singleAccel parent noPack label}

    if [winfo exists $parent$widget] {
        pack $parent$widget -expand 1 -fill both
        return
    }

    APSFrame $widget -parent $parent -label $label -relief flat \
      -packOption "-side top -expand 1 -fill both"
    set w $parent$widget.frame

    APSFrame .search -parent $w -label "Snapshot search" -labelFont "TkHeadingFont"
    APSSCRDateTimeEntryWidget .date -parent $w.search.frame

    APSLabeledEntry .descript -parent $w.search.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 .file -parent $w -label "Snapshot choices" -labelFont "TkHeadingFont"

    makeCompareFilenameDisplayFrame .file1 -parent $w.file.frame -index 1 -refButton 1
    makeCompareFilenameDisplayFrame .file2 -parent $w.file.frame -index 2 -refButton 1

    APSFrame .tol -parent $w -label "" -relief flat \
      -contextHelp "These are entry fields for setting tolerances other than the preordained ones.  To use, put a nonzero value in one of the boxes.  If you put values in both, the absolute tolerance is used."
    set percentTolerance 0
    set absoluteTolerance 0
    set showSimilarities 0
    APSLabeledEntry .percentTol -parent $w.tol.frame -width 10 -packOption "-expand 1 -side left" \
      -label "Percent tolerance: " -textVariable percentTolerance \
      -contextHelp "Enter a percentage for comparisons of numerical values.  Only new values that have changed by the given percent of the reference value will be displayed.  Ignored if 0, or if a nonzero absolute tolerance is given."
    APSLabeledEntry .absoluteTol -parent $w.tol.frame -width 10 -packOption "-expand 1 -side left" \
      -label "Absolute tolerance: " -textVariable absoluteTolerance \
      -contextHelp "Enter a tolerance for comparisons of numerical values.  Only new values that have changed by the given amount will be displayed.  Ignored if 0."
    APSRadioButtonFrame .compareType -parent $w.tol.frame -packOption "-side left" \
      -label "Show " -buttonList "Differences Similarities" \
      -valueList "0 1" -variable showSimilarities -orientation horizontal \
      -contextHelp "Choose whether to view differences or similarities between snapshots."

    APSFrame .ops -parent $w -label "" -relief flat
    APSFrame .ops2 -parent $w -label "" -relief flat

    set sortChoice byError
    APSRadioButtonFrame .sort -parent $w.ops.frame -label "  Sort by: " \
      -buttonList {none fracError value error name} \
      -valueList {none byFracError byValue byError byName} \
      -orientation horizontal -packOption "-side left" \
      -variable sortChoice \
      -contextHelp "Allows choosing the order in which data will be listed in the printouts.  Sorting by fractional error will bring the items with the largest difference relative to their tolerance to the top. Sorting by error will bring the items with the largest difference to the top.  Sorting by value will bring the item with the largest value to the top.  Sorting by name orders items alphabetically."

    APSButton .search -parent $w.ops2.frame -text "SEARCH" -width "" \
      -command "runAPSListSCRMatch -parent $w -callback compareSnapnameCallback -listWidgetVariable compareSnapListWidget -atticWidgetVar apsSCRCompareAtticWidget" \
      -contextHelp \
      "Performs a search based on the beamline selection, the date search string, and the description search string." 
    APSButton .searchattic -parent $w.ops2.frame -text "SEARCH ATTIC" -width "" \
      -command "runAPSListSCRMatch -parent $w -callback compareSnapnameCallback -listWidgetVariable compareSnapListWidget -atticWidgetVar apsSCRCompareAtticWidget -attic 1" \
      -contextHelp \
      "Performs a search based on the beamline selection, the date search string, and the description search string." 
    APSButton .clear -parent $w.ops2.frame -width "" \
      -text "CLEAR" \
      -command {clearCompareFilenames ; clearSearchString; clearTolerances; clearSort} \
      -contextHelp "Clears the filenames and search string."
    APSButton .compare -parent $w.ops2.frame -width "" \
      -text "COMPARE" -command compareFiles \
      -contextHelp "Does a snapshot comparison.  If one filename is selected, then the comparison is to the present configuration.  If two filenames are selected, then the comparison is between the configurations in the files.  To select files, use the SEARCH button."
    APSButton .pcompare -parent $w.ops2.frame -width "" \
      -text "PARTIAL COMPARE..." -command "compareFiles -partial 1"\
      -contextHelp "Does a partial snapshot comparison, which includes only selected beamlines and categories.  If one filename is selected, then the comparison is to the present configuration.  If two filenames are selected, then the comparison is between the configurations in the files.  To select files, use the SEARCH button."
    APSButton .custom -parent $w.ops2.frame -width "" \
      -text "CUSTOM COMPARE..." -command "compareFiles -custom 1" \
      -contextHelp "Does one or more snapshot comparisons using methods customized to the system.  E.g., for SR a comparison could involve plots of corrector changes."


}

proc makeSaveFrame {widget args} {
    set parent ""
    set noPack 0
    set label ""
    set singleAccel ""
    APSStrictParseArguments {parent noPack label singleAccel}

    if [winfo exists $parent$widget] {
        pack $parent$widget
        return
    }

    APSFrame $widget -parent $parent -label $label -noPack $noPack -relief flat
    set w $parent$widget.frame
    
    APSLabeledEntry .descrip -parent $w -width 80 \
      -textVariable snapDescription -label "Description: " \
      -contextHelp "Enter a text description for the snapshot." \
      -packOption "-expand true"

    APSFrame .scrgroups -parent $w -label "SCR System Selection" -labelFont "TkHeadingFont"

    global apsSCRGroupMembers apsSCRGroupDescription apsSCRSystem apsSCRGroupMenuOrder apsUpgrade
    set index 0
    
    foreach group $apsSCRGroupMenuOrder {
        if {$group == "Obsolete"} {continue}
        incr index
        set varList ""
        foreach member $apsSCRGroupMembers($group) {
            global mrsSave${member}
            lappend varList mrsSave${member}
            set mrsSave${member} 0
        }
        set lpr 7
        if {$group == "Special"} {
            set lpr 4
        }
        ttk::label $w.scrgroups.frame.cbLabel$index -text $apsSCRGroupDescription($group)
        grid $w.scrgroups.frame.cbLabel$index -row [expr $index - 1] -column 0 -sticky e -padx 2
        APSCheckButtonFrame .cb$index -parent $w.scrgroups.frame \
          -label "" -orientation horizontal \
          -allNone 1 -limitPerRow $lpr \
          -buttonList $apsSCRGroupMembers($group) \
          -variableList $varList -gridPack "-row [expr $index - 1] -column 1 -sticky w"
        
if 0 {
        APSCheckButtonFrame .cb$index -parent $w.scrgroups.frame \
          -label $apsSCRGroupDescription($group) -orientation horizontal \
          -allNone 1 -limitPerRow 7 \
          -buttonList $apsSCRGroupMembers($group) \
          -variableList $varList
}
    }
    set mrsSave$apsSCRSystem 1

    global apsSCRSaveType
    set apsSCRSaveType "routine"
    APSRadioButtonFrame .rbsaves -parent $w \
      -label "SCR Save Type Selection" -orientation vertical \
      -variable apsSCRSaveType \
      -buttonList {"Regular Save" "Routine Save" "Routine Shift Save" "Poor Performance Save" "Limited Save"} \
      -valueList "basic routine shift poor limited " \
      -commandList {"" "" SetupRoutineShiftSave "" ""} \
      -contextHelp "Regular Saves are used to save a system snapshot. Routine Saves will automatically disappear from the system after sufficient time has passed. Poor Performance Saves are used when it needs to be noted that the system performance was poor when the save was created. Limited Saves allow the user to select a limited set of sub-systems to save." \
        -labelFont "TkHeadingFont"

    APSFrame .scrbuttons -parent $w -label "" -relief flat
    set w $w.scrbuttons.frame
    APSButton .dosave -parent $w -text SAVE -width "" \
      -command {SaveSnapshot} \
      -contextHelp "Saves a snapshot for the selected systems with the description given."
    APSButton .doclear -parent $w -text CLEAR -command {set snapDescription ""} -width "" \
      -contextHelp "Clears the snapshot description."
    if {$apsUpgrade} {
        APSButton .abortserver -parent $w -text "ABORT PVA SAVE RESTORE SERVER" -width "" \
          -command {APSSCRAbortCASRRunControl -machine $apsSCRSystem -statusCallback setStatusText } \
          -contextHelp "abort the sddspvasaverestore server for selected system."
    } else {
        APSButton .abortserver -parent $w -text "ABORT CASAVE SERVER" -width "" \
          -command {APSSCRAbortCASRRunControl -machine $apsSCRSystem -statusCallback setStatusText } \
          -contextHelp "abort the sddscasr server for selected system."
    }
    APSButton .info -parent $w -text "INFO" -width "" \
      -command {RunControInfo -machine $apsSCRSystem -statusCallback setStatusText } \
      -contextHelp "bring up the run control MEDM screen"   
}

proc SetupRoutineShiftSave {args} {
    global apsSCRGroupMembers apsSCRGroupMenuOrder
    foreach group $apsSCRGroupMenuOrder {
        if {$group == "Obsolete"} {continue}
        foreach member $apsSCRGroupMembers($group) {
            global mrsSave$member
            set mrsSave$member 0
        }
    }
    foreach member "LPL Booster BRF SR SRF" {
        set mrsSave$member 1
    }
}

proc SaveSnapshot {args} {
    global apsSCRSaveType snapDescription
    if {$apsSCRSaveType == "basic"} {
        saveMultipleSystems -description $snapDescription -routine 0
    } elseif {$apsSCRSaveType == "routine"} {
        saveMultipleSystems -description $snapDescription -routine 1
    } elseif {$apsSCRSaveType == "shift"} {
        saveMultipleSystems -description $snapDescription -routine 1 -shift 1
    } elseif {$apsSCRSaveType == "poor"} {
        saveMultipleSystems -description $snapDescription -routine 0 -poorPerformance 1
    } elseif {$apsSCRSaveType == "limited"} {
        saveMultipleSystems -description $snapDescription -routine 0 -limited 1
    }
}

proc removeSnapshot {} {
    global apsSCRRestoreFilename apsSCRSnapDir errorInfo 
    global apsSCRRestoreDescription apsSCRUseRefForRestore apsSCRSystem
    set snapDir $apsSCRSnapDir/$apsSCRSystem
    if $apsSCRUseRefForRestore {
        setStatusText "You can't remove a preferred file."
        return
    }
    if [catch {APSSCRGetPreferredDataLists -system $apsSCRSystem} dataLists] {
        setStatusText "$dataLists"
        return
    }
    set suffixList [lindex $dataLists 1]
    foreach suffix $suffixList {
        set refFile $snapDir/$apsSCRSystem-$suffix.gz
        if [file exists $refFile] {
	    set refName [file tail [file readlink $refFile]]
	    if [catch {file readlink $snapDir/$refName} refName1] {
	    } else {
		set refName [file tail $refName1]
	    }
            if [string compare [file rootname $refName] [file rootname $apsSCRRestoreFilename]]==0 {
                setStatusText "You can't remove a preferred file ('$suffix')."
                return
            }
        }
    }

    if {[string length $apsSCRRestoreFilename] == 0} {
        setStatusText "No file to remove"
        return
    }
    if ![APSYesNoPopUp "You are asking to remove snapshot $apsSCRRestoreFilename, '$apsSCRRestoreDescription'.  Do you really want to do this?"] {
        setStatusText "Remove cancelled."
        return
    }
    setStatusText "Removing $apsSCRRestoreFilename ..."
    set filename0 [APSRemoveGzipExtension $apsSCRRestoreFilename]
    if {[catch {file copy -force $snapDir/$apsSCRRestoreFilename $snapDir/wasteBasket}] || \
          ([file exists $snapDir/categ$filename0] && \
             [catch {file copy -force $snapDir/categ$filename0 $snapDir/wasteBasket}]) || \
          ([file exists $snapDir/categories/categ$filename0] && \
             [catch {file copy -force $snapDir/categories/categ$filename0 $snapDir/wasteBasket}]) || \
          ([file exists $snapDir/beam$filename0] && \
             [catch {file copy -force $snapDir/beam$filename0 $snapDir/wasteBasket}]) || \
          ([file exists $snapDir/beamlines/beam$filename0] && \
             [catch {file copy -force $snapDir/beamlines/beam$filename0 $snapDir/wasteBasket}]) || \
          ([file exists $snapDir/c$filename0] && \
             [catch {file copy -force $snapDir/c$filename0 $snapDir/wasteBasket}]) || \
          ([file exists $snapDir/collapsed/c$filename0] && \
             [catch {file copy -force $snapDir/collapsed/c$filename0 $snapDir/wasteBasket}]) || \
          ([file exists $snapDir/u$filename0] && \
             [catch {file copy -force $snapDir/u$filename0 $snapDir/wasteBasket}]) } {
        setStatusText "Problem copying snapshot to wastebasket."
        APSAlertBox [APSUniqueName .] -errorMessage "$errorInfo"
        return 
    }
    if {[catch {file delete -force $snapDir/$apsSCRRestoreFilename \
                  $snapDir/categ$filename0 \
                  $snapDir/categories/categ$filename0 \
                  $snapDir/beam$filename0 \
                  $snapDir/beamlines/beam$filename0 \
                  $snapDir/c$filename0 \
                  $snapDir/collapsed/c$filename0 \
                  $snapDir/u$filename0 }]} {
        setStatusText "Problem removing snapshot."
        APSAlertBox [APSUniqueName .] -errorMessage "$errorInfo"
        return 
    }
    set waveformFiles [glob -nocomplain $snapDir/${filename0}.*]
    foreach file $waveformFiles {
	if [regexp {.gz} $file a b] {
	    continue
	}
	if [catch {file copy -force $file $snapDir/wasteBasket} result] {
	    setStatusText "Problem copying waveform snapshot to wastebasket."
	    APSAlertBox [APSUniqueName .] -errorMessage "$result"
	    return 
	}
	if [catch {file delete -force $file } result] {
	    setStatusText "Problem removing waveform snapshot."
	    APSAlertBox [APSUniqueName .] -errorMessage "$result"
	    return 
	}
    }
    setStatusText "Removed $apsSCRRestoreFilename"
    if [catch {APSSCRLogAction -action remove -file $apsSCRRestoreFilename} result] {
        setStatusText "$result"
    }
    clearRestoreFilename
    clearSearch
    APSClearSCRFilterFlags
    if {[winfo exists .userFrame.apsSCRlist]} {
        destroy .userFrame.apsSCRlist
        update
    }
}

proc TransferSnapshot {} {
    global apsSCRRestoreFilename apsSCRSnapDir errorInfo 
    global apsSCRRestoreDescription apsSCRUseRefForRestore apsSCRSystem
    set snapDir $apsSCRSnapDir/$apsSCRSystem
    if $apsSCRUseRefForRestore {
        setStatusText "You can't transfer a preferred file."
        return
    }
    if [catch {APSSCRGetPreferredDataLists -system $apsSCRSystem} dataLists] {
        setStatusText "$dataLists"
        return
    }
    set suffixList [lindex $dataLists 1]
    foreach suffix $suffixList {
        set refFile $snapDir/$apsSCRSystem-$suffix.gz
        if [file exists $refFile] {
            set refName [file tail [file readlink $refFile]]
	    if [catch {file readlink $snapDir/$refName} refName1] {
	    } else {
		set refName $refName1
	    }
            if [string compare [file rootname $refName] [file rootname $apsSCRRestoreFilename]]==0 {
                setStatusText "You can't remove a preferred file ('$suffix')."
                return
            }
        }
    }

    if {[string length $apsSCRRestoreFilename] == 0} {
        setStatusText "No file to remove"
        return
    }
    if ![APSYesNoPopUp "You are asking to remove snapshot $apsSCRRestoreFilename, '$apsSCRRestoreDescription'.  Do you really want to do this?"] {
        setStatusText "Remove cancelled."
        return
    }
    setStatusText "Removing $apsSCRRestoreFilename ..."
    set filename0 [APSRemoveGzipExtension $apsSCRRestoreFilename]
    if {[catch {file copy -force $snapDir/$apsSCRRestoreFilename $snapDir/wasteBasket}] || \
          ([file exists $snapDir/categ$filename0] && \
             [catch {file copy -force $snapDir/categ$filename0 $snapDir/wasteBasket}]) || \
          ([file exists $snapDir/categories/categ$filename0] && \
             [catch {file copy -force $snapDir/categories/categ$filename0 $snapDir/wasteBasket}]) || \
          ([file exists $snapDir/beam$filename0] && \
             [catch {file copy -force $snapDir/beam$filename0 $snapDir/wasteBasket}]) || \
          ([file exists $snapDir/beamlines/beam$filename0] && \
             [catch {file copy -force $snapDir/beamlines/beam$filename0 $snapDir/wasteBasket}]) || \
          ([file exists $snapDir/c$filename0] && \
             [catch {file copy -force $snapDir/c$filename0 $snapDir/wasteBasket}]) || \
          ([file exists $snapDir/collapsed/c$filename0] && \
             [catch {file copy -force $snapDir/collapsed/c$filename0 $snapDir/wasteBasket}]) || \
          ([file exists $snapDir/u$filename0] && \
             [catch {file copy -force $snapDir/u$filename0 $snapDir/wasteBasket}]) } {
        setStatusText "Problem copying snapshot to wastebasket."
        APSAlertBox [APSUniqueName .] -errorMessage "$errorInfo"
        return 
    }
    if {[catch {file delete -force $snapDir/$apsSCRRestoreFilename \
                  $snapDir/categ$filename0 \
                  $snapDir/categories/categ$filename0 \
                  $snapDir/beam$filename0 \
                  $snapDir/beamlines/beam$filename0 \
                  $snapDir/c$filename0 \
                  $snapDir/collapsed/c$filename0 \
                  $snapDir/u$filename0 }]} {
        setStatusText "Problem removing snapshot."
        APSAlertBox [APSUniqueName .] -errorMessage "$errorInfo"
        return 
    }
    setStatusText "Removed $apsSCRRestoreFilename"
    if [catch {APSSCRLogAction -action remove -file $apsSCRRestoreFilename} result] {
        setStatusText "$result"
    }
    clearRestoreFilename
    clearSearch
    APSClearSCRFilterFlags
    if {[winfo exists .userFrame.apsSCRlist]} {
        destroy .userFrame.apsSCRlist
        update
    }
}

proc exportSnapshot {} {
    global apsSCRRestoreFilename apsSCRSnapDir apsSCRUseRefForRestore apsSCRSystem
    set snapDir $apsSCRSnapDir/$apsSCRSystem
    if {[string length $apsSCRRestoreFilename] == 0} {
        setStatusText "No file to export."
        return
    }
    if {[catch {APSInfoDialog [APSUniqueName .] -width 80 \
                  -name "Export file dialog" -infoMessage \
                  "Input the name of the file to which to export filtered data." \
                  -default [pwd]/ } exportFile] || \
          ![string length $exportFile]} {
        setStatusText "No filename given for exported data."
        return
    }
    if {[file exists $exportFile] && \
          ![APSMultipleChoice [APSUniqueName .] \
              -question "$exportFile exists.  Overwrite?" \
              -labelList {Yes No} -returnList {1 0}]} {
        setStatusText "Export aborted."
        return
    }
    
    setStatusText "Exporting $apsSCRRestoreFilename to $exportFile"
    reviewSnapshot -exportFile $exportFile
}

set replacementData ""
proc alterSnapshot {} {
    global apsSCRRestoreFilename apsSCRSnapDir apsSCRUseRefForRestore apsSCRSystem
    global replacementData replacementDescription apsSCRRestoreDescription
    set snapDir $apsSCRSnapDir/$apsSCRSystem
    if {[string length $apsSCRRestoreFilename] == 0} {
        setStatusText "No file to alter."
        return
    }
    
    set replacementData ""
    set replacementDescription "Altered: $apsSCRRestoreDescription"
    set dbwin [APSUniqueName .]
    APSDialogBox $dbwin -name "Snapshot Alteration" -width 60 -contextHelp \
      "To alter a snapshot, you must supply an SDDS file containing all the columns that are present in a normal snapshot.  This file must contain one or more rows giving replacement data for process variables.  For example, it could be a filtered snapshot that you exported to a private file." \
      -cancelCommand {set replacementData ""}
    APSLabeledEntry .le1 -parent $dbwin.userFrame -width 80 -label "Replacement data file: " \
      -textVariable replacementData -fileSelectButton 1 -fileSelectPath $snapDir -contextHelp \
      "Enter the name of the file from which to take replacement data, i.e., data that is put in place of corresponding data in the snapshot.  Corresponding data is data for the same PV."
    APSLabeledEntry .le2 -parent $dbwin.userFrame -width 80 -label "Description: " \
      -textVariable replacementDescription -contextHelp \
      "Enter a description for the altered snapshot."
    update
    tkwait window $dbwin
    
    if {![string length $replacementData]} {
        setStatusText "Snapshot alteration cancelled."
        return
    }
    if {![file exists $replacementData]} {
        setStatusText "$replacementData not found: snapshot alteration cancelled."
        return
    }
    setStatusText "Altering $apsSCRRestoreFilename..."
    set snapshot [lindex [APSSCRMakeSnapshotFilename -machine $apsSCRSystem] 0]
    if [catch {APSSCRAlterSnapshot \
                 -sourceSnapshot $apsSCRSnapDir/$apsSCRSystem/$apsSCRRestoreFilename \
                 -description $replacementDescription \
                 -replacementData $replacementData} result] {
        setStatusText $result
        return
    }
    setStatusText "Done."
    if [catch {APSSCRLogAction -action "create-by-alter-with-$replacementData" -file $result} result1] {
        setStatusText "$result1"
    }
}

proc EditSnapshot {} {
    global apsSCRRestoreFilename apsSCRSnapDir apsSCRUseRefForRestore apsSCRSystem
    global replacementData replacementDescription apsSCRRestoreDescription apsSCRUseAtticForRestore
    global apsSCRAtticDir
    if $apsSCRUseAtticForRestore {
        set snapDir $apsSCRAtticDir/$apsSCRSystem
    } else {
        set snapDir $apsSCRSnapDir/$apsSCRSystem
    }
    if {[string length $apsSCRRestoreFilename] == 0} {
        setStatusText "No file to Edit."
        return
    }
    set waveformFile $snapDir/[file root $apsSCRRestoreFilename].waveform.gz
    
    if [catch {sdds load $snapDir/$apsSCRRestoreFilename origData} result] {
        setStatusText "$result"
        return
    }
    set value [lindex $origData(Column.ValueString) 0]
    set name [lindex $origData(Column.ControlName) 0]
    set editData(ColumnNames) "ControlName ValueString"
    set editData(ColumnInfo.ControlName) "type SDDS_STRING"
    set editData(ColumnInfo.ValueString) "type SDDS_STRING"
    set editData(Column.ControlName) [list $name]
    set editData(Column.ValueString) [list $value]
    
    set tmp2 [APSTmpDir]/[APSTmpString]
    APSAddToTmpFileList -ID EditSnapshot -fileList $tmp2
    if [catch {sdds save $tmp2 editData} result] {
        setStatusText $result
        return
    }
    set initialSize [llength $name]
    setStatusText "Editing $apsSCRRestoreFilename..."
    setStatusText "Save file and close sddsedit window when you are done editing."
    exec sddsedit -fileName $tmp2 -hideColumns ControlName -complexAction 0 
    
    set newName [APSGetSDDSColumn -fileName $tmp2 -column ControlName -page 1]
    set newValue [APSGetSDDSColumn -fileName $tmp2 -column ValueString -page 1]
    set newSize [llength $newName] 
    if {$newSize > $initialSize} {
        setStatusText "Error: modified data has more rows than $apsSCRRestoreFilename"
        return
    }
    set isNumber [lindex $origData(Column.IsNumerical) 0]
    set errors 0
    # check new data for validity
    # replace with old data if the new data is invalid
    if {$newSize < $initialSize} {
        # since rows were deleted, some extra work is needed to line up the
        # new and old data.
        foreach nm $name isN $isNumber {
            if [string length $nm] {
                set i [lsearch -exact $newName $nm]
                if {$i>=0} {
                    set val [lindex $newValue $i]
                    if {$isN=="y" && [scan $val %f scannedVal]!=1} {
                        # data is supposed to be numeric, but isn't
                        setStatusText "Error: non numeric value $val was entered for $nm."
                        incr errors
                    }
                    lreplace $value $i $i [lindex $newValue $i]
                }
            }
        }
    } else {
        foreach nm $name val $newValue isN $isNumber {
            if [string length $nm] {
                if {$isN=="y" && [scan $val %f scannedVal]!=1} {
                    setStatusText "Error: non numeric value $val is given for $nm."
                    incr errors
                }
            }
        }
        set value $newValue
    }
    if $errors {
        setStatusText "Edit failed due to above errors"
        bell
        return
    }
    set origData(Column.ValueString) [list $value]
    set tmp1 [APSTmpDir]/[APSTmpString]
    APSAddToTmpFileList -ID EditSnapshot -fileList $tmp1
    if [catch {sdds save $tmp1 origData} result] {
        setStatusText $result
        return
    }
    set description "Edited: $apsSCRRestoreDescription"
    # setStatusText "Altering $apsSCRRestoreFilename..."
    set dataList [APSSCRMakeSnapshotFilename -machine $apsSCRSystem]
    set newFilename [lindex $dataList 0]
    set timeList [lrange $dataList 1 end]
    set time0 [format %.0lf [lindex $timeList 8]]
    #set snapshot [lindex [APSSCRMakeSnapshotFilename -machine $apsSCRSystem] 0]
    
    if [catch { exec sddsprocess $tmp1 \
                  "-reprint=param,SnapshotDescription,[APSMakeSafeQualifierString $description]" \
                  "-redefine=param,Time,$time0" \
                  "-reprint=param,SnapshotFilename,$newFilename" -nowarn} result] {
        setStatusText $result
        return
    }
    set sourceFile $snapDir/$apsSCRRestoreFilename
    set snaproot  [file tail [file rootname $sourceFile]]
    set snapexten [file extension $sourceFile]
    set snapdir  [file dirname $sourceFile]/
    if {[string compare $snapdir ./]==0} {
        set snapdir ""
    }
    set newroot   [file tail [file rootname $newFilename]]
    set newexten  .gz
    if [catch {
        exec gzip -c $tmp1 > $snapdir$newroot.gz
        if {[file exists ${snapdir}/collapsed]} {
            exec sddscollapse $snapdir$newroot.gz ${snapdir}/collapsed/c$newroot
        } else {
            exec sddscollapse $snapdir$newroot.gz ${snapdir}c$newroot
        }
        if {[file exists ${snapdir}/categories/categ$snaproot]} {
            exec cp ${snapdir}/categories/categ$snaproot ${snapdir}/categories/categ$newroot 
        } else {
            exec cp ${snapdir}categ$snaproot ${snapdir}categ$newroot 
        }
        if {[file exists ${snapdir}/beamlines/beam$snaproot]} {
            exec cp ${snapdir}/beamlines/beam$snaproot ${snapdir}/beamlines/beam$newroot
        } else {
            exec cp ${snapdir}beam$snaproot ${snapdir}beam$newroot
        }
    } result] {
        setStatusText $result
        return
    }
    if [file exist $waveformFile] {
        exec cp $waveformFile ${snapdir}${newroot}.waveform.gz
    }
    setStatusText "Done."
}


proc reviewSnapshot {args} {
    set all 0
    set custom 0
    set exportFile ""
    APSStrictParseArguments {all exportFile custom}

    global apsSCRSystem apsSCRSnapDir apsSCRPVNameFilter apsSCRUseAtticForRestore apsSCRAtticDir
    global apsSCRFilterFileName apsSCRFilterFileDir apsSCRInvertFilterFile
    global apsSCRCustomReviewList apsSCRCustomReviewDescription noConnections

    if {$custom} {
        if {[llength $apsSCRCustomReviewList($apsSCRSystem)]==0} {
            setStatusText "No custom review choices available for $apsSCRSystem"
            return
        }
        global apsSCRCustomReviewDescription
        if [catch {APSChooseItemFromList -name CustomReviewChoices:$apsSCRSystem \
                     -itemList $apsSCRCustomReviewDescription($apsSCRSystem) \
                     -returnList $apsSCRCustomReviewList($apsSCRSystem) \
                     -returnIndices 0 -multiItem 0} reviewChoice] {
            setStatusText "Problem choosing custom review: $reviewChoice"
            return
        }
        if ![llength $reviewChoice] {
            setStatusText "No custom review choice made"
            return
        }
        set reviewChoice [lindex $reviewChoice 0]
    }

    # These are local to the SaveCompareRestore application and could be
    # passed as arguments.
    global errorInfo showReadOnly protectionLock manualFieldsOnly apsSCRRestoreFilename 
    global invertChoices

    if $apsSCRUseAtticForRestore {
	set snapDir $apsSCRAtticDir/$apsSCRSystem
    } else {
	set snapDir $apsSCRSnapDir/$apsSCRSystem
    }

    if {![APSCheckSCRSelections] && ($invertChoices == 0)} {
        setStatusText "Select one or more categories and one or more beamlines."
        return
    }

    set mode review
    if [string length $exportFile] {
        set mode export
        set localShowReadOnly 1
        set localProtectionLock 0
        set localManualFieldsOnly 0
    } else {
        set localShowReadOnly $showReadOnly
        set localProtectionLock $protectionLock
        set localManualFieldsOnly $manualFieldsOnly
    }

    if {[string length $apsSCRRestoreFilename] == 0} {
        setStatusText "No file to $mode"
        return
    }
    if {[string compare $mode review]==0} {
        if !$custom  {
            setStatusText "Preparing printout..."
        } else {
            setStatusText "Preparing filtered file..."
        }
    }

    if {$all || $custom} {
        lappend selectionArgs -protectionLock 0 \
          -includeReadOnlys 1 
    } else {
        lappend selectionArgs -protectionLock $localProtectionLock \
          -includeReadOnlys $localShowReadOnly \
          -manualFieldsOnly $localManualFieldsOnly \
          -invertChoices $invertChoices -noConnections $noConnections
    }

    if [catch {eval APSMakeSCRMatchOptions $snapDir/$apsSCRRestoreFilename \
                 -pvNameFilter {$apsSCRPVNameFilter} \
                 $selectionArgs } matchOpt] {
        setStatusText "Problem making matching options for snapshot:"
        setStatusText "$matchOpt"
    }
   
    set tmpfile [APSTmpDir]/${apsSCRRestoreFilename}[APSTmpString]
    if [string compare $mode export]==0 {
        set filteredFile $exportFile
    } else {
        set filteredFile $tmpfile.f
    }

    if [string length $apsSCRFilterFileName]==0 {
        set extraCmd cat
    } else {
        if $apsSCRInvertFilterFile {
            set extraCmd "sddsselect -nowarning -pipe $apsSCRFilterFileDir/$apsSCRFilterFileName -match=ControlName -invert "
        } else {
            set extraCmd "sddsxref -nowarning -pipe $apsSCRFilterFileDir/$apsSCRFilterFileName -match=ControlName -take=Index | sddssort -column=Index -pipe "
        }
    }

    # -match=column,ControlName=?0,! is to eliminate literal \0 control name strings.
    if [catch {eval exec sddsprocess $snapDir/$apsSCRRestoreFilename -pipe=out \
                 "$matchOpt" -nowarning \
                 -format=column,ValueString,ValueString,doubleFormat=%.13g \
                 -match=column,ControlName=?0,! \
                 | $extraCmd \
                 | sddsprocess -pipe=in $filteredFile \
                 -redefine=parameter,Count,n_rows,type=long \
                 -reprint=parameter,PVCount,%ld,Count} result] {
        setStatusText "Error: $result"
        setStatusText "No PVs match the searching options."
        return
    }
    if [string compare $mode review]==0 {
        if $custom {
            if [catch {eval $reviewChoice -snapshot $filteredFile \
                         -machine $apsSCRSystem} result] {
                return -code error "Error: $result"
            }
        } else {
            if [catch {exec sddsbreak -rowlimit=40 $filteredFile -pipe=out \
                         | sddsprintout -pipe=in $tmpfile -nowarning -format=string=%9s \
                         -postpagelines=2 \
                         -parameter=SnapshotFilename,end \
                         -parameter=SnapshotDescription,end -parameter=TimeStamp,end \
                         -parameter=PVCount \
                         -col=ControlName,format=%-32s -col=ValueString,format=%-22s \
                         -col=IsProtected,label=Prtctd \
                         -col=OpsIntervention,label=Manl \
                         -col=IsReadOnly,label=RdOnly \
                         -col=Description,format=%-32s } result] {
                setStatusText "Error: $result"
                return
            }
           # catch {file delete $filteredFile}
           
            set controlNameList [exec sdds2stream -col=ControlName $filteredFile]
            set valueList [exec sdds2stream -col=ValueString $filteredFile]
            set index [lsearch -regexp $valueList .waveform]
            if {$index>=0} {
                ReviewWaveformSnapshort -snapshot $snapDir/$apsSCRRestoreFilename
            }
            APSFileDisplayWindow [APSUniqueName .fileDisp] -fileName $tmpfile \
              -comment "Filtered printout of $apsSCRRestoreFilename" -deleteOnClose 1 -width 120 \
              -height 51 -printCommand "enscript -r" -sddsExportableFile $snapDir/$apsSCRRestoreFilename \
              -modal 0
        }
    }
    if [catch {APSSCRLogAction -file $apsSCRRestoreFilename -action $mode} result] {
        setStatusText "$result"
    }
    setStatusText "Done ${mode}ing"
}

proc ReviewWaveformSnapshort {args} {
    set snapshot ""
    APSParseArguments {snapshot}
    set waveformFile [file root $snapshot].waveform.gz

    set tmpfile [APSTmpDir]/[APSTmpString].waveform.print
    if [catch {exec sddsprintout $waveformFile -par=WaveformPV -col=Index -col=Waveform $tmpfile } result] {
        return -code error $result
    }
    APSFileDisplayWindow [APSUniqueName .fileDisp] -fileName $tmpfile \
      -comment "Waveform printout of $waveformFile" -deleteOnClose 1 -width 120 \
      -height 51 -printCommand "enscript -r" -sddsExportableFile $waveformFile \
      -modal 0
}

proc APSSCRCheckCurrentAOAI {args} {
    set filename ""
    set tolerance 0.5
    set interactive 0
    set snapshotName ""
    APSStrictParseArguments {filename tolerance interactive snapshotName}
    if $tolerance<=0 {
        return -code error "APSSCRCheckCurrentAOAI: tolerance<=0"
    }

    set tmpRoot [APSTmpDir]/[APSTmpString]
    APSAddToTmpFileList -ID APSSCRCheckCurrentAOAI -fileList "$tmpRoot.AO $tmpRoot.1 $tmpRoot.2 $tmpRoot.mtbad"

    if [catch {exec sddscombine /home/helios/oagData/sr/HCorrectorStatus/config.sdds \
                 /home/helios/oagData/sr/VCorrectorStatus/config.sdds \
                 -pipe=out -merge | \
                 sddsprocess -pipe=in \
                 $tmpRoot.hvbad -nowarning -filter=column,Nonexistent,0.5,1.5
        exec sddsprocess $filename -match=column,ControlName=*CurrentAO $tmpRoot.1 -nowarning \
                 -edit=column,PSName,ControlName,%/:CurrentAO// \
                 -scan=column,AOValue,ValueString,%lf,type=double,units=A} result] {
        return -code error "APSSCRCheckCurrentAOAI: $result"
    }
    if [catch {exec sdds2stream -rows $tmpRoot.1} result] {
        return -code error "APSSCRCheckCurrentAOAI: $result"
    }
    if [string compare "0 rows" $result]==0 {
        return 0
    }
    if [catch {exec sddsselect $tmpRoot.1 $tmpRoot.hvbad -invert -match=PSName=DeviceName $tmpRoot.AO } result] {
        return -code error "APSSCRCheckCurrentAOAI: $result"
    }
    if [catch {exec sddsprocess $filename -match=column,ControlName=*CurrentAI -pipe=out -nowarning \
                 -edit=column,PSName,ControlName,%/:CurrentAI// \
                 -scan=column,AIValue,ValueString,%lf,type=double,units=A \
                 | sddsxref -pipe $tmpRoot.AO -match=PSName -nowarning -take=AOValue \
                 | sddsprocess -pipe -nowarning \
                 "-define=column,Difference,AIValue AOValue -,units=A" \
                 -filter=column,Difference,[expr -1*$tolerance],$tolerance,! \
                 -process=Difference,count,NumberOut \
                 | tee $tmpRoot.1 \
                 | sdds2stream -pipe -parameter=NumberOut} result] {
        APSDeleteTmpFileList -ID APSSCRCheckCurrentAOAI
        return -code error "APSSCRCheckCurrentAOAI: $result"
    }
    if {!$interactive || !$result} {
        APSDeleteTmpFileList -ID APSSCRCheckCurrentAOAI
        return $result
    }
    if [catch {exec sddsprintout $tmpRoot.1 $tmpRoot.2 \
                 "-title=The following supplies had suspicious current setpoints and readbacks in snapshot $snapshotName\n" \
                 -column=PSName -column=AOValue,format=%12.4f -column=AIValue,format=%12.4f \
                 -column=Difference,format=%12.4f} result] {
        APSDeleteTmpFileList -ID APSSCRCheckCurrentAOAI
        return -code error $result
    }
    set widget [APSUniqueName .]
    APSFileDisplayWindow $widget -comment "CurrentAO-CurrentAI out-of-bounds" \
      -fileName $tmpRoot.2 -sddsExportableFile $tmpRoot.1 -deleteOnClose 1
    pack forget $widget.buttonRow.close.button
    global apsSCRCheckCurrentAOAI
    set apsSCRCheckCurrentAOAI -1
    APSButton .continue -parent $widget.buttonRow -text "Continue" \
      -highlightColor red -highlight 1 \
      -command "set apsSCRCheckCurrentAOAI 1" -packOption "-side right"
    APSButton .abort -parent $widget.buttonRow -text "Abort" \
      -highlightColor red -highlight 1 \
      -command "set apsSCRCheckCurrentAOAI 0" -packOption "-side right"
#    $widget.buttonRow.abort configure 
#    $widget.buttonRow.continue configure 
    bell
    tkwait variable apsSCRCheckCurrentAOAI
    destroy $widget
    APSDeleteTmpFileList -ID APSSCRCheckCurrentAOAI
    return [expr !$apsSCRCheckCurrentAOAI]
}

proc restoreSnapshot {args} {
    set doRamp 0
    APSStrictParseArguments {doRamp}
    global apsSCRRestoreFilename apsSCRSystem apsSCRSnapDir errorInfo showReadOnly 
    global apsSCRPVNameFilter protectionLock manualFieldsOnly restoreLock
    global apsSCRFilterFileName apsSCRFilterFileDir invertChoices
    global apsSCRInvertFilterFile eraseList controlNameList
    global rampFile apsSCRUseCASRServer lab
    global apsSCRUseRefForRestore apsSCRUseAtticForRestore apsSCRAtticDir apsNetworkDomain apsUpgrade
    
#    if {[string compare $apsNetworkDomain "accel.ntw0rk"] != 0 && [string compare $apsNetworkDomain "aps4.anl.gov"] != 0} {
#        setStatusText "You can not restore snapshot on non-acceleration stations, please login to helios workstation."
#	return
#    }
    
   # if {$apsSCRSystem=="SRXrayBPM"} {
   #     setStatusText "No setpoints exist in SRXrayBPM snapshots for restoring."
   #     return
   # }
    if [winfo exists .manual] {
        # prevents reexecuting this procedure while the manual restore window is up
        return
    }
    if $apsSCRUseAtticForRestore {
        if ![APSYesNoPopUp "You are restoring a snapshot from attic directory. This may produce undesirable results. Are you sure you want to proceed?"] {
            setStatusText "restore snapshot from attic was cancelled."
            return
        }
        set snapDir $apsSCRAtticDir/$apsSCRSystem
    } else {
        set snapDir $apsSCRSnapDir/$apsSCRSystem
    }
    if {[string length $apsSCRRestoreFilename] == 0} {
        setStatusText "No file  to restore"
        return
    }
    if {![APSCheckSCRSelections] && ($invertChoices == 0)} {
        setStatusText "Select one or more categories and one or more beamlines."
        return
    }
    if {$restoreLock} {
        setStatusText "Restore lock is on.  Turn off to do restore."
        return
    }
    if {!$protectionLock} {
        if ![APSYesNoPopUp "You are asking to restore protected variables.  Are you sure?  You can review the protected variables using the REVIEW button first"] {
            setStatusText "Restore cancelled."
            return
        }
        setStatusText "Will be restoring protected variables."
    }

    setStatusText "Preparing filtered file..."
    if [catch {APSMakeSCRMatchOptions $snapDir/$apsSCRRestoreFilename -includeReadOnlys 0 \
                 -pvNameFilter $apsSCRPVNameFilter -protectionLock $protectionLock \
                 -invertChoices $invertChoices} matchOpt] {
        setStatusText "Problem filtering file:"
        setStatusText "$matchOpt"
    }

    # set tmpfile [APSTmpDir]/${apsSCRRestoreFilename}[APSTmpString]
    if [string length $apsSCRFilterFileName]==0 {
        set extraCmd cat
    } else {
        if $apsSCRInvertFilterFile {
            set extraCmd "sddsselect -nowarning -pipe $apsSCRFilterFileDir/$apsSCRFilterFileName -match=ControlName -invert "
        } else {
            set extraCmd "sddsselect -pipe $apsSCRFilterFileDir/$apsSCRFilterFileName -match=ControlName"
        }
    }
    set tmpfile [APSTmpDir]/${apsSCRRestoreFilename}[APSTmpString]
    APSAddToTmpFileList -ID restoreSnapshot -fileList "$tmpfile ${tmpfile}.1"

    # -match=column,ValueString=,! and -match=column,ControlName=?0,! are to eliminate
    # empty lines from various versions of BURT.
    # shang changed, removed the filter of empty strings since sometimes the string pv values could be empty string
    # for example S33B:P3:BunchPatternSO, and now we use sddscasr for restore, it works for empty string.
    if {$apsUpgrade} {
        if [catch {eval exec sddsprocess $snapDir/$apsSCRRestoreFilename -pipe=out "$matchOpt" \
                       "-match=column,ControlName=?0,!" "-match=col,ValueString=_NoConnection_,!" \
                       | sddsconvert -pipe -retain=parameter,SnapType \
                       | $extraCmd > $tmpfile} result] {
            APSDeleteTmpFileList -ID restoreSnapshot
            return -code error "RestoreSnapshot(1): $result"
        }
    } else {
        if [catch {eval exec sddsprocess $snapDir/$apsSCRRestoreFilename -pipe=out "$matchOpt" -match=column,ControlType=pv \
                       "-match=column,ControlName=?0,!" "-match=col,ValueString=_NoConnection_,!" \
                       | sddsconvert -pipe -retain=parameter,SnapType \
                       | $extraCmd > $tmpfile} result] {
            APSDeleteTmpFileList -ID restoreSnapshot
            return -code error "RestoreSnapshot(1): $result"
        }
    }
    #filter out ca errors from versions of sddscasr
    

    if [string compare $apsSCRSystem SR]==0 {
        if [catch {APSMakeSCRMatchOptions $snapDir/$apsSCRRestoreFilename -includeReadOnlys 1 \
                     -pvNameFilter $apsSCRPVNameFilter -protectionLock $protectionLock \
                     -invertChoices $invertChoices} matchOpt] {
            setStatusText "Problem filtering file:"
            setStatusText "$matchOpt"
            APSDeleteTmpFileList -ID restoreSnapshot
            return
        }
        if {$apsUpgrade} {
            if [catch {eval exec sddsprocess $snapDir/$apsSCRRestoreFilename -pipe=out "$matchOpt" \
                           "-match=column,ValueString=,!" "-match=column,ControlName=?0,!" -nowarning \
                           | sddsconvert -pipe -retain=parameter,SnapType \
                           | $extraCmd > ${tmpfile}.1} result] {
                APSDeleteTmpFileList -ID restoreSnapshot
                return -code error "RestoreSnapshot(2): $result"
            }
        } else {
            if [catch {eval exec sddsprocess $snapDir/$apsSCRRestoreFilename -pipe=out "$matchOpt" -match=column,ControlType=pv \
                           "-match=column,ValueString=,!" "-match=column,ControlName=?0,!" -nowarning \
                           | sddsconvert -pipe -retain=parameter,SnapType \
                           | $extraCmd > ${tmpfile}.1} result] {
                APSDeleteTmpFileList -ID restoreSnapshot
                return -code error "RestoreSnapshot(2): $result"
            }
        }
        if [APSSCRCheckCurrentAOAI -filename ${tmpfile}.1 -tolerance 2 -interactive 1 \
              -snapshotName $apsSCRRestoreFilename] {
            setStatusText "Restore cancelled."
            APSDeleteTmpFileList -ID restoreSnapshot
            return
        }
    }
    
    set snapshotColumnList [APSGetSDDSNames -class column -fileName $snapDir/$apsSCRRestoreFilename]
    if {[llength $snapshotColumnList] && [lsearch -exact $snapshotColumnList OpsIntervention]!=-1} {
        set rampFile [APSTmpDir]/[APSTmpString]
        eval exec sddsprocess $tmpfile $tmpfile.0 "-match=col,OpsIntervention=+y,!" -nowarning
        eval exec sddsprocess $tmpfile $rampFile "-match=col,OpsIntervention=+y" -nowarning
	APSAddToTempFileList $rampFile $tmpfile
	file rename -force $tmpfile.0 $tmpfile
        catch {exec sdds2stream -rows $rampFile} rows
        if [string compare $rows "0 rows"]!=0 {
	    set manualSelectedList ""
	    catch {exec sdds2stream $rampFile -parameter=SnapshotFilename,SnapshotDescription,TimeStamp} parList
	    catch {exec sdds2stream $rampFile -columns=ControlName,ValueString,IsProtected} colList

            exec sddsprintout -nowarning $rampFile $rampFile.1 \
              -col=ControlName,format=%32s -col=ValueString,format=%22s -col=IsProtected
	    APSAddToTempFileList $rampFile.1
            if {[file readable $rampFile.1]} {
                set lineIndex 0
                set cList ""
                set fid [open $rampFile.1]
                while {[gets $fid line] >= 0} {
		    if $lineIndex {
		        lappend cList $line
		    }
		    if {[string match *--------* $line]} {
                        set lineIndex 1
                    }
                }
                close $fid
	    }

	    set controlNameList ""
	    set eraseList ""
	    set k [llength $colList]
	    for {set j 0} {$j < $k} {incr j +3} {
                set name [lindex $colList $j]
                lappend controlNameList $name
                lappend eraseList $name
            }

            APSWindow .manual -name "OPERATOR INTERVENTION REQUIRED" -contextHelp ""
	    set parent1 .manual.userFrame
	    pack [ttk::frame $parent1.f1] -fill both -expand false
	    pack [ttk::label $parent1.f1.l1 -text "These process variables can only be\
                   restored manually by an operator."\
                    -font {courier 12 bold}] -side left -fill both -expand false
	    set i 0
	    foreach elem [list SnapshotFilename SnapshotDescription TimeStamp] {
                pack [ttk::frame $parent1.frame$i] -side top -fill both -expand false
                pack [ttk::label $parent1.frame$i.label$i -text "$elem = [lindex $parList $i]"]\
                  -side left -fill both -expand false
                incr i
	    }
	    pack [ttk::frame $parent1.f2] -fill both -expand false
	    pack [ttk::label $parent1.f2.l2 -text "                      ControlName       \
                  ValueString       IsProtected" \
                    -font {courier 12 bold}] -side left -fill both -expand false

	    APSScrolledList .manList -parent $parent1 -height 15 -name "Manual List"\
              -itemList $cList
	    set parent2 .manual.buttonRow
	    APSButton .accept -parent $parent2 -packOption "-side left" -text "Accept"\
              -command AcceptManualListSelection -contextHelp ""
	    APSButton .select -parent $parent2 -packOption "-side left" -text "Select All"\
              -command SelectAllManualList -contextHelp ""
	    APSButton .clear -parent $parent2 -packOption "-side left" -text "Clear Selection"\
              -command ClearSelection -contextHelp ""
	    set closeCommand "destroy .manual"
	    $parent2.close.button configure -command $closeCommand
        }
    }

    set debugMode 0
    if $debugMode {
        exec sddsconvert -nowarning $tmpfile $tmpfile.a -ascii
        APSFileDisplayWindow [APSUniqueName .fileDisp] -fileName $tmpfile.a \
          -comment "Filtered file prior to restore" -deleteOnClose 1 \
          -printCommand "enscript -r"
    } else {
        set nameList [APSGetSDDSNames -fileName $tmpfile -class column]
        if [lsearch $nameList ControlNameOut]!=-1 {
            # delete rows with blank ControlNameOut
            # rename ControlNameOut to ControlName
            # allows restoring data to a different PV than it came from (for NASA)
            if [catch {exec sddsprocess $tmpfile -pipe=out \
                         -match=column,ControlNameOut=,! \
                         | sddsconvert -pipe=in $tmpfile.a \
                         -delete=column,ControlName \
                         -rename=column,ControlNameOut=ControlName} result] {
                setStatusText "Error preprocessing restore data: $result"
                APSDeleteTmpFileList -ID restoreSnapshot
                return
            }
            file rename -force $tmpfile.a $tmpfile
        }
        set logFile [APSTmpDir]/[APSTmpString]

        set errorInRestore 0
        set restoreTimeStamp "[clock format [clock seconds]]"
        if [catch {APSSCRLogAction -file $apsSCRRestoreFilename -action restore-start} result] {
            setStatusText "$result"
        }
        
        #Added restore-info for logMessage to record which beamlines and categories were selected
        set action "restore-info"
        if {$protectionLock} {
            append action " PROTECT"
        }
        if {$invertChoices} {
            append action " INVERT"
        }
        if {$apsSCRPVNameFilter != ""} {
            append action " PVNameFilter=$apsSCRPVNameFilter"
        }
        global apsSCRFilterBeamline apsSCRFilterCategory
        if {[info exists apsSCRFilterBeamline]} {
            set bl ""
            foreach filt [array names apsSCRFilterBeamline] {
                if [subst \$apsSCRFilterBeamline($filt)] {
                    lappend bl $filt
                }
            }
            append action " BEAMLINES=[join $bl ,]"
        }
        if {[info exists apsSCRFilterCategory]} {
            set fc ""
            foreach filt [array names apsSCRFilterCategory] {
                if [subst \$apsSCRFilterCategory($filt)] {
                    lappend fc $filt
                }
            }
            append action " CATEGORIES=[join $fc ,]"
        }
        if [catch {APSSCRLogAction -file $apsSCRRestoreFilename -action "$action"} result] {
            setStatusText "$result"
        }
        global apsSCRPendIOTime
        if ![info exist apsSCRPendIOTime($apsSCRSystem)] {
            set apsSCRPendIOTime($apsSCRSystem) 80
        }

        if !$doRamp {
            global apsSCRUseCarestore apsUpgrade
            setStatusText "Restoring..."
            if {$apsUpgrade} {
                if [catch {exec sddspvasaverestore $tmpfile -restore=verify -logFile=$logFile -pendIOTime=$apsSCRPendIOTime($apsSCRSystem) \
                         -waveform=directory=$apsSCRSnapDir/$apsSCRSystem,onefile,rootname=[file root $apsSCRRestoreFilename],extension=.waveform.gz} result] {
                    set errorInRestore 1
                    setStatusText "Error from sddspvasaverestore restore: $result"
                } else {
                    set fd [open $logFile "r"]
                    while {![eof $fd]} {
                        set text [gets $fd]
                        if {[string match -nocase "*error*" $text]} {
                            set errorInRestore 1
                            break
                        }
                    }
                    close $fd
                }
            } else {
                if [catch {exec sddscasr $tmpfile -restore=verify -logFile=$logFile -pendIOTime=$apsSCRPendIOTime($apsSCRSystem)  \
                         -waveform=directory=$apsSCRSnapDir/$apsSCRSystem,onefile,rootname=[file root $apsSCRRestoreFilename],extension=.waveform.gz} result] {
                    set errorInRestore 1
                    setStatusText "Error from sddscasr restore: $result"
                } else {
                    set fd [open $logFile "r"]
                    while {![eof $fd]} {
                        set text [gets $fd]
                        if {[string match -nocase "*error*" $text]} {
                            set errorInRestore 1
                            break
                        }
                    }
                    close $fd
                }
            }
            if $errorInRestore {
                global apsScriptHost
                set logSCRFile [APSTmpDir]/SCR[APSTmpString]
                if {[file exists $logFile]} {
                    catch {file copy $logFile $logSCRFile}
                    catch {APSSendEMail -address soliday \
                             -subject "Problem restoring SCR file."  \
                             -message "Problem restoring SCR file\nHost=${apsScriptHost}\nSCRfile=${snapDir}/${apsSCRRestoreFilename}\nLogfile=$logSCRFile"} 
                    if {$apsUpgrade} {
                        APSFileDisplayWindow [APSUniqueName .fileDisp] -fileName $logFile \
                          -comment "Error output from sddspvasaverestore" -deleteOnClose 1 \
                          -printCommand "enscript -r"
                    } else {
                        APSFileDisplayWindow [APSUniqueName .fileDisp] -fileName $logFile \
                          -comment "Error output from sddscasr" -deleteOnClose 1 \
                          -printCommand "enscript -r"
                    }
                } else {
                    catch {APSSendEMail -address soliday \
                             -subject "Problem restoring SCR file."  \
                             -message "Problem restoring SCR file\nHost=${apsScriptHost}\nSCRfile=${snapDir}/${apsSCRRestoreFilename}\nresult=$result"} 
                    
                }
            }
        } else {
            if [catch {APSRampToSnapshot -initDialog 1 \
                         -logFile $logFile -fileName $tmpfile -statusCallback setStatusText} result] {
                setStatusText "$result"
                set errorInRestore 1
            }
        }
        if [catch {APSSCRLogAction -file $apsSCRRestoreFilename -action restore-end} result] {
            setStatusText "$result"
        }
        #   file delete $tmpfile
    }
   
    #track restored file
    if !$lab {
	if [catch {TrackRestoreFile -sourceFile $apsSCRRestoreFilename \
		       -machine $apsSCRSystem -restoreFile $tmpfile \
		       -timeStamp $restoreTimeStamp} result] {
	    setStatusText "TrackRestoreFile: $result"
	}
    }
    APSClearSCRFilterFlags
    set invertChoices 0
    set protectionLock 1
    set restoreLock 1
    
    catch {APSLogButtonCommand -button RESTORE -command restoreSnapshot -application SaveCompareRestore \
        -parameters "system=$apsSCRSystem apsSCRRestoreFilename=$apsSCRRestoreFilename doRamp=$doRamp" }
    if {$apsSCRSystem=="SRBPLD"} {
        #toggle SR BM/ID BPLD enable PV to active the IOC
	if [catch {exec cavput -list=S -range=begin=1,end=39,interval=2,format=%02d -list=-LMPS:BPLD:BM_Enable-SP=0 -pend=5} result] {
	    return -code error "Error toggle BM-BPLD enable1: $result"
	}
	after 1000
	if [catch {exec cavput -list=S -range=begin=1,end=39,interval=2,format=%02d -list=-LMPS:BPLD:BM_Enable-SP=1 -pend=5} result] {
	    return -code error "Error toggle BM-BPLD enable2: $result"
	}
	if [catch {exec cavput -list=S -range=begin=1,end=39,interval=2,format=%02d -list=-LMPS:BPLD: -list=ID1,ID2 -list=_Enable-SP=0 -pend=5 } result] {
	    return -code error "Error toggle ID-BPLD enable1: $result"
	}
	after 1000
	if [catch {exec cavput -list=S -range=begin=1,end=39,interval=2,format=%02d -list=-LMPS:BPLD: -list=ID1,ID2 -list=_Enable-SP=1 -pend=5 } result] {
	    return -code error "Error toggle ID-BPLD enable2: $result"
	}
        return
    }
    setStatusText "Restore completed"
    APSDeleteTmpFileList -ID restoreSnapshot
}

proc TrackRestoreFile {args} {
    set sourceFile ""
    set machine ""
    set restoreFile ""
    set timeStamp ""
    APSParseArguments {sourceFile machine restoreFile timeStamp}
    global env apsSCRTopDirectory

    set restoreDir $apsSCRTopDirectory/restoreTracking
    if {![string length $restoreFile] || ![string length $sourceFile] } {
        return
    }
    set suffix [lindex [APSSCRMakeSnapshotFilename -machine $machine] 0]
    regexp "${machine}(.*)" $suffix a suffix
    if ![file exist $restoreDir/$machine] {
        exec mkdir $restoreDir/$machine
        #catch {exec setfacl -m mask:rwx $restoreDir/$machine}
    }
    if [regexp {(.*).gz} $sourceFile a b] {
        set prefix $b
    } else {
        set prefix $sourceFile
    }
    set filename ${prefix}_${suffix}
    
    if [catch {exec sddsprocess $restoreFile \
                 "-reprint=par,System,$machine" \
                 "-reprint=par,SourceFile,$sourceFile" \
                 "-reprint=par,User,$env(USER)" \
                 "-reprint=par,TimeStamp,$timeStamp" -pipe=out \
                 | gzip -c > $restoreDir/${machine}/$filename.gz } result] {
        return -code error "Error gzipping file: $result"
    }
}
proc AcceptManualListSelection {} {
    global eraseList controlNameList rampFile manualSelectedList
    set manualSelectedList [.manual.userFrame.manList.listbox curselection]
    if ![llength $manualSelectedList] {return}
    SetManualListButtons 0
    set operatorSelList ""
    foreach index $manualSelectedList {
        set pvName [lindex $controlNameList $index]
	lappend operatorSelList $pvName
	set pvIndex [lsearch $eraseList $pvName]
	set eraseList [lreplace $eraseList $pvIndex $pvIndex]
    }

    if [llength $operatorSelList] {
        set matchList ""
        foreach e $eraseList {
	    lappend matchList "-match=col,ControlName=$e,!"
        }
        if [catch {eval exec sddsprocess $rampFile $rampFile.2 \
                     -noWarnings $matchList} result] {
            setStatusText "$result"
        }
        APSAddToTempFileList $rampFile.2
        set logFile [APSTmpDir]/[APSTmpString]
        global apsSCRRestoreFilename
        if [catch {APSSCRLogAction -file $apsSCRRestoreFilename -action ramp-manual} result] {
            setStatusText "$result"
        }
        if [catch {APSRampToSnapshot -initDialog 1 \
                     -logFile $logFile -fileName $rampFile.2 -statusCallback setStatusText} result] {
            setStatusText "$result"
        } 
        SetManualListButtons 1
        bell
        set eraseList $controlNameList
    }
}

proc SetManualListButtons {state} {
    if !$state {
        APSDisableButton .manual.buttonRow.close.button
        APSDisableButton .manual.buttonRow.accept.button
        APSDisableButton .manual.buttonRow.select.button
        APSDisableButton .manual.buttonRow.clear.button
    } else {
        APSEnableButton .manual.buttonRow.close.button
        APSEnableButton .manual.buttonRow.accept.button
        APSEnableButton .manual.buttonRow.select.button
        APSEnableButton .manual.buttonRow.clear.button
    }
}

proc SelectAllManualList {} {
    .manual.userFrame.manList.listbox selection set 0 end
}

proc ClearSelection {} {
    .manual.userFrame.manList.listbox selection clear 0 end
}

proc restoreSnapnameCallback {index} {
    global descriptionArray modeWidget manualFieldsOnly showReadOnly apsSCRUseRefForRestore
    global apsSCRRestoreReference

    set manualFieldsOnly 0
    set showReadOnly 0
    set apsSCRUseRefForRestore 0
    set name [lindex $descriptionArray(SnapshotFilename) $index]
    set descrip [lindex $descriptionArray(SnapshotDescription) $index]
    setSnapname $name $descrip
    set apsSCRRestoreReference [FindPreferredRefChoice $name]
}

proc FindPreferredRefFilenameList {args} {
    global apsSCRSystem apsSCRPreferredList apsSCRSnapDir apsSCRPreferredFilenameList
    set apsSCRPreferredFilenameList ""
    
    foreach item $apsSCRPreferredList {
        if  ![string compare $item <FromSearchList>] {
            lappend apsSCRPreferredFilenameList NONE
            continue
        }
        if [catch {APSSCRResolvePreferredFileChoice -system $apsSCRSystem -choice $item} file] {
            setStatusText $file
            lappend apsSCRPreferredFilenameList NONE
            continue
        }
        if [file exist $apsSCRSnapDir/$apsSCRSystem/$file] {
            set file [file readlink $apsSCRSnapDir/$apsSCRSystem/$file]
	    if [catch {file readlink $apsSCRSnapDir/$apsSCRSystem/[file tail $file]} file1] {
	    } else {
		set file $file1
	    }
            lappend apsSCRPreferredFilenameList [file tail $file]
        } else {
            lappend apsSCRPreferredFilenameList NONE
        }
    }
}
proc FindPreferredRefChoice {filename} {
    global apsSCRPreferredFilenameList apsSCRPreferredList
    set item <FromSearchList>
    if ![regexp {.gz} $filename a b] {
        set filename ${filename}.gz
    }
    set index [lsearch -exact $apsSCRPreferredFilenameList $filename]
    if $index>=0 {
        set item [lindex $apsSCRPreferredList $index]
    }
    return $item
}

proc setSnapname {name descrip} {
    global descriptionArray modeWidget manualFieldsOnly showReadOnly 
    global apsSCRRestoreFilename apsSCRRestoreDescription apsSCRSnapDir apsSCRSystem
    global restoreSnapListWidget restoreCategoryWidget apsSCRAtticDir apsSCRUseAtticForRestore
    global apsSCRUseRefForRestore apsSCRRestoreAtticWidget restoreFrame

    if {$apsSCRRestoreAtticWidget && !$apsSCRUseRefForRestore} {
        set snapDir $apsSCRAtticDir/$apsSCRSystem
        set apsSCRUseAtticForRestore 1
    } else {
        set snapDir $apsSCRSnapDir/$apsSCRSystem
        set apsSCRUseAtticForRestore 0
    }
    set manualFieldsOnly 0
    set showReadOnly 0
    if ![file exists $snapDir/$name] {
        if [file exists $snapDir/${name}.gz] {
            set name ${name}.gz
        } else {
            setStatusText "No file found! ($name)"
            return
        }
    }

    set columnNameList [APSGetSDDSNames -class column -fileName $snapDir/$name]
    set readOnlyFlagsPresent [expr [lsearch -exact $columnNameList IsReadOnly]!=-1]
    set protectionFlagsPresent [expr [lsearch -exact $columnNameList IsProtected]!=-1]
    set manualFlagsPresent  [expr [lsearch -exact $columnNameList OpsIntervention]!=-1]

    # $apsSCRRestoreFilename is the actual name of the file, $name is the name without the .gz extension,
    # if any
    set apsSCRRestoreFilename $name
    set name [APSRemoveGzipExtension $name]

    set apsSCRRestoreDescription $descrip

    foreach widget [list $restoreSnapListWidget $restoreCategoryWidget] {
        if [winfo exists $widget] {
            destroy $widget
        }
    }
    update

    setStatusText "File for review/restore selected.  "
    if !$readOnlyFlagsPresent {
        setStatusText "Warning: no read-only classifications for this file."
        $modeWidget.top.showReadOnly.frame.button1 configure -state disabled
        bell
    } else {
        $modeWidget.top.showReadOnly.frame.button1 configure -state normal
    }

    if !$protectionFlagsPresent {
        setStatusText "Warning: no protection classifications for this file."
        $modeWidget.top.protect.frame.button1 configure -state disabled
        bell
    } else {
        $modeWidget.top.protect.frame.button1 configure -state normal
    }

    if !$manualFlagsPresent {
        setStatusText "Warning: no manual-mode classifications for this file."
        $modeWidget.top.manualFieldsOnly.frame.button1 configure -state disabled
        bell
    } else {
        $modeWidget.top.manualFieldsOnly.frame.button1 configure -state normal
    }

    setStatusText "Making filter category buttons..."
    global apsSCRPVNameFilter
    set apsSCRPVNameFilter ""
    APSPVFilterWidget .apsSCRcateg -parent $restoreFrame -fileName $apsSCRRestoreFilename \
      -snapDir $snapDir -rootname $apsSCRSystem -limitPerRow 8

    if {$apsSCRSystem == "LPL"} {
        set setLinacBody {
            global apsSCRFilterBeamline
            set apsSCRFilterBeamline($var) 1
        }
        set setLinacCmd [list foreach var "L0 L1 L2 L3 L4 L5 L6 LINAC Laser PCGun1 PCgun1 PCgun2 rfGun rfGun1 rfGun2 LI Misc" $setLinacBody]

        set setParBody {
            global apsSCRFilterBeamline
            set apsSCRFilterBeamline($var) 1
        }
        set setParCmd [list foreach var "BTS LTP LTP1 LTP2 PAR PTB PTB1 PTB2 PTB3 Misc" $setLinacBody]
        
        set setLetBody {
            global apsSCRFilterBeamline
            set apsSCRFilterBeamline($var) 1
        }
        set setLetCmd [list foreach var "BTS LTP LTP1 LTP2 PTB PTB1 PTB2 PTB3 Misc" $setLinacBody]

        APSDialogBoxAddButton .setlinac \
          -parent ${restoreFrame}.apsSCRcateg.frame.list2 \
          -text "LINAC" \
          -command "${restoreFrame}.apsSCRcateg.frame.list2.buttonRow.clear.button invoke ; $setLinacCmd" \
          -contextHelp "Set all LINAC checkbuttons." \
          -size small

        APSDialogBoxAddButton .setpar \
          -parent ${restoreFrame}.apsSCRcateg.frame.list2 \
          -text "PAR" \
          -command "${restoreFrame}.apsSCRcateg.frame.list2.buttonRow.clear.button invoke ; $setParCmd" \
          -contextHelp "Set all PAR checkbuttons." \
          -size small

        APSDialogBoxAddButton .setlet \
          -parent ${restoreFrame}.apsSCRcateg.frame.list2 \
          -text "LET" \
          -command "${restoreFrame}.apsSCRcateg.frame.list2.buttonRow.clear.button invoke ; $setLetCmd" \
          -contextHelp "Set all LET checkbuttons." \
          -size small
    }

    set restoreCategoryWidget $restoreFrame.apsSCRcateg
}

proc makeRestoreFilenameDisplayFrame {widget args} {
    set parent ""
    set refButton 0
    APSStrictParseArguments {parent refButton}

    global apsSCRRestoreFilename apsSCRRestoreDescription apsSCRSystem apsSCRPreferredReference apsSCRFilterList
    global safetyMode modeWidget saveCompareOnly restoreOnly apsSCRPreferredList
    global apsSCRRestoreComboboxFrame apsSCRRestoreReference apsSCRRestoreComboboxMenu

    APSFrame $widget -parent $parent -label "Snapshot choice" -labelFont "TkHeadingFont"
    ttk::frame $parent$widget.frame.f1 -borderwidth 2
    pack $parent$widget.frame.f1 -side top -anchor w
    set w0 $parent$widget.frame.f1

    set height 0
    set unfiltered ""
    foreach item $apsSCRPreferredList filter $apsSCRFilterList {
        if {[string range $item 0 4] == "Attic"} {
            break
        }
        incr height
        set i [string last "MeV" $item]
        set ii [string last "Mev" $item]
        if {$ii > $i} {set i $ii}
        if {$i != -1} {
            lappend preferred([string trim [string range $item [expr $i - 4] [expr $i - 1]]]) $item
        }
        if {$filter == 0} {
            lappend unfiltered $item
        }
    }
    if {[info exists preferred]} {
        foreach energy [lsort [array names preferred]] {
            foreach item $unfiltered {
                lappend preferred($energy) $item
            }
        }
    }
    ttk::label $w0.cblabel -text "Preferred Choice:"
    if {$height < 5} {
        ttk::combobox $w0.cb -textvariable apsSCRRestoreReference -state readonly -values $apsSCRPreferredList -width 80
    } else {
        ttk::combobox $w0.cb -textvariable apsSCRRestoreReference -state readonly -values $apsSCRPreferredList -width 80 -height $height
    }
    grid $w0.cblabel -row 0 -column 0 -sticky e
    grid $w0.cb -row 0 -column 1 -sticky ew
    if {[info exists preferred]} {
        ttk::menubutton $w0.energy -text MeV -underline 0 -menu $w0.energy.m
        menu $w0.energy.m -tearoff 0
        grid $w0.energy -row 0 -column 2 -sticky ew
        $w0.energy.m add command -label "" -command "energySelect -w $w0.energy -cb $w0.cb -energy 0"
        foreach energy [lsort [array names preferred]] {
            $w0.energy.m add command -label "${energy}MeV" -command "energySelect -w $w0.energy -cb $w0.cb -energy $energy -preferred \"$preferred($energy)\""
        }
        set apsSCRRestoreComboboxMenu $w0.energy
    }
    set apsSCRRestoreComboboxFrame $w0.cb
    bind $w0.cb <<ComboboxSelected>> "APSComboboxRunCallback %W -callback SetRestorePreferredFile -textFont TkDefaultFont -editable 0 -textVariable apsSCRRestoreReference"

    ttk::label $w0.fileLabel -text "Filename:"
    ttk::entry $w0.fileEntry -textvariable apsSCRRestoreFilename -state readonly -width 80
    grid $w0.fileLabel -row 1 -column 0 -sticky e
    grid $w0.fileEntry -row 1 -column 1 -sticky ew

    ttk::label $w0.descripLabel -text "Description:"
    ttk::entry $w0.descripEntry -textvariable apsSCRRestoreDescription -state readonly -width 80
    grid $w0.descripLabel -row 2 -column 0 -sticky e
    grid $w0.descripEntry -row 2 -column 1 -sticky ew



if 0 {
    APSFrameGrid .fg -parent $w0 -yList {top medium bot} 
    set w $w0.fg
    APSComboboxFrame .file1 -parent $w.top -label "Preferred choice:" -width 50 \
      -textVariable apsSCRRestoreReference -callback SetRestorePreferredFile \
      -itemList $apsSCRPreferredList -packOption "-side left -fill x" -maxWidth 1 \
      -contextHelp "choose a prefered reference file from list."
    set apsSCRRestoreComboboxFrame $w.top.file1.cb
    APSLabeledOutput .file -parent $w.medium -label "Filename :       " -width 40 \
      -textVariable apsSCRRestoreFilename -contextHelp "Displays the name of the snapshot that you've chosen." \
      -packOption "-side left"
    
    APSLabeledOutput .descrip -parent $w.bot -label "Description:     " -width 80 \
      -textVariable apsSCRRestoreDescription -packOption "-side left" \
      -contextHelp "Displays the text of the description entered by the operator who saved the snapshot."
    }
}

proc SetRestorePreferredFile {index} {
    global apsSCRRestoreFilename apsSCRRestoreDescription apsSCRSystem apsSCRSnapDir apsSCRUseRefForRestore \
      apsSCRRestoreRefChoice restoreCategoryWidget apsSCRPreferredList apsSCRUbopLink apsSCRRestoreReference
    
    #set item [lindex $apsSCRPreferredList $index]
    set item [set apsSCRRestoreReference]

    set state [string compare $item <FromSearchList>]
    if !$state {
        if $apsSCRUseRefForRestore {
            set apsSCRRestoreFilename ""
            set apsSCRRestoreDescription ""
            set apsSCRUseRefForRestore 0
            if [winfo exists $restoreCategoryWidget] {
                destroy $restoreCategoryWidget
            }
            update
        }
        return
    }
    set apsSCRUseRefForRestore 1
    if [catch {APSSCRResolvePreferredFileChoice -system $apsSCRSystem -choice $item} file] {
        setStatusText $file
        set apsSCRRestoreFilename ""
        set apsSCRRestoreDescription ""
        set apsSCRUseRefForRestore 0
        if [winfo exists $restoreCategoryWidget] {
            destroy $restoreCategoryWidget
        }
        update
        return
    }
    if ![file exists $apsSCRSnapDir/$apsSCRSystem/$file] {
        setStatusText "Preferred file $apsSCRSnapDir/$apsSCRSystem/$file not found for $apsSCRSystem"
        set apsSCRUseRefForRestore 0
        set apsSCRRestoreFilename ""
        set apsSCRRestoreDescription ""
        set apsSCRUseRefForRestore 0
        if [winfo exists $restoreCategoryWidget] {
            destroy $restoreCategoryWidget
        }
        return 
    }
    update
    set file [file readlink $apsSCRSnapDir/$apsSCRSystem/$file]
   # if {$apsSCRSystem=="SR" && [string compare $item "User beam operator preferred"]==0} {
#	APSSCRGetUBOPLink
#	setStatusText "Current UBOP link is \"$apsSCRUbopLink\"."
#    }
    if [catch {file readlink $apsSCRSnapDir/$apsSCRSystem/[file tail $file]} file1] {
    } else {
	set file $file1
    }
    set filename0 [file tail $file]
    if [string compare $filename0 $apsSCRRestoreFilename]==0 {
        return 
    }
    set apsSCRRestoreFilename $filename0
    if {[file exists $apsSCRSnapDir/$apsSCRSystem/collapsed]} {
        set apsSCRRestoreDescription [join [APSGetSDDSColumn -page 0 -column SnapshotDescription \
                                              -fileName $apsSCRSnapDir/$apsSCRSystem/collapsed/c[file tail [file rootname $file]]]]
    } else {
        set apsSCRRestoreDescription [join [APSGetSDDSColumn -page 0 -column SnapshotDescription \
                                              -fileName $apsSCRSnapDir/$apsSCRSystem/c[file tail [file rootname $file]]]]
    }
    setSnapname $apsSCRRestoreFilename $apsSCRRestoreDescription
    
}

proc installPreferredSnapshot {} {
    global apsSCRRestoreFilename apsSCRSnapDir apsSCRAccelManagerAccount apsSCRSystem apsSCRRestoreDescription apsNetworkDomain
    global apsSCRUseAtticForRestore
#    if {[string compare $apsNetworkDomain "accel.ntw0rk"] != 0 && [string compare $apsNetworkDomain "aps4.anl.gov"] != 0} {
#	setStatusText "You can not install SCR reference on non-acceleration stations, please login to helios workstation."
#	return
#    }
    if $apsSCRUseAtticForRestore {
        setStatusText "Attic snapshots are not allowed to be installed into preferred file."
        return
    }
    set snapDir $apsSCRSnapDir/$apsSCRSystem

    if ![string length $apsSCRRestoreFilename] {
        setStatusText "No snapshot chosen."
        return
    }
    if [string first "Routine save" $apsSCRRestoreDescription]!=-1 {
        setStatusText "Can't make routine save into preferred file."
        return
    }

    if [catch {APSSCRGetPreferredChoiceList -system $apsSCRSystem} choiceList] {
        setStatusText "No preferred choices for $apsSCRSystem"
        return
    }
    if [llength $choiceList]!=1 {
        if {[catch \
               {APSListSelectDialog [APSUniqueName .] -itemList $choiceList -name "Preferred Choices" \
                  -contextHelp \
                  "Select the preferred name assignment by double-clicking on an item from the list."} choice] || \
              ![string length $choice]} {
            setStatusText "No preferred file chosen."
            return
        }
    } else {
        set choice Reference
    }

    setStatusText "Working on installation of preferred/reference file..."
    if [catch {APSSCRInstallPreferredFile -system $apsSCRSystem -choice $choice \
                 -filename $apsSCRRestoreFilename} result] {
        setStatusText "$result"
        return
    }
    setStatusText "Preferred/reference file installed."
}

set noConnections 0
proc makeRestoreFrame {widget args} {
    global apsSCRSystem apsSCRConfigStartYear apsSCRConfigStartMonth apsSCRConfigStartDay
    global apsSCRConfigEndYear apsSCRConfigEndMonth apsSCRConfigEndDay searchString 
    global modeWidget safetyMode restoreFrame noConnections

    set parent ""
    set noPack 0
    set label ""
    APSStrictParseArguments {parent noPack label}

    if [winfo exists $parent$widget] {
        pack $parent$widget -expand 1 -fill both
        return
    }

    APSFrame $widget -parent $parent -label $label -relief flat \
      -packOption "-side top -expand 1 -fill both"
    set w $parent$widget.frame
    set restoreFrame $w
    APSFrame .search -parent $w -label "Snapshot search" -relief ridge -labelFont "TkHeadingFont"
    APSSCRDateTimeEntryWidget .date -parent $w.search.frame -relief flat

    set w1 $w.search.frame
    APSFrame .search1 -parent $w1 -relief flat 
    APSLabeledEntry .descript -parent $w1.search1.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." \
      -packOption "-side left -anchor n"

    ttk::frame $w1.search1.frame.buttons
    ttk::frame $w1.search1.frame.buttons.top
    ttk::frame $w1.search1.frame.buttons.bottom
    pack $w1.search1.frame.buttons -side left
    pack $w1.search1.frame.buttons.top -anchor w
    pack $w1.search1.frame.buttons.bottom -anchor w
 
    APSButton .search -parent $w1.search1.frame.buttons.top -text "SEARCH" -size small \
      -command "runAPSListSCRMatch -parent $w -callback restoreSnapnameCallback -routine 0 \
-listWidgetVariable restoreSnapListWidget -categoryWidgetVariable restoreCategoryWidget -atticWidgetVar apsSCRRestoreAtticWidget" \
      -contextHelp \
      "Performs a search based on the beamline selection, the date search string, and the description search string." \
      -packOption "-side left" 
    APSButton .searchattic -parent $w1.search1.frame.buttons.top -text "SEARCH ATTIC" -size small \
      -command "runAPSListSCRMatch -parent $w -callback restoreSnapnameCallback -routine 0 \
-listWidgetVariable restoreSnapListWidget -categoryWidgetVariable restoreCategoryWidget -atticWidgetVar apsSCRRestoreAtticWidget -attic 1" \
      -contextHelp \
      "Performs a search based on the beamline selection, the date search string, and the description search string." \
      -packOption "-side left" 
    APSButton .rsearch -parent $w1.search1.frame.buttons.bottom -text "ROUTINE-SAVE SEARCH" -size small \
      -command "runAPSListSCRMatch -parent $w -callback restoreSnapnameCallback -routine 1 \
-listWidgetVariable restoreSnapListWidget -categoryWidgetVariable restoreCategoryWidget -atticWidgetVar apsSCRRestoreAtticWidget" \
      -contextHelp \
      "Performs a search based on the beamline selection, the date search string, and the description search string." \
      -packOption "-side left" 
    
    APSButton .shiftsearch -parent $w1.search1.frame.buttons.bottom -text "SHIFT-SAVE SEARCH" -size small \
      -command "runAPSListSCRMatch -parent $w -callback restoreSnapnameCallback -routine 1 -shift 1 -listWidgetVariable restoreSnapListWidget -categoryWidgetVariable restoreCategoryWidget -atticWidgetVar apsSCRRestoreAtticWidget" \
      -contextHelp \
      "Performs a search based on the beamline selection, the date search string, and the description search string." \
      -packOption "-side left" 
    
    makeRestoreFilenameDisplayFrame .filename -parent $w 
    set w $w.filename.frame
    
    APSFrameGrid .fg1 -parent $w -yList {top bot} 
    set w $w.fg1
     if !$safetyMode {
        APSButton .restore -parent $w.bot -text "RESTORE" -command restoreSnapshot -size small \
          -contextHelp "Restores the selected process variables.  If LOCK is on, this button will not function.\
 If PROTECTION is on, then protected variables (if any) in the file will not be restored."
        APSButton .ramp -parent $w.bot -text "RAMP" -command "restoreSnapshot -doRamp 1" -size small \
          -contextHelp "Ramps to the new values for the selected process variables.  If LOCK is on, this button will not function.\
 If PROTECTION is on, then protected variables (if any) in the file will not be restored."
        APSButton .abortRamp -parent $w.bot -text "ABORT RAMP" -command "set apsRampToSnapshotAbort 1" -size small \
          -contextHelp "Aborts ramping to a snapshot."
        APSButton .remove -parent $w.bot -text "REMOVE" -command removeSnapshot -size small \
          -contextHelp "Removes snapshot to a waste-basket area.  Use this feature carefully, as you won't be able to get the snapshot back without assistance."
    }
    APSButton .review -parent $w.bot -text "REVIEW" -command reviewSnapshot -size small \
      -contextHelp "Shows a text listing of the data that the RESTORE command will restore if pressed."
    APSButton .reviewall -parent $w.bot -text "REVIEW ALL" -command "reviewSnapshot -all 1" -size small \
      -contextHelp "Shows a text listing of all of the data in the snapshot that is selected by the filters, regardless of read-only, manual, or protected modes."
    APSButton .customreview -parent $w.bot -text "CUSTOM REVIEW..." -command "reviewSnapshot -custom 1" \
      -size small \
      -contextHelp "Brings up a menu of custom review choices for this system."
    
   

    APSButton .export -parent $w.bot -text EXPORT -command exportSnapshot -size small \
      -contextHelp "Allows exporting a snapshot to a private file.  The data exported is whatever is selected by the category and subcategory buttons and the filter file, if any.  The protection, show-read-only, and show-manual-only settings are ignored."
    if !$safetyMode {
        APSButton .alter -parent $w.bot -text ALTER -command alterSnapshot -size small \
          -contextHelp "Allows altering data in a snapshot file."
        APSButton .edit -parent $w.bot -text EDIT -command EditSnapshot -size small \
          -contextHelp "Allows editing data in a snapshot file."  
        APSButton .refer -parent $w.bot -text "INSTALL" -command installPreferredSnapshot -size small \
          -contextHelp "Installs snapshot as one of the preferred snapshots (e.g., reference snapshot) for a system.  Some installations can only be done by the reponsible accelerator manager, but others may be done by operators as well."
    }
    APSButton .clear -parent $w.bot -text "CLEAR" -command clearRestoreFilename -size small \
      -contextHelp "Clears the file choice."
    APSButton .attic -parent $w.bot -text "MOVE TO/FROM ATTIC" -command moveSnapshot -size small \
      -contextHelp "Moves the file to or from the attic."

    if !$safetyMode {
        APSCheckButtonFrame .lock -parent $w.top -label "" -packOption "-side left" \
          -buttonList LOCK -variableList restoreLock -orientation horizontal -relief flat \
          -contextHelp "Controls the restore lock. The RESTORE button will \
not function if the LOCK is on.  This control reverts to the ON state after 20 seconds." 
        bind $w.top.lock.frame.button1 <Button> {after 10000 {set restoreLock 1}}
    }
    APSCheckButtonFrame .protect -parent $w.top -label "" -packOption "-side left" \
      -buttonList PROTECT -variableList protectionLock -orientation horizontal -relief flat \
      -commandList EnforceProtectionSecurity \
      -contextHelp "Controls the protection lock.  Process variables classified as protected,\
if any exist, will not be restored if this control is on. This control reverts to the ON \
state after 20 seconds."
    
    bind $w.top.protect.frame.button1 <Button> {after 10000 {set protectionLock 1}}
    
    APSCheckButtonFrame .showReadOnly -parent $w.top -label "" -packOption "-side left" \
      -buttonList {"SHOW READ-ONLY"} -variableList showReadOnly -orientation horizontal -relief flat \
      -contextHelp "Selects whether process variables classified as read-only, if any exist,\
are shown or not during review.  Read-only data is never sent back to the IOCs, \
but can be reviewed if you enable this button."

    APSCheckButtonFrame .manualFieldsOnly -parent $w.top -label "" -packOption "-side left" \
      -buttonList {"MANUAL FIELDS ONLY"} -variableList manualFieldsOnly -orientation horizontal -relief flat \
      -contextHelp "Selects whether only manual restore fields are reviewed/restored.  Not functional \
if manual classification data is not present in the file."

    APSCheckButtonFrame .invert -parent $w.top -label "" -packOption "-side left" \
      -buttonList {"INVERT SELECTIONS"} \
      -variableList invertChoices -orientation horizontal -relief flat \
      -contextHelp "Allows inversion of the selections made with the pv name filter and beamline/category buttons."
    APSCheckButtonFrame .no -parent $w.top -label "" -packOption "-side left" \
      -buttonList {"_NoConnection_"} -orientation horizontal -variableList noConnections -relief flat \
      -contextHelp "Select to review the PVs whose value string are _NoConnection_"
    set modeWidget $w
}

proc runAPSListSCRMatch {args} {
    global apsSCRSystem apsSCRConfigStartYear apsSCRConfigStartMonth apsSCRConfigStartDay
    global apsSCRConfigEndYear apsSCRConfigEndMonth apsSCRConfigEndDay searchString apsSCRAtticDir
    global compareAtticWidget
    

    set parent ""
    set routine 0
    set shift 0
    set callback ""
    set listWidgetVariable ""
    set categoryWidgetVariable ""
    set attic 0
    set atticWidgetVar ""
    APSStrictParseArguments {parent routine shift callback listWidgetVariable\
                               categoryWidgetVariable attic atticWidgetVar}
    if {[string length $categoryWidgetVariable]} {
        global $categoryWidgetVariable
        if [winfo exists [subst \$$categoryWidgetVariable]] {
            destroy [subst \$$categoryWidgetVariable]
            set $categoryWidgetVariable ""
        }
    }
    set labelFont "TkHeadingFont"
    if $attic {
        set label ATTIC
    } else {
        set label NORMAL
    }

    APSListSCRMatch -machine $apsSCRSystem -height 8 -listOrder decreasing \
      -startYear $apsSCRConfigStartYear -startMonth $apsSCRConfigStartMonth \
      -startDay $apsSCRConfigStartDay \
      -endYear $apsSCRConfigEndYear -endMonth $apsSCRConfigEndMonth \
      -endDay $apsSCRConfigEndDay \
      -descriptionFragment $searchString -parent $parent \
      -attic $attic -label $label -labelFont $labelFont \
      -statusCallback setStatusText -callback $callback -routine $routine \
      -shift $shift
    if ![winfo exist $parent.apsSCRlist] {
        return
    }
    pack configure $parent.apsSCRlist -fill both 
    pack configure $parent.apsSCRlist.frame -fill both -expand true
    pack configure $parent.apsSCRlist.frame.list -fill both -expand true
    pack configure $parent.apsSCRlist.frame.list.lbox -fill both -expand true
    if [string length $listWidgetVariable] {
        global $listWidgetVariable
        set $listWidgetVariable $parent.apsSCRlist
    }
    if [string length $atticWidgetVar] {
        global $atticWidgetVar
        set $atticWidgetVar $attic
    }
}


proc APSSCRGetPreferredFilterList {args} {
    global apsSCRSystemList apsSCRRefChoiceDir
    set system ""
    APSStrictParseArguments {system}
    if [string length $system]==0 {
        return -code error "APSSCRGetPreferredFilterList: No system named"
    }
    if [lsearch -exact $apsSCRSystemList $system]==-1 {
        return -code error "APSSCRGetPreferredFilterList: invalid system $system"
    }
    set choiceFile $apsSCRRefChoiceDir/$system.sdds
    if ![file exists $choiceFile]  {
        set choiceList {"Operator Preferred" "System Manager Reference"}
        set filterList ""
    } else {
        if [catch {sdds open $choiceFile} fid] {
            return -code error "APSSCRGetPreferredFilterList: unable to open $choiceFile: $fid"
        }
        if [catch {sdds getColumn $fid ChoiceName} choiceList] {
            catch {sdds close $fid}
            return -code error "APSSCRGetPreferredFilterList: unable to read ChoiceName from $choiceFile: $choiceList"
        }
        if [catch {sdds getColumn $fid Filter} filterList] {
            set filterList ""
            foreach ele $choiceList {
                lappend filterList 1
            }
        }
        catch {sdds close $fid}
    }
    return $filterList
}




set apsSCRRestoreComboboxFrame ""
set apsSCRCompareComboboxFrame1 ""
set apsSCRCompareComboboxFrame2 ""
set apsSCRRestoreComboboxMenu ""
set apsSCRCompareComboboxMenu1 ""
set apsSCRCompareComboboxMenu2 ""
proc changeSystem {} {
    global apsSCRSystemDescription apsSCRSystem restoreRefListWidget compare1RefListWidget compare2RefListWidget apsSCRPendIOTime
    global apsSCRPreferredList apsSCRRestoreComboboxFrame apsSCRCompareComboboxFrame1 apsSCRCompareComboboxFrame2 apsSCRRestoreReference apsSCRPreferredFilenameList
    global apsSCRCompareComboboxMenu1 apsSCRCompareComboboxMenu2 apsSCRRestoreComboboxMenu apsSCRFilterList
    clearAll
    set apsSCRPreferredList [concat <FromSearchList> [APSSCRGetPreferredChoiceList -system $apsSCRSystem]]
    set apsSCRFilterList [concat <FromSearchList> [APSSCRGetPreferredFilterList -system $apsSCRSystem]]
    FindPreferredRefFilenameList 
    set apsSCRRestoreReference ""

    set height 0
    set unfiltered ""
    foreach item $apsSCRPreferredList filter $apsSCRFilterList {
        if {[string range $item 0 4] == "Attic"} {
            break
        }
        incr height
        set i [string last "MeV" $item]
        set ii [string last "Mev" $item]
        if {$ii > $i} {set i $ii}
        if {$i != -1} {
            lappend preferred([string trim [string range $item [expr $i - 4] [expr $i - 1]]]) $item
        }
        if {$filter == 0} {
            lappend unfiltered $item
        }
    }
    if {[info exists preferred]} {
        foreach energy [lsort [array names preferred]] {
            foreach item $unfiltered {
                lappend preferred($energy) $item
            }
        }
    }
    if {$height < 5} {
        set height
    }

    if [winfo exist $apsSCRRestoreComboboxFrame] {
        $apsSCRRestoreComboboxFrame configure -values $apsSCRPreferredList -height $height

        if {(![winfo exist $apsSCRRestoreComboboxMenu]) && ([info exists preferred])} {
            set apsSCRRestoreComboboxMenu [string range $apsSCRRestoreComboboxFrame 0 end-3].energy
            ttk::menubutton $apsSCRRestoreComboboxMenu -text MeV -underline 0 -menu $apsSCRRestoreComboboxMenu.m
            menu $apsSCRRestoreComboboxMenu.m -tearoff 0
            grid $apsSCRRestoreComboboxMenu -row 0 -column 2 -sticky ew
        } elseif {[winfo exist $apsSCRRestoreComboboxMenu]} {
            $apsSCRRestoreComboboxMenu configure -text MeV
        }
        if {[info exists preferred]} {
            $apsSCRRestoreComboboxMenu.m add command -label "" -command "energySelect -w $apsSCRRestoreComboboxMenu -cb $apsSCRRestoreComboboxFrame -energy 0"
            foreach energy [lsort [array names preferred]] {
                $apsSCRRestoreComboboxMenu.m add command -label "${energy}MeV" -command "energySelect -w $apsSCRRestoreComboboxMenu -cb $apsSCRRestoreComboboxFrame -energy $energy -preferred \"$preferred($energy)\""
            }
        } else {
            destroy $apsSCRRestoreComboboxMenu.m
            destroy $apsSCRRestoreComboboxMenu
        }
    }
    
    if [winfo exist $apsSCRCompareComboboxFrame1] {
        $apsSCRCompareComboboxFrame1 configure -values $apsSCRPreferredList -height $height

        if {(![winfo exist $apsSCRCompareComboboxMenu1]) && ([info exists preferred])} {
            set apsSCRCompareComboboxMenu1 [string range $apsSCRCompareComboboxFrame1 0 end-3].energy
            ttk::menubutton $apsSCRCompareComboboxMenu1 -text MeV -underline 0 -menu $apsSCRCompareComboboxMenu1.m
            menu $apsSCRCompareComboboxMenu1.m -tearoff 0
            grid $apsSCRCompareComboboxMenu1 -row 0 -column 2 -sticky ew
        } elseif {[winfo exist $apsSCRCompareComboboxMenu1]} {
            $apsSCRCompareComboboxMenu1 configure -text MeV
        }
        if {[info exists preferred]} {
            $apsSCRCompareComboboxMenu1.m add command -label "" -command "energySelect -w $apsSCRCompareComboboxMenu1 -cb $apsSCRCompareComboboxFrame1 -energy 0"
            foreach energy [lsort [array names preferred]] {
                $apsSCRCompareComboboxMenu1.m add command -label "${energy}MeV" -command "energySelect -w $apsSCRCompareComboboxMenu1 -cb $apsSCRCompareComboboxFrame1 -energy $energy -preferred \"$preferred($energy)\""
            }
        } else {
            destroy $apsSCRCompareComboboxMenu1.m
            destroy $apsSCRCompareComboboxMenu1
        }
    }
    if [winfo exist $apsSCRCompareComboboxFrame2] {
        $apsSCRCompareComboboxFrame2 configure -values $apsSCRPreferredList -height $height

        if {(![winfo exist $apsSCRCompareComboboxMenu2]) && ([info exists preferred])} {
            set apsSCRCompareComboboxMenu2 [string range $apsSCRCompareComboboxFrame2 0 end-3].energy
            ttk::menubutton $apsSCRCompareComboboxMenu2 -text MeV -underline 0 -menu $apsSCRCompareComboboxMenu2.m
            menu $apsSCRCompareComboboxMenu2.m -tearoff 0
            grid $apsSCRCompareComboboxMenu2 -row 0 -column 2 -sticky ew
        } elseif {[winfo exist $apsSCRCompareComboboxMenu2]} {
            $apsSCRCompareComboboxMenu2 configure -text MeV
        }
        if {[info exists preferred]} {
            $apsSCRCompareComboboxMenu2.m add command -label "" -command "energySelect -w $apsSCRCompareComboboxMenu2 -cb $apsSCRCompareComboboxFrame2 -energy 0"
            foreach energy [lsort [array names preferred]] {
                $apsSCRCompareComboboxMenu2.m add command -label "${energy}MeV" -command "energySelect -w $apsSCRCompareComboboxMenu2 -cb $apsSCRCompareComboboxFrame2 -energy $energy -preferred \"$preferred($energy)\""
            }
        } else {
            destroy $apsSCRCompareComboboxMenu2.m
            destroy $apsSCRCompareComboboxMenu2
        }
    }
    #  setStatusText "delete reference"
    set refList [concat <FromSearchList> [APSSCRGetPreferredChoiceList -system $apsSCRSystem]]
    foreach widget [list $restoreRefListWidget $compare1RefListWidget $compare2RefListWidget] {
        if [winfo exists $widget] {
            $widget delete 0 end
            eval $widget insert 0 $refList
        }
    }

    global apsSCRGroupMembers apsSCRGroupMenuOrder
    foreach group $apsSCRGroupMenuOrder {
        foreach member $apsSCRGroupMembers($group) {
            global mrsSave$member
            set mrsSave$member 0
        }
    }
    set mrsSave$apsSCRSystem 1

    setStatusText "System changed to $apsSCRSystemDescription($apsSCRSystem)"
    if ![info exist apsSCRPendIOTime($apsSCRSystem)] {
        set apsSCRPendIOTime($apsSCRSystem) 80
    }
   # APSSCRGetUBOPLink
}

proc EnforceProtectionSecurity {args} {
    global protectionLock apsSCRSystem
    if [lsearch -exact [list LPL LINAC LTS] $apsSCRSystem]!=-1 {
        global env
        if [lsearch -exact [list erwin linac pasky flood gfystro borland nda par lemery soliday yinesun lberkland] $env(USER)]==-1 {
            set protectionLock 1
            APSAlertBox [APSUniqueName .] \
              -errorMessage "You do not have permission to release protection." \
              -type error 
        }
    }
}

proc RunControInfo {args} {
    set machine ""
    set statusCallback ""
    APSStrictParseArguments {machine statusCallback}
    if {$machine=="XrayTranslation"} {
        set sys XrayTr
    } else {
        set sys $machine
    } 
    exec medm -x -attach -macro RCPV=${sys}:ScrRunControlRC ./sr/psApp/APSRunControlSingle.adl &
}

proc ChangePendIOTime {args} {
    global apsSCRPendIOTime apsSCRSystem changeIOTime
    if ![info exist apsSCRPendIOTime($apsSCRSystem)] {
        set apsSCRPendIOTime($apsSCRSystem) 80 
    }  
    set oldValue [set apsSCRPendIOTime($apsSCRSystem)]
    
    set w [APSUniqueName .]
    set changeIOTime 0
    APSDialogBox $w -name "View/Change $apsSCRSystem pend IO Time" \
        -contextHelp "view/change CA pend IO Time." \
        -okCommand "set changeIOTime 1" \
        -cancelCommand "set changeIOTime 0"
    APSLabeledEntry .time -parent $w.userFrame -label "$apsSCRSystem Pend IO Time (s):" \
        -width 30 -textVariable apsSCRPendIOTime($apsSCRSystem)
    tkwait window $w
    if !$changeIOTime {
        set  apsSCRPendIOTime($apsSCRSystem) $oldValue
    }
   
}

proc moveSnapshot {} {
    global apsSCRRestoreFilename apsSCRSnapDir errorInfo apsSCRAtticDir
    global apsSCRRestoreDescription apsSCRUseRefForRestore apsSCRSystem apsSCRRestoreAtticWidget
    if {!$apsSCRRestoreAtticWidget} {
        set snapDir $apsSCRSnapDir/$apsSCRSystem
        if $apsSCRUseRefForRestore {
            setStatusText "You can't move a preferred file."
            return
        }
        if [catch {APSSCRGetPreferredDataLists -system $apsSCRSystem} dataLists] {
            setStatusText "$dataLists"
            return
        }
        set suffixList [lindex $dataLists 1]
        foreach suffix $suffixList {
            set refFile $snapDir/$apsSCRSystem-$suffix.gz
            if [file exists $refFile] {
                set refName [file tail [file readlink $refFile]]
                if [catch {file readlink $snapDir/$refName} refName1] {
                } else {
                    set refName [file tail $refName1]
                }
                if [string compare [file rootname $refName] [file rootname $apsSCRRestoreFilename]]==0 {
                    setStatusText "You can't move a preferred file ('$suffix')."
                    return
                }
            }
        }
    }

    if {[string length $apsSCRRestoreFilename] == 0} {
        setStatusText "No file to move"
        return
    }

    if {!$apsSCRRestoreAtticWidget} {
        set snapDir $apsSCRSnapDir/$apsSCRSystem
        set moveToDir $apsSCRAtticDir/$apsSCRSystem
        if ![file exist $moveToDir] {
            set oldDir [pwd]
            cd $apsSCRAtticDir
            if [catch {exec mkdir -p $apsSCRSystem} result] {
                cd $oldDir
                return -code error "Error in creating directory: $result"
            }
            cd $oldDir
        }
    } else {
        set snapDir $apsSCRAtticDir/$apsSCRSystem
        set moveToDir $apsSCRSnapDir/$apsSCRSystem
    }

    set snapshot $apsSCRRestoreFilename
    set filename0 [APSRemoveGzipExtension $snapshot]

    setStatusText "Moving $snapshot ...[file exists $snapDir/categ$filename0][file exists $snapDir/categories/categ$filename0]"

    if {[catch {file rename -force $snapDir/$snapshot $moveToDir}]} {
        setStatusText "Problem moving snapshot to $snapDir."
        APSAlertBox [APSUniqueName .] -errorMessage "$errorInfo"
        return 
    }
    if {[file exists $snapDir/categ$filename0]} {
        if {[catch {file rename -force $snapDir/categ$filename0 $moveToDir}]} {
            setStatusText "Problem moving snapshot to $moveToDir."
            APSAlertBox [APSUniqueName .] -errorMessage "$errorInfo"
            return 
        }
    }

    if {[file exists $snapDir/categories/categ$filename0]} {
        if {[catch {file rename -force $snapDir/categories/categ$filename0 $moveToDir/categories}]} {
            setStatusText "Problem moving snapshot to $moveToDir."
            APSAlertBox [APSUniqueName .] -errorMessage "$errorInfo"
            return 
        }
    }

    if {[file exists $snapDir/beam$filename0]} {
        if {[catch {file rename -force $snapDir/beam$filename0 $moveToDir}]} {
            setStatusText "Problem moving snapshot to $moveToDir."
            APSAlertBox [APSUniqueName .] -errorMessage "$errorInfo"
            return 
        }
    }

    if {[file exists $snapDir/beamlines/beam$filename0]} {
        if {[catch {file rename -force $snapDir/beamlines/beam$filename0 $moveToDir/beamlines}]} {
            setStatusText "Problem moving snapshot to $moveToDir."
            APSAlertBox [APSUniqueName .] -errorMessage "$errorInfo"
            return 
        }
    }

    if {[file exists $snapDir/c$filename0]} {
        if {[catch {file rename -force $snapDir/c$filename0 $moveToDir}]} {
            setStatusText "Problem moving snapshot to $moveToDir."
            APSAlertBox [APSUniqueName .] -errorMessage "$errorInfo"
            return 
        }
        if {$apsSCRRestoreAtticWidget} {
            if {[catch {exec sddsprocess -nowarn ${moveToDir}/c$filename0 \
                          "-reedit=column,SnapshotDescription,i/Restored save: /"} results]} {
                setStatusText "Problem moving snapshot to $moveToDir."
                APSAlertBox [APSUniqueName .] -errorMessage "$errorInfo"
                return 
            }
            file delete ${moveToDir}/c${filename0}~
        }
    }

    if {[file exists $snapDir/collapsed/c$filename0]} {
        if {[catch {file rename -force $snapDir/collapsed/c$filename0 $moveToDir/collapsed}]} {
            setStatusText "Problem moving snapshot to $moveToDir."
            APSAlertBox [APSUniqueName .] -errorMessage "$errorInfo"
            return 
        }
        if {$apsSCRRestoreAtticWidget} {
            if {[catch {exec sddsprocess -nowarn ${moveToDir}/collapsed/c$filename0 \
                          "-reedit=column,SnapshotDescription,i/Restored save: /"} results]} {
                setStatusText "Problem moving snapshot to $moveToDir."
                APSAlertBox [APSUniqueName .] -errorMessage "$errorInfo"
                return 
            }
            file delete ${moveToDir}/collapsed/c${filename0}~
        }
    }

    if {[file exists $snapDir/${filename0}.waveform.gz]} {
        if {[catch {file rename -force $snapDir/${filename0}.waveform.gz $moveToDir}]} {
            setStatusText "Problem moving snapshot to $moveToDir."
            APSAlertBox [APSUniqueName .] -errorMessage "$errorInfo"
            return 
        }
    }


    setStatusText "Moved $snapshot"

    if [catch {APSSCRLogAction -action move -file $snapshot} result] {
        setStatusText "$result"
    }
    clearRestoreFilename
    clearSearch
    APSClearSCRFilterFlags
    if {[winfo exists .userFrame.apsSCRlist]} {
        destroy .userFrame.apsSCRlist
        update
    }
}


set args $argv
set singleAccel ""
set saveCompareOnly 0
set restoreOnly 0
set topDirectory ""
set inhibitLogging 0
set safetyMode 0
set lab 0
set system ""
APSStrictParseArguments {singleAccel saveCompareOnly restoreOnly topDirectory inhibitLogging safetyMode lab system}


if {$saveCompareOnly && $restoreOnly} {
    puts stderr "Can't use saveCompareOnly and restoreOnly together."
    exit 1
}

if [catch {APSSCRDefineVariables -topDirectory $topDirectory -inhibitLogging $inhibitLogging} result] {
    puts stderr "Error define SCR variables: $result"
    exit 1
}

if $lab {
    set apsSCRSnapDir /home/oxygen/DIAG/oagData/SCR/snapshots
    set apsSCRRequestDir /home/oxygen/DIAG/oagData/SCR/requestFiles
}

set apsSCRSystem ""
if [string length $singleAccel] {
    APSSCRSetSystemList $singleAccel
} else {
    # allow a pre-selected system to be set in variable apsSCRPreSelectedSystem
    if {[info exists apsSCRPreSelectedSystem] && [string length $apsSCRPreSelectedSystem]} {
        set apsSCRSystem $apsSCRPreSelectedSystem
    }
}


# These variables are used in this file only unless otherwise noted.
# names of comparison files
set apsSCRCompareFile1 ""
set apsSCRCompareFile2 ""
set apsSCRCompareRef1 0  
set apsSCRCompareRef2 0
#if apsSCRCompareRef1 is 1 -- means compare file1 is a reference file
#if apsSCRCompareRef2 is 1 -- means comapre file2 is a reference file
# descriptions of comparison files
set apsSCRCompareDescrip1 ""
set apsSCRCompareDescrip2 ""
# flags: use preferred file for comparison?
set apsSCRUseRefForCompare1 0
set apsSCRUseRefForCompare2 0
set apsSCRCompareAtticWidget 0
# preferred file choices---valid only if flag is 1
set apsSCRCompareRefChoice1 ""
set apsSCRCompareRefChoice2 ""
# flag: put chosen file in first or second compare slot
set fillFirstCompareSlot 1

# name of restore file and description
set apsSCRRestoreFilename ""
set apsSCRRestoreDescription ""
# flag: use preferred file for restore?
set apsSCRUseRefForRestore 0
set apsSCRUseAtticForRestore 0
set apsSCRRestoreAtticWidget 0
# preferred file choice---valid only if flag is 1
set apsSCRRestoreRefChoice ""

# restore/review mode check-button variables
set restoreLock 1
set protectionLock 1
set showReadOnly 0
set manualFieldsOnly 0
set invertChoices 0

# year/month/day search limits (used by APSSCRDateTimeEntryWidget)
set apsSCRConfigStartYear ""
set apsSCRConfigStartMonth ""
set apsSCRConfigStartDay ""
set apsSCRConfigEndYear ""
set apsSCRConfigEndMonth ""
set apsSCRConfigEndDay ""
# description match string for snapshot search
set searchString "*"

# variables to store the names of widgets that need to be
# created/destroyed by variable procedures
# XSnapListWidget contains the name of the widget for the snapshot list for operation X
# XRefListWidget contains the name of the widget for the preferred choice list for operation
#    X
# restoreCategoryWidget contains the name of the system/category widget for restore/review
set restoreSnapListWidget ""
set compareSnapListWidget ""
set restoreCategoryWidget ""
set restoreRefListWidget ""
set compare1RefListWidget ""
set compare2RefListWidget ""
set compareAtticWidget 0
set restoreAtticWidget 0

set applicationName SaveCompareRestore
if $saveCompareOnly {
    set applicationName SaveCompare
} elseif $restoreOnly {
    set applicationName Restore
} elseif $safetyMode {
    set applicationName SaveCompareReview
}

if [string length $singleAccel] {
    APSApplication . -name $applicationName-$singleAccel \
      -overview "This utility allows saving and comparing values from $singleAccel snapshots."
} else {
    APSApplication . -name $applicationName \
      -overview {This utility allows saving and comparing values from machine snapshots.}
}


set restoreFrame ""

if [string length $system] {
    set apsSCRSystem $system
    changeSystem
}

APSScrolledStatus .status  -parent .userFrame  -textVariable statusText -width 125 \
  -height 8 -withButtons 1 -packOption "-fill x"

if {![string length $singleAccel]} {
    if [string length $apsSCRSystem]==0 {
        APSSCRSystemChoiceWidget .beamline -parent .userFrame -mode menu \
          -menuParent .menu -command changeSystem
        setStatusText "Use the System menu to choose a system and proceed with SCR."
        tkwait variable apsSCRSystem
    } else {
        APSSCRSystemChoiceWidget .beamline -parent .userFrame -mode menu \
          -menuParent .menu -command changeSystem
    }
} else {
    #set apsSCRPreferredList [concat <FromSearchList> [APSSCRGetPreferredChoiceList -system $apsSCRSystem]]
    #set apsSCRFilterList [concat <FromSearchList> [APSSCRGetPreferredFilterList -system $apsSCRSystem]]
    changeSystem
}

setStatusText "Working..."
if $safetyMode {
    set RRLabel "Review"
} else {
    set RRLabel "Restore/Review"
}


if {!$saveCompareOnly && !$restoreOnly} {
    # makeSCRChoices .scr -parent .userFrame
    set widgetList [APSTabFrame .choice -parent .userFrame -label "" \
                      -packOption "-side top -fill both -expand 1"\
                      -labelList [list Save Compare $RRLabel] -width 900 -height 630]
    
    makeSaveFrame .save -parent [lindex $widgetList 0] -noPack 0 -singleAccel $singleAccel
    makeCompareFrame .compare -parent [lindex $widgetList 1] 
    makeRestoreFrame .restore -parent [lindex $widgetList 2]
    #  set restoreFrame [lindex $widgetList 2].restore
    .userFrame.choice.frame.tn select 1
} elseif $saveCompareOnly {
    set widgetList [APSTabFrame .choice -parent .userFrame -label "" \
                      -labelList {Compare Save} -width 900 -height 500 ]
    makeCompareFrame .compare -parent [lindex $widgetList 0] -label ""
    makeSaveFrame .save -parent [lindex $widgetList 1] -label "" -singleAccel $singleAccel
    .userFrame.choice.frame.tn select 0
} else {
    makeRestoreFrame .restore -parent .userFrame -label ""
    #  set restoreFrame .userFrame.restore.frame
}

APSMenubarAddMenu .options -parent .menu -text Options
if {$apsUpgrade} {
    .menu.options.menu add check -label "Use sddspvasaverestore server" -variable apsSCRUseCASRServer
} else {
    .menu.options.menu add check -label "Use sddscasr server" -variable apsSCRUseCASRServer
}
.menu.options.menu add command -label "View/Change pend IO Time" -command "ChangePendIOTime"
set apsSCRUseCASRServer 0

setStatusText "Ready."

set SCRdebug 1

APSRenameExecToAPSBGExec

# Local Variables:
# mode: tcl
# End:
