#!/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  {L1:P1:x L2:P1:x L2:P2:x L2:P3:x L2:P4:x L3:P1:x L3:P2:x L3:P3:x L4:P2:x L4:P3:x L4:P4:x L5:P2:x L5:P3:x L5:P4:x}
set bpmVList  {L1:P1:y L2:P1:y L2:P2:y L2:P3:y L2:P4:y L3:P1:y L3:P2:y L3:P3:y L4:P2:y L4:P3:y L4:P4:y L5:P2:y L5:P3:y L5:P4:y}
set bpmHVarList {L1P1x L2P1x L2P2x L2P3x L2P4x L3P1x L3P2x L3P3x L4P2x L4P3x L4P4x L5P2x L5P3x L5P4x}
set bpmVVarList {L1P1y L2P1y L2P2y L2P3y L2P4y L3P1y L3P2y L3P3y L4P2y L4P3y L4P4y L5P2y L5P3y L5P4y}

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

set ControlStatus "Ready."

proc MakeLinacBPMSetpointConfigMenuAndStatus {} {

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

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

                .menu.controlLaw.menu add command -label "Linac ControlLaw" \
                        -command {exec controllaw -controlList "l2 l4 l5" &}
                .menu.controlLaw.menu add command -label "Linac BPM Setpoints Screen" \
                        -command {exec medm -attach -x ./linac/LI_bpm_setpoints.adl >& /dev/null &}

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

# Make checkbuttons for linac BPMs and execution button.

proc MakeBPMCheckbuttonAndExecuteFrame {widget args} {

        global bpmHList bpmVList bpmHVarList bpmVVarList

        set parent ""
        APSParseArguments {parent}

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

        set w $parent$widget.frame

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

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

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

# Status line update procedure

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

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

proc SetLinacBPMSetpoints {args} {

        global bpmHList bpmVList bpmHVarList bpmVVarList HValList VValList
    global L1P1x L2P1x L2P2x L2P3x L2P4x L3P1x L3P2x L3P3x L4P2x L4P3x L4P4x L5P2x L5P3x L5P4x
    global L1P1y L2P1y L2P2y L2P3y L2P4y L3P1y L3P2y L3P3y L4P2y L4P3y L4P4y L5P2y L5P3y L5P4y

        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"
#                        lappend HCavgetCommandList "$hbpm:x"
                }
                if {$VBPMChoice==1} {
                        set vbpm [lindex $bpmVList $listindex]
                        lappend VBPMSelectList $vbpm
                        lappend VCavgetCommandList "$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 linac 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 L1P1x L2P1x L2P2x L2P3x L2P4x L3P1x L3P2x L3P3x L4P2x L4P3x L4P4x L5P2x L5P3x L5P4x
    global L1P1y L2P1y L2P2y L2P3y L2P4y L3P1y L3P2y L3P3y L4P2y L4P3y L4P4y L5P2y L5P3y L5P4y

        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

MakeLinacBPMSetpointConfigMenuAndStatus
MakeBPMCheckbuttonAndExecuteFrame .bpmFrame -parent .userFrame
