#!/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 CVSRevisionAuthor "\$Revision: 1.10 $ \$Author: soliday $"

set args $argv 
set samplesToAverage 10
set sampleInterval 0.25
set threshold 0.05
set settlingTime 3
set stepSize 0.1
set repetitions 1
set subdivisions 1
set subdivisionFactor 2.5
set upstepCount 5
set upstepFactor 1.5
set usage "Usage: squishLinacTraj -samplesToAverage <num> -sampleInterval <secs> -settlingTime <secs> -stepSize <Amps> -threshold <mm> -repetitions <num> -subdivisions <num> -subdivisionsFactor <num> -upstepCount <number> -upstepFactor <number>"

set argVarList {samplesToAverage sampleInterval settlingTime stepSize threshold \
                  repetitions subdivisions subdivisionFactor upstepCount upstepFactor}
if [llength $args] {
    if {[APSStrictParseArguments $argVarList] || \
        $samplesToAverage<=0 || $sampleInterval<0 || $settlingTime<0 || \
        $stepSize<=0 || $threshold<0 || $repetitions<0 || \
        $subdivisions<0 || $subdivisionFactor<1} {
        puts stderr $usage
        foreach variable $argVarList {
            puts stderr "$variable: [subst \$$variable]"
            }
        exit 1
    }
}

proc APSRunSquishPVs {args} {
    set samplesToAverage 10
    set sampleInterval 0.25
    set settlingTime 5
    set stepSize 0.1
    set threshold 0.1
    set repetitions 1
    set inputFile ""
    set subdivisions 1
    set subdivisionFactor 2.5
    set callback APSNoOp
    set controlVariable ""
    set upstepCount 0
    set upstepFactor 2
    set argVarList {samplesToAverage sampleInterval settlingTime stepSize threshold \
                      repetitions inputFile subdivisions subdivisionFactor \
                      controlVariable upstepCount upstepFactor}
    if {[APSStrictParseArguments $argVarList] || \
          ![string length $inputFile] || ![file exists $inputFile] || \
          $samplesToAverage<=0 || $sampleInterval<0 || $settlingTime<0 || \
          $subdivisions<0 || $subdivisionFactor<1 || \
          $stepSize<=0 || $threshold<0 || $repetitions<0 || \
          $upstepFactor<=1} {
        return -code error "APSRunSquishPVs: bad arguments" }
    if [string length $controlVariable] {
        global $controlVariable
        if [string compare [set $controlVariable] Running]==0 {
            return -code error "APSRunSquishPVs: already running that squish process."
        }
    } else {
        set controlVariable [APSUniqueName dummyControlVariable]
    }
    APSSetVarAndUpdate status Running
    set $controlVariable Running

    eval lappend cmd squishPVs $inputFile \
      -averages=$samplesToAverage,$sampleInterval \
      -settlingTime=$settlingTime -stepSize=$stepSize \
      -threshold=$threshold -repeat=number=$repetitions,pause=1 \
      -subdivisions=$subdivisions,$subdivisionFactor -verbose
    if $upstepCount>0 {
        lappend cmd -upstep=count=$upstepCount,factor=$upstepFactor
    }
    if [catch {exec sdds2stream -parameter=Description $inputFile} result] {
        return -code error "APSRunSquishPVs: $result" }
    set description [lindex $result 0]

    set widget [APSUniqueName .]
    APSExecLog $widget -name "SquishPVs on $description" \
      -callback "APSSetVarAndUpdate status Done ; set $controlVariable Done" \
      -abortCallback "set $controlVariable Done" \
      -cancelCallback "set $controlVariable Done" \
      -width 120 -height 16 -lineLimit 1000 -contextHelp \
      "Shows progress of squishPVs process that is doing optimization task $description" \
      -unixCommand $cmd
    APSDisableButton $widget.buttonRow.ok.button

    return -code ok "Optimization initiated."
}

