#!/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 apsttk 1
APSDebugPath
APSRenameExecToAPSBGExec
set CVSRevisionAuthor "\$Revision: 1.2 $ \$Author: shang $"


proc KillAPSExecLogs {} {
    global APSExecIDList
    forech id $APSExecIDList {
        APSExecLogAbort -id $id -destroy 1
    }
}

proc SetStatus {text} {
    global status
    set status "[exec date +%H:%M:%S] $text"
    update idletasks
}

proc ApplySourceSetpoint {args} {
    set sign ""
    APSParseArguments {sign}

    global delta deltaSum steerSource
    set delta1 [expr $delta * -1.0] 
    EnableDisableButtons -enable 0
    switch $steerSource {
        ID {
            if [catch {exec cavput -list=S -range=beg=1,end=40,format=%02d -list=A:P0=$delta,B:P0=$delta1 \
                           -list=:x:SetpointC -delta=factor=$sign -blunderAhead=silently  
                exec cavput -list=S -range=beg=1,end=40,format=%02d -list=A:P0=$delta1,B:P0=$delta \
                           -list=:y:SetpointC -delta=factor=$sign -blunderAhead=silently 
                exec cavput -list=S -range=beg=1,end=40,format=%02d -list=A:P1=$delta,B:P1=$delta1 \
                           -list=:x:SetpointC -delta=factor=$sign -blunderAhead=silently
                exec cavput -list=S -range=beg=1,end=40,format=%02d -list=A:P1=$delta1,B:P1=$delta \
                           -list=:y:SetpointC -delta=factor=$sign -blunderAhead=silently} result] {
		EnableDisableButtons -enable 1
                SetStatus $result
                bell
                return 1
            }
        } 
        BM {
            if [catch {exec cavput -list=S -range=beg=1,end=40,format=%02d,interval=2 \
			   -list=B:P4=$delta,B:P3=$delta \
                           -list=:x:SetpointC -delta=factor=$sign -blunderAhead=silently
                exec cavput -list=S -range=beg=2,end=40,format=%02d,interval=2 \
                           -list=B:P4=$delta1,B:P3=$delta1 \
                           -list=:x:SetpointC -delta=factor=$sign -blunderAhead=silently
                exec cavput -list=S -range=beg=1,end=40,format=%02d,interval=2 \
                           -list=B:P4=$delta1,B:P3=$delta1 \
                           -list=:y:SetpointC -delta=factor=$sign -blunderAhead=silently
                exec cavput -list=S -range=beg=2,end=40,format=%02d,interval=2 \
                           -list=B:P4=$delta,B:P3=$delta \
                           -list=:y:SetpointC -delta=factor=$sign -blunderAhead=silently } result] {
		EnableDisableButtons -enable 1
                SetStatus $result
                bell
                return 1
            }
        }
    }
    EnableDisableButtons -enable 1
    set deltaSum [format %.03f [expr $deltaSum + $delta * $sign * 1.0]]
    update
    return 0
}

proc TransferOrbitZeroToSetpoint {args} {
    set apply 1
    set plane both
    APSParseArguments {apply plane}
    
    set statusFile /home/helios/oagData/sr/BPMStatus/config.sdds 
    global bpmListH bpmListV
    set putComm ""
    if {$apply == 0} {
        SetStatus "Initializing..."
    }
    EnableDisableButtons -enable 0
    update
    switch $plane {
        h {
            set planeList {H}
            set coordList {x}
        } 
        v {
            set planeList {V}
            set coordList {y}
        }
        default {
            set planeList {H V}
            set coordList {x y}
        }
    }
    set message ""
    foreach plane $planeList coord $coordList {
        if ![info exist bpmList$plane] {
            if [catch {exec sddsprocess $statusFile -pipe=out \
                           -filter=col,Nonexistent$plane,0,0 \
                           | sdds2stream -col=DeviceName -pipe } bpmList$plane] {
		EnableDisableButtons -enable 1
                return -code error "[set bpmList$plane]"
            }
        }
        if [catch {exec cavget -list=[join [set bpmList$plane] ,] \
                       -list=:$coord -list=:SetpointC -dry} pvList] {
	    EnableDisableButtons -enable 1
            return -code error "$pvList"
        }
        if [catch {exec cavget -list=[join [set bpmList$plane] ,] \
                       -list=:$coord -list=:ErrorM -pend=10} dataList] {
	    EnableDisableButtons -enable 1
            return -code error "$dataList"
        }
        foreach pv $pvList data $dataList {
            if {$data == "?"} {
                append message "Steering PV $pv is not functional\n"
            } else {
                lappend putComm $pv=$data
            }
        }
    }
    if $apply {
        if [catch {exec cavput -list=[join $putComm ,] -pend=10 -deltaMode} result] {
	    EnableDisableButtons -enable  1
            return -code error $result
        }
    } else {
        global steerSource
        if {$message != ""} {
            SetStatus $message
        }
        SetStatus "Ready to steer all $steerSource sectors."
    }
    EnableDisableButtons -enable 1
}

