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

#July 18, 2023, H. Shang, for APSU SR bpm

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

set CVSRevisionAuthor "\$Revision: 1.37 $ \$Author: shang $"

APSApplication . -name SRbpmConfig -version $CVSRevisionAuthor \
  -overview "Storage ring bpm configuration tool."

set offsetbpmLabelList {AP0 AP1 AP2 AP3 AP4 AP5 AP6 BP6 BP5 BP4 BP3 BP2 BP1 BP0 CP0}
set offsetbpmList {A:P0 A:P1 A:P2 A:P3 A:P4 A:P5 A:P6 B:P6 B:P5 B:P4 B:P3 B:P2 B:P1 B:P0 C:P0}

proc MakeCheckButtonListFrame {widget args} {
    set parent ""
    set label ""
    set labelList ""
    set state0List ""
    set state1List ""
    set value0List ""
    set value1List ""
    set command ""
    set commandArgumentList ""
    set frameWidth 500
    set frameHeight 500
    set addQuery 0
    if [APSStrictParseArguments \
          {parent labelList state0List state1List command commandArgumentList label frameWidth frameHeight value0List value1List addQuery}]==-1 {
              return
          } 
    set width [expr [APSMaxStringLength $labelList]+1]
    APSFrame $widget -parent $parent -label "" -noPack 0 -width $frameWidth -height $frameHeight
    $parent$widget.frame configure -relief flat
    set w0 $parent$widget.frame
    pack propagate $w0 0
    set index 0
    foreach label $labelList state0 $state0List state1 $state1List argument $commandArgumentList {
        set value0 0
        set value1 1
        if [llength $value0List] {
            set value0 [lindex $value0List $index]
        } 
        if [llength $value1List] {
            set value1 [lindex $value1List $index]
        } 
        if [string match $state0 $state1] {
            APSFrame .a$index -parent $w0 -label $label -orientation horizontal  \
              -packOption "-side top -fill x"
            APSButton .b0 -parent $w0.a$index.frame -text $state1 \
              -command "$command $argument $value1" -size small
        } else {
            APSFrame .a$index -parent $w0 -label $label -orientation horizontal \
              -packOption "-side top -fill x"
            APSButton .b0 -parent $w0.a$index.frame -text $state0 \
              -command "$command $argument $value0" -size small
            APSButton .b1 -parent $w0.a$index.frame -text $state1 \
              -command "$command $argument $value1" -size small
        }
        $w0.a$index.label configure -width $width
        if $addQuery {
            APSButton .b2 -parent $w0.a$index.frame -text "Query" \
            -command "$command $argument __query__" -size small
        }
        incr index
    }
}

proc MakeAPSButtonListFrame {widget args} {
    set parent ""
    set label ""
    set labelList ""
    set command ""
    set commandArgumentList ""
    set itemPerRow 3
    if [APSStrictParseArguments \
          {parent labelList command commandArgumentList label frameWidth frameHeight itemPerRow}]==-1 {
              return
          } 
    set width [expr [APSMaxStringLength $labelList]+1]

    APSFrame $widget -parent $parent -label "" 
    $parent$widget.frame configure -relief flat
    set w0 $parent$widget.frame

    global LiberaButtonList
    set num [llength $labelList]
    set frame 0
    set index 0
    foreach label $labelList commandArg $commandArgumentList {
        set w [APSUniqueName .]
	set frame [expr $index/$itemPerRow]
	set w1 $w0.f$frame.frame
	if ![winfo exist $w1] {
	    APSFrame .f$frame -parent $w0
	    $w1 configure -bd 0 -relief flat
	}
        APSButton $w -parent $w1 -text $label \
		  -command "$command $commandArg" -packOption "-side left"
	if [regexp "Libera" $label] {
	    lappend LiberaButtonList  $w1$w.button
	}      
	incr index
		   
    }
}

proc EnableDisableLiberaButtons {args} {
    global LiberaButtonList EnableDisableLibera
    foreach button $LiberaButtonList {
	if $EnableDisableLibera {
	    APSEnableButton $button
	} else {
	    APSDisableButton $button
	}
    }
}

proc MakeIndividualOpsWidget {widget args} {
    set parent ""
    if [APSStrictParseArguments {parent}]==-1 {
        return
    } 
    set frameWidth 1050
    set frameHeight 200
    APSFrame $widget -parent $parent -label "" 
    $parent$widget.frame configure -relief flat
    set w $parent$widget.frame
    set widgetList [APSTabFrame .controls -parent $parent$widget.frame \
                      -label "BPM Operations" \
                      -labelList "Transfers ZeroValues" \
                      -width $frameWidth -height $frameHeight ]
    pack $parent$widget.frame.controls
    $parent$widget.frame.controls.frame.tn select 0
    set windex 0

    set tabwidget [lindex $widgetList $windex]
    incr windex
    
    MakeAPSButtonListFrame .transfers -parent $tabwidget -label "Operations" -itemPerRow 3 \
      -command TransferOrbit \
      -labelList {"x Setpoint += ErrorCC"    "y Setpoint += ErrorCC"  "x/y Setpoint += ErrorCC" \
		      "x Offset   += ErrorCC"    "y Offset   += ErrorCC"  "x/y Offset   += ErrorCC" \
		      "x Offset   -> Libera "     "y Offset  -> Libera "   "x/y Offset   -> Libera " \
		      "x RF Setpoint += RfErrorM" "ID Xbpm blades xfer" } \
      -commandArgumentList \
      { "-plane x -mode setpointXfer"    "-plane y -mode setpointXfer"   "-plane both -mode setpointXfer" \
	    "-plane x -mode offsetXfer" "-plane y -mode offsetXfer" "-plane both -mode offsetXfer" \
	    "-plane x -mode liberaXfer" "-plane y -mode liberaXfer" "-plane both -mode liberaXfer" \
	    "-plane x -mode RFsetpointXfer"  "-mode IDbladesXfer"
      }
    global offsetTransferTo
    set offsetTransferTo  BpmZeroOffsetC
    APSRadioButtonFrame .offsettype -parent $tabwidget -orientation horizontal  \
	-label "which offset component that the ErrorM would be transferred into:" \
	-buttonList {BpmZero BunchPattern Intensity Generic Hydrostatic(yOnly)} \
	-valueList {BpmZeroOffsetC BunchPatternOffsetC IntensityOffsetC Offset4C HydrostaticOffsetC} \
	-variable offsetTransferTo  -limitPerRow 3
    global EnableDisableLibera 0
    APSCheckButtonFrame .enable -parent $tabwidget -label "" \
	-buttonList "Enable/Disable_libera" -variableList EnableDisableLibera -commandList EnableDisableLiberaButtons
    EnableDisableLiberaButtons
    set tabwidget [lindex $widgetList $windex]
    incr windex
    MakeAPSButtonListFrame .zero -parent $tabwidget -label "Operations" \
      -command TransferOrbit \
      -labelList {"0 -> x setpoint      " "0 -> y setpoint     " "0 -> x/y setpoint     " \
		      "0 -> x offset        " "0 -> y offset       " "0 -> x/y offset       "  \
		      "0 -> x RF setpoint" \
                } \
      -commandArgumentList \
      {"-plane x -mode setpointZero"\
         "-plane y -mode setpointZero" "-plane both -mode setpointZero" \
	   "-plane x -mode offsetZero" "-plane y -mode offsetZero" "-plane both -mode offsetZero" \
	   "-plane x -mode RFsetpointZero"  \
       }
    global zeroOffsetType
    set varList ""
    foreach type {BpmZeroOffsetC BunchPatternOffsetC IntensityOffsetC Offset4C HydrostaticOffsetC} {
	set zeroOffsetType($type) 1
	lappend varList zeroOffsetType($type)
    }
     APSCheckButtonFrame .offsettype1 -parent $tabwidget -orientation horizontal  \
	-label "which offset component to be zeroed:" -allNone 1 \
	-buttonList {BpmZero BunchPattern Intensity Generic Hydrostatic(yOnly)} \
	-variableList $varList  -limitPerRow 5
}