proc createGrid {} {
    global gridArray
    set w .userFrame.tableFrame.frame
    
    set gridArray(correctors) "{L1:SC1 L1:SC2 L1:SC3} {L1:SC4} {L2:SC1} {L2:SC2} {L2:SC3} {L2:SC4} {L3:SM:SC1} {L3:SM:SC2} {L4:SC1} {L4:SC2} {L4:SC3} {L4:SC4 L5:SC1} {L5:SC2} {L5:SC3}"
    set gridArray(bpms) "L1:P1 L2:P1 L2:P2 L2:P3 L2:P4 L3:P1 L3:P2 L3:P3 L4:P2 L4:P3 L4:P4 L5:P2 L5:P3 L5:P4"
    set gridArray(columns) [llength $gridArray(bpms)]

    set gridArray(colors) "grey \#999999 grey \#999999 grey \#999999 grey \#999999 grey \#999999 grey \#999999 grey \#999999"

    set gridArray(groups) {"1 3" "4 4" "5 5" "6 6" "7 7" "8 8" "9 9" "10 10" "11 11" "12 12" "13 13" "14 15" "16 16" "17 17"}

    set index 1
    set index2 1
    foreach item $gridArray(correctors) color $gridArray(colors) {
	foreach item2 $item {
	    label $w.$index,0 -text $item2 -relief ridge -bd 1
	    grid $w.$index,0 -column 0 -row $index -sticky nsew
	    for {set i 1} {$i <= $gridArray(columns)} {incr i} {
		frame $w.$index,$i -relief ridge -bd 1 -bg $color
		grid $w.$index,$i -column $i -row $index -sticky nsew
	    }	
	    for {set i $index2} {$i <= $gridArray(columns)} {incr i} {
		checkbutton $w.$index,$i.$index,$i \
		    -variable gridArray($index,$i) \
		    -pady 0 -padx 0 \
		    -highlightthickness 0 \
		    -bg $color \
		    -command "checkbuttonClicked -index $index,$i"
		pack $w.$index,$i.$index,$i
		lappend gridArray(indexes) $index,$i
	    }
	    incr index
	}
	incr index2
    }
    set index 1
    foreach item $gridArray(bpms) {
	label $w.0,$index -text "[join [split $item :] ": \n"] " -relief ridge -bd 1
	grid $w.0,$index -column $index -row 0 -sticky nsew
	incr index
    }
}

proc checkbuttonClicked {args} {
#    global gridArray
#    APSStrictParseArguments {index}
#    if {$gridArray($index)} {
#	set row [lindex [split $index ,] 0]
#	foreach group $gridArray(groups) {
#	    if {($row >= [lindex $group 0]) && ($row <= [lindex $group 1])} {
#		for {set i [lindex $group 0]} {$i <= [lindex $group 1]} {incr i} {
#		    if {$row != $i} {
#			foreach index $gridArray(indexes) {
#			    if {$i == [lindex [split $index ,] 0]} {
#				set gridArray($index) 0
#			    }
#			}
#		    }
#		}
#	    }
#	}
#    }
}

proc changeSystem {args} {
    global gridArray
    set system positron
    set axis x
    APSStrictParseArguments {system axis}
    if {$system == "positron"} {
	set default "1,1 2,1 3,1 3,2 4,2 4,3 5,3 5,4 6,4 6,5 7,5 7,6 9,7 9,8 10,8 10,9"
	if {$axis == "y"} {
	    append default " 8,6 8,7"
        }
    } else {
	set default "11,7 11,8 12,8 12,9 13,9 13,10 15,10 15,11 16,11 16,12 17,12"
	set default "11,9 11,10 12,10 12,11 13,11 13,12 15,12 15,13 16,13 16,14 17,14"
    }
    foreach index $gridArray(indexes) {
	set gridArray($index) 0
    }

    foreach index $default {
	set gridArray($index) 1
    }

    global Axis Axis2
    if {$axis == "x"} {
	set Axis HZ
	set Axis2 XPOS
    } else {
	set Axis VL
	set Axis2 YPOS
    }
}

