#!/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)]
APSDebugPath

proc MakeConnections {} {
    global epicsVarList errorCode
    set epicsVarList [list TopUpState TopUpIntervals TopUpWarning TopUpInterval \
                        L5P4Sum LTPPH1Sum \
                        LIVD1Gate LIVD1Background LIVD1ImageSource \
                        LIVD1FirstField LIVD1CaptureMode \
                        PARFL3Actuator LTPFL1Actuator L3FS1Actuator \
                        PARFL3CameraSelect LTPFL1CameraSelect \
                        PARFL3Lamp LTPFL1Lamp RemoveLinacFlags RemoveLETFlags \
                        PARMuxSelect LTPXControlLawStatus L2AutoPhaseHoldAtMeas L5AutoPhaseHoldAtMeas \
                        L2PowerStabilizerSusp]
    foreach var $epicsVarList {
        global $var
        set $var 0
    }
    set pvList [list Mt:TopUpAutoEnableC Mt:TopUpIntervals2Inject \
                  Mt:TopUpWarning Mt:TopUpIntervalP L5:P4:BPM.VAL LTP:PH1:BPM.VAL \
                  LI:VD1:cameraTrigDelayPD.GATE LI:VD1:bkgndCaptureRateC LI:VD1:imageSourceC \
                  LI:VD1:firstFieldC LI:VD1:captureModeC \
                  PAR:FL3:act_cont_bo LTP:FL1:act_cont_bo L3:FS1:ActPosC \
                  PAR:FL3:SelectCamC.PROC LTP:FLN:SelSeq1.PROC \
                  PAR:FL3:LampOn LTP:FL1:LampOn LI:VD:allScreensOutSQ PAR:FLN:act_withdraw_all_seq.PROC \
                  LI:VD1:MUX:mv20SelectGrp1C LTP:ControlLawXRC.RUN L2:AUTO:PH:holdAtMeasdBO L5:AUTO:PH:holdAtMeasdBO \
                  L:L2Stabilizer:SDDS.SUSP]
    if [pv linkw $epicsVarList $pvList] {
        return -code error "pv problem: $errorCode"
    }
}

proc MakeL3FS1Frame {widget args} {
    set parent ""
    APSStrictParseArguments {parent}
    APSFrame $widget -parent $parent -label "L3:FS1"
    global L3FS1
    set L3FS1(TransmissionVar) L5P4Sum
    set L3FS1(TransmissionLimit) 0.003
    set L3FS1(FlagRoot) L3:FS1
    set L3FS1(CameraSelectVar) ""
    set L3FS1(LampVar) ""
    set L3FS1(ActuatorVar) L3FS1Actuator
    set L3FS1(Enabled) 0

    APSRadioButtonFrame .rb1 -parent $parent$widget.frame -label "Enable? " \
      -variable L3FS1(Enabled) -buttonList "Yes No" -valueList "1 0" \
      -orientation horizontal
    
}

proc MakeLTPFL1Frame {widget args} {
    set parent ""
    APSStrictParseArguments {parent}
    APSFrame $widget -parent $parent -label "LTP:FL1"
    global LTPFL1
    set LTPFL1(TransmissionVar) LTPPH1Sum
    set LTPFL1(TransmissionLimit) 3.0
    set LTPFL1(FlagRoot) LTP:FL1
    set LTPFL1(ActuatorVar) LTPFL1Actuator
    set LTPFL1(LampVar) LTPFL1Lamp
    set LTPFL1(CameraSelectVar) LTPFL1CameraSelect
    set LTPFL1(Enabled) 0

    APSRadioButtonFrame .rb1 -parent $parent$widget.frame -label "Enable? " \
      -variable LTPFL1(Enabled) -buttonList "Yes No" -valueList "1 0" \
      -orientation horizontal
}

proc MakePARFL3Frame {widget args} {
    set parent ""
    APSStrictParseArguments {parent}
    APSFrame $widget -parent $parent -label "PAR:FL3"
    global PARFL3
    set PARFL3(TransmissionVar) LTPPH1Sum
    set PARFL3(TransmissionLimit) 3.0
    set PARFL3(FlagRoot) PAR:FL3
    set PARFL3(ActuatorVar) PARFL3Actuator
    set PARFL3(LampVar) PARFL3Lamp
    set PARFL3(CameraSelectVar) PARFL3CameraSelect
    set PARFL3(Enabled) 0

    APSRadioButtonFrame .rb1 -parent $parent$widget.frame -label "Enable? " \
      -variable PARFL3(Enabled) -buttonList "Yes No" -valueList "1 0" \
      -orientation horizontal
}
    
