

proc APSRemoveIDfromDefaultConfigsInfo {} {
    return "Removes ID xray bpms from orbit correction configurations while creating new numbered configurations, then does proper links to the default names.\n\nThe dialog box prompts for your initials, which will be appended to the automatically-generated descriptions, and for the sectors of ID bpms that need to be removed.\n\nThe recalculation of each of the matrices takes about 8 seconds.\n\nRemember that the pem only generates new configurations. The changes to orbit correction are not in effect until orbit controllaw is re-started with the new default configurations."
}

proc APSRemoveIDfromDefaultConfigs {args} {
    package require rpn
    # Select which ID to remove from a list of possible IDs.
    # Make union of ID lists in the four default files
    set email(addresses) "decker schroedr"
    #set  defaultList "defaultXR defaultXRDP"
    set  defaultList "default"
    set IDlist ""
    set baseDir /home/helios/oagData/sr/orbitControllaw/lattices/default
    foreach defaultType $defaultList {
        foreach plane {h v} {
            set config ${plane}.${defaultType}
            if ![file exists $baseDir/$config] {
                APSMpReturn error "APSRemoveIDfromDefaultConfigs1: Can't find configuration $config."
            }
            
            if [catch {exec sddsprocess $baseDir/${config}/config -pipe=out \
                         -match=para,NameType=MonitorNames \
                         -match=col,Name=S*ID* -filter=col,Flag,1,1 \
                         -scan=col,ID,Name,S%ld,type=long \
                         | sdds2stream -pipe=in -col=ID} IDlist1] {
                APSMpReturn error "APSRemoveIDfromDefaultConfigs2: $IDlist1]"
            }
            lappend IDlist [split $IDlist1]
        }
    }
    set IDlist [lsort -unique -integer  [join $IDlist]]
    set disabledSectorList ""
    for {set i 1} {$i<41} {incr i} {
        set ii [format %02d $i]
        global sectorsS${ii}Sector
        if {-1 == [lsearch $IDlist $i]} {
            lappend disabledSectorList $i
        }
    }
    #disabledSectorList are all the sectors not in IDlist

    # Dialog uses APSSectorButtons. The selection sets the value
    # of global variables of the type sectorsS<n>Sector so
    # there is no variables to pass or return.
    set reason "Steering occured."
    global env
    set initials $env(USER)
    set confirm 0
    APSMpStep init -promptDialog APSRemoveIDfromDefaultConfigsDialog \
      -vars {reason initials disabledSectorList confirm}

    # determine which sectors have been turned off by the user
    # in the init dialog box
    set turnedOffSectorList ""
    for {set i 1} {$i<41} {incr i} {
        set ii [format %02d $i]
        if {-1 < [lsearch $IDlist $i]} {
            # These global variables were used in the APSSectorButtons
            # of the init dialog box.
            if {[set sectorsS${ii}Sector]==0} {
                lappend turnedOffSectorList $i
            }
        }
    }

    # Here the list of sector to remove can be overridden by the
    # command line arguments.
    APSStrictParseArguments {turnedOffSectorList initials confirm reason}

    if {[llength $turnedOffSectorList]==0} {
        APSMpReturn error "APSRemoveIDfromDefaultConfigs3: No IDs selected for removal"
    }
    set ID $turnedOffSectorList
    foreach param "ID initials" {
        append paramString "$param=\"[set $param]\" "
    }
    catch {APSLogScriptAction \
             -procedure  APSRemoveIDfromDefaultConfigs \
             -action initialize \
             -state ok \
             -parameters $paramString \
         }
    set deviceList ""
    foreach sector $turnedOffSectorList {
        set ssector [format %02d $sector]
        lappend deviceList S${ssector}ID:P?
    }
    set Message ""
    set configList ""
    foreach defaultType $defaultList {
        foreach plane {h v} {
            set config ${plane}.${defaultType}

            APSMpStep RemoveIDFromParticularConfiguration \
              -desc "Removing IDs $turnedOffSectorList from $config"
            if ![file exists $baseDir/$config] {
                APSMpReturn error "APSRemoveIDfromDefaultConfigs4: Can't find configuration $config."
            }
            if [catch {file readlink $baseDir/$config} result] {
                APSMpReturn error "APSRemoveIDfromDefaultConfigs5: Configuration $config is not a link."
            }
            if [catch {exec sdds2stream $baseDir/$config/config -rows=bare} rows] {
                APSMpReturn error "APSRemoveIDfromDefaultConfigs6: $rows"
            }
            set rowsBefore($config) [rpn expr "[split $rows] +"]
            if [catch {APSRemoveDeviceFromDefaultConfig -config $config \
                         -deviceList $deviceList \
                         -initials $initials \
                         -confirm $confirm \
                         -controllawType dcOrbitCorrection \
                         -comment "Removed ID Xray bpms from sector(s) $turnedOffSectorList from $config. $initials" \
                     } result] {
                APSMpReturn error "APSRemoveIDfromDefaultConfigs7: $result"
            }
            if [catch {exec sdds2stream $baseDir/$config/config -rows=bare} rows] {
                APSMpReturn error "APSRemoveIDfromDefaultConfigs8: $rows"
            }
            set rowsAfter($config) [rpn expr "[split $rows] +"]
            if {$rowsBefore($config) == $rowsAfter($config)} {
                append Message "$config: No change.\n"
            } else {
                append Message "$config: Change occured.\n"
                lappend configList $config
            }
        }
    }
    if $confirm {
        APSInfoWindow .info -name "Results of update" \
          -width 50 -infoMessage $Message -modal 1
    }
    foreach address $email(addresses) {
        APSSendEMail -address $address -message "Removed ID xray bpms from sectors $turnedOffSectorList from [join $configList ,]" -subject "ID Xray bpms were removed"
    }
    APSMpReturn ok
}

proc APSRemoveIDfromDefaultConfigsDialog {frame} {
    global APSRemoveIDfromDefaultConfigs

    APSLabeledEntry .reason -parent $frame -label "Enter Reason:" \
      -textVariable APSRemoveIDfromDefaultConfigs(reason) \
      -width 80 \
      -contextHelp "Enter the reason for the removal here. Note that the automatically generated description may be good enough, e.g. \"Removed ID Xray bpms from sector(s) 6 from v.default.\". The reason entered will be inserted after the automatically generated description and before the initials."

    APSLabeledEntry .initials -parent $frame -label "Enter initials:" \
      -textVariable APSRemoveIDfromDefaultConfigs(initials) \
      -width 80 \
      -contextHelp "Enter your initials here. These will be placed at the end of the configuration descriptions."

    APSSRSectorButtons .sectorButtons -parent $frame \
      -rootname sectors \
      -orientation horizontal \
      -onePerSector 1 \
      -label "Please deselect IDs for removal from default orbit correction" \
      -description "Sector selections" \
      -itemList Sector -packOption "-side top" \
      -itemLabelList Sector 
    # it took me a while but I found the name of the button widgets.
    foreach sector $APSRemoveIDfromDefaultConfigs(disabledSectorList) {
        $frame.sectorButtons.frame.f1.sector$sector.item0 configure -state disable
    }

    APSRadioButtonFrame .confirm -parent $frame -orientation horizontal \
      -variable APSRemoveIDfromDefaultConfigs(confirm) \
      -label "Confirm all configurations?" \
      -buttonList {"Yes I enjoy clicking"  "No I need to move on with my life"} -valueList {1 0} \
      -contextHelp "Choose whether to confirm all default configuration calculations. A list of device changes are written to the pop-up window."


}

proc APSRemoveBMfromDefaultConfigsInfo {} {
    return "Removes BM:P2 xray bpms from the vertical default orbit correction configuration while creating new numbered configuration, then does proper links to the default names.\n\nThe dialog box prompts for your initials, which will be appended to the automatically-generated descriptions, and for the sectors of BM bpms that need to be removed.\n\nOnly BM:P2's are removed rather than both because the closing of the PS1 shutter is the most common fault with the BM bpms.\n\nThe recalculation of each of the matrices takes about 8 seconds.\n\nRemember that the pem only generates new configurations. The changes to orbit correction are not in effect until orbit controllaw is re-started with the new default configurations."
}

# this removes only BM:P2's rather than both because the
# closing of the PS1 shutter is the most common fault with the BM bpms.
proc APSRemoveBMfromDefaultConfigs {args} {
    package require rpn
    # Select which BM to remove from a list of possible BMs.
    # Make union of BM lists in the four default files
    #set  defaultList "default defaultXR defaultDP defaultXRDP"
    set  defaultList "default"
    set BMlist ""
    set baseDir /home/helios/oagData/sr/orbitControllaw/lattices/default
    set plane v
    foreach defaultType $defaultList {
        set config ${plane}.${defaultType}
        if ![file exists $baseDir/$config] {
            APSMpReturn error "APSRemoveBMfromDefaultConfigs: Can't find configuration $config."
        }
        # select only the BM:P2
        if [catch {exec sddsprocess $baseDir/${config}/config -pipe=out \
                     -noWarning \
                     -match=para,NameType=MonitorNames \
                     -match=col,Name=S*BM:P2 -filter=col,Flag,1,1 \
                     -scan=col,BM,Name,S%ld,type=long \
                     | sdds2stream -pipe=in -col=BM} BMlist1] {
            APSMpReturn error "APSRemoveBMfromDefaultConfigs: $BMlist1]"
        }
        lappend BMlist [split $BMlist1]
    }
    set BMlist [lsort -unique -integer  [join $BMlist]]
    set disabledSectorList ""
    for {set i 1} {$i<41} {incr i} {
        set ii [format %02d $i]
        global sectorsS${ii}Sector
        if {-1 == [lsearch $BMlist $i]} {
            lappend disabledSectorList $i
        }
    }

    # Dialog uses APSSectorButtons. The selection sets the value
    # of global variables of the type sectorsS<n>Sector so
    # there is no variables to pass or return.
    set reason "PS1 shutter closed."
    global env
    set initials $env(USER)
    set confirm 0
    APSMpStep init -promptDialog APSRemoveBMfromDefaultConfigsDialog \
      -vars {reason initials disabledSectorList confirm}
    
    # determine which sectors have been turned off by the user
    # in the init dialog box
    set turnedOffSectorList ""
    for {set i 1} {$i<41} {incr i} {
        set ii [format %02d $i]
        if {-1 < [lsearch $BMlist $i]} {
            # These global variables were used in the APSSectorButtons
            # of the init dialog box.
            if {[set sectorsS${ii}Sector]==0} {
                lappend turnedOffSectorList $i
            }
        }
    }

    # Here the list of sector to remove can be overridden by the
    # command line arguments.
    APSStrictParseArguments {reason initials turnedOffSectorList confirm}

    if {[llength $turnedOffSectorList]==0} {
        APSMpReturn error "APSRemoveBMfromDefaultConfigs: No BMs selected for removal"
    }
    set BM $turnedOffSectorList
    foreach param "BM initials" {
        append paramString "$param=\"[set $param]\" "
    }
    catch {APSLogScriptAction \
             -procedure  APSRemoveBMfromDefaultConfigs \
             -action initialize \
             -state ok \
             -parameters $paramString \
         }
    set deviceList ""
    foreach sector $turnedOffSectorList {
        # only remove the P2's not the P1's
        set ssector [format %02d $sector]
        lappend deviceList S${ssector}BM:P2
    }
    set Message ""
    set plane v
    foreach defaultType $defaultList {
        set config ${plane}.${defaultType}
        APSMpStep RemoveBMFromParticularConfiguration \
          -desc "Removing BMs $turnedOffSectorList from $config"
        if ![file exists $baseDir/$config] {
            APSMpReturn error "APSRemoveBMfromDefaultConfigs: Can't find configuration $config."
        }
        if [catch {file readlink $baseDir/$config} result] {
            APSMpReturn error "APSRemoveBMfromDefaultConfigs: Configuration $config is not a link."
        }
        if [catch {exec sdds2stream $baseDir/$config/config -rows=bare \
                 } rows] {
            APSMpReturn error "APSRemoveBMfromDefaultConfigs: $rows"
        }
        set rowsBefore($config) [rpn expr "[split $rows] +"]
        if [catch {APSRemoveDeviceFromDefaultConfig -config $config \
                     -deviceList $deviceList \
                     -initials $initials \
                     -confirm $confirm \
                     -controllawType dcOrbitCorrection \
                     -comment "Removed BM Xray bpms from sector(s) $turnedOffSectorList from $config. $initials" \
                 } result] {
            APSMpReturn error "APSRemoveBMfromDefaultConfigs: $result"
        }
        if [catch {exec sdds2stream $baseDir/$config/config -rows=bare \
                 } rows] {
            APSMpReturn error "APSRemoveBMfromDefaultConfigs: $rows"
        }
        set rowsAfter($config) [rpn expr "[split $rows] +"]
        if {$rowsBefore($config) == $rowsAfter($config)} {
            append Message "$config: No change.\n"
        } else {
            append Message "$config: Change occured.\n"
        }
    }
    APSInfoWindow .info -name "Results of updates" \
      -width 50 -infoMessage $Message -modal 1

    APSMpReturn ok
}