proc RunSquishLinacTraj {} {
    APSDisableButton .userFrame.run.button

    set output "SDDS1"
    foreach parameter "CorrectorPV Gain Description" type "string double string" {
	append output "\n&parameter name=$parameter, type=$type, &end"
    }
    foreach column "BpmPV Weight LowerLimit UpperLimit" type "string double double double" {
	append output "\n&column name=$column, type=$type, &end"
    }
    append output "\n&data mode=ascii, &end"

    global gridArray Axis Axis2
    set active ""
    foreach index $gridArray(indexes) {
	if {$gridArray($index)} {
	    lappend active $index
	}
    }
    if {![llength $active]} {
	APSEnableButton .userFrame.run.button 
	return
    }
    set temp ""
    set i 0
    foreach index $active {
	if {$i != [lindex [split $index ,] 0]} {
	    if {$i != 0} {
		append temp :
	    }
	    set i [lindex [split $index ,] 0]
	}
	append temp "$index "
    }
    set active [split $temp :]
    
    set page 0
    set question ""
    foreach group $active {
	if {[llength $group] == 1} {
	    set weightList "1.0"
	} else {
	    set weightList "10.0"
	    for {set i 1} {$i < [llength $group]} {incr i} {
		lappend weightList "1.0"
	    }
	}
	
	incr page
	append output "\n! page number $page"
	set correctorIndex [expr [lindex [split [lindex $group 0] ,] 0] - 1]
	if {($correctorIndex != 16) && ([llength $group] < 2) && (![llength $question])} {
	    set question [tk_messageBox \
			      -type yesno \
			      -default no \
			      -icon warning \
			      -message "Warning: you've chosen to steer using a single BPM as the readback. This might result in poor steering and beam loss. Are you sure you want to do this?"]
	    if {$question != "yes"} {
		APSEnableButton .userFrame.run.button 
		return
	    }
	}
	
	if {[string range [lindex [join $gridArray(correctors)] $correctorIndex] 0 1] == "L1"} {
	    append output "\n[lindex [join $gridArray(correctors)] $correctorIndex]:$Axis:CurrentAO"
	} else {
	    append output "\n[lindex [join $gridArray(correctors)] $correctorIndex]:$Axis:PS:setCurrentAO"
	}
	append output "\n1.0\nlinac squish file\n\t[llength $group]"
	foreach index $group weight $weightList {
	    set bpmIndex [expr [lindex [split $index ,] 1] - 1]
	    append output "\n[lindex $gridArray(bpms) $bpmIndex]:BPM.$Axis2 $weight -5.0 5.0"
	}
    }
    set fileName /tmp/[APSTmpString]
    APSAddToTempFileList $fileName
    if [catch {open $fileName w} fID] {
	return -code error $fID
    }
    puts $fID $output
    catch {close $fID}
    global samplesToAverage sampleInterval settlingTime stepSize threshold repetitions systemChoice upstepCount upstepFactor subdivisions subdivisionFactor
    catch {APSRunSquishPVs \
               -samplesToAverage $samplesToAverage \
               -sampleInterval $sampleInterval \
               -settlingTime $settlingTime \
               -stepSize $stepSize \
               -threshold $threshold \
               -repetitions $repetitions \
               -inputFile $fileName \
               -controlVariable [file rootname [file tail $systemChoice]]ControlVariable \
               -upstepCount $upstepCount -upstepFactor $upstepFactor \
               -subdivisions $subdivisions \
               -subdivisionFactor $subdivisionFactor } status
    update idletasks
    APSEnableButton .userFrame.run.button 
}

APSApplication . -name squishLinacTraj -version $CVSRevisionAuthor \
  -overview {This tool provides minimization of the linac trajectory for horizontal and vertical.  The linac is cut into two parts: upstream and downstream of the L3 solenoids.}

set status Working...
APSScrolledStatus .status -parent .userFrame -width 60 -textVariable status
update

