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

set auto_path [linsert $auto_path 0  /usr/local/oag/apps/lib/$env(HOST_ARCH)]
set auto_path [linsert $auto_path 0  /usr/local/oag/lib_patch/$env(HOST_ARCH)]
APSDebugPath
set CVSRevisionAuthor "\$Author: shang $"
set args $argv
set system BTS
APSParseArguments {system}

APSApplication . -name ${system}LatticeSetup \
  -overview "Converts elegant lattice data to current setpoints for ${system} magnets."

proc setStatus {text} {
    APSSetVarAndUpdate status $text
}

setStatus "Working..."
APSScrolledStatus .status -parent .userFrame -textVariable status -height 10 -width 85
update

switch $system {
    BTS {
	set apsPSDeviceFile /home/helios/oagData/deviceConfig/booster/BTSOps.pvTable
	set apsMagnetsDir /home/helios/oagData/BTS/magnets/
	set mainDir $OAGGlobal(BTSLatticesDirectory)
    } 
    ptb {
	set apsPSDeviceFile /home/helios/oagData/deviceConfig/ptb/ptbOps.pvTable
	set apsMagnetsDir /home/helios/oagData/ptb/magnets
	set mainDir $OAGGlobal(PTBLatticesDirectory)
    }
}

APSLinkToDevicePVs -fileList $apsPSDeviceFile

proc PickLattice {args} {
    set sectionDir ""
    if [APSStrictParseArguments {sectionDir}] {
        return -code error "invalid arguments (PickLattice)"
    }
    
    global latticeDirectory latticeName runRootname system
   # puts $sectionDir
   # puts $latticeDirectory($sectionDir)
    
    if {![file exists $latticeDirectory($sectionDir)] \
          || ![file isdirectory $latticeDirectory($sectionDir)]} {
        return -code error "$latticeDirectory not found or not a directory"
    }
    set oldDir [pwd]
    cd $latticeDirectory($sectionDir)
    set rootnameList [lsort [glob -nocomplain *?*]]
    set validList ""
   # puts $rootnameList
    foreach rootname $rootnameList {
        if ![file isdirectory $rootname] {
            continue
        }
        if {![file exists $rootname/$runRootname($sectionDir).param] || \
              (![file exists $rootname/$runRootname($sectionDir).twi] && \
                 ![file exists $rootname/$runRootname($sectionDir).cen]) } {
            continue
        }
        lappend validList $rootname
    }

    if ![llength $validList] {
        APSSetVarAndUpdate status "No recognized/valid subdirectories found in $latticeDirectory($sectionDir)"
        cd $oldDir
        return
    }
    set latticeName($sectionDir) [APSChooseItemFromList -name "Lattice choice" \
                                    -itemList $validList -returnList $validList ]
    if ![string length $latticeName($sectionDir)] {
        cd $oldDir
        return
    }
    cd $oldDir
}

# Allows viewing lattice functions