proc APSRemoveBMfromDefaultConfigsDialog {frame} {
    global APSRemoveBMfromDefaultConfigs

    APSLabeledEntry .reason -parent $frame -label "Enter Reason:" \
      -textVariable APSRemoveBMfromDefaultConfigs(reason) \
      -width 80 \
      -contextHelp "Enter the reason for the removal here. Note that the automatically generated description may be good enough, e.g. \"Removed BM Xray bpms from sector(s) 6 from v.default.\". The reason entered will be inserted after the automatically generated description and before the initials."

    APSLabeledEntry .initials -parent $frame -label "Enter initials:" \
      -textVariable APSRemoveBMfromDefaultConfigs(initials) \
      -width 80 \
      -contextHelp "Enter your initials here. These will be placed at the end of the configuration descriptions."

    APSSRSectorButtons .sectorButtons -parent $frame \
      -rootname sectors \
      -orientation horizontal \
      -onePerSector 1 \
      -label "Please deselect BM:P2s for removal from default orbit correction" \
      -description "Sector selections" \
      -itemList Sector -packOption "-side top" \
      -itemLabelList Sector 
    # it took me a while but I found the name of the button widgets.
    foreach sector $APSRemoveBMfromDefaultConfigs(disabledSectorList) {
        $frame.sectorButtons.frame.f1.sector$sector.item0 configure -state disable
    }

    APSRadioButtonFrame .confirm -parent $frame -orientation horizontal \
      -variable APSRemoveBMfromDefaultConfigs(confirm) \
      -label "Confirm all configurations?" \
      -buttonList {"Yes, I enjoy clicking"  "No, let's get this over with fast"} -valueList {1 0} \
      -contextHelp "Choose whether to confirm all default configuration calculations. A list of device changes are written to the pop-up window."


}

proc APSRemoveDeviceFromDefaultConfigsInfo {} {
    return "Removes bpms or correctors from the default orbit correction configurations while creating new numbered configurations, then does proper links to the default names.\n\nThe dialog box prompts for your initials, which will be appended to the automatically-generated descriptions, and for a list of devices (a combination of bpms or correctors) that need to be removed.\n\nThe recalculation of each of the matrices takes about 8 seconds."
}

proc APSRemoveDeviceFromDefaultConfigs {args} {
    package require rpn
    #set  defaultList "default defaultDP defaultXR defaultXRDP"
    set  defaultList "default"
    set baseDir /home/helios/oagData/sr/orbitControllaw/lattices/default
    set reason "Bad devices"
    global env
    set initials $env(USER)
    set deviceList ""
    set confirm 0
    set plane both
    APSStrictParseArguments {reason initials deviceList confirm plane}

    APSMpStep init -promptDialog APSRemoveDeviceFromDefaultConfigsDialog \
      -vars {reason initials deviceList confirm plane}
    
    foreach param "deviceList initials plane" {
        append paramString "$param=\"[set $param]\" "
    }
    catch {APSLogScriptAction \
             -procedure  APSRemoveDeviceFromDefaultConfigs \
             -action initialize \
             -state ok \
             -parameters $paramString \
         }
    if [string match $plane both] {
        set planeList {h v}
    } else {
        set planeList $plane
    }
    set changed 0
    foreach defaultType $defaultList {
        foreach plane $planeList {
            set config ${plane}.${defaultType}

            APSMpStep "Removing $deviceList from $config"
            if ![file exists $baseDir/$config] {
                APSMpReturn error "APSRemoveDeviceFromDefaultConfig: Can't find configuration $config."
            }
            if [catch {file readlink $baseDir/$config} result] {
                APSMpReturn error "APSRemoveDeviceFromDefaultConfig: Configuration $config is not a link."
            }
            set prev$config [file tail $result]
            
            if [catch {APSRemoveDeviceFromDefaultConfig -config $config \
                         -deviceList $deviceList \
                         -initials $initials \
                         -confirm $confirm \
                         -controllawType dcOrbitCorrection \
                         -comment "Removed $deviceList from $config. $initials" \
                     } result] {
                APSMpReturn error "APSRemoveDeviceFromDefaultConfig: $result"
            }
            
            set new$config [file  tail [file readlink $baseDir/$config]]
            
            if [string compare [set prev$config] [set new$config]]==0 {
                append Message "$config: No change.\n" 
            } else {
                append Message "$config: Change occured.\n"
                set changed 1
            }
        }
    }
    # confirm==0 means express execution
    if {$changed} {
        APSInfoWindow .info -name "Results of updates" \
          -width 50 -infoMessage $Message -modal 1
        switch [APSMultipleChoice [APSUniqueName .] -modal 1 -question "Do you want to keep the changes or do you want to undo it?" -labelList {"Keep" "Undo"} -returnList {keep undo} -name "Undo?"] {
            keep {
                APSAlertBox .alert -type warning -name warning -beep once \
                  -errorMessage "${Message}\nIf you made changes to DC OC configurations, you need restart the orbit correction controllaw."
            }
            undo {
                APSMpStep "Restore previous DC OC default links."
                foreach defaultType $defaultList {
                    foreach plane $planeList {
                        set config ${plane}.${defaultType}
                        set oldLink [set prev${config}]
                        set newLink [set new${config}]
                        if [string compare $oldLink $newLink]!=0 {
                            APSMpStep "relink DCOC $config to $oldLink"
                            if [catch {APSMakeLink -local 1 -log 1 -permissions 00775 \
                                         -filename $baseDir/$oldLink \
                                         -linkname $baseDir/$config \
                                     } result] {
                                APSMpReturn error "APSAddDeviceToDefaultConfigs: $result"
                            }
                        }
                    }
                }
                APSAlertBox .done -type done -errorMessage "The default congfigs were restored -- no changes made to DC OC default configs."
            }
        }
    }
    
    APSMpReturn ok
}

proc APSRemoveBPMFromDefaultRFControllawConfigsInfo {} {
    return "Removes bpms from rf frequency controllaw h/v configurations while creating new numbered configurations, then does proper links to the default names.\n\nThe dialog box prompts for your initials, which will be appended to the automatically-generated descriptions, and for a list of devices (a combination of bpms or correctors) that need to be removed."
}

proc APSRemoveBPMFromDefaultRFControllawConfigsDialog {frame} {
    global APSRemoveBPMFromDefaultRFControllawConfigs
    
    APSLabeledEntry .reason -parent $frame -label "Enter Reason:" \
      -textVariable APSRemoveBPMFromDefaultRFControllawConfigs(reason) \
      -width 80 \
      -contextHelp "Enter the reason for the removal here. Note that the automatically generated description may be good enough, e.g. \"Removed S01A:P1 from h.default.\". The reason entered will be inserted after the automatically generated description and before the initials."

    APSLabeledEntry .initials -parent $frame -label "Enter initials:" \
      -textVariable APSRemoveBPMFromDefaultRFControllawConfigs(initials) \
      -width 80 \
      -contextHelp "Enter your initials here. These will be placed at the end of the configuration descriptions."
    
    APSLabeledEntry .badDevices -parent $frame -label "Enter bad bpms (Use format S01A:P1 ):" \
      -textVariable APSRemoveBPMFromDefaultRFControllawConfigs(deviceList) \
      -width 40 \
      -contextHelp "Enter a spaced-separated list of bad bpms. Use format S01A:P1. Wildcards are allowed."
    
    
    APSRadioButtonFrame .confirm -parent $frame -orientation horizontal \
      -variable APSRemoveBPMFromDefaultRFControllawConfigs(confirm) \
      -label "Confirm all configurations?" \
      -buttonList {"Yes, I enjoy clicking"  "No, let's get this over with fast"} -valueList {1 0} \
      -contextHelp "Choose whether to confirm all default configuration calculations. A list of device changes are written to the pop-up window."


}

proc APSRemoveBPMFromDefaultRFControllawConfigs {args} {
    package require rpn
    set baseDir /home/helios/oagData/sr/rfOrbitControllaw/lattices/default
    set reason "Bad devices"
    global env
    set initials $env(USER)
    set deviceList ""
    set confirm 0
    APSStrictParseArguments {reason initials deviceList confirm}
    
    APSMpStep init -promptDialog APSRemoveBPMFromDefaultRFControllawConfigsDialog \
      -vars {reason initials deviceList confirm}
    
    foreach param "deviceList initials" {
        append paramString "$param=\"[set $param]\" "
    }
    catch {APSLogScriptAction \
             -procedure  APSRemoveBPMFromDefaultRFControllawConfigs  \
             -action initialize \
             -state ok \
             -parameters $paramString \
         }

    # there is just the horizontal plane, not the vertical plane
    set plane h
    set config ${plane}.default
    APSMpStep RemoveBPMFromParticularConfiguration \
      -desc "Removing $deviceList from $config"
    if ![file exists $baseDir/$config] {
        APSMpReturn error "APSRemoveBPMFromDefaultRFControllawConfigs: Can't find configuration $config."
    }
    if [catch {file readlink $baseDir/$config} result] {
        APSMpReturn error "APSRemoveBPMFromDefaultRFControllawConfigs: Configuration $config is not a link."
    }
    set oldLink $result 
    if [catch {APSRemoveDeviceFromDefaultConfig -config $config \
                 -deviceList $deviceList \
                 -confirm $confirm \
                 -initials $initials \
                 -controllawType rfControllaw \
                 -comment "Removed $deviceList from $config. $initials" \
             } result] {
        APSMpReturn error "APSRemoveBPMFromDefaultRFControllawConfigs: $result"
    }
    set newLink [file readlink $baseDir/$config]
    if [string compare [file tail $oldLink] [file tail $newLink]]==0 {
        APSAlertBox .alert -type done -name Done \
          -errorMessage "No changes made to $config rf controllaw."
    } else {
        APSInfoWindow .info -name "Results of updates" \
          -width 50 -infoMessage "RF controllaw h.default changed." -modal 1
        switch [APSMultipleChoice [APSUniqueName .] -modal 1 -question "Changes made to $config rf controllaw, do you want to keep the changes or do you want to undo it?" -labelList {"Keep" "Undo"} -returnList {keep undo} -name "Undo?"] {
            keep { 
                #do nothing
                APSAlertBox .alert -type done -name Done \
                  -errorMessage "Changes made to $config rf controllaw."
            }
            undo {
                APSMpStep "Restore previous rf controllaw default links." 
                # there is only the horizontal plane, not the vertical  
                APSMpStep "Relink DC OC $config to $oldLink"
                if [catch {APSMakeLink -local 1 -log 1 -permissions 00775 \
                             -filename $baseDir/$oldLink \
                             -linkname $baseDir/$config \
                         } result] {
                    APSMpReturn error "APSRemoveBPMFromDefaultRFControllawConfigs: $result"
                }
                APSAlertBox .done -type done -name Done -errorMessage "$config rf controllaw was restored -- no changes made."
            }
        }
    }
    APSMpReturn ok
}