set ValidBPMList {}
proc IndividualBPMsSelected {args} {
    global bpmList bpmListColon ValidBPMList FPGAbpmList
    set excludeP0s 0
    set excludeXray 0
    set excludeBMXray 0
    set useWildcard ""
    set excludeFPGA 0
    APSParseArguments {excludeP0s excludeXray useWildcard excludeBMXray excludeFPGA}
    set selectedList ""
    if [llength $ValidBPMList]<2 {
        if [catch {exec sddsprocess /home/helios/oagData/sr/BPMStatus/config.sdds -pipe=out \
                     -filter=column,NonexistentH,0,0,NonexistentV,0,0,| \
                     | sdds2stream -pipe -column=DeviceName} ValidBPMList] {
            SetMainStatus "Unable to get list of valid BPMs: $ValidBPMList"
            set ValidBPMList {}
        }
    }
    if $excludeFPGA {
        if ![info exist FPGAbpmList] {
            if [catch {exec sddsprocess /home/helios/oagData/sr/BPMStatus/config.sdds -pipe=out \
                         -match=column,ElectronicsType=FPGA \
                         | sdds2stream -pipe -column=DeviceName} FPGAbpmList] {
                SetMainStatus "Unable to get list of valid BPMs: $FPGAbpmList"
                set FPGAbpmList ""
            }
        }
    }
    set index 0
    foreach bpm $bpmList {
        if {$excludeXray} {
            if {[string match D? $bpm] || [string match I? $bpm]} {
                incr index
                continue
            }
        }
        if {$excludeBMXray} {
            if {[string match D? $bpm]} {
                incr index
                continue
            }
        }
        if {$excludeP0s} {
            if [regexp P0 $bpm] {
                incr index
                continue 
            }
        }
        if {$useWildcard != "" && ![string match $useWildcard $bpm]} {
            incr index
            continue
        }
        for {set sector 1} {$sector<41} {incr sector} {
	    set sectorf [format %02d $sector]
            global S${sectorf}$bpm
            if {[set S${sectorf}$bpm]} {
                set bpmName $sectorf[lindex $bpmListColon $index]
                if [lsearch -exact $ValidBPMList S$bpmName]>-1 {
                    if {$excludeFPGA} {
                        if {[lsearch -exact $FPGAbpmList S$bpmName]<0} {
                            lappend selectedList $bpmName
                        }
                    } else {
                        lappend selectedList $bpmName
                    }
                }
            }
        }
        incr index
    }
    return $selectedList
}

proc TransferOffsetToLibera {args} {
    set plane ""
    APSParseArguments {plane}
    set BPMsToChange [SelectedBPMList]
    #do not do SB bpm for now ...
    set count [llength $BPMsToChange] 
    if {$count==0} {
        SetMainStatus "No BPMs selected---no transfers done."
        return
    }
    if {$plane=="both"} {
	set planeList {x y}
    } else {
	set planeList $plane
    }
    set xpvList ""
    set ypvList ""
    foreach plane $planeList {
	foreach bpm $BPMsToChange {
	    lappend ${plane}pvList ${bpm}:off_${plane}_sp
	}
    }
    foreach plane $planeList {
	if [catch {exec cavget -list=[join $BPMsToChange ,] -list=:${plane}:OffsetM -printErrors -pend=10} valList] {
	    return -code error "Error reading offsets: $valList"
	}
	set ${plane}valList $valList
    }
    foreach plane $planeList {
	set putList ""
	foreach pv [set ${plane}pvList] val [set ${plane}valList] {
	    lappend putList $pv=$val
	}
	SetMainStatus "transfer $plane plane offsets to libera..."
	if [catch {exec cavput -list=[join $putList ,] -delta -pend=30} result] {
	    return -code error "Error setting libera offsets: $result"
	}
    }
    SetMainStatus "done."
}

