proc APSChooseBestIDSetupGlobalVars {args} {
    global mainDataDirectory web subdirSuffix latticePrefix
    global resultsPlot1List resultsPlot2List resultsPrintList
    global dataDirectory current feType optimizationQuantity
    global straightType additionalOptimizations idLength idMaximumLength scIdMaximumLength
    global idType gap periodOption periodFrac periodMin periodMax
    global defaultRangeLow defaultRangeHigh nBands
    global plotOutputType plotOutputRootname sortType ranks 
    global bandOn bandLow bandHigh referenceType
    global elementNameList KEdgeEnergyList KEdge elementFlag
    
    APSChooseBestIDElementSetup

    if {![info exists subdirSuffix]} {
        set subdirSuffix Data
    }
    if {![info exists latticePrefix]} {
        set latticePrefix aps
    }
    set resultsPlot1List(none) ""
    set resultsPlot2List(none) ""
    set resultsPrintList(none) ""
    set dataDirectory(HPM) $mainDataDirectory/HPM-$subdirSuffix
    set dataDirectory(Revolver2) $mainDataDirectory/HPM-$subdirSuffix
    set dataDirectory(Revolver3) ""
    set dataDirectory(SCU) $mainDataDirectory/SCU-$subdirSuffix
    set current 100
    set feType CFE
    set optimizationQuantity Brightness
    set straightType Short
    set idLength(Full) 0
    set idLength(Half) 1
    set idLength(2.0) 1
    set idLength(2.4) 1
    set idLength(4.8) 0
    set idMaximumLength 10.0
    set scIdMaximumLength 10.0
    set idType(HPM) 1
    set idType(Revolver2) 1
    set idType(Revolver3) 0
    set idType(SCU) 0
    set gap 10.75
    set periodOption All
    set periodFrac .?
    set periodMin 10.0
    set periodMax 56.0
    set defaultRangeLow 0
    set defaultRangeHigh 120
    set nBands 0
    set plotOutputType png
    set plotOutputRootname ""
    set sortType(ave) 1
    set sortType(min) 1
    set sortType(max) 1
    set sortType(dip) 0
    set ranks 1
    set referenceType None
    set additionalOptimizations(TotalPower) 0
    set additionalOptimizations(TotalPowerSpread) 0

    foreach element $elementNameList {
        set elementFlag($element) 0
    }

    for {set i 0} {$i < 1} {incr i} {
	set bandOn($i) 1
	set bandLow($i) 3.3
	set bandHigh($i) 33.0
    }
    for {set i 1} {$i < 10} {incr i} {
	set bandOn($i) 0
	set bandLow($i) 0
	set bandHigh($i) 0
    }

    if {$web} {
	global cgi
	foreach varname "searching current feType optimizationQuantity straightType idMaximumLength scIdMaximumLength gap periodOption periodFrac periodMin periodMax defaultRangeLow defaultRangeHigh ranks referenceType" {
	    set cgi($varname) ""
	}
        foreach element $elementNameList {
            set cgi(elementFlag$element) ""
        }
	foreach varname "idLengthFull idLengthHalf idLength2.0 idLength2.4 idLength4.8" {
	    set cgi($varname) ""
	}
	foreach varname "additionalOptimizationsTotalPower additionalOptimizationsTotalPowerSpread" {
	    set cgi($varname) ""
	}
	foreach varname "idTypeHPM idTypeRevolver2 idTypeSCU" {
	    set cgi($varname) ""
	}
	foreach varname "sortTypeave sortTypemin sortTypemax sortTypedip" {
	    set cgi($varname) ""
	}
	for {set i 0} {$i < 10} {incr i} {
	    foreach varname "bandOn$i bandLow$i bandHigh$i" {
		set cgi($varname) ""
	    }
	}
	Cgi_Parse
	if {$cgi(searching) == 1} {
	    foreach varname "current feType optimizationQuantity straightType idMaximumLength scIdMaximumLength gap periodOption periodFrac referenceType" {
		set $varname $cgi($varname)
	    }
	    foreach varname "periodMin periodMax defaultRangeLow defaultRangeHigh ranks" {
		if {[string trim [lindex $cgi($varname) 0]] != ""} {
		    set $varname [string trim [lindex $cgi($varname) 0]]
		}
	    }
            foreach element $elementNameList {
                set varname elementFlag$element
                set index $element
                if {$cgi($varname) == 1} {
		    set elementFlag($index) 1
		} else {
		    set elementFlag($index) 0
		}
            }
	    foreach varname "idLengthFull idLengthHalf idLength2.0 idLength2.4 idLength4.8" index "Full Half 2.0 2.4 4.8" {
		if {$cgi($varname) == 1} {
		    set idLength($index) 1
		} else {
		    set idLength($index) 0
		}
	    }
	    foreach varname "additionalOptimizationsTotalPower additionalOptimizationsTotalPowerSpread" index "TotalPower TotalPowerSpread" {
		if {$cgi($varname) == 1} {
		    set additionalOptimizations($index) 1
		} else {
		    set additionalOptimizations($index) 0
		}
	    }
	    foreach varname "idTypeHPM idTypeRevolver2 idTypeSCU" index "HPM Revolver2 SCU" {
		if {$cgi($varname) == 1} {
		    set idType($index) 1
		} else {
		    set idType($index) 0
		}
	    }
	    foreach varname "sortTypeave sortTypemin sortTypemax sortTypedip" index "ave min max dip" {
		if {$cgi($varname) == 1} {
		    set sortType($index) 1
		} else {
		    set sortType($index) 0
		}
	    }
	    for {set i 0} {$i < 10} {incr i} {
		set bandOn($i) $cgi(bandOn$i)
		if {[string trim [lindex $cgi(bandLow$i) 0]] != ""} {
		    set bandLow($i) [string trim [lindex $cgi(bandLow$i) 0]]
		}
		if {[string trim [lindex $cgi(bandHigh$i) 0]] != ""} {
		    set bandHigh($i) [string trim [lindex $cgi(bandHigh$i) 0]]
		}
	    }
            if {($periodFrac != ".0")} {
                set periodFrac ".?"
            }
	}
    }
}

