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

APSApplication . -name SRquickOrbCorrect \
  -overview "This application allows correction of the global orbit in the storage ring at fixed intervals."

set SRquickOrbCorrectStatus Ready.
APSScrolledStatus .status -parent .userFrame -width 80 \
        -textVariable SRquickOrbCorrectStatus

cd /home/helios/oagData/sr/orbitCorrection

proc SetSRquickOrbCorrectStatus {text} {
    global SRquickOrbCorrectStatus
    set SRquickOrbCorrectStatus $text
    update
}

proc FindLatestGoodBPMFile {plane} {
    set fileList [glob -nocomplain ${plane}.??????.??????.good]
    if [llength $fileList]==0 {
        return ""
    }
    set fileList [lsort -ascii $fileList]
    return [join [lrange $fileList end end]]
}

set xGoodBPMFile [FindLatestGoodBPMFile x]
set yGoodBPMFile [FindLatestGoodBPMFile y]

proc MakeGoodBPMFile {filenameVariable plane} {
    set rootname [exec date +${plane}.%y%m%d.%H%M%S]
    APSExecLog .makefile$plane -width 60 -contextHelp \
      "Executes commands to make good BPM files." \
      -unixCommand "./findGoodBPMs $plane $rootname 3"
    global $filenameVariable 
    set $filenameVariable $rootname.good
}

proc PickGoodBPMFile {filenameVariable plane} {
    global $filenameVariable
    set name [APSFileSelectDialog .fsd \
                -width 40 -path . -pattern ${plane}.??????.??????.good]
    set $filenameVariable [file tail $name]
}


proc MakeBPMWidget {widget args} {
    set parent ""
    APSStrictParseArguments {parent}

    APSFrame $widget -parent $parent -label "BPM Settings" \
      -contextHelp "BPM settings frame"
    set w $parent$widget.frame

    APSFrameGrid .fg -parent $w -yList {x y}
    foreach plane {x y} {
        global ${plane}GoodBPMFile
        APSLabeledOutput .lo$plane -parent $w.fg.$plane -label "$plane plane good BPM file: " \
          -textVariable ${plane}GoodBPMFile -contextHelp \
          "Shows the name of the good BPM file file for the $plane plane."
        APSButton .m$plane -parent $w.fg.$plane -text MAKE -contextHelp \
          "Generates a new good BPM file for the $plane plane." \
          -command "MakeGoodBPMFile ${plane}GoodBPMFile $plane"
        APSButton .p$plane -parent $w.fg.$plane -text "PICK..." -contextHelp \
          "Selects an existing good BPM file for the $plane plane." \
          -command "PickGoodBPMFile ${plane}GoodBPMFile $plane"
    }
}

set xCorrectionGain 0.1
set yCorrectionGain 0.1
set xSingularValues 100
set ySingularValues 140
set correctionInterval 15
set correctionTime 24

proc MakeEntryWidget {widget args} {
    global xCorrectionGain yCorrectionGain correctionInterval correctionTime
    global xSingularValues ySingularValues
    set parent ""
    APSStrictParseArguments {parent}

    APSFrame $widget -parent $parent -label "Correction Settings" \
      -contextHelp {Correction settings frame}
    set w $parent$widget.frame
    foreach plane {x y} {
        APSLabeledEntry .gain$plane -parent $w -width 5 -label "$plane gain: " \
          -textVariable ${plane}CorrectionGain -contextHelp \
          "Supply the $plane gain (a number greater than 0 but less than 1).  It gives the fraction of the full correction that is applied at each step."
        APSLabeledEntry .singV$plane -parent $w -width 5 -label "$plane singular values: " \
          -textVariable ${plane}SingularValues -contextHelp \
          "Supply the number of singular values for the $plane."
    }

    APSLabeledEntry .interval -parent $w -width 5 -label "Interval (sec): " \
      -textVariable correctionInterval -contextHelp \
      "Supply the interval between corrections in seconds. "
    APSLabeledEntry .time -parent $w -width 5 -label "Time (hours): " \
      -textVariable correctionTime -contextHelp \
      "Supply the maximum total time for which correction will be done."
}

set xIsRunning no
set yIsRunning no

