#!/bin/sh  
# \
exec oagwish "$0" "$@"


# set the path to pick up OAG libraries
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.12 $ \$Author: soliday $"

proc APSLabeledEntryGrid { widget args } {
    global apsContextHelp
    set parent ""
    set noPack 0
    set packOption "-side top -fill x"
    set labelList ""
    set variableList ""
    set contextHelp ""
    set fileButtons 0
    APSStrictParseArguments {parent noPack packOption labelList variableList contextHelp fileButtons}
    
    if {$contextHelp != ""} {
        set apsContextHelp($parent$widget) $contextHelp
    }
    if {$parent == ""} {
        toplevel $widget -bd 1
        wm title $widget $label
    } else {
        frame $parent$widget -bd 1
        if {!$noPack} {
            eval pack $parent$widget $packOption
        }
    }
    set row 0
    foreach label $labelList variable $variableList {
        label $parent$widget.label$row -text $label
        entry $parent$widget.entry$row -relief sunken -textvariable $variable
        grid $parent$widget.label$row -column 0 -row $row -sticky e
        grid $parent$widget.entry$row -column 1 -row $row -sticky ew
        if {$fileButtons} {
            button $parent$widget.button$row -text "F"
            grid $parent$widget.button$row -column 2 -row $row
        }
        incr row
    }
    grid columnconfigure $parent$widget 1 -weight 1
}

proc calcInv {args} {
    set inFile ""
    set outFile ""
    set minimum 0.01
    APSStrictParseArguments {inFile outFile minimum}

    set linkname ""
    if {[file exists $outFile]} {
        if {[file type $outFile] == "link"} {
            set linkFile [file readlink $outFile]
            set directory [file dirname $linkFile]
            if {[string compare $directory .]==0} {
                set directory [file dirname $outFile]
            }
            set name [file tail $linkFile] 
            set linkname $outFile
            APSSetVarAndUpdate status "$linkname is a link to $linkFile file."
            if [catch {APSNextGenerationedName -name $name -separator "-" \
                        -newFile 1 -directory $directory} genName] {
                set outputFile [file readlink $outFile]
                APSSetVarAndUpdate status "$genName"
                APSSetVarAndUpdate status "\nFile not saved."
                bell
                return
            } else {
                set outFile $directory/$genName
                APSSetVarAndUpdate status "The new generationed file \
                        $outFile was created."
            }
        }
    }
    if {([file exists $inFile] == 0) || ([file isdirectory $inFile] == 1)} {
	APSSetVarAndUpdate status "Response file not found"
	return
    }
    if {[llength $outFile] == 0} {
	APSSetVarAndUpdate status "Output file name needed"
	return
    }
    APSSetVarAndUpdate status "Working..."
    global bpmList actuatorList data
    array set datatemp [array get data]
    set data(ColumnNames) "$actuatorList BPMNames"
    set temp [lindex $data(Column.BPMNames) 0]
    foreach item $bpmList {
	set index [lsearch -exact $temp $item]
	set temp [lreplace $temp $index $index]
    }
    foreach item $temp {
	set index [lsearch -exact [lindex $data(Column.BPMNames) 0] $item]
	foreach item2 $data(ColumnNames) {
	    set data(Column.$item2) [list [lreplace [lindex $data(Column.$item2) 0] $index $index]]
	}
    }
    set data(Column.BPMNames) [list $bpmList]
    set invfilename  /tmp/[APSTmpString]
    if [catch {sdds save $invfilename data} result] {
	APSSetVarAndUpdate status "unable to save $invfilename: $result"
	return
    }
    MpRespMatrixCalcInverseModified \
	-inFile $invfilename \
	-outFile [file nativename $outFile] \
	-minimum $minimum
    if {[llength $linkname]} {
        if {([file exists $linkname]) && ([file exists $outFile])} {
            file delete -- $linkname
            exec ln -s $outFile $linkname
        }
    }
    catch {file delete -force -- $invfilename}
    array set data [array get datatemp]
    APSSetVarAndUpdate status "Ready..."    
}

