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


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

set bpmHList {PTB:PH1 PTB:PH2 PTB:PH3 PTB:PH4 PTB:PH5}
set bpmVList {PTB:PV1 PTB:PV2 PTB:PV3 PTB:PV4 PTB:PV5}
set bpmHVarList {PTBPH1 PTBPH2 PTBPH3 PTBPH4 PTBPH5}
set bpmVVarList {PTBPV1 PTBPV2 PTBPV3 PTBPV4 PTBPV5}

# Set PTB BPM setpoints to the current BPM readback values.  Used in conjunction with controlLaw to steer
# to an arbitrary trajectory.

set ControlStatus "Ready."

proc MakePTBBPMSetpointConfigMenuAndStatus {} {

        APSApplication . -name "PTBBPMSetpointConfig" -version "1.0" \
                         -overview "This is an application to set the PTB BPM setpoints to the current BPM readbacks"

        APSMenubarAddMenu .controlLaw -parent .menu -text "ControlLaw"

                .menu.controlLaw.menu add command -label "PTB ControlLaw" \
                        -command {exec controllaw -controlList "ptb" &}

        APSScrolledStatus .status -parent .userFrame -textVariable ControlStatus \
                          -height 8 -width 65 -packOption {-side top}
}

# Make checkbuttons for PTB BPMs and execution button.

proc MakePTBBPMCheckbuttonAndExecuteFrame {widget args} {

        global bpmHList bpmVList bpmHVarList bpmVVarList

        set parent ""
        APSParseArguments {parent}

        APSFrame $widget -parent $parent -label "PTB BPM Selection" \
                   -packOption {-side left -expand 1 -fill x} \
                   -contextHelp "Selection panel for PTB BPMs."

        set w $parent$widget.frame

        APSCheckButtonFrame .bpmHButtons -parent $w \
                   -label "Horizontal\nPTB BPMs" -buttonList $bpmHList \
                   -variableList "$bpmHVarList" -allNone 1 \
                   -packOption {-side left -expand 1} \
                   -contextHelp "Horizontal PTB BPM selection panel."

        APSButton .transferButton -parent $w \
                   -text "Transfer PTB Readbacks To\nControlLaw Setpoints" \
                   -command {SetPTBBPMSetpoints -statusCallback SetStatus} \
                   -packOption {-side left -expand 1} \
                   -contextHelp "This button transfers current PTB BPM readbacks to controllaw setpoints"

        APSCheckButtonFrame .bpmVButtons -parent $w \
                                -label "Vertical\nPTB BPMs" -buttonList $bpmVList \
                                -variableList "$bpmVVarList" -allNone 1 \
                                -packOption {-side left -expand 1} \
                                -contextHelp "Vertical PTB BPM selection panel."
}

# Status line update procedure

proc SetStatus {text} {
        global ControlStatus
        set ControlStatus $text     
        update
}

# procedure to set PTB bpm steering setpoints to bpm readback values.

proc SetPTBBPMSetpoints {args} {

        global bpmHList bpmVList bpmHVarList bpmVVarList HValList VValList
        global PTBPH1 PTBPH2 PTBPH3 PTBPH4 PTBPH5
        global PTBPV1 PTBPV2 PTBPV3 PTBPV4 PTBPV5

        APSParseArguments {statusCallback}

        if {$statusCallback!=""} {
                $statusCallback "Getting 10 BPM readbacks for selected BPMs and averaging..."
        }

        set listindex 0 
        set HBPMSelectList ""
        set HCavgetCommandList ""
        set HCavputCommandList ""
        set VBPMSelectList ""
        set VCavgetCommandList ""
        set VCavputCommandList ""
        
        foreach hbpm $bpmHList {

                set HBPMChoice [subst $[lindex $bpmHVarList $listindex]]
                set VBPMChoice [subst $[lindex $bpmVVarList $listindex]]

                if {$HBPMChoice==1} {
                        lappend HBPMSelectList $hbpm
                        lappend HCavgetCommandList "$hbpm:x"
                }
                if {$VBPMChoice==1} {
                        set vbpm [lindex $bpmVList $listindex]
                        lappend VBPMSelectList $vbpm
                        lappend VCavgetCommandList "$vbpm:y"
                }
        incr listindex
        }
        if {$HBPMSelectList!="" && $VBPMSelectList!=""} {
                set HBPMCavgetCommand [cavputcavgetMakeCommand cavget $HCavgetCommandList]
                set VBPMCavgetCommand [cavputcavgetMakeCommand cavget $VCavgetCommandList]
                set HValList [eval exec $HBPMCavgetCommand]   
                ConvertListToArray $HValList $HBPMSelectList HBPMValueArray
                set VValList [eval exec $VBPMCavgetCommand]
                ConvertListToArray $VValList $VBPMSelectList VBPMValueArray
                set HCavputCommandList [ComposeCavputCommandList H HBPMValueArray]
                set VCavputCommandList [ComposeCavputCommandList V VBPMValueArray]
                set HBPMCavputCommand [cavputcavgetMakeCommand cavput $HCavputCommandList]
                set VBPMCavputCommand [cavputcavgetMakeCommand cavput $VCavputCommandList]
                eval exec $HBPMCavputCommand
                eval exec $VBPMCavputCommand
                if {$statusCallback!=""} {
                        $statusCallback "Horizontal average BPM readbacks transferred to controllaw setpoints for:\n$HBPMSelectList"
                        $statusCallback "Vertical average BPM readbacks transferred to controllaw setpoints for:\n$VBPMSelectList."
                }
                bell
        } elseif {$HBPMSelectList!="" && $VBPMSelectList==""} {
                set HBPMCavgetCommand [cavputcavgetMakeCommand cavget $HCavgetCommandList]
                set HValList [eval exec $HBPMCavgetCommand]
                ConvertListToArray $HValList $HBPMSelectList HBPMValueArray
                set HCavputCommandList [ComposeCavputCommandList H HBPMValueArray]
                set HBPMCavputCommand [cavputcavgetMakeCommand cavput $HCavputCommandList]
                eval exec $HBPMCavputCommand   
                if {$statusCallback!=""} {
                        $statusCallback "Horizontal average BPM readbacks transferred to controllaw setpoints for:\n$HBPMSelectList"
                }
                bell
        } elseif {$HBPMSelectList=="" && $VBPMSelectList!=""} {
                set VBPMCavgetCommand [cavputcavgetMakeCommand cavget $VCavgetCommandList]
                set VValList [eval exec $VBPMCavgetCommand]
                ConvertListToArray $VValList $VBPMSelectList VBPMValueArray
                set VCavputCommandList [ComposeCavputCommandList V VBPMValueArray]
                set VBPMCavputCommand [cavputcavgetMakeCommand cavput $VCavputCommandList]
                eval exec $VBPMCavputCommand
                if {$statusCallback!=""} {
                        $statusCallback "Vertical average BPM readbacks transferred to controllaw setpoints for:\n$VBPMSelectList"
                }
                bell
        } else {
                if {$statusCallback!=""} {
                        $statusCallback "No BPMs selected."
                }
                bell
        }
}