proc APSChooseBestIDSetupGUI {args} {
    global web elementNameList

    if {!$web} {
	APSApplication . -name chooseBestID \
	    -version 1.0 -overview "Allows choosing the best insertion devices for a given application."
    } else {
	Cgi_Header "Allows choosing the best insertion devices for a given application." {BGCOLOR=white TEXT=black}
	set output "<form ACTION='http://ops.aps.anl.gov/cgi-bin/chooseBestID.cgi' METHOD='GET' NAME='search' >"
    }

    if {!$web} {
	APSChooseBestIDSetStatus Working...
	APSScrolledStatus .status \
	    -parent .userFrame \
	    -textVariable status \
	    -width 65 \
	    -packOption "-fill both -expand true"
    }

    set label "Beam current (mA):"
    set variable current
    set buttonList [list 100 150 200]
    set valueList [list 100 150 200]
    if {!$web} {
	APSRadioButtonFrame .current -parent .userFrame -label $label \
	    -orientation horizontal -variable $variable \
	    -buttonList $buttonList \
	    -valueList $valueList \
	    -contextHelp "100 mA is the present operating current. 150 mA is considered for future improvement, while 200mA is not planned at this time."
    } else {
	global $variable
	append output "$label "
	foreach button $buttonList value $valueList {
	    if {[set $variable] == $value} {
		append output "<input type=radio name=$variable value=$value checked>$button "
	    } else {
		append output "<input type=radio name=$variable value=$value>$button "
	    }
	}
	append output "<br>"
    }

    set label "Front end type:"
    set variable feType
    set buttonList [list Canted HHL]
    set valueList [list CFE HHL]
    if {!$web} {
	APSRadioButtonFrame .rbfe -parent .userFrame -label $label \
	    -orientation horizontal -variable $variable \
	    -buttonList $buttonList \
	    -valueList $valueList \
	    -contextHelp "Choose the type of front end. The HHL (High Heat Load) front end has the highest existing power-handling capacity."
    } else {
	global $variable
	append output "$label "
	foreach button $buttonList value $valueList {
	    if {[set $variable] == $value} {
		append output "<input type=radio name=$variable value=$value checked>$button "
	    } else {
		append output "<input type=radio name=$variable value=$value>$button "
	    }
	}
	append output "<br>"
    }

    set label "Optimization quantity: "
    set variable optimizationQuantity
    set buttonList [list Brightness "Spectral flux density" "Spectral flux"]
    set valueList [list Brightness SpectralFluxDensity SpectralFlux]
    if {!$web} {
	APSRadioButtonFrame .mode -parent .userFrame -label $label \
	    -orientation horizontal -variable $variable \
	    -buttonList $buttonList \
	    -valueList $valueList \
	    -contextHelp "Optimization can be performed for various quantities. The results typically don't depend strongly on this choice, but if you are interested in a particular quantity, this allows you to see plots of that quantity."
    } else {
	global $variable
	append output "$label "
	foreach button $buttonList value $valueList {
	    if {[set $variable] == $value} {
		append output "<input type=radio name=$variable value=$value checked>$button "
	    } else {
		append output "<input type=radio name=$variable value=$value>$button "
	    }
	}
	append output "<br>"
    }

    set label "Additional optimization quantities: "
    set variable additionalOptimizations
    set variableIndexList [list TotalPower TotalPowerSpread]
    set variableList [list additionalOptimizations(TotalPower) additionalOptimizations(TotalPowerSpread)]
    set buttonList [list "Min. Power" "Min. Power Variation"]
    if {!$web} {
	APSCheckButtonFrame .addOpt -parent .userFrame -label $label \
	    -orientation horizontal \
	    -buttonList $buttonList \
	    -variableList $variableList \
	    -contextHelp "In addition to optimizing the main performance measure (e.g., Brightness), one can optimize certain power-related quantities. Even if not selected, the power and power density are limited by the front end choice."
    } else {
	global $variable
	append output "$label "
	foreach button $buttonList variableIndex $variableIndexList {
	    if {[set ${variable}($variableIndex)]} {
		append output "<input type=checkbox name=${variable}$variableIndex value=1 checked>$button "
	    } else {
		append output "<input type=checkbox name=${variable}$variableIndex value=1>$button "
	    }
	}
	append output "<br>"
    }
    
    set label "Straight section type:"
    set variable straightType
    set buttonList [list Short Long]
    set valueList [list Short Long]

    if {!$web} {
	APSRadioButtonFrame .sstype -parent .userFrame -label $label \
	    -orientation horizontal -variable $variable \
	    -buttonList $buttonList \
	    -valueList $valueList \
	    -contextHelp "Straight sections normally accommodate at most 4.8m worth of insertion, and about half that if canting is used. In the upgrade, a number of Long Straight Sections (LSS) will be made available."
    } else {
	global $variable
	append output "$label "
	foreach button $buttonList value $valueList {
	    if {[set $variable] == $value} {
		append output "<input type=radio name=$variable value=$value checked>$button "
	    } else {
		append output "<input type=radio name=$variable value=$value>$button "
	    }
	}
	append output "<br>"
    }

    set label "Undulator length (m): "
    set variable idLength
    set variableIndexList [list Full Half 2.0 2.4 4.8]
    set variableList [list idLength(Full) idLength(Half) idLength(2.0) idLength(2.4) idLength(4.8)]
    set buttonList [list Full Half 2.0 2.4 4.8]
    if {!$web} {
	APSCheckButtonFrame .ulength -parent .userFrame -label $label \
	    -orientation horizontal \
	    -buttonList $buttonList \
	    -variableList $variableList \
	    -contextHelp "Full and Half length IDs are understood for all ID and straight section types. The device lengths chosen will depend on the type of device and incorporate information about what the maximum workable length is thought to be. For example, for canted HPM devices, the assumption is that a 2.1m device can fit in a short straight. For SCUs, the assumption is that 0.6m is needed for warm-to-cold and cold-to-warm transitions. One can also explicitly choose the magnetic length as 2.0 or 2.4 m."
    } else {
	global $variable
	append output "$label "
	foreach button $buttonList variableIndex $variableIndexList {
	    if {[set ${variable}($variableIndex)]} {
		append output "<input type=checkbox name=${variable}$variableIndex value=1 checked>$button "
	    } else {
		append output "<input type=checkbox name=${variable}$variableIndex value=1>$button "
	    }
	}
	append output "<br>"
    }

    set label "Maximum ID magnetic length: "
    set variable idMaximumLength
    set buttonList [list None 2.0m 4.8m]
    set valueList [list 10.0 2.0  4.8]
    if {!$web} {
	APSRadioButtonFrame .rlength -parent .userFrame -label $label \
	    -orientation horizontal -variable $variable \
	    -buttonList $buttonList \
	    -valueList $valueList \
	    -contextHelp "Specify the maximum allowed magnetic length."
    } else {
	global $variable
	append output "$label "
	foreach button $buttonList value $valueList {
	    if {[set $variable] == $value} {
		append output "<input type=radio name=$variable value=$value checked>$button "
	    } else {
		append output "<input type=radio name=$variable value=$value>$button "
	    }
	}
	append output "<br>"
    }

    set label "Maximum SCU magnetic length: "
    set variable scIdMaximumLength
    set buttonList [list None 2.0m 2.5m 3.0m 3.5m]
    set valueList [list  10.0 2.0 2.5 3.0 3.5]
    if {!$web} {
	APSRadioButtonFrame .rlengthsc -parent .userFrame -label $label \
	    -orientation horizontal -variable $variable \
	    -buttonList $buttonList \
	    -valueList $valueList \
	    -contextHelp "Specify the maximum allowed magnetic length for SCUs."
    } else {
	global $variable
	append output "$label "
	foreach button $buttonList value $valueList {
	    if {[set $variable] == $value} {
		append output "<input type=radio name=$variable value=$value checked>$button "
	    } else {
		append output "<input type=radio name=$variable value=$value>$button "
	    }
	}
	append output "<br>"
    }

    set label "Undulator type: "
    set variable idType
    set variableIndexList [list HPM Revolver2 SCU]
    set variableList [list idType(HPM) idType(Revolver2) idType(SCU)] 
    set buttonList [list HPM Revolver2 SCU]
    if {!$web} {
	APSCheckButtonFrame .utype -parent .userFrame -label $label \
	    -orientation horizontal \
	    -buttonList $buttonList \
	    -variableList $variableList
    } else {
	global $variable
	append output "$label "
	foreach button $buttonList variableIndex $variableIndexList {
	    if {[set ${variable}($variableIndex)]} {
		append output "<input type=checkbox name=${variable}$variableIndex value=1 checked>$button "
	    } else {
		append output "<input type=checkbox name=${variable}$variableIndex value=1>$button "
	    }
	}
	append output "<br>"
    }

    set label "HPM and revolver gap (mm): "
    set variable gap
    set buttonList [list 11.0 10.75 10.5 13.0 15.0]
    set valueList [list 11.0 10.75 10.5 13.0 15.0]
    if {!$web} {
	APSRadioButtonFrame .gap -parent .userFrame -label $label \
	    -orientation horizontal -variable $variable \
	    -buttonList $buttonList \
	    -valueList $valueList \
	    -contextHelp "Present APS HPM undulators typically run with a minimum gap of 11 mm, although in some cases gaps as low as 10.5 mm have been provided through careful construction and alignment. For SCUs, the magnetic gap is fixed at 9.5 mm."
    } else {
	global $variable
	append output "$label "
	foreach button $buttonList value $valueList {
	    if {[set $variable] == $value} {
		append output "<input type=radio name=$variable value=$value checked>$button "
	    } else {
		append output "<input type=radio name=$variable value=$value>$button "
	    }
	}
	append output "<br>"
    }

    set label "Periods to consider: "
    set variable periodOption
    set buttonList [list Existing All]
    set valueList [list Existing All]
    if {!$web} {
	APSRadioButtonFrame .periods -parent .userFrame -label $label \
	    -orientation horizontal -variable $variable \
	    -buttonList $buttonList \
	    -valueList $valueList \
	    -contextHelp "For revolvers, we restrict periods to 17 to 33 mm in 1 mm steps. Present APS undulators have periods of 18, 23, 27, 30, 33, 35, and 55 mm. APS-U is presently considering only these periods. However, this software can analyze the benefits of the full selection from 17 to 33 mm. For SCUs all periods are allowed."
    } else {
	global $variable
	append output "$label "
	foreach button $buttonList value $valueList {
	    if {[set $variable] == $value} {
		append output "<input type=radio name=$variable value=$value checked>$button "
	    } else {
		append output "<input type=radio name=$variable value=$value>$button "
	    }
	}
	append output "<br>"
    }

    set label "0.5mm period increments: "
    set variable periodFrac
    set buttonList [list Yes No]
    set valueList [list .? .0]
    if {!$web} {
	APSRadioButtonFrame .periodFrac -parent .userFrame -label $label \
	    -orientation horizontal -variable $variable \
	    -buttonList $buttonList -valueList $valueList \
	    -contextHelp "Select whether to consider periods with 0.5 mm increments. E.g., 32.5 in addition to 32.0"
    } else {
	global $variable
	append output "$label "
	foreach button $buttonList value $valueList {
	    if {[set $variable] == $value} {
		append output "<input type=radio name=$variable value=$value checked>$button "
	    } else {
		append output "<input type=radio name=$variable value=$value>$button "
	    }
	}
	append output "<br>"
    }
    
    set label "Minimum, maximum period (mm): "
    set variableList [list periodMin periodMax] 
    if {!$web} {
	APSLabeledEntryFrame .pMinMax -parent .userFrame -label $label \
	    -orientation horizontal \
	    -variableList $variableList \
	    -contextHelp "Enter the minimum and maximum period to allow."
    } else {
	append output "$label "
	foreach variable $variableList {
	    global $variable
	    append output "<input type=text size=10 name=$variable value=[set $variable]>"
	}
	append output "<br>"
    }

    set label "Optimize: "
    set buttonList [list "Band Ave." "Band Min." "Band Max." "Few Dips"]
    set variableList [list sortType(ave) sortType(min) sortType(max) sortType(dip)]
    set variable sortType
    set variableIndexList [list ave min max dip]
    if {!$web} {
	APSCheckButtonFrame .sort -parent .userFrame -label $label \
	    -orientation horizontal \
	    -buttonList $buttonList \
	    -variableList $variableList \
	    -contextHelp "Select which statistics to optimize in each band. \"Band Ave.\" is the average value in the band, etc. \"Few Dips\" refers to minimization of the number of dips in the spectrum that exceed 50%."
    } else {
	global $variable
	append output "$label "
	foreach button $buttonList variableIndex $variableIndexList {
	    if {[set ${variable}($variableIndex)]} {
		append output "<input type=checkbox name=${variable}$variableIndex value=1 checked>$button "
	    } else {
		append output "<input type=checkbox name=${variable}$variableIndex value=1>$button "
	    }
	}
	append output "<br>"
    }

    set label "Ranks to include: "
    set variable ranks
    if {!$web} {
	APSLabeledEntry .ranks -parent .userFrame -label $label \
	    -textVariable $variable -contextHelp "Enter the number of ranks to include (1 is the default)" 
    } else {
	append output "$label "
	global $variable
	append output "<input type=text size=10 name=$variable value=[set $variable]><br>"
    }

    set label "Default plot range (keV):"
    set variableList [list defaultRangeLow defaultRangeHigh]
    if {!$web} {
	APSLabeledEntryFrame .range -parent .userFrame -label $label \
	    -orientation horizontal -variableList $variableList 
    } else {
	append output "$label "
	foreach variable $variableList {
	    global $variable
	    append output "<input type=text size=10 name=$variable value=[set $variable]>"
	}
	append output "<br>"
    }

    set label "Reference: "
    set variable referenceType
    set buttonList [list None U23 U27 U30 U33] 
    set valueList  $buttonList
    if {!$web} {
        APSRadioButtonFrame .rbref -parent .userFrame -label $label \
          -orientation horizontal -variable $variable \
          -buttonList $buttonList -valueList $valueList -contextHelp \
          "Select the reference curve to display along with the optimum curves."
    } else {
	global $variable
	append output "$label "
	foreach button $buttonList value $valueList {
	    if {[set $variable] == $value} {
		append output "<input type=radio name=$variable value=$value checked>$button "
	    } else {
		append output "<input type=radio name=$variable value=$value>$button "
	    }
	}
	append output "<br>"
    }

    set elementVariableList ""
    set elementButtonList ""
    set Z 1
    foreach element $elementNameList {
        lappend elementButtonList "[format %5s ${element}/$Z]"
        incr Z
        lappend elementVariableList elementFlag($element) 
    }
    set label "K Edges: "
    set variable elementFlag
    set variableIndexList $elementNameList
    set variableList $elementVariableList
    set buttonList $elementButtonList
    if {!$web} {
	APSCheckButtonFrame .kedge -parent .userFrame -label $label \
	    -orientation horizontal -limitPerRow 12 \
	    -buttonList $buttonList \
	    -variableList $variableList -contextHelp "Choose elements for which to add K-edge lines. A region of +/-0.1 keV is added around each line."
    } else {
	global $variable
	append output "<br>$label "
	foreach button $buttonList variableIndex $variableIndexList {
	    if {[set ${variable}($variableIndex)]} {
		append output "<input type=checkbox name=${variable}$variableIndex value=1 checked>$button "
	    } else {
		append output "<input type=checkbox name=${variable}$variableIndex value=1>$button "
	    }
	}
	append output "<br>"
    }

    if {!$web} {
	APSChooseBestIDAddPhotonBand -low 3.3 -high 33.0 -on 1
	
	APSFrame .buttons -parent .userFrame
	set w .userFrame.buttons.frame
	APSButton .addBand -parent $w -text "Add Band" -command APSChooseBestIDAddPhotonBand 
	APSButton .search -parent $w -text "Search" -command APSChooseBestIDRunSearch

	APSChooseBestIDSetStatus Ready.
    } else {
	global bandOn bandLow bandHigh
	for {set i 0} {$i<1} {incr i} {
	    append output "<hr>Band $i &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Enable: "
	    if {$bandOn($i) == 1} {
		append output "<input type=radio name=bandOn$i value=1 checked>Yes "
		append output "<input type=radio name=bandOn$i value=0>No "
	    } else {
		append output "<input type=radio name=bandOn$i value=1>Yes "
		append output "<input type=radio name=bandOn$i value=0 checked>No "
	    }
	    append output "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "
	    append output "Low, High (keV): "
	    append output "<input type=text size=10 name=bandLow$i value=$bandLow($i)> "
	    append output "<input type=text size=10 name=bandHigh$i value=$bandHigh($i)> <br>"
	}
	for {set i 1} {$i<10} {incr i} {
	    append output "<hr>Band $i &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Enable: "
	    if {$bandOn($i) == 1} {
		append output "<input type=radio name=bandOn$i value=1 checked>Yes "
		append output "<input type=radio name=bandOn$i value=0>No "
	    } else {
		append output "<input type=radio name=bandOn$i value=1>Yes "
		append output "<input type=radio name=bandOn$i value=0 checked>No "
	    }
	    append output "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "
	    append output "Low, High (keV): "
	    append output "<input type=text size=10 name=bandLow$i value=$bandLow($i)> "
	    append output "<input type=text size=10 name=bandHigh$i value=$bandHigh($i)> <br>"
	}
	append output "<hr><input type=hidden name=searching value=1>"
	append output "<input TYPE='submit' VALUE='Search'></form>"
	puts $output
    }

}