proc EnableDisableButtons {args} {
    set enable 0
    APSParseArguments {enable}

    global changeButtonList
    
    if $enable {
        foreach button $changeButtonList {
            APSEnableButton $button
        }
    } else {
        foreach button $changeButtonList {
            APSDisableButton $button
        }
    }
}

proc StartSteering {args} {
    global hConfig vConfig steerSource hControlPV vControlPV steerDir hdefault vdefault corrMode
    
    
    EnableDisableButtons -enable 0
    if [catch {SelectSteerSource} result] { 
        SetStatus $result
	EnableDisableButtons -enable 1
        return
    }
    SetStatus "Start steering $steerSource sectors..."
    
    SetStatus "Step 1: Start $hdefault and $vdefault controllaw if it is not running."
    set answer [APSMultipleChoice [APSUniqueName .] \
                  -question "Step 1: start $hdefault and $vdefault controllaw.\nPress Continue to continue steering after controllaw started or Continue-AnyWay to continue anyway or Abort to abort steering." \
                  -labelList {"Continue" "Continue-Anyway" "Abort"} \
                  -returnList {1 2 0} \
                  -name "Start Default Controllaw?"] 
    if !$answer {
	SetStatus "Steer $steerSource sectors was aborted." 
	EnableDisableButtons -enable 1
        bell
	return
    }
    if {$answer==1} {
        if [catch {exec cavget -list=S:XDPoffsetTransferRC.RUN,$hControlPV.RUN,$vControlPV.RUN -pend=10 -printErrors} results] { 
            EnableDisableButtons -enable 1
            SetStatus $results
            bell
            return
        }
        set offsetTransfer [lindex $results 0]
        set hRunning [lindex $results 1]
        set vRunning [lindex $results 2]

	if {$corrMode=="DP"} {
	    if !$offsetTransfer {
		EnableDisableButtons -enable 1
		SetStatus "Datapool offset transfer is not running. Please start it before starting $steerSource OC." 
                bell
		return
	    }
	}
	if {!$hRunning || $vRunning} {
	    APSAlertBox .warning -name warning -errorMessage "horizontal and/or vertical plane $steerSource orbit correction ($hConfig $vConfig) is not running. Please start it from SROrbitControllaw."
	}
    }
    if [APSYesNoPopUp "Step 2: transfer orbit errors to setpoints for both planes. Transfer orbits now?"] { 
        SetStatus "Step 2: transfer orbit errors to setpoints for both planes." 
        if [catch {TransferOrbitZeroToSetpoint -plane both -apply 1} result] { 
            SetStatus "$result.\n$steerSource steering not started."
	    EnableDisableButtons -enable 1
            bell
            return
        }
        after 2000
    }
    
    SetStatus "Step 3:  Start orbit correction for $steerSource from SROrbitControllaw."    
    APSInfoWindow .info -name "Start OC for $steerSource" \
      -infoMessage "Please start $steerSource OC from SROrbitControllaw with $hConfig and $vConfig with following parameters\n\nGain=0.2\nInterval for datapool (workstation)=0.5s\nRange Error limit=300A\nUncheck \"despike H\" and \"despike V\" button\n\nThen press \"GENERATE\" button to generate files for $hConfig and $vConfig.\nand then press \"QUICK START\" button to start steering.\n\n Press OK after steering started." \
      -modal 1
    if [catch {APSCheckControllawRunning -config $hConfig} hRunning] {
        SetStatus "$hRunning" 
	EnableDisableButtons -enable 1
        bell
        return
    }
    if !$hRunning {
        SetStatus "horizontal plane $steerSource orbit correction ($hConfig) is not running. Please start it from SROrbitControllaw."
    }
    if [catch {APSCheckControllawRunning -config $vConfig} vRunning] {
	SetStatus "$vRunning" 
	EnableDisableButtons -enable 1
        bell
        return
    }
    if !$vRunning {
        SetStatus "vertical plane $steerSource orbit correction ($vConfig) is not running. Please start it from SROrbitControllaw."
    }
    if {$hRunning && $vRunning} {
        SetStatus "$steerSource steering started."
    }
    EnableDisableButtons -enable 1
}