proc loadResponse {args} {
    APSStrictParseArguments {inFile}
    if {([file exists $inFile] == 0) || ([file isdirectory $inFile] == 1)} {
	APSSetVarAndUpdate status "Response file not found"
	return
    }
    global data
    if [catch {sdds load [file nativename $inFile] data} result] {
	APSSetVarAndUpdate status "unable to load foo.sdds: $result"
	return
    }
    set index [lsearch -exact $data(ColumnNames) BPMNames]
    if {$index == -1} {
	APSSetVarAndUpdate status "Unable to find column BPMNames in the response matrix"
	return
    }
    global bpmList actuatorList bpmCommands actuatorCommands
    set bpmCommands ""
    set actuatorCommands ""
    set bpmList [lindex $data(Column.BPMNames) 0]
    set actuatorList [lreplace $data(ColumnNames) $index $index]
    foreach item $bpmList {
	global $item
	set $item 1
	lappend bpmCommands "AddRemoveItem -bpm $item"
    }
    
    foreach item $actuatorList {
	global $item
	set $item 1
	lappend actuatorCommands "AddRemoveItem -actuator $item"
    }
    exec sddsplot -filename -title= \
        $inFile -column=BPMNames,([join $actuatorList ,]) -separate -same \
        -graph=symbol,scale=3,connect &

    destroy .userFrame.bottom
    pack [frame .userFrame.bottom]
    APSCheckButtonFrame .bpms \
	-parent .userFrame.bottom \
	-label "BPMs" \
	-buttonList [lindex $data(Column.BPMNames) 0] \
	-variableList [lindex $data(Column.BPMNames) 0] \
	-commandList $bpmCommands \
	-limitPerRow 5 -allNone 1
    APSCheckButtonFrame .actuators \
	-parent .userFrame.bottom \
	-label "Actuators" \
	-buttonList $actuatorList \
	-variableList $actuatorList \
	-commandList $actuatorCommands \
	-limitPerRow 5 -allNone 1
}

proc AddRemoveItem {args} {
    set bpm ""
    set actuator ""
    APSStrictParseArguments {bpm actuator}
    if {[llength $bpm]} {
	global bpmList 
	set index [lsearch -exact $bpmList $bpm]
	if {$index == -1} {
	    lappend bpmList $bpm
	} else {
	    set bpmList [lreplace $bpmList $index $index]
	} 
    } elseif {[llength actuator]} {
	global actuatorList 
	set index [lsearch -exact $actuatorList $actuator]
	if {$index == -1} {
	    lappend actuatorList $actuator
	} else {
	    set actuatorList [lreplace $actuatorList $index $index]
	} 
    }
}

proc setInput {args} {
    APSParseArguments {dialog}
    global directory inputFile outputFile
    if {$dialog} {
	set filedialog [APSFileSelectDialog [APSUniqueName .] -pattern {*.resp} -path $directory -width 70] 
	if {$filedialog != ""} {
	    set inputFile $filedialog
	    set directory [file dirname $filedialog]
	    if {[llength $outputFile] == 0} {
		set outputFile [file join $directory [file rootname $inputFile].inv]
	    }
	}
    } else {
	destroy .userFrame.bottom
	if {([file exists $inputFile]) && ([file isdirectory $inputFile] == 0)} {
	    loadResponse -inFile $inputFile
	}
    }
}

proc SetupBeamline {beamline plane wavelength} {
    global directory inputFile outputFile actuatorList bpmList
    set directory /home/helios/oagData/controllaw/$beamline
    switch -exact $beamline {
        LINAC {set inputFile [file join $directory ${plane}Linac.matrix.resp]}
        Bypass/Horizontal {set inputFile [file join $directory ${plane}Bypass.matrix.resp]}
        Bypass/Vertical/usingL4 {set inputFile [file join $directory ${plane}Bypass.matrix.resp]}
        Bypass/Vertical/usingL5 {set inputFile [file join $directory ${plane}Bypass.matrix.resp]}
        LEUTL {set inputFile [file join $directory ${plane}Leutl-${wavelength}.matrix.resp]}
    }
    set outputFile [file rootname $inputFile]
    if {[file exists $outputFile]} {
        eval global $actuatorList
        foreach name $actuatorList {
            set $name 0
        }
        set actuatorList [join [exec sdds2stream $outputFile -column=ActuatorNames]]
        eval global $actuatorList
        foreach name $actuatorList {
            set $name 1
        }
        eval global $bpmList
        foreach name $bpmList {
            set $name 0
        }
        set bpmList [exec sddsquery $outputFile -columnlist]
        set index [lsearch -exact $bpmList ActuatorNames]
        set bpmList [lreplace $bpmList $index $index]
        eval global $bpmList
        foreach name $bpmList {
            set $name 1
        }
    }
}