proc BuildApplication {parent} {
    APSScrolledStatus .status -parent $parent -textVariable status -height 15 -width 60

    MakeL3FS1Frame  .l3fs1 -parent $parent
    MakeLTPFL1Frame .ltpfl1 -parent $parent 
    MakePARFL3Frame .parfl3 -parent $parent

    APSButton .run -parent $parent -text "Run" -command "Run -parent $parent"
    APSButton .stop -parent $parent -text "Stop" -command "Stop -parent $parent"
    APSDisableWidget $parent.stop
}

proc Run {args} {
    global abortAdjustment errorCode epicsVarList
    eval global $epicsVarList

    set abortAdjustment 0
    set parent ""
    APSStrictParseArguments {parent}

    APSDisableButton $parent.run.button
    APSEnableButton $parent.stop.button

    while {!$abortAdjustment} {
        setStatus "Running."
        foreach rootname {L3FS1 LTPFL1 PARFL3} {
            set justWaited 0
            global $rootname

            set flagRoot [set ${rootname}(FlagRoot)]
            set cameraSelectVar [set ${rootname}(CameraSelectVar)]
            set lampVar [set ${rootname}(LampVar)]
            set actuatorVar [set ${rootname}(ActuatorVar)]
            if ![set ${rootname}(Enabled)] {
                setStatus "$rootname not enabled."
                continue
            }

            setStatus "Working on $rootname."
            bell

            if [pv getw $epicsVarList] {
                setStatus "PV problem: $errorCode"
                break
            }
            
            if [string compare $TopUpState "Enable"]==0 {
                setStatus "Waiting for top-up to complete."
                # Need to insert the required code here!
            }
            if $abortAdjustment break

            RemoveFlags

            setStatus "Enabling kickers"
            if [catch {
                switch $rootname {
                    PARFL3 {
                        TogglePulsedMagnetEnables -location PAR
                    } 
                    default {
                        TogglePulsedMagnetEnables -location Gun
                    }
                }
            } result] {
                bell
                setStatus "$result"
                break
            }
            if $abortAdjustment break

            setStatus "Checking transmission"
            APSWaitWithUpdate -waitSeconds 4 -updateInterval 1
            if [pv getw $epicsVarList] {
                bell
                setStatus "PV problem: $errorCode"
                break
            }
            if {[expr [set [set ${rootname}(TransmissionVar)]]<[set ${rootname}(TransmissionLimit)]]} {
                bell
                setStatus "Poor transmission: [set [set ${rootname}(TransmissionVar)]]<[set ${rootname}(TransmissionLimit)]."
                break
            }
            if $abortAdjustment break

            setStatus "Selecting camera and inserting flag"
                if [catch {
                    switch $rootname {
                        L3FS1 {
                            APSConfigureCameraAndScreenPVs \
                              -flagIn 1 -lampOn 0 -flag L3:FS1 -actuatorNumber 1 \
                              -statusCallback setStatus -cameraType CCDH -system LEUTL
                        }
                        PARFL3 {
                            exec cavput -list=PAR:FL4:act_cont_bo.VAL=1
                            after 2000
                            set $cameraSelectVar 1
                            set $actuatorVar 1
                            set $lampVar 0
                            set PARMuxSelect "PAR V-Mux"
                            pv putw [list $cameraSelectVar $actuatorVar $lampVar PARMuxSelect]
                        }
                        default {
                            set $cameraSelectVar 1
                            set $actuatorVar 1
                            set $lampVar 0
                            set PARMuxSelect "PAR V-Mux"
                            pv putw [list $cameraSelectVar $actuatorVar $lampVar PARMuxSelect]
                        }
                    }
                } result] {
                    bell
                    RemoveFlags
                    setStatus "$result"
                    break
                }
                
            set LIVD1Gate Enable
            set LIVD1Background "2 Hz"
            set LIVD1FirstField Odd
            set LIVD1ImageSource Subtracted
            set LIVD1CaptureMode "Ext. Trigger"
            if [pv putw [list LIVD1Gate LIVD1Background LIVD1FirstField LIVD1ImageSource LIVD1CaptureMode]] {
                bell
                setStatus "$errorCode"
                RemoveFlags
                break
            }
            if $abortAdjustment break

            setStatus "Setting MV200 ROI"
            APSWaitWithUpdate -waitSeconds 4 -updateInterval 1
            if [catch {APSSetLinacFlagROI \
                         -flagList $rootname -alreadyInserted 1 -statusCallback setStatus \
                         -xMinSize 500 -yMinSize 75 -clipSize 25 -suppressNoise 1} result] {
                bell
                setStatus "$result"
                RemoveFlags
                break
            }

            switch $rootname {
                L3FS1 {
                    DoL3FS1Optimization
                }
                LTPFL1 {
                    DoLTPFL1Optimization
                }
                PARFL3 {
                    DoPARFL3Optimization
                }
                default {
                    setStatus "Don't know what to do for $rootname yet!"
                    setStatus "Waiting 30s"
                    APSWaitWithUpdate -waitSeconds 30 -updateInterval 1 -abortVariable abortAdjustment
                }
            }

            # Remove flag
            set $actuatorVar 0
            if [pv putw $actuatorVar] {
                bell
                setStatus "$errorCode"
                break
            }
            if $abortAdjustment break

            # Check transmission
            setStatus "Checking transmission"
            APSWaitWithUpdate -waitSeconds 4 -updateInterval 1
            if [pv getw $epicsVarList] {
                setStatus "PV problem: $errorCode"
                break
            }
            if {[expr [set [set ${rootname}(TransmissionVar)]]<[set ${rootname}(TransmissionLimit)]]} {
                bell
                setStatus "Poor transmission: [set [set ${rootname}(TransmissionVar)]]<[set ${rootname}(TransmissionLimit)]."
                break
            }
            if $abortAdjustment break

            # Turn off kickers
            setStatus "Turning off kickers"
            if [catch {
                switch $rootname {
                    PARFL3 {
                        SetPulsedMagnetEnables -location PAR -state 0
                    } 
                    default {
                        SetPulsedMagnetEnables -location Gun -state 0
                    }
                }
            } result] {
                bell
                setStatus "$result"
                break
            }
            if $abortAdjustment break

            setStatus "Waiting 10s "
            APSWaitWithUpdate -waitSeconds 10 -updateInterval 1 -abortVariable abortAdjustment
            set justWaited 1
            if $abortAdjustment break
            # end of loop over flags
        }
        if !$abortAdjustment {
            if !$justWaited {
                setStatus "Waiting 10s "
                APSWaitWithUpdate -waitSeconds 10 -updateInterval 1 -abortVariable abortAdjustment
            }
        } else {
            RemoveFlags
        }
    }

    APSEnableButton $parent.run.button
    APSDisableButton $parent.stop.button
    setStatus "Ready."
}