proc TransferOrbit {args} {
    set plane ""
    set mode ""
    APSStrictParseArguments {plane mode}
    #set BPMsToChange [IndividualBPMsSelected]
    #run SelectedBPMList to get the selected bpms in x and y plane
    global SBBPMList offsetTransferTo
    set BPMsToChange [SelectedBPMList]
    set count [expr [llength $BPMsToChange] + [llength $SBBPMList]]
    if {$count==0} {
        SetMainStatus "No BPMs selected---no transfers done."
        return
    }
    if [regexp "libera" $mode] {
	if [catch {TransferOffsetToLibera -plane $plane} result] {
	    return -code error "Error transfer offsets to libera: $result"
	}
	return
    }
    set zero 0
    set xferToy ""
    global zeroOffsetType
    switch $mode {
        setpointXfer {
            set readFrom LowPass1sErrorM
	    set readFrom1 ErrorM
            set xferTo SetpointC
	    set xferTo1 SetpointC
        }
        RFsetpointXfer {
            set readFrom LowPass1sRfErrorM
            set xferTo RfSetpointC
        }
        offsetXfer {
            set readFrom LowPass1sErrorM
	    set readFrom1 ErrorM
            set xferTo $offsetTransferTo
	    set xferTo1 OffsetC
	    if {$plane!="y" && $xferTo=="HydrostaticOffsetC"} {
		SetMainStatus "Hydrostatic offset transfer is only valid for y plane." 
		return
	    }
        }
        setpointZero {
            set zero 1
            set xferTo SetpointC
	    set xferTo1 SetpointC
        }
        RFsetpointZero {
            set zero 1
            set xferTo RfSetpointC
        }
        offsetZero {
            set zero 1
	    set xferTo ""
	    foreach type {BpmZeroOffsetC BunchPatternOffsetC IntensityOffsetC Offset4C} {
		if $zeroOffsetType($type) {
		    if ![string length $xferTo] {
			append xferTo ${type}
		    } else {
			append xferTo ,${type}
		    }
		}
	    }
	    if {$plane=="x"} {
		if ![string length $xferTo] {
		    return -code error "No offset type is being selected for zero x offsets!"
		}
		#set xferTo BpmZeroOffsetC,BunchPatternOffsetC,IntensityOffsetC,Offset4C
	    } elseif {$plane=="y"} {
		if $zeroOffsetType(HydrostaticOffsetC) {
		    if ![string length $xferTo] {
			append xferTo HydrostaticOffsetC
		    } else {
			append xferTo ,HydrostaticOffsetC
		    }
		}
		if ![string length $xferTo] {
		    return -code error "No offset type is being selected for zero y offsets!"
		}
		#set xferTo BpmZeroOffsetC,BunchPatternOffsetC,IntensityOffsetC,Offset4C,HydrostaticOffsetC
	    } else {
		if {![string length $xferTo]}  {
		    return -code error "No offset type chosen for zero x offsets"
		}
		set xferToy ""
		if $zeroOffsetType(HydrostaticOffsetC) {
		    set xferToy HydrostaticOffsetC
		}
		#set xferTo BpmZeroOffsetC,BunchPatternOffsetC,IntensityOffsetC,Offset4C
		#	set xferToy HydrostaticOffsetC
	    }
	    set xferTo1 OffsetC
        }
        IDbladesXfer {
            set IDsectors ""
            foreach bpm $BPMsToChange {
                if ![string match *ID* $bpm] {continue}
                if ![scan $bpm %ld sector] {continue}
                if [lsearch $IDsectors $sector]<0 {
                    lappend IDsectors $sector
                }
            }
            if ![llength $IDsectors] {
                SetMainStatus "No IDs were selected for ID blades transfer."
                return
            }
        }
        default {
            SetMainStatus "Invalid mode: $mode"
            return
        }
    }
    if {$mode=="IDbladesXfer"} {
        SetMainStatus "Transfer ID blades for [llength $IDsectors] sectors...[exec date +%H:%M:%S]"
    } else { 
        switch $plane {
            x -
            y {
            }
            both {
                # Oh, I see what's going on
                set plane [list x y]
            }
            default {
                SetMainStatus "Invalid plane: $plane"
                return
            }
        }
        if !$zero {
            SetMainStatus "Transferring $plane orbit(s) to ${mode}s for $count BPMs...[exec date +%H:%M:%S]"
        } else {
            SetMainStatus "Setting $plane ${mode}s to 0 for $count BPMs...[exec date +%H:%M:%S]"
        }
    }
    switch $mode {
        IDbladesXfer {
            if [catch {exec cavput -list=S -list=[join $IDsectors ,] \
                           -list=ID:XferBladeOffsetC.PROC=1 -pend=30} result ] {
                SetMainStatus "Unable to transfer ID blades: $result"
            }
            SetMainStatus "Done."
            return
        }
        RFsetpointXfer -
        RFsetpointZero 
        {
            # include only bpms that have RF-related setpoints: [AB]:P[12345]
            #changesmadehere
            #set BPMsToChange [IndividualBPMsSelected -excludeXray 1 -useWildcard {[AB]P[12345]}]
	    # Actually not all P0s have a RfErrorM PV, so selecting P0s
	    # will make a cavget hang up. LEm 7/4/13
            set BPMsToChange [SelectedBPMList -excludeIDXray 1 -excludeBMXray 1 ]
            
            if ![llength $BPMsToChange] {
                SetMainStatus "No bpm selected matched the list of RF-related bpms."
                return
            }
            if [catch {exec cavget -pend=120 -list=[join $BPMsToChange ,] -lists=: \
                           -list=[join $plane ,] -list=: -list=$xferTo -dry} pvList] {
                SetMainStatus "$pvList"
                return
            }
            
            # include only bpms that have RF-related setpoints: [AB]:P[12345]
            if !$zero {
                if [catch {exec cavget -pend=120 -list=[join $BPMsToChange ,] -list=: \
                               -list=[join $plane ,] -list=:${readFrom} } dataList] {
                    SetMainStatus "$dataList"
                    return
                }
            } else {
                set dataList [APSReplicateItem -item 0.0 -number [llength $pvList]]
            }
        }
        default {
            # other transfers
            switch $plane {
                x -
                y {
                    set BPMsToChange [getnonBpm $BPMsToChange $plane]
                    if {![llength $BPMsToChange] && ![llength $SBBPMList]} {
                        SetMainStatus "Bpms selected do not work in plane $plane."
                        set pvList ""
			set pvList1 ""
                        if !$zero {
                            set dataList ""
			    set dataList1 ""
                        }
                    } else {
			set pvList ""
			set pvList1 ""
			set dataList ""
			set dataList1 ""
			if [llength $BPMsToChange] {
                 	    if [catch {exec cavget -pend=120 -list=[join $BPMsToChange ,] -list=: \
					   -list=[join $plane ,] -list=: -list=$xferTo -dry} pvList] {
				SetMainStatus "Error get PV names: [join $pvList]"
				return
			    }
			    if [string length $xferToy] {
				if [catch {exec cavget -pend=120 -list=[join $BPMsToChange ,] -list=: \
					       -list=y -list=: -list=$xferToy -dry} ypvList] {
				    SetMainStatus "Error get PV names: [join $ypvList]"
				    return
				}
				set pvList [concat $pvList $ypvList]
			    }
			}
			if [llength $SBBPMList] {
			    if [catch {exec cavget -pend=120 -list=[join $SBBPMList ,] -list=: \
					   -list=[join $plane ,] -list=: -list=$xferTo1 -dry} pvList1] {
				SetMainStatus "Error get SB PV list: [join $pvList1]"
				return
			    }
			}
			set pvList [concat $pvList $pvList1]
                        if !$zero {
			    if [llength $BPMsToChange] {
				if [catch {exec cavget -pend=120 -list=[join $BPMsToChange ,] -list=: \
					       -list=[join $plane ,] -list=:${readFrom} } dataList] {
				    SetMainStatus "Error reading orbit: $dataList"
				    return
				}
			    }
                 	    if [llength $SBBPMList] {
				if [catch {exec cavget -pend=120 -list=[join $SBBPMList ,] -list=: \
					       -list=[join $plane ,] -list=:${readFrom1}} dataList1] {
				    SetMainStatus "Error reading SB bpms: $dataList1"
				    return
				}
			    }
			    set dataList [concat $dataList $dataList1]
                      } else {
                            set dataList [APSReplicateItem -item 0.0 -number [llength $pvList]]
                        }
                    }
                }
                default {
                    # default is the {x y} list, i.e. do both planes together
                    set xList [getnonBpm $BPMsToChange x]
		    set xList1 ""
		    set pvXList ""
		    set pvXList1 ""
                    if {[llength $xList] || [llength $SBBPMList]} {
			if [llength $xList] {
			    if [catch {exec cavget -pend=120 -list=[join $xList ,] \
					   -list=:x -list=: -list=$xferTo -dry} pvXList] {
				SetMainStatus "$pvXList"
				return
			    }
			}
			if [llength $SBBPMList] {
			    if [catch {exec cavget -pend=120 -list=[join $SBBPMList ,] \
					   -list=:x -list=: -list=$xferTo1 -dry} pvXList1] {
				SetMainStatus "$pvXList1"
				return
			    }
			}
			set pvXList [concat $pvXList $pvXList1]
                        if !$zero {
			    set dataXList ""
			    set dataXList1 ""
			    if [llength $xList] {
				if [catch {exec cavget -pend=120 -list=[join $xList ,] \
					       -list=:x -list=:${readFrom} } dataXList] {
				    SetMainStatus "$dataXList"
				    return
				}
			    }
			    if [llength $SBBPMList] {
				if [catch {exec cavget -pend=120 -list=[join $SBBPMList ,] \
					       -list=:x -list=:${readFrom1} } dataXList1] {
				    SetMainStatus "$dataXList1"
				    return
				}
			    }
			    set dataXList [concat $dataXList $dataXList1]
                        } else {
                            set dataXList [APSReplicateItem -item 0.0 -number [llength $pvXList]]
                        }
                    } else {
                        SetMainStatus "Bpms selected work do not work in plane x."
                        set pvXList ""
                        set dataXList ""
                    }
                    set yList [getnonBpm $BPMsToChange y]
                    
                    if {[llength $yList] || [llength $SBBPMList]} {
			set pvYList ""
			set pvYList1 ""
			if [llength $yList] {
			    if [catch {exec cavget -pend=120 -list=[join $yList ,]  \
					   -list=:y -list=: -list=$xferTo -dry } pvYList] {
				SetMainStatus "$pvYList"
				return
			    }
			    if [string length $xferToy] {
				if [catch {exec cavget -pend=120 -list=[join $yList ,] -list=: \
					       -list=y -list=: -list=$xferToy -dry} ypvList] {
				    SetMainStatus "Error get PV names: [join $ypvList]"
				    return
				}
				set pvYList [concat $pvYList $ypvList]
			    }
			}
			if [llength $SBBPMList] {
			    if [catch {exec cavget -pend=120 -list=[join $SBBPMList ,]  \
					   -list=:y -list=: -list=$xferTo1 -dry } pvYList1] {
				SetMainStatus "$pvYList1"
				return
			    }
			}
			set pvYList [concat $pvYList $pvYList1]
                        if !$zero {
			    set dataYList ""
			    set dataYList1 ""
			    if [llength $yList] {
				if [catch {exec cavget -pend=120 -list=[join $yList ,] \
					       -list=:y -list=:${readFrom}} dataYList] {
				    SetMainStatus "$dataYList"
				    return
				}
			    } 
			    if [llength $SBBPMList] {
				if [catch {exec cavget -pend=120 -list=[join $SBBPMList ,] \
					       -list=:y -list=:${readFrom1}} dataYList1] {
				    SetMainStatus "$dataYList1"
				    return
				}
			    }
			    set dataYList [concat $dataYList $dataYList1]
                        } else {
                            set dataYList [APSReplicateItem -item 0.0 -number [llength $pvYList]]
			    
                        }
                    } else {
                        SetMainStatus "Bpms selected work do not work in plane y."
                        set pvYList ""
                        set dataYList ""
                    }
                    # combine the two lists
		    set pvList [concat $pvXList $pvYList]
		    set dataList [concat $dataXList $dataYList]
                }
            }
        }
    }
    if ![llength $pvList] {
        SetMainStatus "No transfers done."
        return
    }
    set xOptList ""
    set yOptList ""
    foreach pv $pvList datum $dataList {
	if [regexp ":x:" $pv] {
	    lappend xOptList $pv=$datum
	}
	if [regexp ":y:" $pv] {
	    lappend yOptList $pv=$datum
	}
        lappend commandOptList $pv=$datum
    }
    #split the one cavput command into two, because the commandline args is too long when setting both plabes.
    if $zero {
        # Just send zeros to all the items on the list
        #if [catch {exec cavput -pend=120 -list=[join $commandOptList ,]} result] {
        #    SetMainStatus "$result"
        #}
        #SetMainStatus "done."
        #return
        if [llength $xOptList] {
            if [catch {exec cavput -pend=30 -list=[join $xOptList ,]} result] {
                SetMainStatus "Error setting x plane PVs: $result"
            }
        }
        if [llength $yOptList] {
            if [catch {exec cavput -pend=30 -list=[join $yOptList ,]} result] {
                SetMainStatus "Error setting y plane PVs: $result"
	    }
        }
    } else {
        # Add the ErrorCC to the setpoints or offsets
        #if [catch {exec cavput -pend=120 -list=[join $commandOptList ,] -deltaMode} result] {
        #    SetMainStatus "$result"
        #}
	if [llength $xOptList] {
            if [catch {exec cavput -pend=30 -list=[join $xOptList ,] -delta} result] {
                SetMainStatus "Error setting x plane PVs: $result"
            }
        }
        if [llength $yOptList] {
            if [catch {exec cavput -pend=30 -list=[join $yOptList ,] -delta} result] {
                SetMainStatus "Error setting y plane PVs: $result"
            }
        }
    }
    SetMainStatus "Done."
}