# procedure to compose cavput/cavget commands.  Added average option to cavget to average 10
# samples at 1 second intervals.

proc cavputcavgetMakeCommand {action commandList} {

        if {$action=="cavput"} {
                set beforeLastCommaIndex [expr [llength $commandList] - 1]
                set listCommand [lrange $commandList 0 $beforeLastCommaIndex]
                set listCommand [join $listCommand {,}]
                set cavputCommand "-list="
                lappend cavputCommand $listCommand
                set cavputCommand [join $cavputCommand {}]
                set finalcavputCommand "cavput"
                lappend finalcavputCommand $cavputCommand
                return $finalcavputCommand
        } elseif {$action=="cavget"} {
                set beforeLastCommaIndex [expr [llength $commandList] - 1]
                set listCommand [lrange $commandList 0 $beforeLastCommaIndex]
                set listCommand [join $listCommand {,}]
                set cavgetCommand "-list="
                lappend cavgetCommand $listCommand
                set cavgetCommand [join $cavgetCommand {}]
                set finalcavgetCommand "cavget"
                lappend finalcavgetCommand $cavgetCommand "-repeat=number=10,average,pause=1"
                return $finalcavgetCommand
        } else {return 0}
}

# procedure to set PTB BPM setpoint variables to readback values.  Returns a list of cavput commands.  Returns 0
# if no list is created.

proc ComposeCavputCommandList {plane valueArray} {

        global $valueArray
        upvar $valueArray valueArrayName
        global bpmHList bpmVList bpmHVarList bpmVVarList 
        global PTBPH1 PTBPH2 PTBPH3 PTBPH4 PTBPH5
        global PTBPV1 PTBPV2 PTBPV3 PTBPV4 PTBPV5

        set listindex 0

        foreach hbpm $bpmHList {

                set HBPMChoice [subst $[lindex $bpmHVarList $listindex]]
                set VBPMChoice [subst $[lindex $bpmVVarList $listindex]]

                if {$HBPMChoice==1 && $plane=="H"} {
                        lappend HCavputCommandList "$hbpm:SetpointAO=$valueArrayName($hbpm)"
                }
                if {$VBPMChoice==1 && $plane=="V"} {
                        set vbpm [lindex $bpmVList $listindex]
                        lappend VCavputCommandList "$vbpm:SetpointAO=$valueArrayName($vbpm)"
                }
        incr listindex
        }
        if {$plane=="H"} {
                return $HCavputCommandList
        } elseif {$plane=="V"} {
                return $VCavputCommandList
        } else {return 0}
}

# Converts a list to a 1 dimensional array indexed by an index list of the same number of items as the list or less
# If the index list has more items than the list, the resulting list is padded with zeros at the end
# If both lists are null, the array returned is a one element array containing 0
# N. Sereno

proc ConvertListToArray {list indexlist arrayName} {

        global $arrayName
        upvar $arrayName arrayname
        
        set listlength [llength $list]
        set indexlistlength [llength $indexlist]

        set listindex 0
        foreach item $indexlist {

                set arrayname($item) [lindex $list $listindex]
                if {$listindex >= $listlength} {set arrayname($item) 0}
                incr listindex 1
        }

        if {($listlength == 0) && ($indexlistlength == 0)} {set arrayname(0) 0}
}

# Build Application

MakePTBBPMSetpointConfigMenuAndStatus
MakePTBBPMCheckbuttonAndExecuteFrame .bpmFrame -parent .userFrame