proc APSRemoveDeviceFromDefaultConfigsDialog {frame} {
    global APSRemoveDeviceFromDefaultConfigs
    
    
    APSLabeledEntry .reason -parent $frame -label "Enter Reason:" \
      -textVariable APSRemoveDeviceFromDefaultConfigs(reason) \
      -width 80 \
      -contextHelp "Enter the reason for the removal here. Note that the automatically generated description may be good enough, e.g. \"Removed S05B:P5 from v.default.\". The reason entered will be inserted after the automatically generated description and before the initials."

    APSLabeledEntry .initials -parent $frame -label "Enter initials:" \
      -textVariable APSRemoveDeviceFromDefaultConfigs(initials) \
      -width 40 \
      -contextHelp "Enter your initials here. These will be placed at the end of the configuration descriptions."
    APSRadioButtonFrame .plane -parent $frame -buttonList {H V Both} \
      -variable  APSRemoveDeviceFromDefaultConfigs(plane) -orientation horizontal \
      -valueList {h v both} -label "Removed bad devices from which plane?"
    APSLabeledEntry .badDevices -parent $frame -label "Enter bad devices (Use format S01A:P1 S01A:H1):" \
      -textVariable APSRemoveDeviceFromDefaultConfigs(deviceList) \
      -width 40 \
      -contextHelp "Enter a spaced-separated list of bad devices (bpms or correctors). Use format S01A:P1 S01A:H1. Wildcards are allowed."

    APSRadioButtonFrame .confirm -parent $frame -orientation horizontal \
      -variable APSRemoveDeviceFromDefaultConfigs(confirm) \
      -label "Confirm all configurations?" \
      -buttonList {"Yes I enjoy clicking"  "No I need to move on with my life"} -valueList {1 0} \
      -contextHelp "Choose whether to confirm all default configuration calculations. A list of device changes are written to the pop-up window."

}

proc APSRemoveDeviceFromDefaultConfigInfo {args} {
    return "Removes bpms or correctors from a default orbit correction configuration while creating a new numbered configuration and linking it to the default name. The name of the default configuation and a list of bpms must be specified."
}

proc APSRemoveDeviceFromDefaultConfig {args} {
    set deviceList ""
    set confirm 0
    set controllawType dcOrbitCorrection
    set config ""
    set initials ""
    APSStrictParseArguments {deviceList config confirm comment controllawType initials}
    global status env
    package require rpn
    set dcOrbitCorrection 0
    set rtfeedback 0
    set rfControllaw 0
    switch $controllawType {
        rtfeedback {
            set baseDir /home/helios/oagData/sr/rtfeedback/lattices/default
            set rtfeedback 1
        }
        dcOrbitCorrection {
            set baseDir /home/helios/oagData/sr/orbitControllaw/lattices/default
            set dcOrbitCorrection 1
        }
        rfControllaw {
            set baseDir /home/helios/oagData/sr/rfOrbitControllaw/lattices/default
            set rfControllaw 1
        }
        default {
            APSMpReturn error "Invalid controllaw type - $controllawType provided!"
        }
    }
    regexp {[hv]} $config plane 
    set configFile $baseDir/$config/config
    
    if ![llength $deviceList] {
        set status "nothing to be removed."
        APSMpReturn ok
    }
    set hcorrList ""
    set vcorrList ""
    set bpmList ""
    foreach device $deviceList {
        if [regexp {H} $device] {
            lappend hcorrList $device
        } elseif [regexp {V} $device] {
            lappend vcorrList $device
        } else {
            lappend bpmList $device
        }
    }
    set corrList [set ${plane}corrList]
    set removeList [concat $bpmList $corrList]
    set comment "Removed $removeList to $config. $initials"
    
    if ![llength $removeList] {
        set status "Nothing to be added to $config."
        APSMpReturn ok
    }
    set option Name=[lindex $removeList 0]
    foreach item [lrange $removeList 1 end] {
        lappend option Name=$item,|
    }
    set tmpRoot /tmp/[APSTmpString]
    APSAddToTmpFileList -ID removeDevice -fileList $tmpRoot.match
    
    if [catch {exec sddsprocess $configFile $tmpRoot.match \
                 "-match=col,[join $option ,]" -nowarnings} result] {
        APSMpReturn error "APSRemoveDeviceFromDefaultConfig1: $result"
    }
    set rowList [exec sdds2stream -rows=bar $tmpRoot.match]
    if [llength $rowList]>1 {
        set rows [rpn expr "[split $rowList] +"]
    } else {
        set rows $rowList
    }
    if !$rows {
        set status "The devices to be removed are not in $configFile, nothing need to be done."
        APSMpReturn ok
    }
    lappend option ! 
    set newConfig [APSNextGenerationedName \
                     -directory $baseDir \
                     -name ${plane}.[clock format [clock seconds] \
                                       -format %Y-%m%d].00 -newFile 1 -separator .]
    set newConfigFile $baseDir/$newConfig/config
    set time [clock seconds]
    set timeStr [exec date]
    set timeStamp [clock format $time -format %Y/%m%d@%H:%M:%S]
    if [catch {exec mkdir -p $baseDir/$newConfig \
             } result] {
        APSMpReturn error "APSRemoveDeviceFromDefaultConfig2: $result"
    }
    #exec setfacl -m mask:rwx $baseDir/$newConfig
    if [catch {exec sddsprocess $configFile $newConfigFile -nowarnings \
                 -match=col,[join $option ,] \
                 "-redefine=par,CreationTime,$time,type=long" \
                 "-redefine=par,Time,$time,type=long" \
                 "-reprint=par,CreationDate,$timeStr" \
                 "-reprint=par,TimeStamp,$timeStamp" \
                 "-reprint=par,User,$env(USER)" \
                 "-reprint=par,Host,$env(HOST)" \
                 "-reprint=para,Description,[APSMakeSafeQualifierString $comment]" \
             } result] {
        APSMpReturn error "APSRemoveDeviceFromDefaultConfig3: $result"
    }
    APSMpStep "Update description database"
    if [catch {APSUpdateConfigDescriptionDatabase -dataDir $baseDir -newConfig $newConfig} result] {
        APSMpReturn error "APSRemoveDeviceFromDefaultConfig4: $result"
    }
    if [catch {exec sddscollapse $newConfigFile $newConfigFile.collapsed \
             } result] {
        APSMpReturn error "APSRemoveDeviceFromDefaultConfig5: $result"
    }
    APSAddToTmpFileList -ID removeDevice -fileList $tmpRoot.diff
    if [catch {exec sddsselect $configFile $newConfigFile $tmpRoot.diff \
                 -match=Name -invert \
             } result] {
        APSMpReturn error "APSRemoveDeviceFromDefaultConfig6: $result"
    }
    if $confirm {
        if [catch {exec sddsprintout $tmpRoot.diff -col=Name -para=NameType \
                     "-title=Difference between the present and proposed $config.\nThe proposed $config has the following devices removed."  \
                     > $tmpRoot.print \
                 } result] {
            APSMpReturn error "APSRemoveDeviceFromDefaultConfig7: $result"
        }
        catch {open $tmpRoot.print r} fid
        catch {read $fid} dialogText
        close $fid 
        append dialogText "\n\nDo you want to install?"
        set answer [APSYesNoPopUp $dialogText]
        switch $answer {
            0 { 
                #no do not install, return
                APSMpReturn ok
            } 
            1 {
                #yes, continue install as default
            }
        }
    }

    APSMpStep GeneratingMatrices -desc "Generating matrices for $config"
    # generate the matrices
    set oldCorrs [exec sddsprocess $configFile -match=par,NameType=CorrectorNames -pipe=out | sdds2stream -rows=bar -pipe]
    set newCorrs [exec sddsprocess $newConfigFile -match=par,NameType=CorrectorNames -pipe=out | sdds2stream -pipe -rows=bar]
    set removed [expr $oldCorrs - $newCorrs]
    set tikhonov 0
    set SVNnumber 0
    set beta 0
    if [file exist $baseDir/$config/irm] {
        set singularValues [exec sdds2stream -par=NumberOfSingularValuesUsed -page=1 $baseDir/$config/irm]
	set pars [exec sddsquery -par $baseDir/$config/irm]
	if [lsearch -exact $pars "TikhonovFilterUsed"]>=0 {
	    set tikhonov [exec sdds2stream -par=TikhonovFilterUsed -page=1 $baseDir/$config/irm]
	    if $tikhonov {
		set SVNnumber [exec sdds2stream -par=TikhonovSVNNumber -page=1 $baseDir/$config/irm]
		set beta [exec sdds2stream -par=TikhonovBeta  -page=1 $baseDir/$config/irm]
	    }
	}
    } else {
        #set singularValues 320
        #singular values should be the number of correctors
        set singularValues $oldCorrs
    }
    if $removed {
        set new [expr $singularValues - $removed]
        set answer [APSMultipleChoice [APSUniqueName .] -modal 1 \
                      -question "The original number of singular values is $singularValues,\n do you want to reduce the number of singular values by $removed (number of removed correctors) or keep the original number?" \
                      -returnList [list $singularValues $new] \
                      -labelList [list keep-original reduce-by-$removed]]
        set singularValues $answer
    }
    if {$dcOrbitCorrection || $rtfeedback} {
        if [catch {APSSRGenerateOrbCorrFiles \
                     -rootname ${plane}config -generate 1 \
                     -configFile $baseDir/$newConfig/config \
                     -plane $plane \
                     -referenceMatrix $baseDir/refMatrices/${plane}.default \
                     -outputRoot $baseDir/$newConfig/ \
                     -singularValues $singularValues  \
                     -tikhonovFilter $tikhonov -tikhonovSVN $SVNnumber -tikhonovBeta $beta \
                 } result] {
            APSMpReturn error "APSRemoveDeviceFromDefaultConfig8: $result"
        }
        if $dcOrbitCorrection {
            # generate compensation matrices.
            set rtfbBaseDir /home/helios/oagData/sr/rtfeedback/lattices/default
            if [catch {APSSRGenerateOrbCorrFiles \
                         -rootname ${plane}config -generate 1 \
                         -configFile $baseDir/$newConfig/config \
                         -plane $plane \
                         -referenceMatrix $baseDir/refMatrices/${plane}.default \
                         -outputRoot $baseDir/$newConfig/ \
                         -tikhonovFilter $tikhonov -tikhonovSVN $SVNnumber -tikhonovBeta $beta \
                         -compensationConfigFile ${rtfbBaseDir}/${plane}.default/config \
                     } result] {
                APSMpReturn error "APSRemoveDeviceFromDefaultConfig9: $result"
            }
        }
    } elseif $rfControllaw {
        if [catch {APSSRFreqGenerateOrbCorrFiles -rootname ${plane}config -generate 1 \
                     -configFile $baseDir/$newConfig/config \
                     -plane $plane \
                     -referenceMatrix $baseDir/refMatrices/${plane}.default \
                     -outputRoot $baseDir/$newConfig/ \
                     -singularValues $singularValues  \
                     -tikhonovFilter $tikhonov -tikhonovSVN $SVNnumber -tikhonovBeta $beta \
                 } result] {
            APSMpReturn error "APSRemoveDeviceFromDefaultConfig10: $result"
        }
    }
    if [catch {exec sdds2stream $baseDir/$newConfig/irm -par=ConditionNumber} result] {
        APSMpReturn error "APSRemoveDeviceToDefaultConfig11: $result"
    }
    if $confirm {
        if ![APSYesNoPopUp "The condition number of new configuration matrix is $result; would you like to install it to $config?"] {
            APSMpReturn ok
        }
    }
    if [catch {file readlink $baseDir/$config} result] {
        APSMpReturn error "APSRemoveDeviceFromDefaultConfig12: Configuration $config is not a link."
    }
    
    APSMpStep GeneratingLinks -desc "Make new links for $config"
    if [catch {APSMakeLink -local 1 -log 1 -permissions 00775 \
                 -filename $baseDir/$newConfig \
                 -linkname $baseDir/$config \
             } result] {
        APSMpReturn error "APSRemoveDeviceFromDefaultConfig13: $result"
    }
    APSMpReturn ok
}