proc SetMainStatus {text} {
    global mainStatus
    set mainStatus "$text"
    update
}


proc nonBpmfilter {plane} {
    set filename "/home/helios/oagData/sr/BPMStatus/config.sdds"
    if ![file exists $filename] {
        SetMainStatus "$filename for bmp's x or y plane's existence does not exist"
        return
    }
    if {![APSCheckSDDSFile -fileName $filename]} {
        SetMainStatus "$filename is not an SDDS file."
        return
    }
    set bpms [APSGetSDDSColumn -fileName $filename -column DeviceName]
    set noX [APSGetSDDSColumn -fileName $filename -column NonexistentH]
    set noY [APSGetSDDSColumn -fileName $filename -column NonexistentV]
    set xList ""
    set yList ""
    set total [llength $bpms]
    
    for {set i 0} {$i<$total} {incr i} {
        if ![lindex $noX $i] {
            lappend xList [lindex $bpms $i]
        }
        if ![lindex $noY $i] {
            lappend yList [lindex $bpms $i]
        }
    }
    switch $plane {
        x {
            return $xList
        }
        y {
            return $yList
        }
        default {
            return
        }
    }
}

proc getnonBpm {olist plane} {
    set list [nonBpmfilter $plane]
    set validList ""
    foreach bpm $olist {
	if [regexp {SB} $bpm] {
	    lappend validList $bpm
	}  elseif [string match *$bpm* $list] {
            lappend validList $bpm
        }
    }
    return $validList
}

