#!/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 setStatus {text} {
    global status
    set status "[clock format [clock seconds] -format %H:%M:%S]: $text"
    update
}

set args $argv
set configFile ""
set apsScaleUpSize 4
if [APSStrictParseArguments {configFile apsScaleUpSize}] {
    return -code error "invalid arguments: $args"
}

if {[expr $apsScaleUpSize>4] || [expr $apsScaleUpSize<1]} {
    set apsScaleUpSize 4
}


APSApplication . -name LastLightCountdown \
    -version 1.0 -overview "Closes shutters in sequence, then dumps beam."

setStatus Working...
APSScrolledStatus .status \
    -parent .userFrame \
    -textVariable status \
    -width 45 \
    -packOption "-fill both -expand true"

set timeBetween 3.0
APSLabeledEntry .interval -parent .userFrame -textVariable timeBetween \
    -label "Time between closing successive shutters (seconds): " -type real

APSLabeledEntry .filename -parent .userFrame -textVariable configFile \
    -label "Configuration file: " -fileSelectButton 1 -fileSelectValidity 1 -width 60
APSButton .view -parent .userFrame.filename -text "Edit" -packOption "-side right" \
  -command {exec sddsedit $configFile}

set validatedFile ""
APSLabeledOutput .vfilename -parent .userFrame -textVariable validatedFile \
    -label "Validated file: " -width 60
APSButton .transfer -parent .userFrame.vfilename -text Transfer -packOption "-side right" \
  -command {if [string length $validatedFile] { set configFile $validatedFile; set validatedFile "" } }

set dryRun 1
APSRadioButtonFrame .dry -parent .userFrame -orientation horizontal -variable dryRun \
    -label "Mode: " -buttonList {"Dry Run" "Real Deal"} -valueList {1 0}

set font 60
option add *font -bitstream-courier-bold-r-normal-*-$font-*-75-75-*-*-*-*
set counter -1
APSFrame .cframe -parent .userFrame -label "Counter"
entry .userFrame.cframe.frame.counter -relief flat -width 50 -textvariable counter -background white
pack .userFrame.cframe.frame.counter -fill both

set font 160
set counter2 -1
option add *font -bitstream-courier-bold-r-normal-*-$font-*-75-75-*-*-*-*
toplevel .counterFrame 
wm title .counterFrame Counter
entry .counterFrame.counter -relief flat -width 2 -textvariable counter2 -background white
pack .counterFrame.counter -fill both

set font 30
option add *font -bitstream-courier-bold-r-normal-*-$font-*-75-75-*-*-*-*
set pause 0
set abort 0
APSButton .run -parent .userFrame -text "Run" -command RunSequence
APSButton .pause -parent .userFrame -text "Pause" -command "set pause 1; APSSetVarAndUpdate status Pausing..."
APSButton .abort -parent .userFrame -text "Abort" -command "set abort 1; APSSetVarAndUpdate status Aborting..."
APSButton .readtest -parent .userFrame -text "CA Test" -command PerformCATest
APSButton .idcheck -parent .userFrame -text "Check gap settings" -command CheckGapSettings
APSDisableWidget .userFrame.pause
APSDisableWidget .userFrame.abort

proc CheckGapSettings {} {
    global pause abort configFile status timeBetween counter dryRun ready
    if ![string length [string trim $configFile]] {
        APSSetVarAndUpdate status "Configuration file must be specified"
        return 
    }
    if ![file exists $configFile] {
        APSSetVarAndUpdate status "Configuration file $configFile not found"
        return
    }
    set tmpRoot /tmp/[APSTmpString]
    APSAddToTempFileList $tmpRoot.gapFull $tmpRoot.gapSet $tmpRoot.problem
    if [catch {exec sddscombine $configFile -pipe=out -merge -retain=col,ControlName,ValueString \
                 | sddsprocess -pipe -match=col,ControlName=*GapSet* \
                 | tee $tmpRoot.gapSet \
                 | sddsprocess -pipe -reedit=col,ControlName,%/GapSet/FullOpenGap/%/.VAL// \
                 | sddscasr -pipe=in $tmpRoot.gapFull -save} result] {
        APSSetVarAndUpdate status "$result"
        return
    }
    if [catch {exec sddsxref $tmpRoot.gapSet $tmpRoot.gapFull -pipe=out  -take=ValueString -rename=col,ValueString=OpenGapString \
                 | sddsprocess -pipe -scan=col,Setting,ValueString,%le -scan=col,OpenGap,OpenGapString,%le \
                 -nowarning \
                 "-test=column,Setting OpenGap > OpenGap Setting - 5 > || Setting 100 < ||"  \
                 | tee $tmpRoot.problem \
                 | sdds2stream -pipe -rows=bare} result] {
        APSSetVarAndUpdate status "$result"
        return
    }
    if [expr $result > 0] {
        APSSetVarAndUpdate status "Issues with gap settings for $result IDs"
        APSExecLog .show -unixCommand "sddsprintout -col $tmpRoot.problem" 
    } else {
        APSSetVarAndUpdate status "No issues with gap settings"
    }
}