proc APSAddDeviceToDefaultConfigsInfo {} {
    return "Adds bpms or correctors to the eight default orbit correction configurations while creating new numbered configurations, then does proper links to the default names.\n\nThe dialog box prompts for your initials, which will be appended to the automatically-generated descriptions, and for a list of devices (a combination of bpms or correctors) that need to be added.\n\nThe recalculation of each of the matrices takes about 8 seconds."
}

proc APSAddDeviceToDefaultConfigsDialog {frame} {
    global APSAddDeviceToDefaultConfigs

    APSLabeledEntry .reason -parent $frame -label "Enter Reason:" \
      -textVariable APSAddDeviceToDefaultConfigs(reason) \
      -width 80 \
      -contextHelp "Enter the reason for the addition here. Note that the automatically generated description may be good enough, e.g. \"Added S05B:P5 to v.default.\". The reason entered will be inserted after the automatically generated description and before the initials."

    APSLabeledEntry .initials -parent $frame -label "Enter initials:" \
      -textVariable APSAddDeviceToDefaultConfigs(initials) \
      -width 40 \
      -contextHelp "Enter your initials here. These will be placed at the end of the configuration descriptions."

    APSRadioButtonFrame .plane1 -parent $frame -buttonList {H V Both} \
      -variable  APSAddDeviceToDefaultConfigs(plane) -orientation horizontal \
      -valueList {h v both} -label "Add devices to which plane?"
    
    set APSAddDeviceToDefaultConfigs(zeroXBPMsetpoint) 0
    APSRadioButtonFrame .plane -parent $frame -buttonList {Yes No} \
      -variable  APSAddDeviceToDefaultConfigs(zeroXBPMsetpoint) -orientation horizontal \
      -valueList {1 0} -label "Zero xray bpm setpoint?"
    APSLabeledEntry .addDevices -parent $frame -label "Enter devices (Use format S01A:P1 S01A:H1):" \
      -textVariable APSAddDeviceToDefaultConfigs(deviceList) \
      -width 40 \
      -contextHelp "Enter a spaced-separated list of devices (bpms or correctors) to be added. Use format S01A:P1 S01A:H1. Wildcards are not allowed."

    APSRadioButtonFrame .confirm -parent $frame -orientation horizontal \
      -variable APSAddDeviceToDefaultConfigs(confirm) \
      -label "Confirm all configurations?" \
      -buttonList {"Yes I enjoy clicking"  "No I need to move on with my life"} -valueList {1 0} \
      -contextHelp "Choose whether to confirm all default configuration calculations. A list of device changes are written to the pop-up window."

}

proc APSAddDeviceToDefaultConfigs {args} {
    package require rpn
    #set  defaultList "default defaultDP defaultXR defaultXRDP"
    set  defaultList "default"
    set baseDir /home/helios/oagData/sr/orbitControllaw/lattices/default
    set reason "add new devices"
    global env
    set initials $env(USER)
    set deviceList ""
    set confirm 0
    set plane both
    set zeroXBPMsetpoint 1
    APSStrictParseArguments {reason initials deviceList confirm plane zeroXBPMsetpoint}

    APSMpStep init -promptDialog APSAddDeviceToDefaultConfigsDialog \
      -vars {reason initials deviceList confirm plane}
    
    foreach param "deviceList initials" {
        append paramString "$param=\"[set $param]\" "
    }
    catch {APSLogScriptAction \
             -procedure  APSAddDeviceToDefaultConfigs \
             -action initialize \
             -state ok \
             -parameters $paramString \
         }
    if {$plane=="both"} {
        set planeList {h v}
    } else {
        set planeList $plane
    }
    set changed 0
    set xray 1
    foreach device $deviceList {
        if {![string match *ID* $device]} {
            set xray 0
            break
        }
    }
    if $xray {
        #set defaultList {defaultXR defaultXRDP}
    }
    foreach defaultType $defaultList {
        foreach plane $planeList {
            set config ${plane}.${defaultType}
            APSMpStep "adding devices to $config"
            if ![file exists $baseDir/$config] {
                APSMpReturn error "APSAddDeviceToDefaultConfigs: Can't find configuration $config."
            }
            if [catch {file readlink $baseDir/$config} result] {
                APSMpReturn error "APSAddDeviceToDefaultConfigs: Configuration $config is not a link."
            }
            set prev$config [file tail $result]
            
            if [catch {APSAddDeviceToDefaultConfig -config $config \
                         -deviceList $deviceList \
                         -confirm $confirm \
                         -initials $initials \
                     } result] {
                APSMpReturn error "APSAddDeviceToDefaultConfigs: $result"
            }
            set new$config [file tail [file readlink $baseDir/$config]]
            
            if [string compare [set prev$config] [set new$config]]==0 {
                append Message "OC $config: No change.\n"
            } else {
                append Message "OC $config: Change occured.\n"
                set changed 1
            }
        }
    }
    APSInfoWindow .info -name "Results of updates" \
      -width 50 -infoMessage $Message -modal 1
    if $changed {
        switch [APSMultipleChoice [APSUniqueName .] -modal 1 -question "Do you want to keep the changes or do you want to undo it?" -labelList {"Keep" "Undo"} -returnList {keep undo} -name "Undo?"] {
            keep {
                if {$xray && $zeroXBPMsetpoint} {
                    APSMpStep "zero xray bpm setpoint."
                    set putList ""
                    foreach device $deviceList {
                        if ![regexp "ID" $device] {
                            continue
                        }
                        foreach plane $planeList {
                            switch $plane {
                                h {
                                    set coord x
                                }
                                v {
                                    set coord y
                                }
                            }
                            lappend putList ${device}:${coord}:SetpointC=0
                        }
                    }
                    if [llength $putList] {
                        if [catch {exec cavput -list=[join $putList ,] -pend=10} result] {
                            return -code error "Error zero xray bpm setpoint for adding device pem: $result"
                        }
                    }
                }
                APSAlertBox .alert -type warning -name warning -beep once \
                  -errorMessage "If you made changes to DC OC configurations, you need restart the orbit correction controllaw."
            }
            undo {
                APSMpStep "Restore previous DC OC default links."
                foreach defaultType $defaultList {
                    foreach plane $planeList {
                        set config ${plane}.${defaultType}
                        set oldLink [set prev${config}]
                        set newLink [set new$config]
                        if [string compare $oldLink $newLink]!=0 {
                            APSMpStep "relink DCOC $config to $oldLink"
                            if [catch {APSMakeLink -local 1 -log 1 -permissions 00775 \
                                         -filename $baseDir/$oldLink \
                                         -linkname $baseDir/$config \
                                     } result] {
                                APSMpReturn error "APSAddDeviceToDefaultConfigs: $result"
                            }
                        }
                    }
                }
                APSAlertBox .alert -type warning -name warning -beep once \
                  -errorMessage "The OC DC default configs were restored. -- no changes made to them."
            }
        }
    }
    APSMpReturn ok
}

proc APSAddDeviceToDefaultConfigInfo {args} {
    return "Adds bpms or correctors to a default orbit correction configuration while creating a new numbered configuration and linking it to the default name. The name of the default configuation and a list of bpms must be specified."
}