proc CollectAdjustedOrbit {args} {
    global hControlPV vControlPV outputDir rootname bpmListH bpmListV steerSource startSector endSector OAGGlobal
    EnableDisableButtons -enable 0
    update idletasks
    if [catch {exec cavget -list=${hControlPV}.RUN,${vControlPV}.RUN -pend=10 -printErrors} results] { 
	EnableDisableButtons -enable 1
        SetStatus $results
        bell
        return
    }
    set hRunning [lindex $results 0]
    set vRunning [lindex $results 1]
    if {!$hRunning || !$vRunning} {
	EnableDisableButtons -enable 1
        SetStatus "h or v plane $steerSource OC is not running."
        bell
        return
    }
    set monFile $outputDir/${rootname}.adjusted
    set tmpRoot /tmp/[APSTmpString]
    if {![file exist $monFile]} {
        APSAddToTmpFileList -ID steerall -fileList "$tmpRoot.x $tmpRoot.y"
        foreach plane {H V} coord {x y} {
            if [catch {exec sddsmakedataset -pipe=out \
                           -col=Name,type=string -data=[join [set bpmList$plane] ,] \
                           | sddsprocess -pipe \
                           -edit=col,ControlName,Name,ei/:$coord:AdjustedM/ \
                           | sddsxref -pipe $OAGGlobal(SRLatticesDirectory)/scripts/SRBPMPosition.xref \
                           -reused=page -match=Name=BPMName -take=s -nowarning \
                           | sddssort -pipe=in $monFile.$coord -col=s} result] {
		EnableDisableButtons -enable 1
                SetStatus $result
                bell
                return
            }
        }
    }
    set filename $outputDir/${rootname}[clock format [clock seconds] -format "%Y-%j-%m%d-%H%M%S"]
    foreach coord {x y} {
        if [catch {exec sddscasr -save -pend=10 $monFile.$coord -pipe=out \
                     | sddsprocess -pipe -match=column,CAError=n \
                     | sddsprocess -pipe=in $tmpRoot.$coord -scan=col,Original,ValueString,%lf } result] {
	    EnableDisableButtons -enable 1
            SetStatus $result
            bell
            return
        }
    }
    if {[ApplySourceSetpoint -sign 1]} {
        return
    }
    APSInfoWindow .info \
      -name "ADT Screen Save" \
      -infoMessage "Delta setpoint applied, please wait until the orbit stablized." \
      -modal 1
    # after 2000
    foreach coord {x y} {
        if [catch {exec sddscasr -save -pend=10 $monFile.$coord -pipe=out \
                     | sddsprocess -pipe -match=column,CAError=n \
                     | sddsprocess -pipe=in $tmpRoot.$coord.1 -scan=col,Value1,ValueString,%lf } result] {
	    EnableDisableButtons -enable 1
            SetStatus $result
            bell
            return
        }
    }
    if {[ApplySourceSetpoint -sign -1]} {
        return
    }
    APSInfoWindow .info \
      -name "ADT Screen Save" \
      -infoMessage "Minus delta setpoint applied, please wait until the orbit stablized." \
      -modal 1
    #after 2000
    foreach coord {x y} type {Horizontal Vertical} {
        if [catch {exec sddscasr -save -pend=10 $monFile.$coord -pipe=out \
                     | sddsprocess -pipe -match=column,CAError=n \
                     | sddsprocess -pipe=in $tmpRoot.$coord.2 -scan=col,Value2,ValueString,%lf } result] {
	    EnableDisableButtons -enable 1
            SetStatus $result
            bell
            return
        }
        if [catch {exec sddsxref $tmpRoot.$coord $tmpRoot.$coord.1 $tmpRoot.$coord.2 \
                       -pipe=out -match=ControlName -reuse \
                       -take=Value* \
                       | sddsprocess -pipe=in $tmpRoot.data.$coord \
                       "-scan=col,Sector,Name,S%ld,type=long" \
                       "-define=col,DiffAfterApply,Value1 Original -" \
                       "-print=par,Description,$type adjustedCC orbit difference" \
                       "-define=col,DiffAfterRestore,Value2 Original -" } result] {
	    EnableDisableButtons -enable 1
            SetStatus $result
            bell
            return
        }
    }
    if [catch {exec sddscombine $tmpRoot.data.x $tmpRoot.data.y $filename -over} result] {
	EnableDisableButtons -enable 1
        SetStatus $result
        bell
        return
    }
    set space [expr ($endSector - $startSector) / 4 + 1]
    
    catch {exec sddsplot -split=page -sep=page -grap=line,vary -legend -title=@Description \
               "-ylabel=AdjustedM Orbit Difference" -filter=col,Sector,$startSector,$endSector \
               -topline=[file tail $filename] -enumeratedScales=interval=$space \
               -col=Name,Diff*  $filename &}
    EnableDisableButtons -enable 1
}