proc MakeBPMSelectionFrame {widget args} {
    set parent ""
    global plane
    APSStrictParseArguments {parent}
    global rootname
    set rootname ""
    switch $plane {
        h {
            set rootname hconfig
        }
        v {
            set rootname vconfig
        }
        default {
            return -code error "The plane has to be h or v"
        }
    }
    set rootname vconfig
    if [winfo exist $parent$widget] {
        destroy $parent$widget
    }
    set BPMSuffixList [list A:P0 A:P1 A:P2 A:P3 A:P4 B:P5 B:P4 B:P3 B:P2 B:P1 B:P0 C:P0]
    
    
    set BPMMissingList [APSGetMissingBPMList -plane $plane]
    
    set includeP0s 1
    set includeIDs 0
    set includeBMs 0
    
    pack [frame $parent$widget]
    set wList [APSTabFrame .tab -parent $parent$widget -labelList {"Regular BPM" "SingleBunch BPM"} -width 1100 -height 500]
    set wA [lindex $wList 0]
    set wB [lindex $wList 1]
    APSFrame .up -parent $wA
    APSRadioButtonFrame .choosePlane -variable plane -valueList {h v} -buttonList {h v} \
	-parent $wA.up.frame -orientation vertical -packOption "-side left" -label "Plane" \
	-commandList {"setbpmPlane h" "setbpmPlane v"}
    
    #make file frame 
    APSFrame .read -parent $wA.up.frame \
        -contextHelp "Use this frame to read combine bpms."
    set w0 $wA.up.frame.read.frame
    global ${rootname}ReadFile ${rootname}ReadDescription ${rootname}Plane
    global ${rootname}FilterEnd1 ${rootname}MainDir ${rootname}LatSubDir ${rootname}Lattice
    set ${rootname}Plane $plane
    set ${rootname}ReadFile ${plane}.default
    set ${rootname}ReadDescription ""
    set ${rootname}FilterEnd1 .*
    set ${rootname}MainDir /home/helios/oagData/sr/orbitControllaw
    set ${rootname}LatSubDir lattices
    set ${rootname}Lattice default
    APSFrameGrid .grid -parent $w0 -xList {x1 x2}
    set w1 $w0.grid.x1
    set w2 $w0.grid.x2
    APSLabeledEntry .maindir -parent $w1 -label "Main directory: " \
        -textVariable ${rootname}MainDir -width 50 -contextHelp \
        "Enter the name of the main directory for the orbit correction system."
    APSFileSelectWidget .lattice -parent $w1 -label "Lattice: " \
        -pathVariableList [list ${rootname}MainDir ${rootname}LatSubDir] -mode directory -width 50 \
        -variable ${rootname}Lattice -incrementButtons 0 -contextHelp \
        "Enter the name of the lattice with which to work."
    APSFileSelectWidget .file -parent $w1 -variable ${rootname}ReadFile -label "Config: " \
        -pathVariableList [list ${rootname}MainDir ${rootname}LatSubDir ${rootname}Lattice] \
        -mode directory -filterVariableList \
        [list ${rootname}Plane ${rootname}FilterEnd1] -width 50 \
        -incrementButtons 1 -contextHelp \
        "Enter the name of the configuration file to read."
    
    APSButton .io0 -parent $w2 -text Read(replace) -size small -packOption "-side top" -command \
	"APSReadOrbitCorrectionConfig -rootname $rootname -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}ReadFile/config -logic replace -includeP0s $includeP0s -includeIDs $includeIDs -includeBMs $includeBMs -nameTypeList Monitor" \
	-contextHelp "Press to read data to replace the existing configuration, using the named configuration file."
    APSButton .io1 -parent $w2  -text Read(or) -size small -packOption "-side top" -command \
	"APSReadOrbitCorrectionConfig -rootname $rootname -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}ReadFile/config -logic or -includeP0s $includeP0s -includeIDs $includeIDs -includeBMs $includeBMs -nameTypeList Monitor" \
	-contextHelp "Press to read data to or with the existing configuration, using the named configuration file."
    APSButton .io2 -parent $w2 -text Read(and) -size small -packOption "-side top" -command \
	"APSReadOrbitCorrectionConfig -rootname $rootname -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}ReadFile/config -logic and -includeP0s $includeP0s -includeIDs $includeIDs -includeBMs $includeBMs -nameTypeList Monitor" \
	-contextHelp "Press to read data to and with the existing configuration, using the named configuration file." 
    APSButton .io3 -parent $w2 -text Read(not) -size small -packOption "-side top"  -command \
	"APSReadOrbitCorrectionConfig -rootname $rootname -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}ReadFile/config -logic not -includeP0s $includeP0s -includeIDs $includeIDs -includeBMs $includeBMs -nameTypeList Monitor" \
	-contextHelp "Press to read data specifying elements to turn off, using the named configuration file."
    #make cheack button frame
    APSFrame .but -parent $wA
    set w2 $wA.but.frame
    
    APSSRMonitorCheckButtons .smbut -parent $w2 -rootname $rootname -noLabel 1 -sectorControl 1 -packOption "-side top" \
        -orientation horizontal  -includeP0s 1 -includeIDs 0 -includeBMs 0 -colorDesc 1
    
    #make SB bpm selection
    #make Single bunch bpm selection frame
    APSFrame .sb -parent $wB -packOption "-side top"
    global sbSectorList sbItemList sbLabelList sbCBWidget
    set sbMissingList [exec sddsprocess /home/helios/oagData/sr/BPMStatus/config.sdds -pipe=out \
			   -match=col,DeviceName=*SB-* -filter=col,NonexistentV,1,1 -filter=col,NonexistentH,1,1 \
			   | sdds2stream -pipe=in -col=DeviceName]
    set missingList ""
    foreach name $sbMissingList {
	set name0 [regsub "SB\\-" $name ""]
	lappend missingList $name0
    }
    APSSRSectorButtons .sbbpm -parent $wB.sb.frame -rootname sb -label "Single Bunch BPMs" -colorDesc 0  -sectorControl 1 \
	-itemList $sbItemList -itemLabelList $sbLabelList -sectorList $sbSectorList -missingList $missingList
    APSSetSRSectorButtons -mode all-off -rootname sb  -itemList $sbItemList -sectorList $sbSectorList
    
}