proc DoPARFL3Optimization {} {
    global errorCode abortAdjustment epicsVarList
    eval global $epicsVarList

    # Need to ensure that LTP x controllaw is running
    if [pv getw LTPXControlLawStatus] {
        return -code error "$errorCode"
    }
    if !$LTPXControlLawStatus {
        setStatus "LTP x controllaw is not running. Please start it."
        bell
        after 1000
        bell
        return
    }

    if !$abortAdjustment {
        # need to start L5 phase feedback (hold at present)
        set L5AutoPhaseHoldAtMeas 1
        if [pv putw L5AutoPhaseHoldAtMeas] {
            return -code error "$errorCode"
        }

        # Start optimizer
        setStatus "Starting optimizer"
        set optDir /home/helios/oagData/linac/quickFeedbacks
        set logFile /tmp/PARLF3Log.[pid]
        global optimizerDone  optimizerWidget
        set optimizerDone 0
        APSExecLog  $optimizerWidget -width 120 -height 16 -lineLimit 1000 \
          -contextHelp "Shows progress of optimizer." \
          -unixCommand "sddsoptimize -measFile=$optDir/L5PhaseOptPARFL3.meas -varFile=$optDir/L5PhaseOptPARFL3.vars \
-testValues=file=$optDir/L5PhaseOptPARFL3.tests,limit=1000 -simplex=no1dscan -verbose -logFile=$logFile" \
          -callback "set optimizerDone 1" \
          -abortCallback "set optimizerDone 2" \
          -cancelCallback "set optimizerDone 2" 
        if !$optimizerDone {
            tkwait variable optimizerDone
        }
        switch $optimizerDone {
            1 {
                setStatus "Optimizer has completed"
            }
            default {
                setStatus "Optimizer aborted."
                set abortAdjustment 1
            }
        }
    }
}