proc PerformCATest {} {
    global pause abort configFile status timeBetween counter dryRun ready
    if ![string length [string trim $configFile]] {
        APSSetVarAndUpdate status "Configuration file must be specified"
        return 
    }
    if ![file exists $configFile] {
        APSSetVarAndUpdate status "Configuration file $configFile not found"
        return
    }
    APSSetVarAndUpdate status "Performing CA read test with $configFile"
    set tmpRoot /tmp/[APSTmpString]
    APSAddToTempFileList $tmpRoot.merged $tmpRoot.probed $tmpRoot.exist $tmpRoot.noWrite $tmpRoot.validated
    if [catch {exec sddscombine $configFile $tmpRoot.merged -merge -retain=col,ControlName} result] {
        APSSetVarAndUpdate status "Error: $result"
        return
    }
    APSSetVarAndUpdate status "This may take up to 30 seconds"
    APSExecLog .exec -name "CA Test for LastLightCountdown" -width 100 \
      -unixCommand "sddscasr $tmpRoot.merged -save -pipe=out -pendIoTime=30 | sddssort -column=CAError,decr -column=ControlName -pipe | tee $tmpRoot.probed | sddsprintout -pipe=in -column=ControlName,format=%30s -column=ValueString,format=%30s -column=CAError" \
      -callback "set ready 1" -abortCallback "set ready 2" -cancelCallback "set ready 2"
    tkwait variable ready
    set nTotal [exec sdds2stream -rows=bare $tmpRoot.merged]
    APSSetVarAndUpdate status "Checked $nTotal PVs."

    if [ catch {exec sddsprocess $tmpRoot.probed -pipe=out -match=col,CAError=n -nowarning | tee $tmpRoot.exist | sdds2stream  -pipe -rows=bare} result] {
        APSSetVarAndUpdate status "$result"
        return
    }
    set noWriteList ""
    if { $result == 0 } {
        APSSetVarAndUpdate status "None of the $nTotal PVs in the file appear to exist!"
    } else {
        APSSetVarAndUpdate status "[expr $nTotal-$result] PVs don't exist."
        APSSetVarAndUpdate status "Checking write access to $result PVs that exist. Please wait."
        set pvList [exec sdds2stream $tmpRoot.exist -column=ControlName]
        if [catch {exec sddscainfo $tmpRoot.exist -pipe=out \
            | sddsprocess -pipe -nowarning -match=col,WriteAccess=n \
            | sdds2stream -pipe -column=ControlName} noWriteList] {
            APSSetVarAndUpdate status "Error: $noWriteList"
            return
           }
        APSSetVarAndUpdate status "$result"
        set badCount [llength $noWriteList]
        foreach pv $noWriteList {
            APSSetVarAndUpdate status "no write access to $pv"
        }
        APSSetVarAndUpdate status "Write access issues on $badCount existing PVs."
    }
    global validatedFile
    set validatedFile ""
    if [llength $noWriteList] {
        if [ catch {exec sddsmakedataset $tmpRoot.noWrite \
                      -column=ControlName,type=string -data=[join $noWriteList ,]
            exec sddsselect $tmpRoot.exist $tmpRoot.noWrite $tmpRoot.good -match=ControlName -invert
            exec sddsselect $configFile $tmpRoot.good $tmpRoot.validated -match=ControlName -reuse=page,row } result] {
            APSSetVarAndUpdate status "$result"
        }
        set validatedFile $tmpRoot.validated
    } else {
        if [ catch {exec sddsselect $configFile $tmpRoot.exist $tmpRoot.validated -match=ControlName -reuse=page,row } result] {
            APSSetVarAndUpdate status "$result"
        }
        set validatedFile $tmpRoot.validated
    }
}