proc dirSelectDialog {widget args} {
    global dirSelection steerDir
    set filter ""
    APSParseArguments {filter}
    set oldDir [pwd]
    cd $steerDir
    if [string length $filter] {
        set dirList [lsort -decreasing [glob -nocomplain $filter]]
    } else {
        set dirList [lsort -decreasing [glob -nocomplain *]]
    }
    APSScrolledListWindow $widget \
        -name "Directory selection" \
        -label "Select a directory" \
        -itemList $dirList \
        -selectionVar dirSelection
    tkwait variable dirSelection
    return $dirSelection
    cd $oldDir
}

proc FindDir {args} {
    global steerDir
    set dirVariable ""
    set filter ""
    set trim 0
    APSParseArguments {filter dirVariable trim}
    global $dirVariable
    
    set dirName [eval dirSelectDialog .findDirDialog -filter $filter]
    if [string length $dirName] {
        # Trim the current working directory from the name
        if $trim {
            set dirName [file tail $dirName]
        }
        set $dirVariable $dirName
    }
}

proc PlotOrbitDifference {args} {
    global outputDir rootname endSector startSector

    set filename  [APSFileSelectDialog [APSUniqueName .] -width 70 -reverseSort 1\
		       -path $outputDir -pattern ${rootname}????-*]
    if ![string length $filename] {
	return
    }
    set space [expr ($endSector - $startSector)/4 + 1]
    catch {exec sddsplot -split=page -sep=page -grap=line,vary -legend -title=@Description \
               "-ylabel=AdjustedM Orbit Difference" -filter=col,Sector,$startSector,$endSector \
               -topline=[file tail $filename] -enumeratedScales=interval=$space \
               -col=Name,Diff*  $filename &}

}
proc StartControllaw {args} {
    set hConfig ""
    set vConfig ""
    APSStrictParseArguments {hConfig vConfig}

}

proc SelectSteerSource {} {
    global steerSource hConfig vConfig rootname hdefault vdefault hControlPV vControlPV corrMode outputDir
    global steerDir
    SetStatus "Steer all $steerSource sectors."
    set hConfig h.All${steerSource}Steering
    set vConfig v.All${steerSource}Steering
    
    set rootname ${steerSource}Steer
    set outputDir [APSGoToDailyDirectory -subdirectory ${steerSource}Steer]
    if {![file exists $steerDir/$hConfig/config]} {
        SetStatus "Missing file $steerDir/$hConfig/config"
        set types {"" ""}
    } else {
        set types [exec sdds2stream $steerDir/$hConfig/config -par=PVType]
    }
    if {[lindex $types 0]=="DP" && [lindex $types 1]=="DP"} {
        set hMode DP
        set hControlPV DP:S:OrbitControlLawXSDDS
        set vControlPV DP:S:OrbitControlLawYSDDS
        set hdefault h.defaultDP
        set vdefault v.defaultDP
    } else {
        set hMode scalar
        set hControlPV S:RC:OrbitControlLawXC
        set vControlPV S:RC:OrbitControlLawYC
        set hdefault h.default
        set vdefault v.default
    }
    if {![file exists $steerDir/$vConfig/config]} {
        SetStatus "Missing file $steerDir/$vConfig/config"
        set types {"" ""}
    } else {
        set types [exec sdds2stream $steerDir/$vConfig/config -par=PVType]
    }
    if {[lindex $types 0]=="DP" && [lindex $types 1]=="DP"} {
        set vMode DP
    } else {
        set vMode scalar
    }
    if [string compare $vMode $hMode]!=0 {
        return -code error "the corrector type of h plane config is different from the v plane config!"
    }
    set corrMode $hMode
}