proc DoLTPFL1Optimization {} {
    global errorCode abortAdjustment epicsVarList
    eval global $epicsVarList

    # Need to ensure that LTP x controllaw is running
    if [pv getw LTPXControlLawStatus] {
        return -code error "$errorCode"
    }
    if !$LTPXControlLawStatus {
        setStatus "LTP x controllaw is not running. Please start it."
        bell
        after 1000
        bell
        return
    }

    if !$abortAdjustment {
        # need to start L5 phase feedback (hold at present)
        set L5AutoPhaseHoldAtMeas 1
        if [pv putw L5AutoPhaseHoldAtMeas] {
            return -code error "$errorCode"
        }

        # Start optimizer
        setStatus "Starting optimizer"
        set optDir /home/helios/oagData/linac/quickFeedbacks
        set logFile /tmp/LTPFL1Log.[pid]
        global optimizerDone  optimizerWidget
        set optimizerDone 0
        APSExecLog  $optimizerWidget -width 120 -height 16 -lineLimit 1000 \
          -contextHelp "Shows progress of optimizer." \
          -unixCommand "sddsoptimize -measFile=$optDir/L5PhaseOpt.meas -varFile=$optDir/L5PhaseOpt.vars \
-testValues=file=$optDir/L5PhaseOpt.tests,limit=1000 -simplex=no1dscan -verbose -logFile=$logFile" \
          -callback "set optimizerDone 1" \
          -abortCallback "set optimizerDone 2" \
          -cancelCallback "set optimizerDone 2" 
        if !$optimizerDone {
            tkwait variable optimizerDone
        }
        switch $optimizerDone {
            1 {
                setStatus "Optimizer has completed"
            }
            default {
                setStatus "Optimizer aborted."
                set abortAdjustment 1
            }
        }
    }
}

proc DoL3FS1Optimization {} {
    global errorCode abortAdjustment epicsVarList
    eval global $epicsVarList

    # Start L2Pwr->L3:P1 controllaw
    setStatus "Starting L2Pwr->L3:P1 controllaw"
    # suspend the L2 power stabilizer
    set L2PowerStabilizerSusp 1
    if [pv putw L2PowerStabilizerSusp] {
        return -code error "$errorCode"
    }
    ControlFeedback -mode start -id L2PwrL3P1
    APSWaitWithUpdate -waitSeconds 4 -updateInterval 1

    if !$abortAdjustment {
        # need to start L2 phase feedback (hold at present)
        set L2AutoPhaseHoldAtMeas 1
        if [pv putw L2AutoPhaseHoldAtMeas] {
            return -code error "$errorCode"
        }

        # Start optimizer
        setStatus "Starting optimizer"
        set optDir /home/helios/oagData/linac/optimizerInputs
        set logFile /tmp/L3FS1Log.[pid]
        global optimizerDone  optimizerWidget
        set optimizerDone 0
        APSExecLog  $optimizerWidget -width 120 -height 16 -lineLimit 1000 \
          -contextHelp "Shows progress of optimizer." \
          -unixCommand "sddsoptimize -measFile=$optDir/L2PhaseOpt.meas -varFile=$optDir/L2PhaseOpt.vars \
-testValues=file=$optDir/L2PhaseOpt.tests,limit=1000 -simplex=no1dscan -verbose -logFile=$logFile" \
          -callback "set optimizerDone 1" \
          -abortCallback "set optimizerDone 2" \
          -cancelCallback "set optimizerDone 2" 
        if !$optimizerDone {
            tkwait variable optimizerDone
        }
        switch $optimizerDone {
            1 {
                setStatus "Optimizer has completed"
            }
            default {
                setStatus "Optimizer aborted."
                set abortAdjustment 1
            }
        }
    }

    # Stop L2Pwr->L3:P1 controllaw
    ControlFeedback -mode abort -id L2PwrL3P1

    # transfer L2 power setpoint and restart L2 power control if it was originally running
    if [catch {APSCAAverageAndTransfer -average 10 \
                 -interval 0.5 -readbackList L-K2:LLRF:SD:Fwd_PkPwrRemoteM \
                 -setpointList L2:SD:DC1ARF:SetpointP \
                 -statusCallback setStatus} result] {
        return -code error "$result"
    }
    after 2000
    set L2PowerStabilizerSusp 0
    if [pv putw L2PowerStabilizerSusp] {
        return -code error "$errorCode"
    }
    
}

proc Stop {args} {
    global abortAdjustment
    setStatus "Aborting..."
    set abortAdjustment 1
}