proc APSChooseBestIDSetStatus {text} {
    global status web
    if {$web} {
	puts "[clock format [clock seconds] -format %H:%M:%S]: $text <br>"
    } else {
	set status "[clock format [clock seconds] -format %H:%M:%S]: $text"
	update
    }
}

proc APSChooseBestIDAddPhotonBand {args} {
    set low 0
    set high 0
    set on 1
    APSStrictParseArguments {low high on}
    global nBands bandLow bandHigh bandOn
    
    if $nBands==0 {
	APSFrame .bands -parent .userFrame 
    }
    set bandLow($nBands) $low
    set bandHigh($nBands) $high
    set bandOn($nBands) $on
    APSFrame .band$nBands -parent .userFrame.bands.frame -label "Band $nBands"
    set w .userFrame.bands.frame.band$nBands.frame
    APSRadioButtonFrame .onoff -parent $w -label "Enable: " \
	-orientation horizontal -packOption "-side left" \
	-variable bandOn($nBands) -buttonList [list Yes No] -valueList [list 1 0]
    APSLabeledEntryFrame .lohi -parent $w -label "Low, High (keV): " \
	-orientation horizontal -packOption "-side left" \
	-variableList [list bandLow($nBands) bandHigh($nBands)] 
    incr nBands
}

proc APSChooseBestIDRunSearch {} {
    global current feType optimizationQuantity straightType idLength additionalOptimizations idType gap periodOption
    global nBands bandLow bandHigh bandIDs bandOn
    global dataDirectory idMaximumLength periodMin periodMax periodFrac scIdMaximumLength
    global resultsPlot1List resultsPlot2List resultsPrintoutList resultsTag
    global ranks sortType referenceType defaultRangeLow defaultRangeHigh
    global elementFlag pickedElementList 

    set ranks [expr int($ranks)]
    if $ranks<1 {set ranks 1}

    set pickedElementList ""
    foreach element [array names elementFlag] {
        if {$elementFlag($element)} {
            lappend pickedElementList $element
        }
    }

    set resultsTag $current,$feType,$optimizationQuantity,$straightType,$gap,$periodOption,$nBands,$idMaximumLength,$periodMin,$periodMax,$scIdMaximumLength,$ranks,$sortType(ave),$sortType(min),$sortType(max),$sortType(dip),$referenceType,$defaultRangeLow,$defaultRangeHigh,[join $pickedElementList ,]
    if [string compare $periodFrac .0]==0 {
	append resultsTag ,.0
    } else {
	append resultsTag ,.5
    }
    foreach name [list idLength idType bandOn bandLow bandHigh additionalOptimizations] {
	foreach tag [array names $name] {
	    lappend resultsTag [set $name\($tag)]
	}
    }
    if [lsearch [array names resultsPlot1List] $resultsTag]!=-1 {
	APSChooseBestIDSetStatus "Displaying cached results."
	eval exec /usr/local/oag/apps/bin/linux-x86_64/sddsplot.00068 $resultsPlot1List($resultsTag) &
	eval exec /usr/local/oag/apps/bin/linux-x86_64/sddsplot.00068 $resultsPlot2List($resultsTag) &
	set tmpW .[APSTmpString]
	eval APSFileDisplayWindow $tmpW $resultsPrintoutList($resultsTag) 
        APSButton .replot -parent $tmpW.buttonRow -text Replot -command "APSChooseBestIDReplot \"$resultsTag\""
        APSButton .savePlot -parent $tmpW.buttonRow -text "Save Plots" -command "APSChooseBestIDSavePlots \"$resultsTag\""
	return
    }

    APSChooseBestIDSetStatus "Working..."
    set dataFileList [APSChooseBestIDFindRelevantFiles]
    if [llength $dataFileList]==0 {
	APSChooseBestIDSetStatus "No data matching your request."
	return 
    }
    APSChooseBestIDSetStatus "[llength $dataFileList] files found"
    APSChooseBestIDSetStatus "Analyzing..."

    set rootname /tmp/[APSTmpString]

    set bestFileList [APSChooseBestIDFindBestFiles -dataFileList $dataFileList -rootname $rootname]
    APSChooseBestIDSetStatus "Done."
}

proc APSChooseBestIDReplot {tag} {
    global resultsPlot1List resultsPlot2List resultsPrintoutList
    eval exec /usr/local/oag/apps/bin/linux-x86_64/sddsplot.00068 $resultsPlot1List($tag) &
    eval exec /usr/local/oag/apps/bin/linux-x86_64/sddsplot.00068 $resultsPlot2List($tag) &
}