proc RunSequence {} {
    global pause abort configFile status timeBetween counter dryRun counter2
    set pause 0
    set abort 0
    if ![string length [string trim $configFile]] {
        APSSetVarAndUpdate status "Configuration file must be specified"
        return 
    }
    if [expr $timeBetween<0.5] {
        APSSetVarAndUpdate status "Time between actions is too short"
        return 
    }
    if [expr $timeBetween<3.0] {
        if ![APSQueryToProceed -message "The time between actions is less than 3.0 s. Is this what you want?"] {
            APSSetVarAndUpdate status "Sequence aborted before starting."
            return 
        }
    }

    if ![file exists $configFile] {
        APSSetVarAndUpdate status "Configuration file $configFile not found"
        return
    }

    if [catch {sdds load $configFile data} result] {
        APSSetVarAndUpdate status "Configuration file $configFile has an issue: $result"
        return
    }
    if [lsearch -exact $data(ColumnNames) ControlName]==-1 {
        APSSetVarAndUpdate status "Configuration file $configFile is missing ControlName column"
        return
    }
    if [lsearch -exact $data(ColumnNames) ValueString]==-1 {
        APSSetVarAndUpdate status "Configuration file $configFile is missing ValueString column"
        return
    }
    if [lsearch -exact $data(ParameterNames) Counter]==-1 {
        APSSetVarAndUpdate status "Configuration file $configFile is missing Counter parameter"
        return
    }

    set npages [llength $data(Parameter.Counter)]
    APSSetVarAndUpdate status "Configuration file has $npages pages"
    APSSetVarAndUpdate status "Countdown will be: $data(Parameter.Counter)"

    if $dryRun {
        set message "Confirm that you wish to DRY RUN the shutter closing sequence"
    } else {
        set message "Confirm that you wish to proceed with ACTUAL shutter closing sequence!"
    }
    if ![APSQueryToProceed -message $message] {
         APSSetVarAndUpdate status "Sequence aborted before starting."
         return 
    }

    ToggleButtons
    for {set page 0} {$page<$npages} {incr page} {
        set counter [lindex $data(Parameter.Counter) $page]
        if [string length $counter]<3 {
            set counter2 $counter
        }
        set confirmationNeeded [lindex $data(Parameter.ConfirmationNeeded) $page]
        set description [lindex $data(Parameter.Description) $page]
        update
        if [llength $data(Column.ControlName)] {
            set putOpt ""
            foreach pv [lindex $data(Column.ControlName) $page] value [lindex $data(Column.ValueString) $page] {
                lappend putOpt $pv=$value
            }
            if [llength $putOpt] {
                set confirmed 1
                if {[string length $confirmationNeeded] && $confirmationNeeded} {
                    set confirmed [APSMultipleChoice .ask -question "Proceed with $description?" \
                                       -labelList {"Yes" "No"} -returnList {1 0} ]
                }
                if $confirmed {
                    APSSetVarAndUpdate status "[join $putOpt ,]"
                    if !$dryRun {
                        if [catch {exec cavput -list=[join $putOpt ,]} result] {
                            APSSetVarAndUpdate status "Problem sending values [join $putOpt ,]: $result"
                            if ![APSQueryToProceed -message "Problem sending values"] {
                                ToggleButtons
                                APSSetVarAndUpdate status "Sequence aborted due to problem."
                                return 
                            }
                        }
                        APSSetVarAndUpdate status "Sent values: $putOpt"
                    } else {
                        APSSetVarAndUpdate status "Pretended to send values: $putOpt"
                    }
                } else {
                        APSSetVarAndUpdate status "Skipping sending of values: $putOpt"
                }
            }
        }
        APSWaitWithUpdate -waitSeconds $timeBetween -updateInterval 0.25 -abortVariable abort
        if $pause {
            if ![APSQueryToProceed -message "Paused. Do you want to proceed?"] {
                APSSetVarAndUpdate status "Sequence aborted due to user request."
                ToggleButtons
                return 
            }
        }
        set pause 0
        if $abort {
            if ![APSQueryToProceed -message "Abort pressed. What do you want to do?"] {
                APSSetVarAndUpdate status "Sequence aborted due to user request."
                ToggleButtons
                return 
            }
        }
        set abort 0
    }
    set message "So long, APS, and thanks for all the photons."
    set counter $message
    APSSetVarAndUpdate status $message
    ToggleButtons
    return
}

proc ToggleButtons {} {
    APSEnableDisableWidget .userFrame.run -toggle 1
    APSEnableDisableWidget .userFrame.abort -toggle 1
    APSEnableDisableWidget .userFrame.pause -toggle 1
}


APSSetVarAndUpdate status "Ready."