proc FeedbackPretest {args} {
    set id ""
    set RCPV ""
    APSStrictParseArguments {id RCPV}
    global ${id}FeedbackRunning 
    set FeedbackRunning [set ${id}FeedbackRunning]
    if $FeedbackRunning {
        return -code error "$id feedback already running."
    }
    if {[catch {exec cavget -list=$RCPV.RUN} result] || $result==1} {
        return -code error "$id feedback already running ($RCPV.RUN=$result)."
    }
    set ${id}FeedbackRunning 1
}

proc FeedbackCallback {args} {
    set mode ""
    set id Bend
    set RCPV APS:RunControlFixed0RC
    APSStrictParseArguments {mode id RCPV}
    global ${id}FeedbackRunning  ${id}FeedbackFrame
    set ${id}FeedbackRunning 0
    bell 
    switch $mode {
        ok {
            APSSetVarAndUpdate status "$id feedback process has completed."
            return
        }
        default {
            exec cavput -list=$RCPV.ABRT=1
            catch {after 2000 "destroy [set ${id}FeedbackFrame]"}
            APSSetVarAndUpdate status "$id feedback process has been terminated."
            return
        }
    }
}

proc ControlFeedback {args} {
    set mode ""
    set id ""
    set RCPV ""
    APSStrictParseArguments {mode id offset gain RCPV}

    global feedbackWidget

    switch $id {
        L2PwrL3P1 {
            set RCPV APS:RunControlFixed0RC
        }
        default {
        }
    }

    switch $mode {
        start {
            if [catch {FeedbackPretest -id $id -RCPV $RCPV} result] {
                setStatus "$result"
                return
            }
            exec medm -attach -x -macro \"RCPV=$RCPV\" ./sr/psApp/APSRunControlSingle.adl &
            switch $id {
                L2PwrL3P1 {
                    set readbackPV L3:P1:BPM.XPOS
                    set gain 0.2
                    set rootname L2Pwr-L3P1
                    set description "L3:P1:BPM using L2 power"
                    set deltaLimit 1
                    set mode proportional
                    set interval 1
                    set samples 1
                }
            }

            set tmpFile /tmp/[APSTmpString]
            APSAddToTempFileList $tmpFile

            set dataDir /home/helios/oagData/linac/quickFeedbacks
            eval lappend cmd sddscontrollaw $dataDir/${rootname}.inv \
              -testValues=$dataDir/${rootname}.tests \
              -gain=$gain -interval=$interval -steps=10000 -average=$samples,interval=1 \
              -delta=value=1 -verbose -$mode
            lappend cmd -runControlPV=string=$RCPV
            lappend cmd "-runControlDescription=string=$description"
            lappend cmd -actionLimit=value=0.1
            set ${id}FeedbackFrame \
              [APSExecLog $feedbackWidget \
                 -name "Feedback on $description" \
                 -callback "FeedbackCallback -mode ok -id $id -RCPV $RCPV" \
                 -abortCallback "FeedbackCallback -mode abort -id $id -RCPV $RCPV" \
                 -cancelCallback "FeedbackCallback -mode cancel -id $id -RCPV $RCPV" \
                 -width 120 -height 16 -lineLimit 1000 -contextHelp \
                 "Shows progress of sddscontrollaw process that is doing feedback." \
                 -unixCommand $cmd]
        }
        abort {
            exec cavput -list=$RCPV.ABRT=1
            catch {after 2000 "destroy [set ${id}FeedbackFrame]"}
        }
        suspend {
            exec cavput -list=$RCPV.SUSP=1
        }
        resume {
            exec cavput -list=$RCPV.SUSP=0
            exec cavput -list=L:L2Stabilizer:SDDS.SUSP=1
        }
    }
}

proc RemoveFlags {} {
    global RemoveLinacFlags RemoveLETFlags
    setStatus "Removing flags"
    set RemoveLinacFlags 1
    set RemoveLETFlags 1
    pv putw [list RemoveLinacFlags RemoveLETFlags]
}

proc setStatus {text} {
    APSSetVarAndUpdate status "[clock format [clock seconds] -format %H:%M:%S:] $text"
}

set status ""
set abortAdjustment 0
set L2PwrL3P1FeedbackRunning 0
set feedbackWidget .feedback
set optimizerWidget .optimize

APSApplication . -name PhaseLinacUsingFlags
BuildApplication .userFrame
MakeConnections
update
setStatus "Ready."