#note this Plane is only for configuration files 

proc SelectedBPMList {args} {
    global Plane
    global rootname
    set sectorCount 40
    set excludeP0s 0
    set excludeIDXray 1
    set excludeBMXray 1
    set excludeFPGA 0
    set electronicsType *
    set useWildcard ""
    APSParseArguments {excludeP0s excludeIDXray useWildcard excludeBMXray electronicsType excludeFPGA}
    set BPMSuffixList [list A:P1 A:P2 A:P3 A:P4 A:P5 A:P6 B:P6 B:P5 B:P4 B:P3 B:P2 B:P1]
    set excludeSuffix ""
    if !$excludeP0s {
        set BPMSuffixList [concat A:P0 $BPMSuffixList B:P0 C:P0]
    } else {
        lappend excludeSuffix A:P0 B:P0 C:P0
    }
    if !$excludeIDXray {
        set BPMSuffixList [concat $BPMSuffixList ID:P1 ID:P2]
    } else {
        lappend excludeSuffix ID:P1 ID:P2
    }
    if !$excludeBMXray {
        set BPMSuffixList [concat $BPMSuffixList BM:P1 BM:P2]
    } else {
        lappend excludeSuffix BM:P1 BM:P2
    }
    set AllowedByElectronicsList ""
    if [string compare $electronicsType *]!=0 {
        if [catch {exec sddsprocess /home/helios/oagData/sr/BPMStatus/config.sdds -pipe=out \
                       -match=column,ElectronicsType=$electronicsType \
                       | sdds2stream -pipe -column=DeviceName} AllowedByElectronicsList] {
            SetMainStatus "Unable to get list of BPMs with electronics $electronicsType"
            return ""
        }
    }
    if $excludeFPGA {
        global FPGAbpmList
        if ![info exist FPGAbpmList] {
            if [catch {exec sddsprocess /home/helios/oagData/sr/BPMStatus/config.sdds -pipe=out \
                           -match=column,ElectronicsType=FPGA \
                           | sdds2stream -pipe -column=DeviceName} FPGAbpmList] {
                SetMainStatus "Unable to get list of BPMs with electronics FPGA"
                return ""
            }
        }
    }
    set names ""
    for {set sector 1} {$sector<=$sectorCount} {incr sector} {
	set sectorf [format %02d $sector]
        foreach exSuffix $excludeSuffix {
            set nameFlagx1 ${rootname}S${sectorf}$exSuffix
            global $nameFlagx1
            #  set $nameFlagx1 0
        }
        foreach suffix $BPMSuffixList {
            set nameFlagx ${rootname}S${sectorf}${suffix}
            global $nameFlagx 
            if {$useWildcard != "" && ![string match $useWildcard $suffix]} {
                #  set $nameFlagx 0
                continue
            }           
            if [set $nameFlagx] {
                if {![llength $AllowedByElectronicsList] || \
                        [lsearch -exact $AllowedByElectronicsList S${sectorf}${suffix}]!=-1} {
                    if $excludeFPGA {
                        if [lsearch -exact $FPGAbpmList S${sectorf}${suffix}]<0 {
                            lappend names S${sectorf}$suffix
                        }
                    } else {
                        lappend names S${sectorf}$suffix
                    }
                }
            }
        }
    }
    #got single bunch bpms
    global sbItemList sbSectorList SBBPMList
    set sbList ""
    foreach sector $sbSectorList {
	foreach item $sbItemList {
	    set var sb$sector$item
	    global $var
	    if [set $var] {
		#lappend sbList ${sector}[string index $item 0]-SB[string range $item 1 end]
		lappend sbList ${sector}SB-$item
	    }
	}
    }
    set SBBPMList $sbList
    return $names
}