proc APSAddDeviceToDefaultConfig {args} {
    set config ""
    set deviceList ""
    set confirm 0
    set comment ""
    set rtfeedback 0
    set initials ""
    APSStrictParseArguments {config deviceList confirm comment rtfeedback initials}
    global status env
    
    if $rtfeedback {
        set baseDir /home/helios/oagData/sr/rtfeedback/lattices/default
    } else {
        set baseDir /home/helios/oagData/sr/orbitControllaw/lattices/default
    }
    regexp {[hv]} $config plane 
    if $rtfeedback {
        set okCol OkForRTFeedback
    } elseif [regexp {DP} $config] {
        set okCol OkForFastDCOrbitCorrection
    } else {
        set okCol OkForDCOrbitCorrection
    }
    set Plane [string toupper $plane]
    set configFile $baseDir/$config/config
    
    set tmpRoot /tmp/[APSTmpString]
    if ![llength $deviceList] {
        #nothing to be added
        APSMpReturn ok
    }
    
    set hcorrList ""
    set vcorrList ""
    set bpmList ""
    foreach device $deviceList {
        if [regexp {H} $device] {
            lappend hcorrList $device
        } elseif [regexp {V} $device] {
            lappend vcorrList $device
        } else {
            lappend bpmList $device
        }
    }
    set corrList [set ${plane}corrList]
    set addList [concat $bpmList $corrList]
    set comment "Added $addList to $config. $initials"
    if ![llength $addList] {
        set status "Nothing to be added to $config."
        APSMpReturn ok
    }
    set option Name=[lindex $addList 0]
    foreach item [lrange $addList 1 end] {
        lappend option Name=$item,|
    }
    APSAddToTmpFileList -ID removeDevice -fileList $tmpRoot.match
    if [catch {exec sddsprocess $configFile $tmpRoot.match \
                 "-match=col,[join $option ,]" -nowarnings} result] {
        APSMpReturn error "APSRemoveDeviceFromDefaultConfig: $result"
    }
    set rowList [exec sdds2stream -rows=bar $tmpRoot.match]
    if [llength $rowList]>1 {
        set rows [rpn expr "[split $rowList] +"]
    } else {
        set rows $rowList
    }
    if {$rows==[llength $deviceList]} {
        set status "The devices to be added are already in $configFile, nothing need to be done."
        APSMpReturn ok
    }
    
    set bpmOption ""
    set corrOption ""
    
    if [llength $bpmList] {
        set bpmOption DeviceName=[lindex $bpmList 0]
        foreach item [lrange $bpmList 1 end] {
            lappend bpmOption DeviceName=$item,|
        }
    }
    if [llength $corrList] {
        set corrOption DeviceName=[lindex $corrList 0]
        foreach item [lrange $corrList 1 end] {
            lappend corrOption DeviceName=$item,|
        }
    }
    set corrStatusFile /home/helios/oagData/sr/[string toupper $plane]CorrectorStatus/config.sdds
    set bpmStatusFile /home/helios/oagData/sr/BPMStatus/config.sdds 
    
    APSAddToTmpFileList -ID 1 -fileList "$tmpRoot.corr.add $tmpRoot.bpm.add $tmpRoot.corr $tmpRoot.corr.add1 $tmpRoot.bpm $tmpRoot.bpm.add1 $tmpRoot.bpm.add2 $tmpRoot.corr.add2"
    set addCorrs 0
    if [llength $corrList] {
        if [catch {exec sddsprocess $corrStatusFile $tmpRoot.corr.add -nowarnings \
                     -filter=col,Nonexistent,0,0 \
                     -filter=col,$okCol,1,1 \
                     "-match=col,[join $corrOption ,]" } result] {
            APSMpReturn error "APSAddDeviceToDefaultConfig: $result"
        }
        set addCorrs [exec sdds2stream -rows=bar $tmpRoot.corr.add]
    }
    set addBPMs 0
    if [llength $bpmList] {
        if [catch {exec sddsprocess $bpmStatusFile $tmpRoot.bpm.add -nowarnings \
                     -filter=col,Nonexistent$Plane,0,0 \
                     -filter=col,${okCol}$Plane,1,1 \
                     "-match=col,[join $bpmOption ,]" } result] {
            APSMpReturn error "APSAddDeviceToDefaultConfig: $result"
        }
        set addBPMs [exec sdds2stream -rows=bar $tmpRoot.bpm.add]
    }
    if {!$addBPMs && !$addCorrs} {
        set status "Nothing to be added to $config."
        APSMpReturn ok
    }
    if [catch {exec sddsprocess $baseDir/$config/config \
                 -match=par,NameType=MonitorNames $tmpRoot.bpm
        exec sddsprocess $baseDir/$config/config \
                 -match=par,NameType=CorrectorNames $tmpRoot.corr } result] {
        APSMpReturn error "APSAddDeviceToDefaultConfig: $result"
    } 
    if $addBPMs {
        APSAddToTmpFileList -ID addDevice -fileList $tmpRoot.bpm.add1
        if [catch {exec sddsselect $tmpRoot.bpm.add $tmpRoot.bpm -invert \
                     -match=DeviceName=Name $tmpRoot.bpm.add1} result] {
            APSMpReturn error "APSAddDeviceToDefaultConfig: $result"
        }
        set addBPMs [exec sdds2stream -rows=bar $tmpRoot.bpm.add1]
        if $addBPMs {
            if [catch {exec sddsconvert $tmpRoot.bpm.add1 -pipe=out -retain=col,DeviceName,ElectronicsType \
                         | sddsconvert -pipe -rename=col,DeviceName=Name \
                         | sddsprocess -pipe=in $tmpRoot.bpm.add2 \
                         -define=col,Flag,1,type=short \
                         -define=col,Weight,1.0,type=double \
                         -define=col,Despike,1,type=long } result] {
                APSMpReturn error "APSAddDeviceToDefaultConfig: $result"
            }
            if [catch {exec sddscombine $tmpRoot.bpm $tmpRoot.bpm.add2 -merge -pipe=out \
                         | sddssort -pipe=in -unique -numericHigh -col=Name $tmpRoot.bpm} result] {
                APSMpReturn error "APSAddDeviceToDefaultConfig: $result"
            }
        }
    }
    if $addCorrs {
        APSAddToTmpFileList -ID addDevice -fileList $tmpRoot.corr.add1
        if [catch {exec sddsselect $tmpRoot.corr.add $tmpRoot.corr -match=DeviceName=Name \
                     -invert $tmpRoot.corr.add1} result] {
            APSMpReturn error "APSAddDeviceToDefaultConfig: $result"
        }
        set addCorrs [exec sdds2stream -rows=bar $tmpRoot.corr.add1]
        if $addCorrs {
            if [catch {exec sddsconvert $tmpRoot.corr.add1 -pipe=out -retain=col,DeviceName,ElectronicsType \
                         | sddsconvert -pipe -rename=col,DeviceName=Name \
                         | sddsprocess -pipe=in $tmpRoot.corr.add2 \
                         -print=col,ElectronicsType,\"\" \
                         -define=col,Flag,1,type=short \
                         -define=col,Weight,1.0,type=double \
                         -define=col,Despike,1,type=long } result] {
                APSMpReturn error "APSAddDeviceToDefaultConfig: $result"
            }
            if [catch {exec sddscombine $tmpRoot.corr $tmpRoot.corr.add2 -merge -pipe=out \
                         | sddssort -pipe=in -unique -numericHigh -col=Name $tmpRoot.corr} result] {
                APSMpReturn error "APSAddDeviceToDefaultConfig: $result"
            }
        }
    }
    if {!$addBPMs && !$addCorrs} {
        set status "Nothing to be added to $config."
        APSMpReturn ok
    }
    
    set newConfig [APSNextGenerationedName \
                     -directory $baseDir \
                     -name ${plane}.[clock format [clock seconds] \
                                       -format %Y-%m%d].00 -newFile 1 -separator .]
    set newConfigFile $baseDir/$newConfig/config
    if [catch {exec mkdir -p $baseDir/$newConfig \
             } result] {
        APSMpReturn error "APSAddDeviceToDefaultConfig: $result"
    }
    
    set time [clock seconds]
    set timeStr [exec date]
    set timeStamp [clock format $time -format %Y/%m%d@%H:%M:%S]
    
    if [catch {exec sddscombine $tmpRoot.bpm $tmpRoot.corr -pipe=out \
                 | sddsconvert -pipe -del=par,Filename,NumberCombined \
                 | sddsprocess -pipe=in $newConfigFile \
                 "-redefine=par,CreationTime,$time,type=long" \
                 "-redefine=par,Time,$time,type=long" \
                 "-reprint=par,CreationDate,$timeStr" \
                 "-reprint=par,TimeStamp,$timeStamp" \
                 "-reprint=par,User,$env(USER)" \
                 "-reprint=par,Host,$env(HOST)" \
                 "-reprint=par,Description,[APSMakeSafeQualifierString $comment]" } result] {
        APSMpReturn error "APSAddDeviceToDefaultConfig: $result"
    }
    APSMpStep "Update description database"
    if [catch {APSUpdateConfigDescriptionDatabase -dataDir $baseDir -newConfig $newConfig} result] {
        APSMpReturn error "APSAddDeviceFromDefaultConfig: $result"
    }
    if [catch {exec sddscollapse $newConfigFile $newConfigFile.collapsed \
             } result] {
        APSMpReturn error "APSAddDeviceToDefaultConfig: $result"
    }
    if $confirm {
        # check difference between configurations
        set tmpfile /tmp/[APSTmpString]
        if [catch {exec sddsselect $newConfigFile $configFile $tmpfile.diff \
                     -match=Name -invert \
                 } result] {
            APSMpReturn error "APSAddDeviceToDefaultConfig: $result"
        }
        if [catch {exec sdds2stream $tmpfile.diff -rows=bare \
                 } rows] {
            APSMpReturn error "APSAddDeviceToDefaultConfig: $rows"
        } 
        if [catch {exec sddsprintout $tmpfile.diff -col=Name -para=NameType \
                     "-title=Difference between the present and proposed $config.\nThe proposed $config has the following devices added."  \
                     > $tmpfile.print \
                 } result] {
            APSMpReturn error "APSAddDeviceToDefaultConfig: $result"
        }
        catch {open $tmpfile.print r} fid
        catch {read $fid} dialogText
        close $fid
        append dialogText "\n\nDo you want to install?"
        if ![APSYesNoPopUp $dialogText] {
            APSMpReturn ok
        }
    }
    APSMpStep GeneratingMatrices -desc "Generating matrices for $config"
    set oldCorrs [exec sddsprocess $configFile -match=par,NameType=CorrectorNames -pipe=out | sdds2stream -rows=bar -pipe]
    set newCorrs [exec sddsprocess $newConfigFile -match=par,NameType=CorrectorNames -pipe=out | sdds2stream -rows=bar -pipe]
    set addedCorrs [expr $newCorrs - $oldCorrs]
    # generate the matrices
    set tikhonov 0
    set SVNnumber 0
    set beta 0
    if [file exist $baseDir/$config/irm] {
        set singularValues [exec sdds2stream -par=NumberOfSingularValuesUsed -page=1 $baseDir/$config/irm]
	set pars [exec sddsquery -par $baseDir/$config/irm]
	if [lsearch -exact $pars "TikhonovFilterUsed"]>=0 {
	    set tikhonov [exec sdds2stream -par=TikhonovFilterUsed -page=1 $baseDir/$config/irm]
	    if $tikhonov {
		set SVNnumber [exec sdds2stream -par=TikhonovSVNNumber -page=1 $baseDir/$config/irm]
		set beta [exec sdds2stream -par=TikhonovBeta  -page=1 $baseDir/$config/irm]
		set alpha [exec sdds2stream -par=TikhonovAlpha -page=1 $baseDir/$config/irm]
	    }
	}
    } else {
        #set singularValues 320
        set singularValues $oldCorrs
    }
    if $addedCorrs {
        set new [expr $singularValues + $addedCorrs]
        set answer [APSMultipleChoice [APSUniqueName .] -modal 1 \
                      -question "The original number of singular values is $singularValues,\n do you want to added the number of singular values by $addedCorrs (number of added correctors) or keep the original number?" \
                      -returnList [list $singularValues $new] \
                      -labelList [list keep-original add-by-$addedCorrs]]
        set singularValues $answer
    }
    
    if [catch {APSSRGenerateOrbCorrFiles \
                 -rootname ${plane}config -generate 1 \
                 -configFile $baseDir/$newConfig/config \
                 -plane $plane \
                 -referenceMatrix $baseDir/refMatrices/${plane}.default \
                 -outputRoot $baseDir/$newConfig/ \
                 -singularValues $singularValues  \
                 -tikhonovFilter $tikhonov -tikhonovSVN $SVNnumber -tikhonovBeta $beta \
             } result] {
        APSMpReturn error "APSAddDeviceToDefaultConfig: $result"
    }
    if !$rtfeedback {
        # generate compensation matrices.
        set rtfbBaseDir /home/helios/oagData/sr/rtfeedback/lattices/default
        if [catch {APSSRGenerateOrbCorrFiles \
                     -rootname ${plane}config -generate 1 \
                     -configFile $baseDir/$newConfig/config \
                     -plane $plane \
                     -referenceMatrix $baseDir/refMatrices/${plane}.default \
                     -outputRoot $baseDir/$newConfig/ \
                     -compensationConfigFile ${rtfbBaseDir}/${plane}.default/config \
                 } result] {
            APSMpReturn error "APSAddDeviceToDefaultConfig: $result"
        }
        APSMpStep "Regenerate controllaw files."
        if [catch {APSGenerateControllawFiles -regenerateFiles 1 \
                     -dataDir $baseDir -directory $newConfig \
                     -PVSuffix msAve -BPMLimit 10 -XBPMLimit 0.5 \
                     -corrLimit 149.5 -rangeErrorLimit 10 \
                     -S35DCCTLimitH 15 -S35DCCTLimitV 15 \
                 } result] {
            APSMpReturn error "APSAddDeviceToDefaultConfig: $result"
        }
    }
    if [catch {exec sdds2stream $baseDir/$newConfig/irm -par=ConditionNumber} result] {
        APSMpReturn error "APSAddDeviceToDefaultConfig: $result"
    }
    if $confirm {
        if ![APSYesNoPopUp "The condition number of new configuration matrix is $result; would you like to install it to $config?"] {
            APSMpReturn ok
        }
    }
    if [catch {file readlink $baseDir/$config} result] {
        APSMpReturn error "APSAddDeviceToDefaultConfig: Configuration $config is not a link."
    }
    APSMpStep GeneratingLinks -desc "Make new links for $config"
    if [catch {APSMakeLink -local 1 -log 1 -permissions 00775 \
                 -filename $baseDir/$newConfig \
                 -linkname $baseDir/$config \
             } result] {
        APSMpReturn error "APSAddDeviceToDefaultConfig: $result"
    }
    APSMpReturn ok
}

#NO LONGER USED - It may be used to create a new FOFB version instead of RTFB
proc APSAddDeviceToDefaultRTFBConfigInfo {args} {
    return "Adds bpms or correctors to a default rtfb configuration while creating a new numbered configuration and linking it to the default name. The name of the default configuation and a list of bpms must be specified."
}

#This procedure has been placed in the attic
proc APSAddDeviceToDefaultRTFBConfigDialog {frame} {  
    global APSAddDeviceToDefaultRTFBConfig
    
    APSLabeledEntry .reason -parent $frame -label "Enter Reason:" \
      -textVariable APSAddDeviceToDefaultRTFBConfig(reason) \
      -width 80 \
      -contextHelp "Enter the reason for the removal here. Note that the automatically generated description may be good enough, e.g. \"Added S05B:P5\". The reason entered will be inserted after the automatically generated description and before the initials."
    
    APSLabeledEntry .initials -parent $frame -label "Enter initials:" \
      -textVariable APSAddDeviceToDefaultRTFBConfig(initials) \
      -width 40 \
      -contextHelp "Enter your initials here. These will be placed at the end of the configuration descriptions."

    APSRadioButtonFrame .plane -parent $frame -buttonList {H V Both} \
      -variable  APSAddDeviceToDefaultRTFBConfig(plane) -orientation horizontal \
      -valueList {h v both} -label "Add devices to which plane?"

    APSLabeledEntry .badDevices -parent $frame -label "Enter news devices to be added (Use format S01A:P1 S01A:H1):" \
      -textVariable APSAddDeviceToDefaultRTFBConfig(deviceList) \
      -width 40 \
      -contextHelp "Enter a spaced-separated list of new devices (bpms or correctors). Use format S01A:P1 S01A:H1. Wildcards are not allowed."
    
    APSRadioButtonFrame .confirm -parent $frame -orientation horizontal \
      -variable APSAddDeviceToDefaultRTFBConfig(confirm) \
      -label "Confirm all configurations?" \
      -buttonList {"Yes I enjoy clicking"  "No I need to move on with my life"} -valueList {1 0} \
      -contextHelp "Choose whether to confirm all default configuration calculations. A list of device changes are written to the pop-up window."
    
}

#This procedure has been placed in the attic
proc APSAddDeviceToDefaultRTFBConfig {args} {
    package require rpn
    set baseDir /home/helios/oagData/sr/rtfeedback/lattices/default
    set reason "add new devices"
    global env
    set initials $env(USER)
    set deviceList ""
    set confirm 0
    set plane both
    APSStrictParseArguments {reason initials deviceList confirm plane}
    APSMpStep init -promptDialog APSAddDeviceToDefaultRTFBConfigDialog \
      -vars {reason initials deviceList confirm plane}
    foreach param "deviceList initials" {
        append paramString "$param=\"[set $param]\" "
    }
    catch {APSLogScriptAction \
             -procedure  APSAddDeviceToDefaultRTFBConfig \
             -action initialize \
             -state ok \
             -parameters $paramString \
         }
    
    if [catch {APSRemoveDeviceFromDefaultRTFBConfig \
                 -plane $plane \
                 -add 1 -reason $reason \
                 -initials $initials \
                 -deviceList $deviceList \
                 -confirm $confirm} result] {
        APSMpReturn error "APSAddDeviceToDefaultRTFBConfig: $result"
    }
    APSMpReturn ok
}

proc APSRestoreDefaultConfigsInfo {} {
    return "It restores old RTFB and OC defaults from selection of a list of old links."
}

proc APSRestoreDefaultConfigsInitDialog {frame} {
    global APSRestoreDefaultConfigs
    #    set defaultList {h.default h.defaultXR h.defaultDP h.defaultXRDP  h.defaultRTFB v.default v.defaultXR v.defaultDP v.defaultXRDP  v.defaultRTFB}
    set defaultList {h.default v.default}
    foreach default $defaultList {
        set APSRestoreDefaultConfigs($default) 0
        lappend defaultVarList APSRestoreDefaultConfigs($default)
    }
    APSCheckButtonFrame .check -parent $frame -orientation horizontal -label "Default configs:"\
      -limitPerRow 5 -buttonList $defaultList -variableList $defaultVarList \
      -allNone 1
}

proc APSRestoreDefaultConfigs {args} {
    #set defaultList {h.default h.defaultXR h.defaultDP h.defaultXRDP  h.defaultRTFB v.default v.defaultXR v.defaultDP v.defaultXRDP v.defaultRTFB}
    set defaultList {h.default v.default}
    #  set typeList {plain plain DP DP plain \
      #                    plain plain DP DP plain}
    # set isXrayList {0 1 0 1 0 \
      #                    0 1 0 1 0}
    global APSRestoreDefaultConfigs
    foreach var $defaultList {
        set $var 0
    }
    APSMpStep init -promptDialog APSRestoreDefaultConfigsInitDialog \
      -vars $defaultList
    set chosen 0
    foreach default $defaultList {
        if [set $default] {
            set chosen 1
            break
        }
    }
    if {!$chosen} {
        APSMpReturn error "No defaults were chosen for restore."
    }
    set dataDir /home/helios/oagData/logDaemonData/UpdateSoftLinkAudit
    set oldDir [pwd]
    cd $dataDir
    set files [glob -nocomplain *.log] 
    set tmpRoot /tmp/[APSTmpString]
    if [catch {eval exec sddscombine $files -merge -pipe=out \
                 | sddssort -pipe=in $tmpRoot.1 -col=Time,decreasing } result] {
        return -code error "APSMpRestorDefaultConfigs: $result"
    }
    APSAddToTmpFileList -ID restoreDefaults -fileList $tmpRoot.1
    set widget ""
    foreach default $defaultList {
        if {[string length $widget] && [winfo exist $widget]} {
            tkwait window $widget
        }
        if [set $default] {
            if ![regexp {(.*)[hv]} $default plane] {
                continue
            }
            if [regexp {RTFB} $default] {
                set defaultDir /home/helios/oagData/sr/rtfeedback/lattices/default  
                set type RTFB
                regsub {RTFB} $default "" default
            } else {
                set defaultDir /home/helios/oagData/sr/orbitControllaw/lattices/default 
                set type OC
            }
            if [regexp {XR} $default] {
                set XR 1
            } else {
                set XR 0
            }
            if [regexp {DP} $default] {
                set PVType DP
            } else {
                set PVType plain
            }
            set configFile $defaultDir/${plane}configDesc.sdds
            if [catch {exec sddsprocess $tmpRoot.1 $tmpRoot.$default.$type \
                         -match=col,Link=$defaultDir/$default } result] {
                APSMpReturn error "APSMpRestoreDefaultConfigs: $result"
            }
            APSAddToTmpFileList -ID restoreDefaults -fileList $tmpRoot.$default.$type 
            if [catch {exec sddsxref $tmpRoot.$default.$type $configFile -pipe=out \
                         -match=NewFile=Filename -take=Description,PVType,IsXray -nowarnings \
                         | sddsprocess -pipe=in $tmpRoot.$default.$type.desc \
                         -filter=col,IsXray,$XR,$XR -match=col,PVType=$PVType } result] {
                APSMpReturn error "APSMpRestoreDefaultConfigs: $result"
            }
            APSAddToTmpFileList -ID restoreDefaults -fileList $tmpRoot.$default.$type.desc  
            set widget [APSUniqueName .list] 
            global apsRestore${default}
            APSSDDSListbox $widget -labelMaker APSSDDSListboxDefaultLabelMaker -arrayName apsRestore${default} \
              -widthLimit 120 -height 40 -trim 1 \
              -fileName $tmpRoot.$default.$type.desc \
              -callback "APSRestoreDefaultConfigsCallback $widget $type $default apsRestore${default} " \
              -columnList {NewFile Description} \
              -contextHelp "Double-click to select a old-configuration for restore" -doneButton 0 \
              -label "$type configuration list, chose config for restoring $default"
        }
    }
    if {[string length $widget] && [winfo exist $widget]} {
        tkwait window $widget
    }
    APSInfoWindow .info -name "RestoreConfig Recommandations" -infoMessage \
      "If you just restore OC default links, please make sure if current RTFB matrix matches, \notherwise, please use \"compute\" in \"SR Orbit Correction Configuration\" application to generate compensation matrix;\n\nIf you restored RTFB default links, probably you need recompute the compensation matrix for each default OC configurations." -modal 1
    APSMpReturn ok
}

proc APSRestoreDefaultConfigsCallback {widget type default arrayName index} {
    global $arrayName
    
    set restoreConfig [lindex [set ${arrayName}(NewFile)] $index]
    set restoreDesc [lindex [set ${arrayName}(Description)] $index]
    switch $type {
        RTFB {
            set defaultDir /home/helios/oagData/sr/rtfeedback/lattices/default  
        } 
        OC { 
            set defaultDir /home/helios/oagData/sr/orbitControllaw/lattices/default
        }
        default {
            APSMpReturn error "Unknown type - $type given"
        }
    }
    set link [file readlink $defaultDir/$default]
    switch [APSMultipleChoice [APSUniqueName .] -modal 1 -question "The current $type $default link is $link, are you sure to restore $default to $restoreConfig ($restoreDesc)?\n\n Press \"Continue\" to go ahead, \"Choose different config\" to select a different configuration, or \"Cancel\" to abort" -labelList {"Continue" "Choose different config" "Cancel"} -returnList {continue re-select cancel} -name "Restore $default to $restoreConfig?"] {
        continue {
            # restore config
        }
        re-select {
            APSMpReturn ok
        }
        cancel {
            if [winfo exist $widget] {
                destroy $widget
            }
            APSMpReturn ok
        }
    }
    
    APSMpStep "Restore $defaultDir/$default to $restoreConfig"
    if [catch {APSMakeLink -local 1 -log 1 -permissions 00775 \
                 -filename $defaultDir/$restoreConfig \
                 -linkname $defaultDir/$default \
             } result] {
        APSMpReturn error "APSRemoveDeviceFromDefaultConfig: $result"
    }
    APSMpStep "done."
    
    if [winfo exist $widget] {
        destroy $widget
    }
    APSMpReturn ok
}

#Not used
proc APSRemoveDeviceFromDefaultRTFBConfigInfo {args} {
    return "Removes bpms or correctors from a default rtfb configuration while creating a new numbered configuration and linking it to the default name. The name of the default configuation and a list of bpms must be specified."
}

#Not used
proc APSRemoveDeviceFromDefaultRTFBConfigDialog {frame} {  
    global APSRemoveDeviceFromDefaultRTFBConfig
    
    APSLabeledEntry .reason -parent $frame -label "Enter Reason:" \
      -textVariable APSRemoveDeviceFromDefaultRTFBConfig(reason) \
      -width 80 \
      -contextHelp "Enter the reason for the removal here. Note that the automatically generated description may be good enough, e.g. \"Removed S05B:P5\". The reason entered will be inserted after the automatically generated description and before the initials."
    
    APSLabeledEntry .initials -parent $frame -label "Enter initials:" \
      -textVariable APSRemoveDeviceFromDefaultRTFBConfig(initials) \
      -width 40 \
      -contextHelp "Enter your initials here. These will be placed at the end of the configuration descriptions."
    APSRadioButtonFrame .plane -parent $frame -buttonList {H V Both} \
      -variable  APSRemoveDeviceFromDefaultRTFBConfig(plane) -orientation horizontal \
      -valueList {h v both} -label "Removed bad devices from which plane?"
    
    APSLabeledEntry .badDevices -parent $frame -label "Enter bad devices (Use format S01A:P1 S01A:H1):" \
      -textVariable APSRemoveDeviceFromDefaultRTFBConfig(deviceList) \
      -width 40 \
      -contextHelp "Enter a spaced-separated list of bad devices (bpms or correctors). Use format S01A:P1 S01A:H1. Wildcards are allowed."
    
    APSRadioButtonFrame .confirm -parent $frame -orientation horizontal \
      -variable APSRemoveDeviceFromDefaultRTFBConfig(confirm) \
      -label "Confirm all configurations?" \
      -buttonList {"Yes I enjoy clicking"  "No I need to move on with my life"} -valueList {1 0} \
      -contextHelp "Choose whether to confirm all default configuration calculations. A list of device changes are written to the pop-up window."
    
}

#Moved to the attic
proc APSRemoveDeviceFromDefaultRTFBConfig {args} {
    package require rpn
    set baseDir /home/helios/oagData/sr/rtfeedback/lattices/default
    set reason "Bad devices"
    global env
    set initials $env(USER)
    set deviceList ""
    set confirm 0
    set add 0
    set plane both
    APSStrictParseArguments {reason initials deviceList confirm add plane}
    if !$add {
        APSMpStep init -promptDialog APSRemoveDeviceFromDefaultRTFBConfigDialog \
          -vars {reason initials deviceList confirm plane}
        foreach param "deviceList initials plane" {
            append paramString "$param=\"[set $param]\" "
        }
        catch {APSLogScriptAction \
                 -procedure  APSRemoveDeviceFromDefaultRTFBConfig \
                 -action initialize \
                 -state ok \
                 -parameters $paramString \
             }
    }
    global BPMLimit XBPMLimit corrLimit rangeErrorLimit S35DCCTLimitH S35DCCTLimitV 
    global dialogBoxResponse PVSuffix
    set S35DCCTLimitH 15
    set S35DCCTLimitV 15
    set BPMLimit 10
    set XBPMLimit 0.5
    set corrLimit 149.5
    set rangeErrorLimit 10
    set PVSuffix msAve
    #set ocDefaultList "default defaultDP defaultXR defaultXRDP"
    set ocDefaultList "default"
    set ocBaseDir /home/helios/oagData/sr/orbitControllaw/lattices/default
    if {$plane=="both"} {
        set planeList {h v}
    } else {
        set planeList $plane
    }
    set changed 0
    foreach plane $planeList {
        set ${plane}RTFBdefault [file readlink $baseDir/${plane}.default]
        set config ${plane}.default
        if !$add {
            APSMpStep "Removing $deviceList from $config"
        } else {
            APSMpStep "Adding $deviceList to $config"
        }
        if ![file exists $baseDir/$config] {
            APSMpReturn error "APSRemoveDeviceFromDefaultRTFBConfig: Can't find configuration $config."
        }
        if [catch {file readlink $baseDir/$config} result] {
            APSMpReturn error "APSRemoveDeviceFromDefaultRTFBConfig: Configuration $config is not a link."
        }
        set ${plane}RTFBOldLink [file tail $result]
        if !$add {
            if [catch {APSRemoveDeviceFromDefaultConfig -config $config \
                         -deviceList $deviceList \
                         -initials $initials \
                         -confirm $confirm \
                         -controllawType rtfeedback \
                         -comment "Removed $deviceList from $config. $initials" \
                     } result] {
                APSMpReturn error "APSRemoveDeviceFromDefaultRTFBConfig: $result"
            }
        } else {
            if [catch {APSAddDeviceToDefaultConfig -config $config \
                         -deviceList $deviceList \
                         -confirm $confirm \
                         -rtfeedback 1 \
                         -initials $initials \
                         -comment "Added $deviceList to $config. $initials" \
                     } result] {
                APSMpReturn error "APSRemoveDeviceFromDefaultRTFBConfig: $result"
            }
        }
        set ${plane}RTFBNewLink [file tail [file readlink $baseDir/$config]]
        
        if  [string compare [set ${plane}RTFBOldLink] [set ${plane}RTFBNewLink]]==0 {
            append Message "RTFB $config: No change.\n"
        } else {
            append Message "RTFB $config: Change occured.\n"
            set changed 1
        }
    }
    set dcOrbitChanged 0
    APSInfoWindow .info -name "Results of RTFB config updates" \
      -width 50 -infoMessage $Message -modal 1
    if $changed {
        APSMpStep "Load RTFB matrix..."
        if [catch {exec cavget -list=Mt:TopUpAutoEnableC.VAL -num} topup] {
            APSMpReturn error "Unable to read Mt:TopUpAutoEnableC.VAL: $topup"
        }
        if $topup {
            APSInfoWindow .info -name "Wait for injection" -width 50 -modal 1 \
              -infoMessage "You need to wait for topup injection to bring the current above 102mA, and then abort topup. Press OK when you are done."
        }
        global tcl_platform
        if {$tcl_platform(os) == "Linux"} {
            set domain [exec dnsdomainname]
        } else {
            set domain [exec domainname]
        }
        if {([string compare "accel.ntw0rk" $domain]==0) || ([string compare "aps4.anl.gov" $domain]==0)} {
            global apshpFilterCutoffVert apshpFilterCutoffHoriz apshpFilterInitialVert apshpFilterInitialHoriz apshpFilterRampPoints apshpFilterRampInterval
            APSMpSetRTFBGlobalParameters -readonly 1
            
            if [catch {exec cavget -list=SRFB:GBL:LoopStatusBI.VAL -pend=30} RTFBLoopStatus] {
                APSMpReturn error $RTFBLoopStatus
            }
            if {$RTFBLoopStatus=="On"} {
                APSMpStep OpenRTFBLoops -desc "Open RTFB loops."
                if [catch {APSMpRTFBResetOpenLoops -hpFilterInitialVert $apshpFilterInitialVert \
                             -hpFilterInitialHoriz $apshpFilterInitialHoriz } result] {
                    APSMpReturn error "APSMpRTFBPreReboot3: $result"
                }
            }
            APSMpStep LoadResponseMatrix -desc "Load Response Matrix"
            if [catch {APSMpRTFBLoadResponseMatrix} result] {
                APSMpReturn error "$result"
            }
            after 2000
            if {$RTFBLoopStatus=="On"} {
                APSMpStep CloseRTFBLoops -desc "Close RTFB loops."
                if [catch {APSMpRTFBCloseLoops -hpFilterCutoffVert $apshpFilterCutoffVert \
                             -hpFilterCutoffHoriz $apshpFilterCutoffHoriz \
                             -hpFilterInitialVert $apshpFilterInitialVert \
                             -hpFilterInitialHoriz $apshpFilterInitialHoriz \
                             -hpFilterRampPoints $apshpFilterRampPoints \
                             -hpFilterRampInterval $apshpFilterRampInterval } result] {
                    APSMpReturn error "APSMpRTFBCloseLoops: $set"
                }   
            }
        }
        
        set answer [APSMultipleChoice [APSUniqueName .] -modal 1 -question "If you made a change in RTFB BPMs, you must press regenerate button to regenerate the compensation files and the controllaw files for each DC configuration.\n\nIf you did not make any BPM changes, you may press \"Cancel\"."  \
                      -labelList {Regenerate Cancel} -returnList {Regenerate Cancel} ]
        if {$answer=="Regenerate"} {
            
            APSMpStep "Update SR global orbit correction configurations."
            set dialogBoxResponse ""
            set win [APSUniqueName .]
            APSDialogBox $win -cancelCommand "set dialogBoxResponse cancel"  \
              -okCommand "set dialogBoxResponse ok"  -name "Controllaw test file limits" 
            set w $win.userFrame
            APSLabeledEntry .le0 -parent $w -label "bpm limit (mm)" \
              -textVariable BPMLimit -width 10
            APSLabeledEntry .le1 -parent $w -label "Xray bpm limit (mm)" \
              -textVariable XBPMLimit -width 10
            APSLabeledEntry .le2 -parent $w -label "corrector limit (A)" \
              -textVariable corrLimit -width 10
            APSLabeledEntry .le3 -parent $w -label "Range Error limit (A)" \
              -textVariable rangeErrorLimit -width 10
            APSLabeledEntry .currLimitH -parent $w -label "S35DCCT lower limit (mA) for H plane" \
              -textVariable S35DCCTLimitH -width 10 \
              -contextHelp "Enter the lower limit of S35DCCT readback below which the sddscontrollaw correction iteration is skipped."
            APSLabeledEntry .currLimitV -parent $w -label "S35DCCT lower limit (mA) for V plane" \
              -textVariable S35DCCTLimitV -width 10 \
              -contextHelp "Enter the lower limit of S35DCCT readback below which the sddscontrollaw correction iteration is skipped."
            APSRadioButtonFrame .pvSuffix -parent $w -label "bpm PV type" \
              -variable PVSuffix -valueList {ms msAve mswAve} \
              -buttonList {ms msAve mswAve} -orientation horizontal -contextHelp \
              "Select the memory/scanner PV type (i.e. bpm data type)."
            tkwait window $win
            update
            if {$dialogBoxResponse=="cancel"} {
                APSMpStep regeneratecancelled -desc "Orbit correction files regeneration was cancelled."
                APSMpReturn ok
            }
            foreach plane $planeList {
                if [string compare [set ${plane}RTFBOldLink] [set ${plane}RTFBNewLink]]!=0 {
                    foreach default $ocDefaultList {
                        set config ${plane}.$default
                        if [catch {file readlink $ocBaseDir/$config} ${plane}$default] {
                            APSMpReturn error "APSRemoveDeviceFromDefaultRTFBConfig: DC oc configuration $config is not a link."
                        }
                        if {![file exist $ocBaseDir/$config] \
                              || ![file exist $ocBaseDir/$config/config]} {
                            continue
                        }
                        set newConfig [APSNextGenerationedName \
                                         -directory $ocBaseDir \
                                         -name ${plane}.[clock format [clock seconds] \
                                                           -format %Y-%m%d].00 -newFile 1 -separator .]
                        if ![file exist $newConfig] {
                            exec cp -r $ocBaseDir/$config $ocBaseDir/$newConfig
                        } else {
                            set fileList [glob $ocBaseDir/$config/*]
                            foreach file $fileList {
                                exec cp $file $ocBaseDir/$newConfig/.
                            }
                        }
                        set tmpfile /tmp/[APSTmpString]
                        if [catch {exec sddsprocess $ocBaseDir/$newConfig/config $tmpfile -nowarnings \
                                     "-reprint=par,Description,Removed [APSMakeSafeQualifierString $deviceList] from default RTFB. $initials" } result] {
                            APSMpReturn error $result
                        }
                        exec cp $tmpfile $ocBaseDir/$newConfig/config

                        APSMpStep "Update description database"
                        if [catch {APSUpdateConfigDescriptionDatabase \
                                     -dataDir $ocBaseDir -newConfig $newConfig} result] {
                            APSMpReturn error "APSRemoveDeviceFromDefaultRTFBConfig: $result"
                        }

                        APSMpStep "Regenerate compensation files for DC OC $newConfig."
			set tikhonov 0
			set SVNnumber 0
			set beta 0
                        if [file exist $ocBaseDir/$config/irm] {
                            set singularValues [exec sdds2stream -par=NumberOfSingularValuesUsed -page=1 $ocBaseDir/$config/irm]
			    set pars [exec sddsquery -par $baseDir/$config/irm]
			    if [lsearch -exact $pars "TikhonovFilterUsed"]>=0 {
				set tikhonov [exec sdds2stream -par=TikhonovFilterUsed -page=1 $ocBaseDir/$config/irm]
				if $tikhonov {
				    set SVNnumber [exec sdds2stream -par=TikhonovSVNNumber -page=1 $ocBaseDir/$config/irm]
				    set beta [exec sdds2stream -par=TikhonovBeta  -page=1 $ocBaseDir/$config/irm]
				}
			    }
                        } else {
                            set singularValues 320
                        }
                        if [catch {APSSRGenerateOrbCorrFiles -rootname ${plane}config -generate 1 \
                                     -configFile $ocBaseDir/$newConfig/config -plane $plane \
                                     -referenceMatrix $ocBaseDir/refMatrices/$plane.default \
                                     -outputRoot $ocBaseDir/$newConfig -singularValues $singularValues \
                                     -tikhonovFilter $tikhonov -tikhonovSVN $SVNnumber -tikhonovBeta $beta \
                                     -compensationConfigFile $baseDir/$plane.default/config } result] {
                            APSMpReturn $result
                        }

                        APSMpStep "Regenerate controllaw files for DC OC $newConfig."
                        if [catch {APSGenerateControllawFiles -regenerateFiles 1 \
                                     -dataDir $ocBaseDir -directory $newConfig \
                                     -PVSuffix $PVSuffix -BPMLimit $BPMLimit -XBPMLimit $XBPMLimit \
                                     -corrLimit $corrLimit -rangeErrorLimit $rangeErrorLimit \
                                     -S35DCCTLimitH $S35DCCTLimitH -S35DCCTLimitV $S35DCCTLimitV \
                                 } result] {
                            APSMpReturn error "GenerateFiles: $result"
                        }

                        APSMpStep GeneratingLinks -desc "Make new links for DC OC $config"
                        if [catch {APSMakeLink -local 1 -log 1 -permissions 00775 \
                                     -filename $ocBaseDir/$newConfig \
                                     -linkname $ocBaseDir/$config \
                                 } result] {
                            APSMpReturn error "APSRemoveDeviceFromDefaultConfig: $result"
                        }
                        set dcOrbitChanged 1
                    }
                }
            }
        }
        switch [APSMultipleChoice [APSUniqueName .] -modal 1 -question "Do you want to keep the changes or do you want to undo it?" -labelList {"Keep" "Undo"} -returnList {keep undo} -name "Undo?"] {
            keep {
                APSAlertBox .alert -type warning -name warning -beep once \
                  -errorMessage "If you made changes to RTFB and DC OC configurations, you need restart the orbit correction controllaw."
            }
            undo {
                APSMpStep RestoreRTFBPrevLinks -desc "Restore previous RTFB default links."
                set rtfbChanged 0
                foreach plane $planeList {
                    set config [set ${plane}RTFBOldLink]
                    set newConfig [set ${plane}RTFBNewLink] 
                    if [string compare $config $newConfig]!=0 {
                        APSMpStep "relink RTFB $plane.default to $config"
                        if [catch {APSMakeLink -local 1 -log 1 -permissions 00775 \
                                     -filename $baseDir/$config \
                                     -linkname $baseDir/${plane}.default \
                                 } result] {
                            APSMpReturn error "APSRemoveDeviceFromDefaultConfig: $result"
                        }
                        set rtfbChanged 1
                    }
                }
                if $rtfbChanged {
                    #reload RTFB matrix for undo.
                    APSMpStep "Load RTFB matrix..."
                    if [catch {exec cavget -list=Mt:TopUpAutoEnableC.VAL -num} topup] {
                        APSMpReturn error "Unable to read Mt:TopUpAutoEnableC.VAL: $topup"
                    }
                    if $topup {
                        APSInfoWindow .info -name "Wait for injection" -width 50 -modal 1 \
                          -infoMessage "You need to wait for topup injection to bring the current above 102mA, and then abort topup. Press OK when you are done."
                    }
                    global tcl_platform
                    if {$tcl_platform(os) == "Linux"} {
                        set domain [exec dnsdomainname]
                    } else {
                        set domain [exec domainname]
                    }
                    if {([string compare "accel.ntw0rk" $domain]==0) || ([string compare "aps4.anl.gov" $domain]==0)} {
                        global apshpFilterCutoffVert apshpFilterCutoffHoriz apshpFilterInitialVert apshpFilterInitialHoriz apshpFilterRampPoints apshpFilterRampInterval
                        APSMpSetRTFBGlobalParameters -readonly 1
                        
                        if [catch {exec cavget -list=SRFB:GBL:LoopStatusBI.VAL -pend=30} RTFBLoopStatus] {
                            APSMpReturn error $RTFBLoopStatus
                        }
                        if {$RTFBLoopStatus=="On"} {
                            APSMpStep OpenRTFBLoops -desc "Open RTFB loops."
                            if [catch {APSMpRTFBResetOpenLoops -hpFilterInitialVert $apshpFilterInitialVert \
                                         -hpFilterInitialHoriz $apshpFilterInitialHoriz } result] {
                                APSMpReturn error "APSMpRTFBPreReboot3: $result"
                            }
                        }
                        APSMpStep LoadResponseMatrix -desc "Load Response Matrix"
                        if [catch {APSMpRTFBLoadResponseMatrix} result] {
                            APSMpReturn error "$result"
                        }
                        after 2000
                        if {$RTFBLoopStatus=="On"} {
                            APSMpStep CloseRTFBLoops -desc "Close RTFB loops."
                            if [catch {APSMpRTFBCloseLoops -hpFilterCutoffVert $apshpFilterCutoffVert \
                                         -hpFilterCutoffHoriz $apshpFilterCutoffHoriz \
                                         -hpFilterInitialVert $apshpFilterInitialVert \
                                         -hpFilterInitialHoriz $apshpFilterInitialHoriz \
                                         -hpFilterRampPoints $apshpFilterRampPoints \
                                         -hpFilterRampInterval $apshpFilterRampInterval } result] {
                                APSMpReturn error "APSMpRTFBCloseLoops: $set"
                            }   
                        }
                    }
                }
                if {$dcOrbitChanged} {
                    APSMpStep RestoreOCPrevLinks -desc "Restore previous DC orbit correction default links."
                    foreach plane $planeList {
                        if [string compare [set ${plane}RTFBOldLink] [set ${plane}RTFBNewLink]]!=0 {
                            foreach default $ocDefaultList {
                                set config [set ${plane}$default]
                                APSMpStep "Relink DC OC $plane.$default to $config"
                                if [catch {APSMakeLink -local 1 -log 1 -permissions 00775 \
                                             -filename $ocBaseDir/$config \
                                             -linkname $ocBaseDir/${plane}.$default \
                                         } result] {
                                    APSMpReturn error "APSRemoveDeviceFromDefaultRTFBConfig: $result"
                                }
                            }
                        }
                    }
                } else {
                    APSMpStep None -desc "DC OC configurations were not changed."
                }
		APSAlertBox .done -type done \
                  -errorMessage "The default congfigs were restored -- no changes made to RTFB and DC OC default configs."
            }
        }
    }
    APSMpReturn ok
}

#Called by SRXrayBPMStatusUpdate
proc APSMpSRSetXrayBPMStatusPVs {args} {
    #FIX THIS
    #According to L. Emery the :OrbitCorrConfigX won't be used
    #and the :XrayBPMsInUseX PVs won't be used in the APSU in the beginning
    APSMpReturn ok

    set config ""
    set dataDir /home/helios/oagData/sr/orbitControllaw/lattices/default
    APSStrictParseArguments {config dataDir} 
    
    set plane [string index $config 0]
    switch $plane {
        h {
            set ext1 :OrbitCorrConfigX
            set ext2 :XrayBpmsInUseX
            set value "x xray bpm enabled"
        }
        v {
            set ext1 :OrbitCorrConfigY
            set ext2 :XrayBpmsInUseY
            set value "y xray bpm enabled"
        }
        default {
            return -code error "APSMpSRSetXrayBPMStatusPVs1: invalid config provided, should be [hv].****"
        }
    }
    set IDsectorFile /home/helios/oagData/sr/IDs/sectors.sdds
    set tmpRoot /tmp/[APSTmpString]
    
    if [catch {exec sddsprocess $dataDir/$config/config -match=par,NameType=MonitorNames \
                 -scan=col,Sector,Name,S%ld,type=long \
                 -match=col,Name=S*ID* -nowarnings $tmpRoot.id } result] {
        return -code error "APSMpSRSetXrayBPMStatusPVs2: error getting ID xray bpms used in orbit correction: $result"
    }
    APSAddToTmpFileList -ID orbitcorr -fileList $tmpRoot.id
    set rows [exec sdds2stream -rows=bar $tmpRoot.id]
    set InUseSectors ""
    set NotUseSectors ""
    if !$rows {
        #no ID xray bpm is being used
        set NotUseSectors [exec sdds2stream -col=Sector $IDsectorFile]
    } else {
        set InUseSectors [lsort -unique -integer [exec sdds2stream -col=Sector $tmpRoot.id]]
        if [catch {exec sddsselect $IDsectorFile $tmpRoot.id $tmpRoot.IDno -equate=Sector -invert -nowarnings } result] {
            return -code error "APSMpSRSetXrayBPMStatusPVs3: error getting not in used ID xray bpms: $result"
        }
        APSAddToTmpFileList -ID orbitcorr -fileList $tmpRoot.IDno
        set NotUseSectors [lsort -unique -integer [exec sdds2stream -col=Sector $tmpRoot.IDno]]
    }
    
    if [llength $InUseSectors] {
        set sectors ""
        foreach sector $InUseSectors {
            lappend sectors [format %02d $sector]
        }
        if [catch {exec cavput -list=ID -list=[join $sectors ,] -list=$ext1=$config  -pend=30
            exec cavput -list=ID -list=[join $sectors ,] -list=$ext2=Enabled -pend=30 } result] {
            return -code error "APSMpSRSetXrayBPMStatusPVs4: error setting in use Xray bpm status: $result"
        }
    }
    if [llength $NotUseSectors] {
        set sectors ""
        foreach sector $NotUseSectors {
            lappend sectors [format %02d $sector]
        }
        if [catch {exec cavput -list=ID -list=[join $sectors ,] -list=$ext1=""  -pend=30
            exec cavput -list=ID -list=[join $sectors ,] -list=$ext2=Disabled -pend=30 } result] {
            return -code error "APSMpSRSetXrayBPMStatusPVs4: error setting not use Xray bpm status: $result"
        }
    }
    APSMpReturn ok
}

#Called by multiple applications
proc APSSRRemoveXrayBPMFromOrbitCorrection {args} {
    set sector ""
    set retart 1
    set source ID
    set side ""
    APSStrictParseArguments {sector restart source side}
    
    set dataDir /home/helios/oagData/sr/orbitControllaw/lattices/default
    if {$source=="ID" && $sector==27} {
        #do not remove xray bpms for ID27
        return "ID27 xray bpms will be kept if they are in orbit correction."
    }
    if {$source=="ID"} {
        switch $side {
            us -
            US {
                set pv S${sector}${source}:P1
                set pvList S${sector}${source}:P1
            }
            ds -
            DS {
                set pv S${sector}${source}:P2
                set pvList S${sector}${source}:P2
            }
            default {
                set pv S${sector}${source}:P*
                set pvList [list S${sector}${source}:P1 S${sector}${source}:P2]
            }
        }
    } else {
        set pv S${sector}${source}:P*
        set pvList [list S${sector}${source}:P1 S${sector}${source}:P2]
    }
    #set defaultList {defaultXRDP defaultXR}
    set defaultList {default}
    
    if [catch {exec removeXrayBPMsFromDefaultConfigs -xrayBPMs $pv -install 1} result] {
        return -code error "Error removing $pv from default configs: $result"
    }
    #puts $result
    if [llength $result] {
        set message "$pv were removed from [join $result .]."
    } else {
        set message "No bpms were removed."
        return $message
    }
    foreach config $result {
        if ![regexp "XRDP" $config] {
            #only restart XRDP orbit correction
            continue
        }
        if [regexp {h.} $config] {
            set plane h
            set coord x
            set Coord X
        } else {
            set plane v
            set coord y
            set Coord Y
        }
        if [catch {APSCheckControllawRunning -config $config} running] {
            return -code error "APSSRRemoveXrayBPMFromOrbitCorrection2:APSCheckControllawRunning $plane plane): $running"
        }
        if {$running && $restart} {
            #abort controllaw
            catch {exec logMessage -sourceId=steeringAudit \
                     -tag=Instance S:OrbitControlLaw${Coord}SDDS -tag=Action Abort}
            if [catch {exec cavput -list=S:OrbitControlLaw${Coord}SDDS.ABRT=1 -pend=30 } result] {
                return -code error "APSSRRemoveXrayBPMFromOrbitCorrection4: error aborting $plane orbit correction: $result"
            }
            after 2000
            #restart controllaw
            catch {exec logMessage -sourceId=steeringAudit \
                     -tag=Instance S:OrbitControlLaw${Coord}SDDS -tag=Action Start}
            if [catch {exec cavput -list=S:OrbitControlLaw${Coord}SDDS.CMND=1 -pend=30} result] {
                return -code error "APSSRRemoveXrayBPMFromOrbitCorrection7: error starting $plane orbit correction."
            }
            
            #FIX THIS -- This will probably be renamed in the APSU
            if [catch {exec cavput -list=[join $pvList ,] -list=:ms:${coord}:InUseBO=0 -pend=30} result] {
                return -code error "APSSRRemoveXrayBPMFromOrbitCorrection5: error un-setting inUse PVs: $result"
            }
        }
    }
    return $message
}