proc CompareWithSCR {args} {
    set sectionDir ""
    APSParseArguments {sectionDir}
    
    global latticeDirectory latticeName runRootname setpointsOutputFile momentum system OAGGlobal
    
    set output  $setpointsOutputFile($sectionDir)
    if {![string length $output] || ![file exist $output] } {
        setStatus "setpoints file was not generated yet, quit."
        return
    }
    switch $system {
        BTS {
            set SCRsystem Booster
        }
        ptb {
            set SCRsystem LPL
        }
    }
    set snapDir  /home/helios/oagData/SCR/snapshots/$SCRsystem
    global dialogBoxResponse latticeSetup
    set dialogBoxResponse -1
    set latticeSetup(ShortFilename) ""
    APSDialogBox .scr  -cancelCommand "set dialogBoxResponse cancel" \
      -okCommand "set dialogBoxResponse ok"  -name "Select SCR"
    APSAddSCRDialog .file -parent .scr.userFrame -system $SCRsystem \
      -label "Choose SCR file for comparison" \
      -arrayName  latticeSetup \
      -defaultFile $latticeSetup(ShortFilename)
    tkwait window .scr
    if {$dialogBoxResponse=="cancel"} {
        setStatus "compare with SCR  was cancelled."
        return
    }
    if ![string length $latticeSetup(ShortFilename)] {
        setStatus "No SCR file chosen."
        return
    }
    set tmpRoot /tmp/[APSTmpString]
    if [catch {exec sddsprocess $output -pipe=out -scan=col,LatticeValue,ValueString,%lf \
                 | sddsconvert -pipe -retain=col,ControlName,LatticeValue,K1 \
                 | sddsxref -pipe $snapDir/$latticeSetup(ShortFilename) -nowarnings -match=ControlName -take=ValueString \
                 | sddsprocess -pipe -scan=col,SCRValue,ValueString,%lf \
                 | sddsprocess -pipe=in $tmpRoot.1 "-define=col,SCR-Lattice,SCRValue LatticeValue -" } result] {
        return -code error "Error comparing with SCR1: $result"
    }
    global outDir
    if [catch {exec sddsprocess $tmpRoot.1 $tmpRoot.2 -edit=col,DeviceName,ControlName,%/:CurrentAO//  } result] {
        return -code error "Error computing FSE: $result"
    }
    APSAddToTmpFileList -ID btslattice -fileList "$tmpRoot.1 tmpRoot.2"
    set magnetList [join [exec sdds2stream -col=DeviceName $tmpRoot.2]]
    eval global $magnetList
    if [catch { ComputeK1Values -rootname $runRootname($sectionDir) -momentum $momentum($sectionDir) -SCRValueFile $tmpRoot.2 -sectionDir $sectionDir } result] {
        return -code error "Error compute K1 values: $result"
    }
    if [catch {exec sddsprintout $tmpRoot.2 $tmpRoot.print \
                 "-title=compare with $latticeSetup(ShortFilename) SCR"  \
                 -col=ControlName,format=%22s \
                 -col=LatticeValue,format=%6.2f \
                 -col=SCRValue,format=%6.2f \
                 -col=SCR-Lattice,format=%6.2f \
             -col=LatticeK1,format=%8.4f -col=SCRK1,format=%8.4f } result] {
        return -code error  "Error comparing with SCR2: $result"
    }
    
    APSFileDisplayWindow [APSUniqueName .] -fileName $tmpRoot.print -deleteOnClose 1 -width 130 \
      -printCommand "enscript -r" -height 30
    APSAddToTmpFileList -ID btslattice -fileList "$tmpRoot.1 $tmpRoot.print"
    
   
    global SCRchoice
    set SCRchoice($sectionDir) $latticeSetup(ShortFilename)
    cd $outDir
    set rootname $latticeName($sectionDir)-$runRootname($sectionDir)-[file root $latticeSetup(ShortFilename)]
    
    set eleFile $outDir/$rootname.ele
    set magnets [exec sdds2stream -col=DeviceName $tmpRoot.2]
    set replList ""
    foreach magnet $magnets {
        lappend replList [set $magnet]
        lappend origList <$magnet>
    }
    if [catch {exec replaceText $OAGGlobal(BTSLatticesDirectory)/latticeSetupFiles/$runRootname($sectionDir).ele $eleFile \
                 -orig=[join $origList ,] \
                 -repl=[join $replList ,] } result] {
        return -code error "Error creating ele file: $result"
    }
   
    if [catch {exec elegant $eleFile > $outDir/$latticeName($sectionDir).log } result] {
       # return -code error "elegant error: $result"
    }
    
    exec cp  $latticeDirectory($sectionDir)/$latticeName($sectionDir)/$runRootname($sectionDir).twi $rootname.ref.twi
    
    exec sddsplot -pspace=0.10,0.8,0.25,0.95 -title= \
      -grap=line,vary -layout=1,3 -split=page  -group=nameindex  -sep=nameIndex \
      -col=s,betax  -col=s,betay -col=s,etax $rootname.ref.twi -leg=spec=$latticeName($sectionDir) \
      -col=s,betax -col=s,betay -col=s,etax  $rootname.twi -leg=spec=$SCRchoice($sectionDir),edit=%/.gz// \
      -col=s,Profile $rootname.mag -overlay=xmode=normal,yfactor=0.075 \
      -omnipresent &
    
}

set newLatticeDir ""
proc InstallSCRLattice {args} {
    set sectionDir ""
    APSParseArguments {sectionDir}
    global outDir latticeDirectory latticeName runRootname newLatticeName newLatticeDir mainDir SCRchoice OAGGlobal
    
    if ![info exist SCRchoice($sectionDir)] {
        setStatus "SCR file not chosen, please use compare lattice with SCR to compute the SCR lattice first."
        return
    }
    set rootname $latticeName($sectionDir)-$runRootname($sectionDir)-[file root $SCRchoice($sectionDir)]
    cd $outDir
   
    if {![file exist $rootname.lte]} {
        setStatus "$rootname.lte lattice file does not exist yet. Use \"Compare Lattice with SCR\" to generate it first."
        return
    }
    set newLatticeName $rootname
    if ![string length $newLatticeDir] {
        set newLatticeDir $outDir
    }
    APSDialogBox .newlattice -name "New Lattice Name" -cancelCommand "set newLatticeName \"\""
    APSLabeledEntry .dir -parent .newlattice.userFrame -label "Directory to save SCR lattice:" -width 70 \
        -textVariable newLatticeDir
    APSLabeledEntry .name -parent .newlattice.userFrame -label "name of SCR lattice:" -textVariable newLatticeName \
      -width 70

    tkwait window .newlattice 
    if ![string length $newLatticeName] {
        setStatus "new lattice name is not provided, creating new lattice is cancelled."
        return
    }
    cd $newLatticeDir
    
    if [file exist $newLatticeName/bts.lte] {
        if ![APSYesNoPopUp "lattice $newLatticeName already exist, do you want to overwrite it?"] {
            setStatus "$newLatticeName already exist!"
            return
        }
    } else {
        if ![file exist $newLatticeName] {
            exec mkdir $newLatticeName
            exec chmod a+rwx $newLatticeName
        }
    }
    cd $newLatticeName
    exec cp $OAGGlobal(BTSLatticesDirectory)/latticeSetupFiles/work/$runRootname($sectionDir).ele .
    exec cp $outDir/$rootname.lte $runRootname($sectionDir).lte
    if [catch {exec elegant $runRootname($sectionDir).ele > bts.log } result] {
        #return -code error "Error running elegant:$result"
    }
    exec cp $runRootname($sectionDir).twi $outDir/$runRootname($sectionDir)_new.twi
    
    cd $outDir
    exec sddsplot -title= -pspace=0.10,0.8,0.25,0.95 -grap=line,vary -layout=1,3 -split=page -group=nameindex  -sep=nameIndex \
      -col=s,betax -col=s,betay -col=s,etax $runRootname($sectionDir)_new.twi -leg=spec=new_lattice \
      -col=s,betax -col=s,betay -col=s,etax  $rootname.twi -leg=spec=saved_SCR_lattice  \
      -col=s,Profile $rootname.mag -overlay=xmode=normal,yfactor=0.075 \
      -omnipresent &
}


proc ViewLattice {args} {
    set sectionDir ""
    if [APSStrictParseArguments {sectionDir}] {
        return -code error "invalid arguments (ViewLattice)"
    }
    
    global latticeDirectory latticeName runRootname system

    if {![file exists $latticeDirectory($sectionDir)] || ![file isdirectory $latticeDirectory($sectionDir)]} {
        return -code error "$latticeDirectory($sectionDir) not found or not a directory"
    }
    if ![string length $latticeName($sectionDir)] {
        return -code error "No lattice chosen."
    }
    set rootname $latticeDirectory($sectionDir)/$latticeName($sectionDir)/$runRootname($sectionDir)
    if ![file exists $rootname.twi] {
        return -code error "Not found: $rootname.twi"
    }
    exec plotTwiss -fileRoot $rootname &
    setStatus "Plotting Twiss parameters..."

}

proc MakeFilename {args} {
    set sectionDir ""
    if [APSStrictParseArguments {sectionDir}] {
        return -code error "invalid arguments (MakeFilename)"
    }
    
    global latticeDirectory latticeName runRootname setpointsOutputFile system outDir
    if [string length $latticeName($sectionDir)]==0 {
        return -code error "Pick a lattice first"
    }
    set outDir [APSGoToDailyDirectory -subdirectory btsLatticeSetup]
   # set dir [APSGoToDailyDirectory]
    set setpointsOutputFile($sectionDir) [file join $outDir $latticeName($sectionDir).sdds]
}

proc GenerateSetpointFile1 {args} {
    set sectionDir ""
    set convertAll 0
    if [APSStrictParseArguments {sectionDir convertAll}] {
        return -code error "invalid arguments (GenerateSetpointFile1)"
    }
    
    global latticeDirectory latticeName runRootname setpointsOutputFile momentum system

    GenerateSetpointFile \
      -rootname $latticeDirectory($sectionDir)/$latticeName($sectionDir)/$runRootname($sectionDir) \
      -output $setpointsOutputFile($sectionDir) -momentum $momentum($sectionDir)
}

# Generates the magnet setpoints (currents) from the chosen lattice file

proc GenerateSetpointFile {args} {
    set rootname ""
    set output ""
    set momentum 7e3
    APSStrictParseArguments {rootname output momentum}

    global apsMagnetsDir apsPSDeviceFile system

    if ![string length $output] {
        return -code error "No output filename given"
    }
    if ![file exist $rootname.param] {
        return -code "not found: $rootname.param"
    }
    if [string compare [set outputDir [file dirname $output]] .]==0 {
        set outputDir [pwd]
    }

    # generate setpoint for each element by interpolating excitation curves
    # 1a. Extract quad elements from parameters file (data: K1, L)
    # 1b. Extract bend elements from parameters file (data: ANGLE)
    # 2.  Define the momentum
    # 3.  Compute the integrated strength (IS), summed over pieces if needed.
    # 4.  Multiply IS by BnLMultiplier, which accounts for strength differences between
    #     magnets using the same excitation curve.  If BnLMultiplier<1, then the
    #     magnet is weaker than the excitation curve says.
    # 5.  Interpolate the excitation curve to get the current.
    # 6.  Create a file that looks like an SCR save
    set tmpRoot /tmp/[APSTmpString]
    APSAddToTmpFileList -ID GenerateSetpointFile \
       -fileList "$tmpRoot.K1 $tmpRoot.ANGLE $tmpRoot.CN $tmpRoot.K1L $tmpRoot.GS"
    switch $system {
	BTS {
	    set extraOpt "-match=column,ElementName=*B2,!"
	}
	ptb {
	    set extraOpt ""
	}
    }
    set paramFile $rootname.param
    if [catch {exec sddsprocess $paramFile -pipe=out -match=col,ElementType=*QUAD* \
                 -match=col,ElementParameter=K1 \
                 | sddsconvert -pipe=in $tmpRoot.K1 \
                 -rename=column,ParameterValue=K1
        eval exec sddsprocess $paramFile -pipe=out -match=col,ElementType=*BEN* -nowarning \
                 $extraOpt  \
                 "-define=col,K1,ParameterValue" \
                 -match=column,ElementParameter=ANGLE \
                 | sddsconvert -pipe=in $tmpRoot.ANGLE \
                 -rename=column,ParameterValue=GeometricIntegratedStrength
        exec sddsprocess $apsPSDeviceFile $tmpRoot.CN -match=col,Operation=SetCurrent 
        exec sddsprocess $paramFile -pipe=out -match=col,ElementType=*QUAD* \
                 -match=col,ElementParameter=L \
                 | sddsconvert -pipe -rename=col,ParameterValue=L \
                 | sddsxref -pipe $tmpRoot.K1 -take=K1 -match=ElementName \
                 | sddsprocess -pipe=in $tmpRoot.K1L \
                 "-define=column,GeometricIntegratedStrength,K1 L *"
        exec sddscombine -merge $tmpRoot.ANGLE $tmpRoot.K1L -pipe=out \
                 | tee $tmpRoot.GS \
                 | sddsprocess -pipe \
                 "-define=parameter,pCentral,$momentum mev /" \
                 "-define=column,IntegratedStrength,GeometricIntegratedStrength pCentral * 0.001704509390960 *,units=T*m^n" \
                 | sddsbreak -pipe -change=ElementName \
                 | sddsprocess -pipe -process=ElementName,first,%s -process=GeometricIntegratedStrength,sum,%s \
                 -process=IntegratedStrength,sum,%s \
                 | sddscollapse -pipe \
                 | sddsxref -pipe $apsMagnetsDir/crossReference.sdds -nowarning \
                 -match=ElementName -take=*  \
                 | sddsxref -pipe $tmpRoot.CN -match=DeviceName -take=ControlName \
                 | sddsprocess -pipe \
                 "-redefine=column,IntegratedStrength,IntegratedStrength BnLMultiplier / Sign *,units=T" \
                 -print=column,ExcitationFile,$apsMagnetsDir/%s.excitation,ElementName \
                 | sddsinterpset -pipe -order=1 \
                 -data=fileColumn=ExcitationFile,interpolate=Current,functionOf=IntegratedStrength,column=IntegratedStrength \
                 -belowRange=value=0 -aboveRange=extrapolate \
                 | sddsxref -pipe $tmpRoot.GS -match=ElementName -take=ElementType,K1 -fillIn -nowarnings \
                 | sddsxref -pipe $rootname.twi -match=ElementName -take=s \
                 | sddsprocess -pipe \
                 "-print=column,ValueString,%21.15e,Current" \
                 "-define=column,OverLimit,Current abs SupplyLimit > ? 1 : 0 \$ ,type=long" \
                 "-define=column,Momentum,pCentral mev *,units=MeV/c" \
                 | sddsconvert -pipe=in $output \
                 -retain=column,ElementName,DeviceName,ControlName,Current,ValueString,IntegratedStrength,pCentral,Momentum,GeometricIntegratedStrength,SupplyLimit,OverLimit,K1,ElementType,s} result] {
        APSDeleteTmpFileList -ID GenerateSetpointFile 
        return -code error "GenerateSetpointFile: $result"
    }
    
    APSDeleteTmpFileList -ID GenerateSetpointFile 
}

proc ComputeK1Values {args} {
    set rootname ""
    set momentum 7e3 
    set SCRValueFile ""
    set sectionDir ""
    APSStrictParseArguments {rootname  momentum SCRValueFile sectionDir}
    global apsMagnetsDir apsSDeviceFile outDir latticeDirectory latticeName
    
    set tmpRoot /tmp/[APSTmpString]
    cd $outDir
    set magnets [exec sdds2stream -col=DeviceName $SCRValueFile]
    set scrValues [exec sdds2stream -col=SCRValue $SCRValueFile]
    set paramFile $latticeDirectory($sectionDir)/$latticeName($sectionDir)/$rootname.param
    set pcentral [exec rpnl "$momentum mev /"]
    set K1List ""
    foreach magnet $magnets val $scrValues {
        global $magnet
        if {[regexp {BTS:BB} $magnet] || [regexp {BTS:AB} $magnet] || [regexp "BTS:BX" $magnet]} {
            #bending magnet ANGLE = geometricStrength
            if {$val==0} {
                setStatus "Warning: beam is sent to the BTS dump in the SCR file. SCR lattice after AB magnet is invalid"
            }
            if [file exist $apsMagnetsDir/${magnet}_average.excitation] {
                set excitationFile $apsMagnetsDir/${magnet}_average.excitation
            } elseif [file exist $apsMagnetsDir/${magnet}.excitation] {
                set excitationFile $apsMagnetsDir/${magnet}.excitation
            } else {
                return -code error "No excitation file found for $magnet"
            }
            if [catch {exec sddsinterp $excitationFile -col=Current,IntegratedStrength -atValues=$val -pipe=out \
                         | sdds2stream -pipe=in -col=IntegratedStrength } fieldStrength] {
                return -code error "Error getting field strength for $magnet: $fieldStrength"
            }
            if [catch {exec sddsprocess $apsMagnetsDir/crossReference.sdds -pipe=out -match=col,DeviceName=$magnet \
                         | sdds2stream -pipe -col=Sign } Sign] {
                return -code error "Error getting Sign for $magnet: $Sign"
            }
            set Sign [lindex $Sign 0]
            set integStrength $fieldStrength
            set geomStrength [expr $integStrength / $pcentral / 0.00170450939096 * $Sign]
            set K1 $geomStrength
        } else {
            if [catch {exec sddsinterp $apsMagnetsDir/${magnet}.excitation -col=Current,IntegratedStrength -atValues=$val -pipe=out \
                         | sdds2stream -pipe=in -col=IntegratedStrength } fieldStrength] {
                return -code error "Error getting field strength for $magnet: $fieldStrength"
            }
            if [catch {exec sddsprocess $apsMagnetsDir/crossReference.sdds -pipe=out -match=col,DeviceName=$magnet \
                         | sdds2stream -pipe -col=Sign,BnLMultiplier } valList] {
                return -code error "Error getting sign and BnLMultiplier for $magnet: $valList"
            }
            if [catch {exec sddsprocess $paramFile -pipe=out -match=col,ElementName=$magnet -match=col,ElementParameter=L \
                         | sdds2stream -pipe -col=ParameterValue } L] {
                return -code error "Error getting L value for $magnet: $L"
            }
            set Sign [lindex $valList 0]
            set BnLMultiplier [lindex $valList 1]
            set integStrength [expr $fieldStrength / $Sign * $BnLMultiplier]
            set geomStrength [expr $integStrength / $pcentral / 0.00170450939096]
            set K1 [expr $geomStrength / $L]
        }
        set $magnet $K1
        lappend K1List $K1
        setStatus "$magnet current=$val integ=$integStrength geo=$geomStrength  K1=$K1"
    }
    if [catch {exec sddsmakedataset $SCRValueFile.K1 -col=SCRK1,type=double -data=[join $K1List ,] 
        exec sddsconvert $SCRValueFile -pipe=out -rename=col,K1=LatticeK1 \
                 | sddsxref -pipe=in $SCRValueFile.K1 -take=SCRK1 $SCRValueFile.1 } result] {
        return -code error "Error generating SCR K1: $result"
    }
    exec mv $SCRValueFile.1 $SCRValueFile
}



# Reviews data in a previously generated setpoint file

proc ViewSetpointFile {args} {
    set sectionDir ""
    APSStrictParseArguments {sectionDir}
    
    if [APSStrictParseArguments {sectionDir}] {
        return -code error "invalid arguments (PickLattice)"
    }
    
    global latticeDirectory latticeName runRootname setpointsOutputFile
    set fileName $setpointsOutputFile($sectionDir)

    if {![string length $fileName] || ![file exists $fileName]} {
        return -code error "ViewSetpointFile: Give a valid filename ($fileName not found in [pwd])"
    }
    set tmpFile /tmp/[APSTmpString].printout
    if [catch {exec sddsprintout $fileName $tmpFile -column=ControlName,format=%22s \
                -column=ElementName,format=%10s \
                 -column=ValueString,format=%22s \
                 -column=SupplyLimit,label=PSLim,format=%6.2f \
                 -column=OverLimit \
                 -column=GeometricIntegratedStrength,format=%7.4f,label=GeoStrength \
                 -column=IntegratedStrength,format=%8.4f,label=Strength \
                 } result] {
        file delete -force $tmpFile 
        return -code error "ViewSetpointFile: $result"
    }
    APSFileDisplayWindow [APSUniqueName .] -fileName $tmpFile -deleteOnClose 1 -width 130 \
      -printCommand "enscript -r" -height 30
}

# Restore a setpoint file, either by conditioning or simply setting the currents.

proc ConfigureFromSnapshot1 {args} {
    set sectionDir ""
    set statusCallback APSNoOp
    set mode stop
    APSStrictParseArguments {sectionDir statusCallback mode}

    global setpointsOutputFile system
    APSConfigureFromSnapshot -fileName $setpointsOutputFile($sectionDir) \
      -statusCallback $statusCallback -mode $mode
}

set conditioningCycles 1
proc APSConfigureFromSnapshot {args} {
    global apsMagnetsDir apsPSDeviceFile apsRestoreSetpointFile system
    set fileName ""
    set statusCallback APSNoOp
    set mode condition
    APSStrictParseArguments {fileName statusCallback mode}

    if [string compare [set outDir [file dirname $fileName]] .]==0 {
        set outDir [pwd]
    }

    eval $statusCallback "Working..."
    if {![string length $fileName] || ![file exists $fileName]} {
        return -code error "RestoreSetpointFile: Give a valid filename"
    }
    set tmpRoot /tmp/[APSTmpString]

    if [catch {exec sdds2stream $fileName -column=DeviceName} deviceList] {
        return -code error "RestoreSetpointFile: $deviceList"
    }

    # Present a dialog to allow choosing which power supplies to restore or condition
    APSAddToTmpFileList -ID RestoreSetpointFile -fileList "$tmpRoot.snap $tmpRoot.std"

    set w [APSUniqueName .]
    set apsRestoreSetpointFile 1
    APSDialogBox $w -name "${system} PS Control Dialog" -okCommand "set apsRestoreSetpointFile 1" \
      -cancelCommand "set apsRestoreSetpointFile 0" 
   
    global apsRestoreSetpointFile selectedForRestore
    set apsRestoreSetpointFile -1
    foreach device $deviceList {
        set selectedForRestore($device) 1
        lappend varList selectedForRestore($device)
    }
    APSCheckButtonFrame .cb -parent $w.userFrame -label "Devices: " \
      -orientation horizontal -allNone 1 -limitPerRow 5 \
      -variableList $varList -buttonList $deviceList

    global apsConditioningCycles
    set apsConditioningCycles -1
    if [string compare $mode condition]==0 {
        # Also, allow choosing the number of conditioning cycles
        APSLabeledEntry .cycles -parent $w.userFrame -label "Conditioning Cycles (-1=use default)" \
          -textVariable apsConditioningCycles -width 10 \
          -contextHelp "Enter the number of conditioning cycles.  If -1, then default value is used."
    }
    update
    tkwait variable apsRestoreSetpointFile
    if !$apsRestoreSetpointFile {
        eval $statusCallback {"Operation cancelled."}
        return 
    }

    # filter the file to get just the elements of interest
    set matchOptCN ""
    set matchOptDN ""
    foreach device $deviceList {
        if ![set selectedForRestore($device)] continue
        if ![string length $matchOptCN] {
            set matchOptCN -match=column,ControlName=${device}*
            set matchOptDN -match=column,DeviceName=$device
        } else {
            set matchOptCN $matchOptCN,ControlName=${device}*,|
            set matchOptDN $matchOptDN,DeviceName=$device,|
        }
    }
    if ![string length $matchOptCN] {
        eval $statusCallback {"Choose one or more elements."}
        APSDeleteTmpFileList -ID RestoreSetpointFile
        return
    }
    
    # Make standardization file
    set cycles $apsConditioningCycles
    switch $system {
	BTS {
	    set root bts
	}
	ptb {
	    set root ptb
	}
    }
    if [catch {exec sddsxref $apsMagnetsDir/${root}.stdTemplate \
		   $fileName -match=ControlName=DeviceName -pipe=out -nowarning \
		   | sddsprocess -pipe=in $tmpRoot.std \
		   $matchOptDN \
		   "-redefine=column,NumCycles,$cycles 0 < ? NumCycles : $cycles $ ,type=long" \
		   "-redefine=column,Finish,Current,units=A"} result] {
            APSDeleteTmpFileList -ID RestoreSetpointFile
        return -code error "1: $result"
    }

    # Stop standardization 
    if [catch {exec standardize -stop $tmpRoot.std} result] {
        APSDeleteTmpFileList -ID RestoreSetpointFile
        return -code error "2: $result"
    }
    eval $statusCallback {"Conditioning halted."}

    if [string compare $mode stop]==0 {
        return
    }
    after 2000
    if [string compare $mode condition]==0 {
        if [catch {exec standardize $tmpRoot.std} result] {
            APSDeleteTmpFileList -ID RestoreSetpointFile
            return -code error "3: $result"
        }
        eval $statusCallback {"Conditioning initiated."}

        if [catch {exec sdds2stream $tmpRoot.std -column=ControlName} deviceList] {
            return -code error "4: $deviceList"
        }

        set conditioning 1
        # wait for conditioning to complete
        set timeStarted [clock format [clock seconds] -format %H:%M:%S]
        while {$conditioning} {
            APSWaitWithUpdate -waitSeconds 15 -updateInterval 1
            eval $statusCallback {"Conditioning (since $timeStarted)..."}
            if [catch {APSDevSend -deviceList $deviceList -operation QueryConditioning \
                         -group PSOps} result] {
                eval $statusCallback {"Problem checking conditioning status."}
                return -code error "5: $result"
            }
            set conditioning 0
            foreach item $result {
                if $item {
                    set conditioning 1
                }
            }
        }
    }

    # restore setpoints 
    eval $statusCallback {"Restoring values."}
    # Make a snapshot-like file with the setpoints, then restore it
    if [catch {exec sddsprocess $fileName $tmpRoot.snap \
                 $matchOptDN -nowarning \
                 -print=param,SnapType,Absolute \
                 -print=col,ControlType,pv \
                 -print=col,Lineage,- -define=col,Count,1,type=long
        exec sddscasr -restore $tmpRoot.snap} result] {
        APSDeleteTmpFileList -ID RestoreSetpointFile
        return -code error "11: $result"
    }
    eval $statusCallback {"Restore completed."}

    APSDeleteTmpFileList -ID RestoreSetpointFile
}

proc FillTabFrame {widget args} {
    set sectionDir ""
    set beamlineName ""
    APSStrictParseArguments {sectionDir beamlineName}
    global sectionDirList
    if [set sectionIndex [lsearch -exact $sectionDirList $sectionDir]]==-1 {
        return -code error "Unknown section directory: $sectionDir"
    }

    global latticeDirectory latticeName runRootname mainDir env system
    global setpointsOutputFile

    set latticeDirectory($sectionDir) $mainDir/$sectionDir/
    set latticeName($sectionDir) [file tail [file readlink $mainDir/${sectionDir}/default]]
    if {$system=="BTS"} {
	if ![string compare $sectionDir Booster2SR] {
	    set runRootname($sectionDir) bts
	} else {
	    set runRootname($sectionDir) btx
	}
    } else {
	set runRootname($sectionDir) ptb
    }
    APSFrame .lattice -parent ${widget} -label "Lattice Selection"
    set w ${widget}.lattice.frame

    APSLabeledEntry .dirname -parent $w -label "Lattice directory" \
        -textVariable latticeDirectory($sectionDir) -width 65 \
        -contextHelp "Directory where lattice subdirectories reside for this beam path."

    APSLabeledEntry .config -parent $w -label "Lattice name" \
      -textVariable latticeName($sectionDir) -width 65 \
      -contextHelp "Subdirectory of lattice directory containing runs for specific configurations."
    APSLabeledEntry .run -parent $w -label "Run rootname" \
      -textVariable runRootname($sectionDir) -width 65 \
      -contextHelp "Rootname for files within the lattice subdirectory that contain the information of interest.  There must be a .param file and a .twi file."
    APSButton .pickConfig -parent $w -text "Pick Lattice" \
      -command "PickLattice -sectionDir $sectionDir" -contextHelp \
      "Pick a lattice name from the lattice directory"
    APSButton .viewConfig -parent $w -text "View Lattice" \
      -command "ViewLattice -sectionDir $sectionDir" -contextHelp \
      "Displays plots of Twiss parameters and other information."

    APSFrame .gen -parent ${widget} -label "Setpoints File" 
    set w $widget.gen.frame
    APSLabeledEntry .spfile -parent $w -label "Filename" \
      -textVariable setpointsOutputFile($sectionDir) -width 75 \
      -contextHelp "Enter the name of the file to which you want the setpoints data written."
    APSLabeledEntry .momentum -parent $w -label "Momentum" \
      -textVariable momentum($sectionDir) -width 75 \
      -contextHelp "Enter the name of the file to which you want the setpoints data written."
    APSLabeledOutput .scrfile -parent $w -label "SCR File" \
      -textVariable SCRchoice($sectionDir) -width 75 \
      -contextHelp "SCR selection for comparison and lattice computation."
    APSFrame .bf1 -parent $w -relief flat
    set w1 $w.bf1.frame
    APSButton .makename -parent $w1 -text "Make filename" \
      -contextHelp "Creates a filename suitable for the lattice chosen.  Also creates the daily directory." \
      -command "MakeFilename -sectionDir $sectionDir"
    APSButton .gen -parent $w1 -text "Generate" \
      -contextHelp "Generate a file with power supply setpoints." \
      -command \
      "APSSetVarAndUpdate status Working...; \
          GenerateSetpointFile1 -sectionDir $sectionDir; \
          APSSetVarAndUpdate status Done."
    APSButton .view -parent $w1 -text "View" \
      -contextHelp "View the contents of the power supply setpoints file." \
      -command "ViewSetpointFile -sectionDir $sectionDir"
  
    APSButton .compare -parent $w1 -text "Compare With SCR" \
      -contextHelp "compare the generated file with selected SCR file." \
      -command "CompareWithSCR -sectionDir $sectionDir"
    
    #APSButton .compare1 -parent $w1 -text "Compare LatticeWith SCR" \
    \#  -contextHelp "compare the generated file with selected SCR file." \
     \# -command "CompareWithSCR -sectionDir $sectionDir -lattice 1"

    APSButton .install -parent $w1 -text "Save SCR lattice..." \
      -contextHelp "save the SCR lattice." \
      -command "InstallSCRLattice -sectionDir $sectionDir"
    
    global buttonList
    APSFrame .bf2 -parent $w -relief flat
    set w2 $w.bf2.frame
    APSButton .restore -parent $w2 -text "Restore..." \
      -contextHelp "Restore part or all of the power supply setpoints file." \
      -command "ConfigureFromSnapshot1 -mode restore -sectionDir $sectionDir \
                  -statusCallback setStatus"
    lappend buttonList $w2.restore.button
    APSButton .condition -parent $w2 -text "Condition..." \
      -contextHelp "Condition to part or all of the power supply setpoints file." \
      -command "ConfigureFromSnapshot1 -mode condition -sectionDir $sectionDir \
                  -statusCallback setStatus"
    lappend buttonList $w2.condition.button
    APSButton .stopCondition -parent $w2 -text "Stop conditioning..." \
      -contextHelp "Stop conditioning part or all of the power supplies listed in the setpoints file." \
      -command "ConfigureFromSnapshot1 -mode stop -sectionDir $sectionDir \
                  -statusCallback setStatus"
    lappend buttonList $w2.stopCondition.button
    checkbutton $w2.cb -relief flat \
        -command {
            global buttonList
            foreach button $buttonList {
                APSEnableDisableWidget $button -toggle 1 -button 1
            }
        }
    foreach button $buttonList {
        APSDisableButton $button 
    }
    pack $w2.cb -side right

    
}

switch $system {
    BTS {
	set sectionList [list Booster>SR Booster>Dump]
	set sectionDirList [list Booster2SR Booster2Dump]
    }
    ptb {
	set sectionList [list PTB>Booster]
	set sectionDirList [list PAR2Booster]
    }
}


foreach item $sectionDirList {
    lappend sectionCommandList "APSSetVarAndUpdate beamlineSection $item"
  #  puts $item
    set latticeDirectory($item) $mainDir/$item
  #  puts $latticeDirectory($item)
    set latticeName($item) default
    if {[string compare $system "BTS"]==0} {
	if ![string compare $item Booster2SR] {
	    set runRootname($item) bts
	} else {
	    set runRootname($item) btx
	}
    } else {
	set runRootname($item) ptb
    }
  #  puts stderr "latticeDirectory($item) $latticeDirectory($item)"
  #  puts stderr "latticeName($item) $latticeName($item)"
  #  puts stderr "runRootname($item) $runRootname($item)"

}
set beamlineSection [lindex $sectionList 0]

set tabFrameWidgetList [APSTabFrame .main -parent .userFrame -label "" \
    -labelList $sectionList -commandList $sectionCommandList \
    -width 800 -height 325]

foreach tabFrame $tabFrameWidgetList sectionDir $sectionDirList {
    FillTabFrame $tabFrame -sectionDir $sectionDir -beamlineName $sectionDir
    set setpointsOutputFile($sectionDir) ""
    switch $system {
	BTS {
	    set momentum($sectionDir) 7e3
	}
	ptb {
	    set momentum($sectionDir) 325
	}
    }
}


setStatus "Ready."
update