#execution starts here
set APSExecIDList "" 
set interval 0.5
set gain 0.2
set delta 0.075
set deltaSum 0
set steerSource ID
set startSector 1
set endSector 40 

set steerDir /home/helios/oagData/sr/orbitControllaw/lattices/default


set status ""
APSApplication . -name SRSteerAllSectors \
    -overview "SRSteerAllSector provides convenience controls for steering all ID/BM sectors."
dp_atexit append KillAPSExecLogs

set hConfig h.All${steerSource}Steering
set vConfig v.All${steerSource}Steering

set IDSteeringStatus Ready.
APSScrolledStatus .status -parent .userFrame -width 60 -height 8 \
    -textVariable status -packOption "-fill both -expand true"

APSRadioButtonFrame .source -parent .userFrame -variable steerSource \
    -buttonList {ID BM} -valueList {ID BM} \
    -commandList {SelectSteerSource SelectSteerSource} \
    -label "Select Steer source:" -orientation horizontal

APSFrame .f1 -parent .userFrame -name "Option"
set w0 .userFrame.f1.frame
APSFrameGrid .fg -parent $w0 -xList {x1 x2}
set w1 $w0.fg.x1
set w2 $w0.fg.x2
APSLabeledEntry .hconfig -parent $w1 -textVariable hConfig -width 20 -label "Horizontal configuration:"
APSButton .pick -parent $w1.hconfig -text F -packOption "-side right" \
    -command "FindDir -dirVariable hConfig -filter h.*"
APSLabeledEntry .vconfig -parent $w2 -textVariable vConfig -width 20 -label "Vertical configuration:"
APSButton .pick -parent $w2.vconfig -text F -packOption "-side right" \
    -command "FindDir -dirVariable vConfig -filter v.*"
APSLabeledEntry .gain -parent $w1 -textVariable gain -width 20 -label "Gain:" 
APSLabeledEntry .interval -parent $w2 -textVariable interval -width 20 -label "Interval (s): "
APSLabeledEntry .delta -parent $w1 -textVariable delta -width 20 -label "Delta (mm):" \
    -contextHelp "the change value of setpoints at one step."
APSLabeledOutput .sum -parent $w2 -label "Total changes:" -textVariable deltaSum -width 20 \
    -contextHelp "the changes to be applied to bpm setpoints." 
APSLabeledEntry .starts -parent $w1 -textVariable startSector -label "Start sector of plotting:" -width 20
APSLabeledEntry .ends -parent $w2 -textVariable endSector -label "End sector of plotting:" -width 20
set transferPlane both
APSRadioButtonFrame .zero -parent $w1 -variable transferPlane -label "Zero errors for which plane?" -buttonList {h v both} \
    -valueList {h v both} -orientation horizontal
APSButton .zero -parent $w2 -text "Zero Errors" -command {
    global transferPlane
    TransferOrbitZeroToSetpoint -plane $transferPlane
}

set rootname ${steerSource}Steer
set outputDir [APSGoToDailyDirectory -subdirectory ${steerSource}Steer]
APSLabeledEntry .dir -parent .userFrame -label "Output directory:" -width 60 -textVariable outputDir
APSButton .daily -parent .userFrame.dir -text "Daily" -size small -command \
    {
	global steerSouce
	set outputDir [APSGoToDailyDirectory -subdirectory ${steerSource}Steer]
    }
APSLabeledEntry .root -parent .userFrame -label "Output file rootname:" -width 60 -textVariable rootname
APSButton .start -parent .userFrame -text "Start Steering" -command StartSteering -width ""
APSButton .collect -parent .userFrame -text "Collect Orbit" -command CollectAdjustedOrbit -width ""
lappend changeButtonList .userFrame.collect.button
APSButton .view -parent .userFrame -text "Plot Orbit Difference" -command PlotOrbitDifference -width ""
#lappend changeButtonList .userFrame.view.button
APSButton .apply -parent .userFrame -text "Apply Delta" \
    -command "ApplySourceSetpoint -sign 1" -width ""
lappend changeButtonList .userFrame.apply.button
APSButton .restore -parent .userFrame -text "Apply Minus Delta" \
    -command "ApplySourceSetpoint -sign -1" -width ""
lappend changeButtonList .userFrame.restore.button

SelectSteerSource
EnableDisableButtons -enable 1
TransferOrbitZeroToSetpoint -apply 0