proc StartCorrection {args} {
    set dryrun 0
    APSParseArguments {plane dryrun}
    global correctionInterval correctionTime
    foreach elem {CorrectionGain SingularValues IsRunning GoodBPMFile} {
        global ${plane}${elem}
        set $elem [subst \$${plane}${elem}]
    }
    if [string compare $IsRunning yes]==0 {
        SetSRquickOrbCorrectStatus "Plane $plane already running.  Abort the UnixCommand window to restart."
        return
    }
    if [string length $GoodBPMFile]==0 {
        SetSRquickOrbCorrectStatus "No good BPM file for $plane"
        return
    }
    set matrix [file rootname $GoodBPMFile].inv.$SingularValues
    if ![file exists $matrix] {
        SetSRquickOrbCorrectStatus "Generating matrix $matrix"
        set ${plane}MatrixDone 0
        APSExecLog .matrix$plane -width 60 -contextHelp \
          "Executes commands to regenerate inverse matrix for $plane plane." \
          -unixCommand "./reduceSRmatrix $plane [file rootname $GoodBPMFile] $SingularValues"  \
          -callback "set ${plane}MatrixDone 1" \
          -abortCallback "set ${plane}MatrixDone -1" \
          -cancelCallback "set ${plane}MatrixDone -1"
        tkwait variable ${plane}MatrixDone
        if {[subst \$${plane}MatrixDone]==-1} {
            SetSRquickOrbCorrectStatus "Matrix problem."
            catch {exec rm $matrix}
            return
        }
        SetSRquickOrbCorrectStatus "Matrix generated."
    } else {
        SetSRquickOrbCorrectStatus "Using existing matrix $matrix"
    }


    set steps [expr int((3600.0*$correctionTime)/$correctionInterval)+1]
    switch $plane {
        x {
            set fgain [expr -134.96820*$CorrectionGain]
        }
        y {
            set fgain [expr 125.131*$CorrectionGain]
        }
    }

    set ${plane}IsRunning yes
    if !$dryrun {
        APSExecLog .run$plane -width 60 -contextHelp "Executes sddscontrollaw for the $plane plane."  \
          -unixCommand "sddscontrollaw -deltaLimit=value=10 \
        $matrix -gain=$fgain -actuatorColumn=ControlName \
        -interval=$correctionInterval -verbose -steps=$steps -test=bpm.test" \
          -callback "StopCorrectionCallback -plane $plane -mode done" \
          -abortCallback "StopCorrectionCallback -plane $plane -mode aborted" \
          -cancelCallback "StopCorrectionCallback -plane $plane -mode cancelled" 
    } else {
        # dry run uses one step, and -proportional flag 
        # so that the change in corrector is recorded in the output file.
        APSExecLog .run$plane -width 60 -contextHelp "Executes sddscontrollaw for the $plane plane."  \
          -unixCommand "sddscontrollaw -dry -prop -deltaLimit=value=10 \
            $matrix ${matrix}.out -gain=$fgain -actuatorColumn=ControlName \
            -interval=$correctionInterval -verbose -steps=1 -test=bpm.test" \
          -callback "StopCorrectionCallback -plane $plane -mode done -dryrun $dryrun -matrix $matrix" \
          -abortCallback "StopCorrectionCallback -plane $plane -mode aborted" \
          -cancelCallback "StopCorrectionCallback -plane $plane -mode cancelled" 
        
    }
}

proc StopCorrectionCallback {args} {
    set dryrun 0
    APSParseArguments {plane mode dryrun matrix}
    global ${plane}IsRunning
    set ${plane}IsRunning no
    bell
    bell
    bell
    SetSRquickOrbCorrectStatus "$plane plane orbit correction $mode ."
    if {$dryrun && [file exists ${matrix}.out]} {
        cd /home/helios/oagData/sr/orbitCorrection
        catch {exec sddsconvert -retain=col,S*CurrentAO ${matrix}.out -pipe=out \
                 | sddstranspose -pipe=in ${matrix}.CurrentAO -digits=3 \
                 -oldColumn=ControlName -root=Values}
        catch {exec chmod a+w ${matrix}.CurrentAO}
        catch {exec sddsplot -col=ControlName,Values000 ${matrix}.CurrentAO \
                 "-topline=Corrector currents for first iteration" \
                 "-ylabel=Setpoint changes (A)" -file -title= \
                 -enum=int=18,edit=%/:CurrentAO// -axes=x -grap=impulse &}
    }
}

proc MakeActionWidget {widget args} {
    set parent ""
    APSStrictParseArguments {parent}

    APSFrame $widget -parent $parent -label "Actions" \
      -contextHelp {Correction actions frame}
    set w $parent$widget.frame
    
    frame $w.switch
    pack $w.switch  -side top -anchor w
    APSButton .enable -parent $w.switch -text ENABLE -packOption "-side top" \
      -command "APSEnableButton $w.x.start.button; APSEnableButton $w.y.start.button; APSUnmap $w.switch.enable; APSRemap $w.switch.disable"
    APSButton .disable -parent $w.switch -text DISABLE  -packOption "-side top" \
      -command "APSDisableButton $w.x.start.button; APSDisableButton $w.y.start.button; APSRemap $w.switch.enable; APSUnmap $w.switch.disable"
    APSUnmap $w.switch.disable
    foreach plane {x y} {
        frame $w.$plane 
        pack $w.$plane -side top
        APSButton .start -parent $w.$plane -text "START $plane" \
          -command "StartCorrection -plane $plane -dryrun 0" -contextHelp \
          "Starts correction for the $plane plane"
        APSDisableButton $w.$plane.start.button
        global ${plane}IsRunning 
        APSLabeledOutput .running -parent $w.$plane -label "running:" \
          -textVariable ${plane}IsRunning -width 5 \
          -contextHelp "Tells whether correction is running in the $plane plane already."
    }
}

proc MakeTestActionWidget {widget args} {
    set parent ""
    APSStrictParseArguments {parent}

    APSFrame $widget -parent $parent -label "Test Actions" \
      -contextHelp {Dry run correction actions frame. Produces plot of corrector settings changes for one iteration of the sddscontrollaw using the gain given.}
    set w $parent$widget.frame
    
    foreach plane {x y} {
        frame $w.$plane 
        pack $w.$plane -side top
        APSButton .start -parent $w.$plane -text "START $plane" \
          -command "StartCorrection -plane $plane -dryrun 1" -contextHelp \
          "Starts a dry run correction for the $plane plane, and produces a plot of corrector setpoint changes for one iteration of sddscontrollaw"
#        global ${plane}IsRunning 
#        APSLabeledOutput .running -parent $w.$plane -label "running:" \
#          -textVariable ${plane}IsRunning -width 5 \
#          -contextHelp "Tells whether correction is running in the $plane plane already."
    }
}

APSFrameGrid .threeside -parent .userFrame -xList {bpm entries ops}
MakeBPMWidget .bpm -parent .userFrame.threeside.bpm
MakeEntryWidget .entries -parent .userFrame.threeside.entries
MakeActionWidget .ops -parent .userFrame.threeside.ops
MakeTestActionWidget .test -parent .userFrame.threeside.ops