APSApplication . -name InvRespMatrix -version $CVSRevisionAuthor \
  -overview "Provides the ability to get an inverse matrix from a response matrix"


APSMenubarAddMenu .beamlines -parent .menu -text "BeamLines"
.menu.beamlines.menu add command -label "Linac - Horizontal" -command "SetupBeamline LINAC x {}"
.menu.beamlines.menu add command -label "Linac - Vertical" -command "SetupBeamline LINAC y {}"
#.menu.beamlines.menu add command -label "Linac+Leutl - Horizontal" -command "SetupBeamline LINAC_LEUTL x {}"
#.menu.beamlines.menu add command -label "Linac+Leutl - Vertical" -command "SetupBeamline LINAC_LEUTL y {}"
.menu.beamlines.menu add command -label "Bypass - Horizontal" -command "SetupBeamline Bypass/Horizontal x {}"
.menu.beamlines.menu add command -label "Bypass - Vertical - usingL4" -command "SetupBeamline Bypass/Vertical/usingL4 y {}"
.menu.beamlines.menu add command -label "Bypass - Vertical - usingL5" -command "SetupBeamline Bypass/Vertical/usingL5 y {}"
.menu.beamlines.menu add command -label "Leutl-157nm - Horizontal" -command "SetupBeamline LEUTL x 157nm"
.menu.beamlines.menu add command -label "Leutl-157nm - Vertical" -command "SetupBeamline LEUTL y 157nm"
.menu.beamlines.menu add command -label "Leutl-265nm - Horizontal" -command "SetupBeamline LEUTL x 265nm"
.menu.beamlines.menu add command -label "Leutl-265nm - Vertical" -command "SetupBeamline LEUTL y 265nm"

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


set inputFile ""
set outputFile ""
set args $argv
APSParseArguments {inputFile outputFile}

set directory /home/helios/oagData/controllaw
if {![file exists $directory]} {
    set directory [pwd]
}

APSLabeledEntryGrid .files -parent .userFrame \
    -labelList {"Input filename:" "Output filename:"} \
    -variableList {"inputFile" "outputFile"} \
    -fileButtons 1 \
    -contextHelp "Enter the input response file and the output inverse response file"
set minimum 0.01
APSLabeledEntry .minimum -parent .userFrame \
    -label "        Minimum:" \
    -textVariable minimum \
    -type real\
    -contextHelp "minimumSingularValueRatio used in sddspseudoinverse:\nReject singular values less than the\nlargest singular value times this ratio."

pack configure .userFrame.minimum.entry -expand true

.userFrame.files.button0 configure \
    -command  {setInput -dialog 1}
.userFrame.files.button1 configure \
    -command  {
	set filedialog [APSFileSelectDialog [APSUniqueName .] -pattern {*.inv} -path $directory -width 70]
	if {$filedialog != ""} {
	    set outputFile $filedialog
	    set directory [file dirname $filedialog]
	    if {[llength $inputFile] == 0} {
		set inputFile [file join $directory [file rootname $outputFile].resp]
	    }
	}
    }
if [file exist $inputFile] {
   loadResponse -inFile $inputFile 
}

pack [frame .userFrame.buttons] -fill x
APSButton .start \
    -parent .userFrame.buttons \
    -text Invert \
    -command {calcInv -inFile $inputFile -outFile $outputFile -minimum $minimum} 

trace variable inputFile w {setInput -dialog 0}