APSFrame .bpm -parent .userFrame -label "BPM Readings"
set w .userFrame.bpm.frame
APSLabeledEntry .samples -parent $w -label "Samples to average: " \
  -textVariable samplesToAverage -width 32 -contextHelp \
  "Number of samples to average for each BPM reading."
APSLabeledEntry .interval -parent $w -label "Sampling interval (s): " \
  -textVariable sampleInterval -width 32 -contextHelp \
  "Interval in seconds between samples of BPM readings."
APSLabeledEntry .thres -parent $w -label "Change threshold (mm): " \
  -textVariable threshold -width 32 -contextHelp \
  "The size of the change in a BPM reading required for the process to believe it is real."

APSFrame .cor  -parent .userFrame -label "Correctors"
set w .userFrame.cor.frame
APSLabeledEntry .stepsize -parent $w -label "Step size (A): " \
  -textVariable stepSize -width 32 -contextHelp \
  "The size in amperes of the trial steps made with the correctors."
APSLabeledEntry .settling -parent $w -label "Settling time (s): " \
  -textVariable settlingTime -width 32 -contextHelp \
  "The time in seconds to wait after changing a corrector for things to settle down."
APSLabeledEntry .upstepCount -parent $w -label "Interval for increasing step size: " \
  -textVariable upstepCount -width 32 -contextHelp \
  "The number of steps in a single direction that the script will take before it increases the step size."
APSLabeledEntry .upstepFactor -parent $w -label "Factor for increasing step size: " \
  -textVariable upstepFactor -width 32 -contextHelp \
  "The factor by which the step size is increased when a sufficiency number of steps have been taken in one direction."

APSFrame .algor -parent .userFrame -label "Algorithm" 
set w .userFrame.algor.frame
APSLabeledEntry .repetitions -parent $w -label "Repetitions: " \
  -textVariable repetitions -width 32 -contextHelp \
  "Number of times to repeat the optimization before stopping.  Each repetition involves sweeping through all the included correctors."
APSLabeledEntry .subdiv -parent $w -label "Subdivisions: " \
  -textVariable subdivisions -width 32 -contextHelp \
  "Number of times to subdivide the basic step size in the search for the optimum."
APSLabeledEntry .subdivfact -parent $w -label "Subdivision factor: " \
  -textVariable subdivisionFactor -width 32 -contextHelp \
  "Number of times to subdivide the basic step size in the search for the optimum."

set mainDir /home/helios/oagData/linac/squishTraj
set systemChoice horiz/squishPL.in

set fileList {horiz/squishPL.in verti/squishPL.in \
                horiz/squishEL.in verti/squishEL.in}
foreach item $fileList {
    set [file rootname [file tail $item]]ControlVariable Done
}
APSRadioButtonFrame .system -parent .userFrame -orientation horizontal \
  -label "System choice: " -variable systemChoice -limitPerRow 2 \
  -buttonList {"Electron Linac x" "Electron Linac y" \
                 "Positron Linac x" "Positron Linac y"} \
    -valueList $fileList -commandList {"changeSystem -system positron -axis x" "changeSystem -system positron -axis y" "changeSystem -system electron -axis x" "changeSystem -system electron -axis y"}

pack [frame .userFrame.tableFrame] -fill x -pady .1i -padx .1i
grid [label .userFrame.tableFrame.label1 -text "BPMs"] -row 0 -column 1 -sticky ew
grid [label .userFrame.tableFrame.label2  -padx .1i \
	  -text [join [split Correctors ""] \n]] -row 1 -column 0 -sticky ns
grid [frame .userFrame.tableFrame.frame] -row 1 -column 1 -sticky nsew

createGrid

changeSystem -system positron

APSButton .run \
    -parent .userFrame \
    -text Run \
    -command {RunSquishLinacTraj} \
    -contextHelp "Runs squishPVs for the system you've selected."

APSSetVarAndUpdate status Ready