proc setbpmPlane {value} {
    global plane rootname
    global ${rootname}ReadFile ${rootname}ReadDescription ${rootname}Plane
    global ${rootname}FilterEnd1 ${rootname}MainDir ${rootname}LatSubDir ${rootname}Lattice
    
    switch $value {
	h {
	    set plane h
	}
	v {
	    set plane v
	}
    }
    set ${rootname}Plane $plane
    set ${rootname}ReadFile ${plane}.default
    set ${rootname}ReadDescription ""
    set ${rootname}FilterEnd1 .*
    return
}

set xoffsetItemList {x:IncludeBpmZeroOffsetC x:IncludeBunchPatternOffsetC x:IncludeIntensityOffsetC x:IncludeOffset4C}
set yoffsetItemList {y:IncludeBpmZeroOffsetC y:IncludeBunchPatternOffsetC y:IncludeIntensityOffsetC y:IncludeOffset4C y:IncludeHydrostaticOffsetC}
set xoffsetVarList {xBpmZero xBunchPattern xIntensity xGeneric }
set yoffsetVarList {yBpmZero yBunchPattern yIntensity yGeneric yHydrostatic }
foreach var  [concat $xoffsetVarList $yoffsetVarList] {
    set $var 0
}
set xGeneric 1
set yGeneric 1

proc MakeOffsetOptsWidget {widget args} {
    set parent ""
    set plane ""
    set sectorControl 1
    APSParseArguments {parent plane sectorControl}
    global xoffsetItemList yoffsetItemList xoffsetVarList yoffsetVarList offsetbpmList offsetbpmLabelList xMissingList yMissingList
    global xOffsetCBWidget yOffsetCBWidget
    eval global $xoffsetVarList 
    eval global $yoffsetVarList
    switch $plane {
	x {
	    set plane0 h
	}
	y {
	    set plane0 v
	}
    }
    set rootname ${plane}Offset
    set missingList [set ${plane}MissingList]
    set sectorList ""
    for {set i 1} {$i<=40} {incr i} {
	lappend sectorList [format %02d $i]
    }
    APSSRSectorButtons .offset -parent $parent -rootname $rootname \
	-itemList $offsetbpmList -label "" -itemLabelList $offsetbpmLabelList -orientation horizontal \
	-sectorControl 1 -missingList $missingList -packOption "-side top" -colorDesc 0 
    
    global ${plane}OffsetCBWidget
    
    for {set sector 1} {$sector<=40} {incr sector} {
	set sectorf [format %02d $sector]
	foreach bpm $offsetbpmList {
	    set name S${sectorf}$bpm
	    if [lsearch -exact $missingList $name]==-1 {
		set AB [string index $bpm 0]
		set P [string index $bpm 3]
		set command "medm -attach -x -local -macro \"Sector=$sectorf,AB=$AB,P=$P\" /C2/screens/adl/systems/sr/Libera-Bplus/rfbpm_offsets_sector.adl"
		[set ${plane}OffsetCBWidget($name)] configure -selectcolor red -fg red \
		    -command "exec $command &"
	    }
	}
	
    }
    
    APSFrame .fn -parent $parent -packOption "-side top"
    set fn $parent.fn.frame
    switch $plane {
	x {
	    APSCheckButtonFrame .offsetx -parent $fn -label "Type of offsets to be included in the x offset sum:" \
		-buttonList $xoffsetVarList -variableList $xoffsetVarList -limitPerRow 4 -orientation horizontal  -allNone 1
	}
	y {
	    APSCheckButtonFrame .offsety -parent $fn -label "Type of offsets to be included in the y offset sum:" \
		-buttonList $yoffsetVarList -variableList $yoffsetVarList -limitPerRow 4 -orientation horizontal  -allNone 1
	}
    }
    global xrefBPM yrefBPM
    set xrefBPM S02A:P0
    set yrefBPM S02A:P0
    APSLabeledEntry .ref -parent $fn -label "Offset selection reference bpm (reference: red; BPMs of different offsetup: blue):" -textVariable ${plane}refBPM \
	-width 20
    APSButton .read -parent $fn -text "Read" -command "ReadOffsetSetup -plane $plane"
    APSButton .set -parent $fn -text "Set" -command "SetOffsetIncludes -plane $plane"

}

proc CheckOffsetSetup {args} {
    set bpm ""
    set plane ""
    APSStrictParseArguments {bpm plane}
    global xrefBPM yrefBPM offsetSetup xOffsetCBWidget yOffsetCBWidget
    set refBPM [set ${plane}refBPM]
    pv getw $offsetSetup($refBPM.${plane}varList)
    pv getw $offsetSetup($bpm.${plane}varList)
    update
    set refval ""
    foreach var $offsetSetup($refBPM.${plane}varList) {
	if {[set $var]=="Include"} {
	    append refval 1
	} else {
	    append refval 0
	}
    }
    set val ""
    foreach var $offsetSetup($bpm.${plane}varList) {
	if {[set $var]=="Include"} {
	    append val 1
	} else {
	    append val 0
	}
    }
    if {$val!=$refval} {
	SetMainStatus "$bpm $plane plane offset setup is different from the reference bpm $refBPM."
	[set ${plane}OffsetCBWidget($bpm)] configure -selectcolor blue -fg blue
    } else {
	SetMainStatus "$bpm $plane plane offset setup is the same as the reference bpm $refBPM."
	[set ${plane}OffsetCBWidget($bpm)] configure -selectcolor red -fg red
    }

}