proc APSChooseBestIDSavePlots {tag} {
    global resultsPlot1List resultsPlot2List resultsPrintoutList
    global plotOutputType plotOutputRootname savePlotsSem
    
    set tmpW .[APSTmpString]
    APSDialogBox $tmpW \
        -name "Save plots" \
        -okCommand "set savePlotsSem 1" \
        -cancelCommand "set savePlotsSem 0"
    APSRadioButtonFrame .type -parent $tmpW.userFrame -label "Type: " \
        -orientation horizontal -variable plotOutputType \
        -buttonList "PNG PDF Postscript" -valueList "png pdf ps" 
    APSLabeledEntry .rootname -parent $tmpW.userFrame \
        -textVariable plotOutputRootname \
        -label "Rootname: " -width 20 -type alpha 
    set savePlotsSem 0
    tkwait variable savePlotsSem
    if !$savePlotsSem {
        return
    }
    switch $plotOutputType {
        png {
            catch {eval exec /usr/local/oag/apps/bin/linux-x86_64/sddsplot.00068 -device=hpng,onwhite,template=${plotOutputRootname}-%03ld.png -thick=2 -line=0,thick=2 \
                     $resultsPlot1List($tag) }
            catch {eval exec /usr/local/oag/apps/bin/linux-x86_64/sddsplot.00068 -device=hpng,onwhite,template=${plotOutputRootname}-%03ldPower.png -thick=2 -line=0,thick=2 \
                     $resultsPlot2List($tag) }
        }
        ps {
            catch {eval exec /usr/local/oag/apps/bin/linux-x86_64/sddsplot.00068 -device=cpost -output=${plotOutputRootname}.ps -thick=2 -line=0,thick=2 \
                     $resultsPlot1List($tag) }
            catch {eval exec /usr/local/oag/apps/bin/linux-x86_64/sddsplot.00068 -device=cpost -output=${plotOutputRootname}-Power.ps -thick=2 -line=0,thick=2 \
                     $resultsPlot2List($tag) }
        }
        pdf {
            catch {eval exec /usr/local/oag/apps/bin/linux-x86_64/sddsplot.00068 -device=cpost -output=${plotOutputRootname}.ps -thick=2 -line=0,thick=2 \
                     $resultsPlot1List($tag) }
            exec ps2pdf13 ${plotOutputRootname}.ps ${plotOutputRootname}.pdf
            catch {eval exec /usr/local/oag/apps/bin/linux-x86_64/sddsplot.00068 -device=cpost -output=${plotOutputRootname}-Power.ps -thick=2 -line=0,thick=2 \
                     $resultsPlot2List($tag) }
            exec ps2pdf13 ${plotOutputRootname}-Power.ps ${plotOutputRootname}-Power.pdf
            file delete ${plotOutputRootname}.ps ${plotOutputRootname}-Power.ps
        }
    }
    APSChooseBestIDSetStatus "Plots have been saved"
}

proc APSChooseBestIDFindRelevantFiles {} {
    set dataFileList ""
    global current feType optimizationQuantity straightType idLength idType gap periodOption
    global dataDirectory idMaximumLength periodMin periodMax periodFrac scIdMaximumLength
    if {[string compare $feType LCFE]==0 && [string compare $straightType Short]==0} {
        APSChooseBestIDSetStatus "Must choose Long straight for LSS Canted Front End"
        return 
    }
    foreach type [array names idType] {
	if !$idType($type) continue
	foreach length [array names idLength] {
	    if !$idLength($length) continue
	    APSChooseBestIDSetStatus "Searching for $type $length"
	    switch $type {
		HPM {
		    eval lappend dataFileList [APSChooseBestIDFindDataFiles -type $type -dataDirectory $dataDirectory($type) -straightType $straightType -idLength $length -feType $feType -current $current -gap $gap -periodOption $periodOption -maximumLength $idMaximumLength -periodMin $periodMin -periodMax $periodMax -periodFrac $periodFrac]
		}
		Revolver2 {
		    eval lappend dataFileList [APSChooseBestIDFindDataFiles -type $type -dataDirectory $dataDirectory($type) -straightType $straightType -idLength $length -feType $feType -current $current -gap $gap -periodOption $periodOption -maximumLength $idMaximumLength -periodMin $periodMin -periodMax $periodMax -periodFrac $periodFrac]
		}
		Revolver3 {
		    eval lappend dataFileList [APSChooseBestIDFindDataFiles -type $type -dataDirectory $dataDirectory($type) -straightType $straightType -idLength $length -feType $feType -current $current -gap $gap -periodOption $periodOption -maximumLength $idMaximumLength -periodMin $periodMin -periodMax $periodMax -periodFrac $periodFrac]
		}
		SCU {
                    eval lappend dataFileList [APSChooseBestIDFindScuDataFiles -dataDirectory $dataDirectory($type) -straightType $straightType -idLength $length -feType $feType -current $current \
                                                 -maximumLength $scIdMaximumLength -periodMin $periodMin -periodMax $periodMax -periodFrac $periodFrac]
		}
		default {
		    APSChooseBestIDSetStatus "Unknown undulator type \"$type\" !"
		    return 
		}
	    }
	}
    }

    set dataFileList [lsort -unique $dataFileList] 
    return $dataFileList
}

