#!/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  {BTS:APH1 BTS:APH2 BTS:APH3 BTS:BPH1 BTS:BPH2 BTS:CPH1 BTS:CPH2 BTX:PH1}
set bpmVList  {BTS:APV1 BTS:APV2 BTS:APV3 BTS:BPV1 BTS:BPV2 BTS:CPV1 BTS:CPV2 BTX:PV1}
set bpmHVarList {BTSAPH1 BTSAPH2 BTSAPH3 BTSBPH1 BTSBPH2 BTSCPH1 BTSCPH2 BTXPH1}
set bpmVVarList {BTSAPV1 BTSAPV2 BTSAPV3 BTSBPV1 BTSBPV2 BTSCPV1 BTSCPV2 BTXPV1}
set numberToAverage 10

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

set ControlStatus "Ready."

proc MakeBTSBPMSetpointConfigMenuAndStatus {} {

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

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

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

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

# Make checkbuttons for BTS BPMs and execution button.

proc MakeBTSBPMCheckbuttonAndExecuteFrame {widget args} {

    global bpmHList bpmVList bpmHVarList bpmVVarList numberToAverage

    set parent ""
    APSParseArguments {parent}

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

    set w $parent$widget.frame

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

    APSFrame .middle -parent $w -label "" -relief flat \
      -packOption {-side left -expand 1}

    APSButton .transferButton -parent $w.middle.frame \
      -text "Transfer BTS BPM Readbacks To\nControlLaw Setpoints" \
      -command {SetBTSBPMSetpoints -statusCallback SetStatus} \
      -contextHelp "This button transfers current BTS BPM readbacks to controllaw setpoints" \
      -packOption {-side top}
    APSLabeledEntry .averages -parent $w.middle.frame \
      -label "Number to average: " -width 5 \
      -textVariable numberToAverage \
      -contextHelp "Enter the number of trajectory readings to average to get the values for the setpoints." \
      -packOption {-side top}

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

# Status line update procedure

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

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

proc SetBTSBPMSetpoints {args} {

    global bpmHList bpmVList bpmHVarList bpmVVarList HValList VValList numberToAverage
    global BTSAPH1 BTSAPH2 BTSAPH3 BTSBPH1 BTSBPH2 BTSCPH1 BTSCPH2 BTXPH1
    global BTSAPV1 BTSAPV2 BTSAPV3 BTSBPV1 BTSBPV2 BTSCPV1 BTSCPV2 BTXPV1

    APSParseArguments {statusCallback}

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

    set listindex 0 
    set HBPMSelectList ""
    set HCavgetCommandList ""
    set HCavputCommandList ""
    set VBPMSelectList ""
    set VCavgetCommandList ""
    set VCavputCommandList ""

    set prototypeHBPMs [list BTS:APH2 BTS:APH3]

    foreach hbpm $bpmHList {
        set HBPMChoice [subst $[lindex $bpmHVarList $listindex]]
        set VBPMChoice [subst $[lindex $bpmVVarList $listindex]]
        if {$HBPMChoice==1} {
            lappend HBPMSelectList $hbpm
            if {[lsearch -exact $prototypeHBPMs $hbpm] > -1} {
                lappend HCavgetCommandList "$hbpm:BPM.CX"
            } else {
                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]
        puts stderr "HValList $HValList"
        ConvertListToArray $HValList $HBPMSelectList HBPMValueArray
        set HCavputCommandList [ComposeCavputCommandList H HBPMValueArray]
        set HBPMCavputCommand [cavputcavgetMakeCommand cavput $HCavputCommandList]
        eval exec $HBPMCavputCommand   
        puts stderr "HBPMCavputCommand $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 
# $numberToAverage samples at 1 second intervals.

proc cavputcavgetMakeCommand {action commandList} {
    global numberToAverage
    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=$numberToAverage,average,pause=1"
        return $finalcavgetCommand
    } else {return 0}
}

# procedure to set BTS 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 BTSAPH1 BTSAPH2 BTSAPH3 BTSBPH1 BTSBPH2 BTSCPH1 BTSCPH2 BTXPH1
    global BTSAPV1 BTSAPV2 BTSAPV3 BTSBPV1 BTSBPV2 BTSCPV1 BTSCPV2 BTXPV1

    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

MakeBTSBPMSetpointConfigMenuAndStatus
MakeBTSBPMCheckbuttonAndExecuteFrame .bpmFrame -parent .userFrame