set offsetSetup(xsetup) 0
set offsetSetup(ysetup) 0
proc ReadOffsetSetup {args} {
    global offsetbpmList refBPM offsetSetup xoffsetItemList yoffsetItemList xoffsetVarList yoffsetVarList errorCode xrefBPM yrefBPM
    eval global $xoffsetVarList
    eval global $yoffsetVarList
    global xOffsetCBWidget yOffsetCBWidget xMissingList yMissingList
    set plane x
    APSStrictParseArguments {plane}
    SetMainStatus "reading offsets setup for $plane plane..."
    set missingList [set ${plane}MissingList]
    set offsetItemList [set ${plane}offsetItemList]
    set offsetVarList [set ${plane}offsetVarList]
    set refBPM [set ${plane}refBPM]
    
    set pvList ""
    set varList ""
    global errorCode
    if !$offsetSetup(${plane}setup) {
	for {set sector 1} {$sector<=40} {incr sector} {
	    set sectorf [format %02d $sector]
	    foreach bpm $offsetbpmList {
		set name S$sectorf$bpm
		if [lsearch -exact $missingList $name]<0 {
		    set pvList0 ""
		    set varList0 ""
		    foreach item $offsetItemList var $offsetVarList {
			lappend pvList $name:$item
			lappend varList offsetSetup($name.$var)
			lappend pvList0 $name:$item
			lappend varList0 offsetSetup($name.$var)
		    }
		    set offsetSetup($name.${plane}pvList) $pvList0
		    set offsetSetup($name.${plane}varList) $varList0
		}
	    }
	}
	if [pv linkw $varList $pvList] {
	    return -code error "Error link pvs: $errorCode"
	}
	for {set sector 1} {$sector<=40} {incr sector} {
	    set sectorf [format %02d $sector]
	    foreach bpm $offsetbpmList {
		set name S$sectorf$bpm
		if [lsearch -exact $missingList $name]<0 {
		    foreach var $offsetSetup($name.${plane}varList) {
			pv umon $var "CheckOffsetSetup -bpm $name -plane $plane"
		    }
		}
	    }
	}
	set offsetSetup(${plane}varList) $varList
    }
    
    pv getw $offsetSetup(${plane}varList)
    update
    set value ""
    foreach var $offsetSetup($refBPM.${plane}varList) var0 [set ${plane}offsetVarList] {
	if {[set $var]=="Include"} {
	    set val0 1
	} else {
	    set val0 0
	}
	append value $val0
	set $var0 $val0
    }
    set offsetSetup($refBPM.${plane}value) $value
    
    [set ${plane}OffsetCBWidget($refBPM)] configure -selectcolor red -fg red
    
    for {set sector 1} {$sector<=40} {incr sector} {
	set sectorf [format %02d $sector]
	foreach bpm $offsetbpmList {
	    set name S$sectorf$bpm
	    if [lsearch -exact $missingList $name]>=0 {
		continue
	    }
	    set value ""
	    foreach var $offsetSetup($name.${plane}varList) {
		if {[set $var]=="Include"} {
		    set val0 1
		} else {
		    set val0 0
		}
		append value $val0
	    }
	    if {$value!=$offsetSetup($refBPM.${plane}value)} {
		SetMainStatus "$name $plane plane  offsets setup is different from reference ($refBPM)"
		[set ${plane}OffsetCBWidget($name)] configure -selectcolor blue -fg blue
	    } else {
		[set ${plane}OffsetCBWidget($name)] configure -selectcolor red -fg red
	    }
	}
    }
    
    set offsetSetup(${plane}setup) 1
    SetMainStatus "done."
}

proc SetOffsetIncludes {args} {
    set plane ""
    APSStrictParseArguments {plane}
    global xoffsetVarList yoffsetVarList xoffsetItemList yoffsetItemList xMissingList yMissingList offsetbpmList offsetSetup
    eval global $xoffsetVarList 
    eval global $yoffsetVarList
    set missingList [set ${plane}MissingList]
    set valList ""
    for {set sector 1} {$sector<=40} {incr sector} {
	set sectorf [format %02d $sector]
	foreach bpm $offsetbpmList {
	    set name S$sectorf$bpm
	    if [lsearch -exact $missingList $name]>=0 {
		continue
	    }
	    foreach var [set ${plane}offsetVarList] var0 $offsetSetup($name.${plane}varList) pv $offsetSetup($name.${plane}pvList) {
		set $var0 [set $var]
		update
		lappend varList $var0
	    }
	}
    }
    
    SetMainStatus "Set offsets setup for $plane plane...."
    pv putw $varList
    update
    SetMainStatus "confirm..."
    ReadOffsetSetup -plane $plane
    SetMainStatus "done."
}

#medm -x -attach -macro "Sector=01,AB=A,P=0" /C2/iocs/SrBpmOffset/master/opi/adl/rfbpm_offsets_simsector.adl 
set xMissingList [APSGetMissingBPMList -plane x]
set yMissingList [APSGetMissingBPMList -plane y]

set mainStatus "Working..."
APSScrolledStatus .status -parent .userFrame -textVariable mainStatus -width 80 \
    -height 4
update
set sbSectorList {S40 S01 S02}
set sbItemList {A:P1 A:P3 A:P5 B:P5 B:P3 B:P1}
set sbLabelList {A1 A3 A5 B5 B3 B1}

set wList [APSTabFrame .tab -parent .userFrame -labelList {"BPM orbit transfer" "x offset setup" "y offset setup"} -height 860 -width 1050]
set w1 [lindex $wList 0]
set w2 [lindex $wList 1]
set w3 [lindex $wList 2]

set plane v
MakeBPMSelectionFrame .bpm -parent $w1
update
MakeIndividualOpsWidget .indivOps -parent $w1

MakeOffsetOptsWidget .offset -parent $w2 -plane x
MakeOffsetOptsWidget .offset -parent $w3 -plane y
SelectedBPMList
ReadOffsetSetup -plane x
ReadOffsetSetup -plane y

SetMainStatus "Ready."