proc APSChooseBestIDFindBestFiles {args} {
    set dataFileList ""
    set rootname ""
    APSStrictParseArguments {dataFileList rootname}
    global nBands bandLow bandHigh bandIDs bandOn
    global optimizationQuantity straightType current feType gap
    global defaultRangeLow defaultRangeHigh ranks additionalOptimizations
    global sortType web referenceType dataDirectory pickedElementList

    set bandsOn 0
    foreach band [lsort [array names bandOn]] {
	if $bandOn($band) {
	    incr bandsOn
	}
    }
    if {$bandsOn==0 && [llength $pickedElementList]==0} {
	APSChooseBestMBAIDSetStatus "No bands defined or enabled, and no K-edges chosen."
	return
    }

    APSChooseBestIDSetStatus "$bandsOn active bands"
    switch [string tolower $optimizationQuantity] {
	brightness {
	    set quantity Brightness
	    set minimum 1e15
	    set plotMinimum 1e17
	    set units "ph/s/mm\$a2\$n/mrad\$a2\$n/0.1%BW"
	}
	spectralfluxdensity {
	    set quantity FluxDensity
	    set minimum 1e13
	    set plotMinimum 1e15
	    set units "ph/s/mrad\$a2\$n/0.1%BW"
	}
        spectralflux {
	    set quantity TotalFlux
	    set minimum 1e10
	    set plotMinimum 1e12
	    set units "ph/s/0.1%BW"
	}
	default {
	    APSChooseBestIDSetStatus "Unknown optimization mode \"$optimizationQuantity\" !"
	    return
	}
    }
    
    set rangeLow $defaultRangeLow
    set rangeHigh $defaultRangeHigh
    foreach band [lsort [array names bandOn]] {
        if !$bandOn($band) continue
	set low  $bandLow($band)
	set high $bandHigh($band)

	lappend bandLowList  $low
	lappend bandHighList $high

	lappend bandListList "$low-$high"
    
	if [expr $low>$high] {
	    APSChooseBestIDSetStatus "Error (1): band list has low > high ($low > $high)"
	    return
	}
	if [expr $low<$rangeLow] {
	    set rangeLow $low
	}
	if [expr $high>$rangeHigh] {
	    set rangeHigh $high
	}
    }

    global KEdge
    foreach element $pickedElementList {
        set low [expr $KEdge($element)-0.1]
        set high [expr $KEdge($element)+0.1]
	lappend bandLowList  $low
	lappend bandHighList $high

	lappend bandListList "$element"
        
	if [expr $low<$rangeLow] {
	    set rangeLow $low
	}
	if [expr $high>$rangeHigh] {
	    set rangeHigh $high
	}
        lappend bandRangeList $element
    }

    set rangeSpan [expr ($rangeHigh-$rangeLow)]
    set rangeMid  [expr ($rangeLow+$rangeHigh)/2.0]
    set rangeLow  [expr ($rangeMid-1.1*$rangeSpan/2.0)]
    set rangeHigh [expr ($rangeMid+1.1*$rangeSpan/2.0)]

    set sortCount 0
    foreach type [array names sortType] {
        if $sortType($type) {
            incr sortCount
        }
    }
    if $sortCount==0 {
        SetStatus "Error: No quantities selected for maximization."
        return 
    }


    set tmpRoot /tmp/[APSTmpString]
    set optList ""
    set plotOptList [list -mode=y=log,y=spec -limit=ymin=$plotMinimum -scale=$rangeLow,$rangeHigh,0,0 -same=global "-ylabel=$quantity ($units)"] 
    set band 0
    set ndSortOptList3 ""
    lappend optList -process=TotalPower,max,%s
    lappend optList -process=TotalPower,spread,%sSpread
    foreach low $bandLowList high $bandHighList {
	# BrightnessGap<n> is the number of values in band <n> below $minimum.  Want to minimize
	# BrightnessMin<n> is the minimum brightness in band <n>.  Want to maximize
	# BrighntessAve<n> is the average brightness in band <n>.  Want to maximize
	lappend optList -print=parameter,BandRange$band,$low-${high}keV 
        lappend optList -process=${quantity},count,%sGap$band,functionOf=photonEnergy,lower=$low,upper=$high,top=$minimum
        lappend optList -process=${quantity},max,%sMax$band,functionOf=photonEnergy,lower=$low,upper=$high
        lappend optList -process=${quantity},min,%sMin$band,functionOf=photonEnergy,lower=$low,upper=$high
        lappend optList -process=${quantity},ave,%sAve$band,functionOf=photonEnergy,lower=$low,upper=$high
        if $band==0 {
            lappend optList "-define=col,${quantity}Delta,${quantity} Shifted${quantity} - ${quantity} 1e-300 +  /" 
        }
        lappend optList -process=${quantity}Delta,count,${quantity}Dips$band,functionOf=photonEnergy,lower=$low,upper=$high,bottom=0.5
	lappend optList -process=TotalPower,max,%s$band,functionOf=photonEnergy,lower=$low,upper=$high
	lappend optList -process=TotalPower,spread,%sSpread$band,functionOf=photonEnergy,lower=$low,upper=$high
	lappend optList -process=OnAxisPowerDensity,max,%s$band,functionOf=photonEnergy,lower=$low,upper=$high
	lappend onAxisPowerDensityList OnAxisPowerDensity$band
	lappend totalPowerList TotalPower$band

	lappend brightnessMinList ${quantity}Min$band
	lappend plotOptList -drawline=x0v=$low,x1v=$low,q0v=0,q1v=1,line=$band,thick=2
	lappend plotOptList -drawline=x0v=$high,x1v=$high,q0v=0,q1v=1,line=$band,thick=2
	lappend ndSortOptList1 -column=${quantity}Gap$band,min
	lappend sortOptList1 -column=${quantity}Gap$band,incr
        if $sortType(min) {
            lappend ndSortOptList2 -column=${quantity}Min$band,max
            lappend sortOptList2 -column=${quantity}Min$band,decr
        }
        if $sortType(max) {
            lappend ndSortOptList2 -column=${quantity}Max$band,max
            lappend sortOptList2 -column=${quantity}Max$band,decr
        }
        if $sortType(ave) {
            lappend ndSortOptList2 -column=${quantity}Ave$band,max
            lappend sortOptList2 -column=${quantity}Ave$band,decr
        }
        if $sortType(dip) {
            lappend ndSortOptList2 -column=${quantity}Dips$band,min
            lappend sortOptList2 -column=${quantity}Dips$band,incr
        }
#	lappend printOptList -column=BandRange$band -column=${quantity}*$band,format=%13.2e,end
	lappend printOptList($band) -column=BandRange$band -column=${quantity}*$band,format=%13.2e,end
	incr band 
    }
    foreach item [array names additionalOptimizations] {
        if $additionalOptimizations($item) {
            lappend ndSortOptList3 -column=${item},min 
            lappend sortOptList3 -column=${item},decr
        }
    }

    if [expr $band!=($bandsOn+[llength $pickedElementList])] {
        APSChooseBestMBAIDSetStatus "Mismatch in band count"
        return
    }
    
    # Combine all the relevant brightness envelopes (photonEnergy, ${quantity})
    # Perform the processing as indicated above
    # Sort and keep first-rank configurations w.r.t. fewest points with ${quantity}<1e15
    # Sort and keep first-rank cnofigurations w.r.t. max values of band-min and band-average brightness
    # Make a plot for each of those configurations
    if {$web} {
	APSAddToTempFileList $rootname.best
	set tee1 ""
	set tee2 ""
    } else {
	# APSAddToTempFileList $rootname.all $rootname.sort $rootname.best
	set tee1 "| tee $rootname.all"
	set tee2 "| tee $rootname.sort"
    }
    set cmd1 ""
    if [llength $ndSortOptList3] {
        set cmd1 "| /usr/local/oag/apps/bin/linux-x86_64/sddsconvertlogonchange.00018 -pipe -delete=col,Rank,CrowdingDistance,ConstraintsViolation | /usr/local/oag/apps/bin/linux-x86_64/sddssort.00019 -pipe $ndSortOptList3 -nondom | /usr/local/oag/apps/bin/linux-x86_64/sddsprocess.00041 -pipe -filter=col,Rank,1,$ranks"
		       
    } 
    if $bandsOn==1 {
	if [catch {eval exec /usr/local/oag/apps/bin/linux-x86_64/sddscombine.00020 $dataFileList -pipe=out \
                       | /usr/local/oag/apps/bin/linux-x86_64/sddsshift.00016 -pipe -column=${quantity} -shift=1 \
		       | /usr/local/oag/apps/bin/linux-x86_64/sddsprocess.00041 -pipe $optList -nowarning \
		       | /usr/local/oag/apps/bin/linux-x86_64/sddscollapse.00019 -pipe \
		       $tee1 \
		       | /usr/local/oag/apps/bin/linux-x86_64/sddsprocess.00041 -pipe -process=${quantity}Gap0,min,%sMin \
		       "{-test=column,${quantity}Gap0 ${quantity}Gap0Min ==}" \
		       | /usr/local/oag/apps/bin/linux-x86_64/sddssort.00019 -pipe $ndSortOptList2 -nondom \
		       $tee2 \
		       | /usr/local/oag/apps/bin/linux-x86_64/sddsprocess.00041 -pipe "{-redefine=col,Rank,Rank 0 == ? n_rows i_row - : Rank $,type=long}" -filter=column,Rank,1,$ranks -nowarning \
                       $cmd1 \
		       | /usr/local/oag/apps/bin/linux-x86_64/sddsprocess.00041 -pipe \
	               -edit=column,Tag0,Filename,10Z/Z-S/.env/10D \
	               -edit=column,Tag,Filename,10Z/Z-S/.env/10DaS/-P/fZ- \
		       "{-define=column,BrightnessMinMin,$brightnessMinList}" \
		       "{-define=column,TotalPowerMax,$totalPowerList}" \
		       "{-define=column,OnAxisPowerDensityMax,$onAxisPowerDensityList}" \
		       | /usr/local/oag/apps/bin/linux-x86_64/sddssort.00019 -pipe -column=Tag0 -unique \
		       | /usr/local/oag/apps/bin/linux-x86_64/sddssort.00019 -pipe=in $rootname.best -column=BrightnessMinMin,decr $sortOptList1 $sortOptList2} result] {
	    APSChooseBestIDSetStatus "Error (2): $result"
	    return
	}
    } else {
	if [catch {eval exec /usr/local/oag/apps/bin/linux-x86_64/sddscombine.00020 $dataFileList -pipe=out \
                       | /usr/local/oag/apps/bin/linux-x86_64/sddsshift.00016 -pipe -column=${quantity} -shift=1 \
		       | /usr/local/oag/apps/bin/linux-x86_64/sddsprocess.00041 -pipe $optList -nowarning \
		       | /usr/local/oag/apps/bin/linux-x86_64/sddscollapse.00019 -pipe \
		       | /usr/local/oag/apps/bin/linux-x86_64/sddssort.00019 -pipe $ndSortOptList1 -nondom \
		       | /usr/local/oag/apps/bin/linux-x86_64/sddsprocess.00041 -pipe -filter=column,Rank,1,$ranks -nowarning \
		       | /usr/local/oag/apps/bin/linux-x86_64/sddsconvertlogonchange.00018 -pipe -delete=col,Rank,CrowdingDistance,ConstraintsViolation \
		       | /usr/local/oag/apps/bin/linux-x86_64/sddssort.00019 -pipe $ndSortOptList2 -nondom \
		       $tee2 \
		       | /usr/local/oag/apps/bin/linux-x86_64/sddsprocess.00041 -pipe -filter=column,Rank,1,$ranks -nowarning \
                       $cmd1 \
		       | /usr/local/oag/apps/bin/linux-x86_64/sddsprocess.00041 -pipe \
	               -edit=column,Tag0,Filename,10Z/Z-S/.env/10D \
	               -edit=column,Tag,Filename,10Z/Z-S/.env/10DaS/-P/fZ- \
		       "{-define=column,BrightnessMinMin,$brightnessMinList [llength $brightnessMinList] minn}" \
		       "{-define=column,TotalPowerMax,$totalPowerList [llength $totalPowerList] maxn}" \
		       "{-define=column,OnAxisPowerDensityMax,$onAxisPowerDensityList [llength $onAxisPowerDensityList] maxn}" \
		       | /usr/local/oag/apps/bin/linux-x86_64/sddssort.00019 -pipe -column=Tag0 -unique \
		       | /usr/local/oag/apps/bin/linux-x86_64/sddssort.00019 -pipe=in $rootname.best -column=BrightnessMinMin,decr $sortOptList1 $sortOptList2} result] {
	    APSChooseBestIDSetStatus "Error (3): $result"
	    return
	}
    }

    set filenameList [exec /usr/local/oag/apps/bin/linux-x86_64/sdds2stream.00015 -column=Filename $rootname.best]
    set rankList [exec /usr/local/oag/apps/bin/linux-x86_64/sdds2stream.00015 -column=Rank $rootname.best]
    APSChooseBestIDSetStatus "[llength $filenameList] rank-1 choices"
    APSChooseBestIDSetStatus "[join $filenameList ,]"

    set i 1
    set plot2OptList ""
    global latticePrefix
    foreach filename $filenameList rank $rankList {
	set tail [file tail $filename]
	set dirname [file dir $filename]
	if [string match "*-G*.*-P??.?+P??.?-L*-Rev2.*" $tail] {
	    # 2-revolver
	    set type Rev2
	    set fieldList [split $tail -]
	    set P1 [os editstring d [lindex [split [lindex $fieldList 4] +] 0]]
	    set P2 [os editstring d [lindex [split [lindex $fieldList 4] +] 1]]
	    set L [os editstring d [lindex $fieldList 5]]
	    lappend plotOptList -column=photonEnergy,${quantity} $filename -graph=sym
	    lappend plotOptList "-title=Rank:$rank FE:$feType  ${straightType}SS  I:${current}mA  L:${L}cm  gap:${gap}mm  $type" 
	    lappend plotOptList -column=photonEnergy,${quantity} $dirname/${latticePrefix}-$feType-I${current}-G${gap}-P$P1-L${L}-HPM.envp 
	    lappend plotOptList -split=page -graph=line,type=1,thick=2 -legend=spec=${P1}mm
	    lappend plotOptList -column=photonEnergy,${quantity} $dirname/${latticePrefix}-$feType-I${current}-G${gap}-P$P2-L${L}-HPM.envp 
	    lappend plotOptList -split=page -graph=line,type=2,thick=2 -legend=spec=${P2}mm
            lappend plot2OptList -column=photonEnergy,TotalPower $filename 
            lappend plot2OptList "-topline=Rank:$rank FE:$feType  ${straightType}SS  I:${current}mA  L:${L}cm  gap:${gap}mm  $type" -end
            lappend plot2OptList -column=photonEnergy,OnAxisPowerDensity $filename  "-topline=${P1}mm + ${P2}mm" -end
	} elseif [string match "*-SCU.*" $tail] {
	    # SCU
	    set fieldList [split $tail -]
	    set P1 [os editstring d [lindex $fieldList 3]]
	    set L [os editstring d [lindex $fieldList 4]]
	    set type SCU
	    lappend plotOptList -column=photonEnergy,${quantity} $filename -graph=sym
	    lappend plotOptList "-title=Rank:$rank FE:$feType  ${straightType}SS  I:${current}mA  L:${L}cm  $type" 
	    lappend plotOptList -column=photonEnergy,${quantity} $dirname/${latticePrefix}-$feType-I${current}-P$P1-L${L}-${type}.envp 
	    lappend plotOptList -split=page -graph=line,type=1,thick=2 -legend=spec=${P1}mm

            lappend plot2OptList -column=photonEnergy,TotalPower $filename 
            lappend plot2OptList "-topline=Rank:$rank FE:$feType  ${straightType}SS  I:${current}mA  L:${L}cm  $type" -end
            lappend plot2OptList -column=photonEnergy,OnAxisPowerDensity $filename "-topline=${P1}mm" -end
	} else {
	    # HPM
	    set fieldList [split $tail -]
	    set P1 [os editstring d [lindex $fieldList 4]]
	    set L [os editstring d [lindex $fieldList 5]]
	    set type HPM
	    lappend plotOptList -column=photonEnergy,${quantity} $filename -graph=sym
	    lappend plotOptList "-title=Rank:$rank FE:$feType  ${straightType}SS  I:${current}mA  L:${L}cm  gap:${gap}mm  $type" 
	    lappend plotOptList -column=photonEnergy,${quantity} $dirname/${latticePrefix}-$feType-I${current}-G${gap}-P$P1-L${L}-${type}.envp 
	    lappend plotOptList -split=page -graph=line,type=1,thick=2 -legend=spec=${P1}mm

            lappend plot2OptList -column=photonEnergy,TotalPower $filename 
            lappend plot2OptList "-topline=Rank:$rank FE:$feType  ${straightType}SS  I:${current}mA  L:${L}cm  gap:${gap}mm  $type" -end
            lappend plot2OptList -column=photonEnergy,OnAxisPowerDensity $filename "-topline=${P1}mm" -end
	}

        if [string match U* $referenceType] {
            set LRef [FindReferenceLength -type $type -length $L -feType $feType]
            set refPeriod [os editstring %/U// $referenceType]
            set refFile $dataDirectory(HPM)/G${gap}/${latticePrefix}-$feType-I${current}-G${gap}-P${refPeriod}.0-L${LRef}-HPM.envp
            lappend plotOptList -column=photonEnergy,${quantity} $refFile
            lappend plotOptList -split=page -graph=line,type=2,thick=2 -legend=spec=$referenceType/${LRef}cm
            lappend plotOptList -end
        }
        lappend plotOptList -end

	incr i
    }

    global resultsPlot1List resultsPlot2List resultsPrintoutList resultsTag
    set resultsPlot1List($resultsTag) "$plotOptList"
    set resultsPlot2List($resultsTag) "-layout=1,2 $plot2OptList"
    if {$web} {
        puts "<hr>"
        foreach fnl $filenameList {
            file copy -force $fnl /net/epics-ops/web_roots/ops/logging/plots/
            puts "<a href=http://ops.aps.anl.gov/logging/plots/[file tail $fnl]>[file tail $fnl]</a><br>"
        }
	set sec [clock seconds]
	puts "<hr><pre>"
	if {[catch {eval exec /usr/local/oag/apps/bin/linux-x86_64/sddsprintout.00025 $rootname.best -width=600 -column=Tag0,format=%37s -col=Rank -col=TotalPowerMax -col=OnAxisPowerDensityMax} results]} {
	    puts $results
	} else {
	    puts $results
	}
	set latexOutput [APSChooseBestIDLatexHeader]
	append latexOutput [APSChooseBestIDLatexCalcValues]




	if {[catch {eval exec /usr/local/oag/apps/bin/linux-x86_64/sddsprintout.00025 $rootname.best -latex -width=600 -column=Tag0,format=%37s -col=Rank -col=TotalPowerMax -col=OnAxisPowerDensityMax} results]} {
	    append latexOutput ${results}\n
	} else {
	    append latexOutput "${results}\n\\pagebreak\n"
	}
	for {set i 0} {$i < $band} {incr i} {
	    if {[catch {eval exec /usr/local/oag/apps/bin/linux-x86_64/sddsprintout.00025 $rootname.best -width=600 -column=Tag0,format=%37s $printOptList($i)} results]} {
		puts $results
	    } else {
		puts $results
	    }
	    if {[catch {eval exec /usr/local/oag/apps/bin/linux-x86_64/sddsprintout.00025 $rootname.best -latex -width=600 -column=Tag0,format=%37s $printOptList($i)} results]} {
		append latexOutput ${results}\n
	    } else {
		append latexOutput "${results}\n\\pagebreak\n"
	    }
	}
	set i [string first photons/s/mm\$a2\$n/mrad\$a2\$n/0.1\\%BW $latexOutput]
	if {$i != -1} {
	    set j [string first \\begin\{table\} $latexOutput]
	    incr j
	    set k [string first \\begin\{table\} $latexOutput $j]
	    while {$k != -1} {
		set n [string first \n $latexOutput $k]
		set latexOutput [string replace $latexOutput $n $n "Brightness in units of photons/s/mm\$^2\$/mrad\$^2\$/0.1\\% BW \n"]
		set j [expr $k + 1]
		set k [string first \\begin\{table\} $latexOutput $j]
	    }
	}
	set i [string first photons/s/mm\$a2\$n/mrad\$a2\$n/0.1\\%BW $latexOutput]
	while {$i != -1} {
	    set latexOutput [string replace $latexOutput $i [expr $i + 35]]
	    set i [string first photons/s/mm\$a2\$n/mrad\$a2\$n/0.1\\%BW $latexOutput]
	}
	set i [string first photons/s/mrad\$a2\$n/0.1\\%BW $latexOutput]
	if {$i != -1} {
	    set j [string first \\begin\{table\} $latexOutput]
	    incr j
	    set k [string first \\begin\{table\} $latexOutput $j]
	    while {$k != -1} {
		set n [string first \n $latexOutput $k]
		set latexOutput [string replace $latexOutput $n $n "\\newline Spectral flux density in units of photons/s/mrad\$^2\$/0.1\\% BW \n"]
		set j [expr $k + 1]
		set k [string first \\begin\{table\} $latexOutput $j]
	    }
	}
	set i [string first photons/s/mrad\$a2\$n/0.1\\%BW $latexOutput]
	while {$i != -1} {
	    set latexOutput [string replace $latexOutput $i [expr $i + 27]]
	    set i [string first photons/s/mrad\$a2\$n/0.1\\%BW $latexOutput]
	}
	set i [string first photons/s/0.1\\%BW $latexOutput]
	if {$i != -1} {
	    set j [string first \\begin\{table\} $latexOutput]
	    incr j
	    set k [string first \\begin\{table\} $latexOutput $j]
	    while {$k != -1} {
		set n [string first \n $latexOutput $k]
		set latexOutput [string replace $latexOutput $n $n "\\newline Spectral flux in units of photons/s/0.1\\% BW  \n"]
		set j [expr $k + 1]
		set k [string first \\begin\{table\} $latexOutput $j]
	    }
	}
	set i [string first photons/s/0.1\\%BW $latexOutput]
	while {$i != -1} {
	    set latexOutput [string replace $latexOutput $i [expr $i + 17]]
	    set i [string first photons/s/0.1\\%BW $latexOutput]
	}
	puts "</pre><hr>"
	#append latexOutput "\n\\pagebreak\n"

        if {[catch {eval exec /usr/local/oag/apps/bin/linux-x86_64/sddsplot.00068 $plotOptList -device=lpng,template=/net/epics-ops/web_roots/ops/logging/plots/plot${sec}_chooseBestID_1-%03ld.png} results]} {
	}

	set i 1
	while {[file exists /net/epics-ops/web_roots/ops/logging/plots/plot${sec}_chooseBestID_1-[format %03ld $i].png]} {
	    puts "<img src=http://ops.aps.anl.gov/logging/plots/plot${sec}_chooseBestID_1-[format %03ld $i].png><hr>"
	    append latexOutput [APSChooseBestIDLatexImage plot${sec}_chooseBestID_1-[format %03ld $i].png]
	    incr i
	}

        if {[catch {eval exec /usr/local/oag/apps/bin/linux-x86_64/sddsplot.00068 -layout=1,2 $plot2OptList -device=lpng,template=/net/epics-ops/web_roots/ops/logging/plots/plot${sec}_chooseBestID_2-%03ld.png} results]} {
	}

	set i 1
	while {[file exists /net/epics-ops/web_roots/ops/logging/plots/plot${sec}_chooseBestID_2-[format %03ld $i].png]} {
	    puts "<img src=http://ops.aps.anl.gov/logging/plots/plot${sec}_chooseBestID_2-[format %03ld $i].png><hr>"
	    append latexOutput [APSChooseBestIDLatexImage plot${sec}_chooseBestID_2-[format %03ld $i].png]
	    incr i
	}

	set fid [open /net/epics-ops/web_roots/ops/logging/plots/plot${sec}_chooseBestID.tex w]

	
	append latexOutput [APSChooseBestIDLatexFooter]
	puts $fid $latexOutput
	close $fid
	set dir [pwd]
	cd /net/epics-ops/web_roots/ops/logging/plots
	global env
	#set env(TEXINPUTS) ".:/opt/local/share/texmf-dist/tex/latex//"
	if {[catch {exec /usr/local/texlive/2017/bin/x86_64-linux/pdflatex plot${sec}_chooseBestID.tex} results]} {
	    puts "<br><br>ERROR: $results <br><br>"
	} else {
	    puts "<br><a href=http://ops.aps.anl.gov/logging/plots/plot${sec}_chooseBestID.pdf>PDF output</a><br><br>"
	}
	cd $dir
    } else {
	eval exec /usr/local/oag/apps/bin/linux-x86_64/sddsplot.00068 $plotOptList &
	eval exec /usr/local/oag/apps/bin/linux-x86_64/sddsplot.00068 -layout=1,2 $plot2OptList &
	catch {eval exec /usr/local/oag/apps/bin/linux-x86_64/sddsprintout.00025 $rootname.best -width=600 -column=Tag0,format=%37s -col=Rank -col=TotalPowerMax -col=OnAxisPowerDensityMax > $rootname.txt}
	for {set i 0} {$i < $band} {incr i} {
	    catch {eval exec /usr/local/oag/apps/bin/linux-x86_64/sddsprintout.00025 $rootname.best -width=600 -column=Tag0,format=%37s $printOptList($i) >> $rootname.txt}
	}
	set tmpW .[APSTmpString]
	
	APSFileDisplayWindow $tmpW -fileName $rootname.txt -autoWidth 1 -autoWidthLimit 200
	APSButton .replot -parent $tmpW.buttonRow -text Replot -command "APSChooseBestIDReplot \"$resultsTag\""
	APSButton .savePlot -parent $tmpW.buttonRow -text "Save Plots" -command "APSChooseBestIDSavePlots \"$resultsTag\""
    }

    set resultsPrintoutList($resultsTag) "-fileName $rootname.txt -autoWidth 1"
}

proc APSChooseBestIDFindDataFiles {args} {
    set dataDirectory ""
    set straightType ""
    set idLength ""
    set feType ""
    set current 150
    set gap 10.75
    set periodOption All
    set type HPM 
    set maximumLength 10.0
    set periodMin 10.0
    set periodMax 56.0
    set periodFrac .?
    APSStrictParseArguments {dataDirectory straightType idLength feType current gap periodOption type maximumLength periodMin periodMax periodFrac}

    global latticePrefix
    set tag ${latticePrefix}
    set deduction 0
    switch $type {
	HPM {
	    set searchString $dataDirectory/G${gap}/${tag}-${feType}-I${current}-G${gap}-P??${periodFrac}-L
	    set periodValues 1
	}
	Revolver2 {
	    set searchString $dataDirectory/G${gap}/${tag}-${feType}-I${current}-G${gap}-P??${periodFrac}+P??${periodFrac}-L
	    set type Rev2
	    set periodValues 2
	}
	default {
	    APSChooseBestIDSetStatus "Invalid type \"$type\" in APSChooseBestIDFindDataFiles"
	    return 
	}
    }

    switch $feType {
        LCFE -
	CFE {
	    switch $straightType {
		Long {
		    set lengthList [list [expr 350-$deduction] [expr 240-$deduction] [expr 210-$deduction]]
		}
		Short {
		    set lengthList [expr 210-$deduction]
		}
	    }
	    if [string compare $idLength 4.8]==0 {
		set lengthList 480
	    }
	    if [string compare $idLength 2.4]==0 {
		set lengthList 240
	    }
	    if [string compare $idLength 2.0]==0 {
		set lengthList 200
	    }
	    APSChooseBestIDSetStatus "$lengthList"
            set dataFileList ""
	    foreach length $lengthList {
                if [expr $length<=100*$maximumLength] {
                    APSChooseBestIDSetStatus "Search for $searchString${length}-${type}.env"
                    set dataFile0List [lsort [glob -nocomplain $searchString${length}-${type}.env]]
                    APSChooseBestIDSetStatus "--- found [llength $dataFile0List] files"
                    eval lappend dataFileList $dataFile0List
                }
            }
	}
	EHHL -
	VHHL -
	HHL {
	    switch $straightType {
                Long {
		    set length0List [list 480 720 770]
		} 
		Short {
		    set length0List [list 480]
		}
	    }
	    if [string compare $idLength 4.8]==0 {
		set length0List 480
	    }
	    if [string compare $idLength 2.4]==0 {
		set length0List 240
	    }
	    if [string compare $idLength 2.0]==0 {
		set length0List 200
	    }
	    foreach length $length0List {
		if [string compare $idLength "Half"]==0 {
		    lappend lengthList [expr $length/2-$deduction]
		} elseif [string compare $idLength "Full"]==0 {
		    lappend lengthList [expr $length-$deduction]
		    lappend lengthList [expr $length/2-$deduction]
		} else {
		    lappend lengthList [expr $length-$deduction]
		}
	    }
	    set dataFileList ""
	    foreach length $lengthList {
                if [expr $length<=100*$maximumLength] {
                    APSChooseBestIDSetStatus "Search for $searchString${length}-${type}.env"
                    set dataFile0List [lsort [glob -nocomplain $searchString${length}-${type}.env]]
                    APSChooseBestIDSetStatus "--- found [llength $dataFile0List] files"
                    eval lappend dataFileList $dataFile0List
                } else {
                    APSChooseBestIDSetStatus "Ignoring $searchString${length}-${type}.env"
                }
	    }
	}
	default {
	    return 
	}
    }

    if [string compare $periodOption All]==0 {
        set existingPeriodList ""
    } else {
        set existingPeriodList [list 18.0 23.0 27.0 30.0 33.0 35.0 55.0]
    }


    set fileList ""
    switch $periodValues {
	1 {
	    foreach item $dataFileList {
		set partList [split $item -]
		set period [os editstring d [lindex $partList [expr [llength $partList]-3]]]
		if {[llength $existingPeriodList] && [lsearch -exact $existingPeriodList $period]==-1} continue
		if {[expr $period>=$periodMin] && [expr $period<=$periodMax]} {
		    lappend fileList $item
		}
	    }
	}
	2 {
	    foreach item $dataFileList {
		set partList [split $item -]
		set periodDataList [eval os editstring d [split [lindex $partList [expr [llength $partList]-3]] +]]
		set period1 [lindex $periodDataList 0]
		set period2 [lindex $periodDataList 1]
                if {[llength $existingPeriodList] && [lsearch -exact $existingPeriodList $period1]==-1} continue
                if {[llength $existingPeriodList] && [lsearch -exact $existingPeriodList $period2]==-1} continue
		if {[expr $period1>=$periodMin] && [expr $period1<=$periodMax] && \
			[expr $period2>=$periodMin] && [expr $period2<=$periodMax]} {
		    lappend fileList $item
		}
	    }
	}
	3 {
	    foreach item $dataFileList {
		set partList [split $item -]
		set periodDataList [eval os editstring d [split [lindex $partList [expr [llength $partList]-3]] +]]
		set period1 [lindex $periodDataList 0]
		set period2 [lindex $periodDataList 1]
		set period3 [lindex $periodDataList 2]
                if {[llength $existingPeriodList] && [lsearch -exact $existingPeriodList $period1]==-1} continue
                if {[llength $existingPeriodList] && [lsearch -exact $existingPeriodList $period2]==-1} continue
                if {[llength $existingPeriodList] && [lsearch -exact $existingPeriodList $period3]==-1} continue
		if {[expr $period1>=$periodMin] && [expr $period1<=$periodMax] && \
			[expr $period2>=$periodMin] && [expr $period2<=$periodMax] && \
			[expr $period3>=$periodMin] && [expr $period3<=$periodMax]} {
		    lappend fileList $item
		}
	    }
	}
    }
    return $fileList 
}

proc APSChooseBestIDFindScuDataFiles {args} {
    set dataDirectory ""
    set straightType ""
    set idLength ""
    set feType ""
    set current 150
    set gap 10.75
    set maximumLength 10.0
    set periodMin 10.0
    set periodMax 56.0
    set periodFrac .?
    APSStrictParseArguments {dataDirectory straightType idLength feType current gap maximumLength periodMin periodMax periodFrac}

    global latticePrefix
    set tag ${latticePrefix}
    set deduction 90
    set type SCU

    set searchString $dataDirectory/${tag}-${feType}-I${current}-P??${periodFrac}-L
    set fileList ""
    switch $feType {
        LCFE -
	CFE {
	    switch $straightType {
		Long {
		    set lengthList [list [expr 355-$deduction] [expr 320-$deduction] [expr 290-$deduction]]
                    if [string compare $idLength 4.8]==0 {
                        set lengthList 480
                    }
                    if [string compare $idLength 2.4]==0 {
                        set lengthList 240
                    }
                    if [string compare $idLength 2.0]==0 {
                        set lengthList 200
                    }
		} 
		Short {
		    set lengthList [expr 210-$deduction]
		}
	    }
	    APSChooseBestIDSetStatus "$lengthList"
	    foreach length $lengthList {
                if [expr $length<=100*$maximumLength] {
                    APSChooseBestIDSetStatus "Search for $searchString${length}-${type}.env"
                    set dataFile0List [lsort [glob -nocomplain $searchString${length}-${type}.env]]
                    APSChooseBestIDSetStatus "--- found [llength $dataFile0List] files"
                    eval lappend fileList $dataFile0List
                }
            }
	}
	EHHL -
	VHHL -
	HHL {
	    switch $straightType {
		Long {
		    set length0List [list 320 480 720 770]
		} 
		Short {
		    set length0List [list 320 480]
		}
	    }
	    if [string compare $idLength 4.8]==0 {
		set length0List 480
	    }
	    if [string compare $idLength 2.4]==0 {
		set length0List 240
	    }
	    if [string compare $idLength 2.0]==0 {
		set length0List 200
	    }
	    APSChooseBestIDSetStatus "$length0List"
	    foreach length $length0List {
		if [string compare $idLength "Half"]==0 {
		    lappend lengthList [expr $length/2-$deduction]
		} elseif [string compare $idLength "Full"]==0 {
		    lappend lengthList [expr $length-$deduction]
		    lappend lengthList [expr $length/2-$deduction] 
		} else {
		    lappend lengthList $length
		}
	    }
	    foreach length $lengthList {
                if [expr $length<=100*$maximumLength] {
                    APSChooseBestIDSetStatus "Search for $searchString${length}-${type}.env"
                    set dataFile0List [lsort [glob -nocomplain $searchString${length}-${type}.env]]
                    APSChooseBestIDSetStatus "--- found [llength $dataFile0List] files"
                    eval lappend fileList $dataFile0List
                }
            }
        }
    }

    set fileList1 ""
    foreach item $fileList {
	set partList [split $item -]
	set period [os editstring d [lindex $partList [expr [llength $partList]-3]]]
	if {[expr $period>=$periodMin] && [expr $period<=$periodMax]} {
	    lappend fileList1 $item
	}
    }
    return $fileList1
}

proc APSChooseBestIDLatexHeader {args} {
    return "\\documentclass\[11pt\]\{article\}
\\usepackage\{latexsym,html\}
\\usepackage\[pdftex\]\{graphicx\}
\\usepackage\[landscape\]\{geometry\}
\\usepackage\[justification=centering\]\{caption\}
\\usepackage\{enumerate\}

\\pagestyle\{plain\}
\\tolerance=10000
\\newenvironment\{req\}\{\\begin\{equation\} \\rm\}\{\\end\{equation\}\}
\\setlength\{\\topmargin\}\{0.15 in\}
\\setlength\{\\oddsidemargin\}\{0 in\}
\\setlength\{\\evensidemargin\}\{0 in\}
\\setlength\{\\textwidth\}\{6.5 in\}
\\setlength\{\\headheight\}\{-0.5 in\}
\\setlength\{\\textheight\}\{9 in\}
\\begin\{document\}\n"
}


proc APSChooseBestIDLatexFooter {args} {
    return "\\end\{document\}\n"
}

proc APSChooseBestIDLatexImage {filename} {
    return "\\begin\{figure\}\[htbp\!\]
\\centering\%
\\includegraphics\[width=8in\]\{${filename}\}
\\end\{figure\}
\\pagebreak\n"
}

proc APSChooseBestIDLatexCalcValues {args} {
    append output "\\begin\{description\}
\\setlength\{\\itemsep\}\{1pt\}
\\setlength\{\\parskip\}\{0pt\}
\\setlength\{\\parsep\}\{0pt\}\n"

    append output "\\item\[Today's date:\] [clock format [clock seconds]]\n"

    global current
    append output "\\item\[Beam current (mA):\] ${current}\n"

    global feType
    if {$feType == "CFE"} {
	set feTypeString Canted
    } else {
	set feTypeString $feType
    }
    append output "\\item\[Front end type:\] ${feTypeString}\n"

    global optimizationQuantity
    if {$optimizationQuantity == "SpectralFluxDensity"} {
	set optimizationQuantityString "Spectral flux density"
    } elseif {$optimizationQuantity == "SpectralFlux"} {
	set optimizationQuantityString "Spectral flux"
    } else {
	set optimizationQuantityString $optimizationQuantity
    }
    append output "\\item\[Optimization quantity:\] ${optimizationQuantityString}\n"

    global straightType
    append output "\\item\[Straight section type:\] ${straightType}\n"

    global idLength
    set idLengthString ""
    if {$idLength(Full)} {
	lappend idLengthString "Full"
    }
    if {$idLength(Half)} {
	lappend idLengthString "Half"
    }
    if {$idLength(2.0)} {
	lappend idLengthString "2.0"
    }
    if {$idLength(2.4)} {
	lappend idLengthString "2.4"
    }
    if {$idLength(4.8)} {
	lappend idLengthString "4.8"
    }
    append output "\\item\[Undulator length (m):\] [join $idLengthString ", "]\n"

    global idMaximumLength
    if {$idMaximumLength == "10.0"} {
	set idMaximumLengthString "None"
    } else {
	set idMaximumLengthString $idMaximumLength
    }
    append output "\\item\[Maximum ID magnetic length (m):\] ${idMaximumLengthString}\n"

    global scIdMaximumLength
    if {$scIdMaximumLength == "10.0"} {
	set scIdMaximumLengthString "None"
    } else {
	set scIdMaximumLengthString $scIdMaximumLength
    }
    append output "\\item\[Maximum SCU magnetic length (m):\] ${scIdMaximumLengthString}\n"

    global idType
    set idTypeString ""
    if {$idType(HPM)} {
	lappend idTypeString "HPM"
    }
    if {$idType(Revolver2)} {
	lappend idTypeString "Revolver2"
    }
    if {$idType(SCU)} {
	lappend idTypeString "SCU"
    }
    append output "\\item\[Undulator type:\] [join $idTypeString ", "]\n"

    global gap
    append output "\\item\[HPM and revolver gap (mm):\] ${gap}\n"

    global periodOption
    append output "\\item\[Periods to consider:\] ${periodOption}\n"

    global periodFrac
    if {$periodFrac == ".?"} {
	set periodFracString "Yes"
    } else {
	set periodFracString "No"
    }
    append output "\\item\[0.5mm period increments:\] ${periodFracString}\n"

    global periodMin
    append output "\\item\[Minimum period (mm):\] ${periodMin}\n"

    global periodMax
    append output "\\item\[Maximum period (mm):\] ${periodMax}\n"

    global sortType
    set sortTypeString ""
    if {$sortType(ave)} {
	lappend sortTypeString "Band Ave"
    }
    if {$sortType(min)} {
	lappend sortTypeString "Band Min"
    }
    if {$sortType(max)} {
	lappend sortTypeString "Band Max"
    }
    if {$sortType(dip)} {
	lappend sortTypeString "Few Dips"
    }
    append output "\\item\[Optimize:\] [join $sortTypeString ", "]\n"

    global ranks
    append output "\\item\[Ranks to include:\] ${ranks}\n"

    global defaultRangeLow defaultRangeHigh
    append output "\\item\[Default plot range (keV):\] $defaultRangeLow to $defaultRangeHigh \n"
    
    global referenceType
    append output "\\item\[Reference:\] ${referenceType}\n"

    global bandOn bandLow bandHigh
    for {set i 0} {$i<10} {incr i} {
	if {$bandOn($i) == 1} {
	    append output "\\item\[Band $i range (keV):\] $bandLow($i) to $bandHigh($i) \n"
	}
    }

    global elementNameList elementFlag
    set kedgesString ""
    set Z 1
    foreach element $elementNameList {
        if {$elementFlag($element)} {
            lappend kedgesString "[format %5s ${element}/$Z]"
        }
        incr Z
    }
    append output "\\item\[K Edges:\] [join $kedgesString ", "]\n"


    append output "\\end\{description\}
\\pagebreak\n"

    return $output

}

proc FindReferenceLength {args} {
    APSStrictParseArguments {type length feType}
    switch $feType {
        CFE {
            if [expr $length<=210] {
                return 210
            } 
            if [expr $length<=240] {
                return 240
            }
            return 350
        }
        LCFE {
            return 350
        }
        HHL -
        VHHL {
            if [expr $length<=240] {
                return 240
            }
            if [expr $length<=480] {
                return 480
            }
            return 720
        }
    }
}
