set apsTmpStringCount 0
proc APSTmpString { } {
    global env apsTmpStringCount
    set tString [clock format [clock seconds] -format %y%m%d-%H%M%S]-[pid]
    if {[info exists env(USER)]} {
        set tString ${tString}$env(USER)$apsTmpStringCount
    } else {
        set tString ${tString}$apsTmpStringCount
    }
    incr apsTmpStringCount
    regsub -all " " $tString "" tString1
    return $tString1
}
proc APSParseArguments {optlist} {
    upvar args arguments
    set length [llength $arguments]
    set index 0
    set leftovers {}
    while {$index<$length} {
        set arg [lindex $arguments $index]
        if {[string index $arg 0]=="-"} {
            set keywordName [string range $arg 1 end]
            if {[lsearch -exact $optlist $keywordName]!=-1} {
                incr index
                if {$index==$length} {
                    lappend leftovers $arg
                } else {
                    set valueString [lindex $arguments $index]
                    uplevel "set $keywordName {$valueString}"
                    incr index
                }
            } else {
                incr index
                lappend leftovers $arg
            }
        } else {
            lappend leftovers $arg
            incr index
        }
    }
    set arguments [concat $leftovers]
}
#-------------------------------------------------------------------------------------------------------------------------
proc Fit_MakeElementNameFromTagName {args} {
    #------ elegant can create a mixture of names when some names have #N in it and others don't.
    #------ To handle it, add #1 at the end, then delete second # symbol and after it.
    #------ Also delete #X and #Y
    set output ""
    set tagNameColumn TagName
    set elementNameColumn ElementName
    set addElementOccurence 0
    APSParseArguments {input output tagNameColumn elementNameColumn addElementOccurence}
    set columnList [join [exec sddsquery $input -col] ]
    set localFile $input.tmp
    if {[lsearch -exact $columnList $elementNameColumn] == -1} {
	exec sddsprocess $input $input.tmp "-edit=col,$elementNameColumn,$tagNameColumn,@#X@@ @#Y@@ S?@#@ K"
    } else {
	file copy -force $input $input.tmp
    }
    if $addElementOccurence {
	#--- Overwrite if exists:
	exec sddsconvert $input.tmp -pipe=out -del=col,ElementOccurence \
	    | sddsprocess -pipe "-edit=col,TagNameCopy,$tagNameColumn,@#X@@ @#Y@@ e i@#1@ a 2S?@#@ 2d" \
	    "-scan=col,ElementOccurence,TagNameCopy,%ld,type=long,edit=Z#" \
	    | sddsconvert -pipe=in $input.tmp1 -del=col,TagNameCopy
	set localFile $input.tmp1
    }
    if [string length $output] {
	file copy -force $localFile $output
    } else {
	file copy -force $localFile $input
    }
    catch {file delete $input.tmp $input.tmp1}
}
#-------------------------------------------------------------------------------------------------------------------------
proc Fit_MakeElementNameFromTagNameSingle {args} {
    APSParseArguments {tagName}
    set hashIndex [string first "#" $tagName]
    if {$hashIndex == -1} {return -code error "Error: element $tagName does not have \"#\" in its name."}
    set elementName [string replace $tagName $hashIndex [expr $hashIndex + 3]]
    set elementOccurence [string range $tagName [expr $hashIndex +1 ] [expr $hashIndex + 3]]
    return [list $elementName $elementOccurence]
}
#-------------------------------------------------------------------------------------------------------------------------
#------ This procedure reads variables from definitionFile and makes them global
proc Fit_ReadDefinitionFile {args} {
    set variableList ""
    set warnings 1
    set abortOnError 1
    APSParseArguments {definitionFile workDir variableList warnings abortOnError}

    #------ List of required variables in the definition file:
    #------ List1 is definition of internally used files:
    set requiredList1 [list dispColumn rmDerivFile rmDerivInverseFile rmDerivFileS rmDerivFileV rmDerivFileSV \
			   rmDerivFileU rmDifferenceFile dispersionFile hrmMeasured vrmMeasured hrmDifference \
			   vrmDifference hrmIterFile vrmIterFile elementsUpdateFile noCorrectorsFile weightFile \
			   manualWeightFile iterationsLogFile weightCorrectorsFile variableFile allElementsFile \
			   averageErrorFile nonlinFile elementOrderFile dispMeasuredFile rmDerivElementFile \
			   sigmaWeightFileX sigmaWeightFileY specialElementsInputFile specialParamFile variableArchiveFile \
			   iterationsLogFileSDDS]
    #------ List2 is various variables defined by user that are too many to input from the GUI:
    set requiredList2 [list hCalibFactor vCalibFactor dispCalibFactor dispFitWeight thetaKickX thetaKickY \
			   bRho zeroBpmTol kickRMD matlabScriptDir directRMCalc fixedOrbitLength \
			   offDiagWeight adjustAverageGains \
			   showMatchingMachineConfigOnly twiFile momentsFile svdProgramName closedOrbit useDoubleOrbits \
			   useQsubLong useQsubShort numberOfQsubTasksLong numberOfQsubTasksShort waitTimeLong \
			   waitTimeShort waitIntervalLong waitIntervalShort qsubCommandLong qsubCommandShort \
			   queueSystemNameShort queueSystemNameLong qsubRespProcCommandShort qsubRespProcCommandLong \
			   submissionPauseLong submissionPauseShort useQuadConstraints badBpmSigmaLimit \
			   rmdQuadDelta rmdTiltDelta tiltCorFraction remotePath verbose useSigmaWeightFile \
			   useDirectRMDCalc recalcIterRMD recalcIterRMDErrorLevel]
    set requiredList [concat $requiredList1 $requiredList2]
    #------ This list is for variables that are not required but possible:
    set possibleList [list twissRefFile twissRefElement malignElement useIntercept useSlope useCubic dontUsePrevQuadConstr \
			  convergenceTolerance convergenceTolerance0 convergenceTolerance1 convergenceTolerance2 resErrorMax \
			  useParallelMultiplication matrixDivisions badBpmNSigmasPlotting elemByElemSR ignoreBpmListDiffs \
			  quadConstraintWeight quadConstraintFile directDispersionCalc dispDirectParamList]

    #------ Reading only requested variables:
    if [string length $variableList] {
	if [catch {open $definitionFile r} fid] {
	    return -code error $fid
	}
	while {([gets $fid line] >= 0) && ([llength $variableList]> 0)} {
	    if {[string compare "\#" [string index $line 0]] != 0} {
		if {[string compare [lindex $line 0] "set"] == 0} {
		    set varName [lindex $line 1]
		    set index [lsearch -exact $variableList $varName]
		    if {$index != -1} {
			set varValue [lindex $line 2]
			uplevel "set $varName $varValue"
		    }
		    set variableList [lreplace $variableList $index $index]
		}
	    }
	}
	close $fid
	if [llength $variableList] {
	    if $abortOnError {
		return -code error "Error: the following variables were not defined in $definitionFile: $variableList"
	    } else {
		puts stdout "Warning: the following variables were not defined in $definitionFile: $variableList"
	    }
	}
	return
    }

    #------ Reading the entire definition file...
    if [catch {open $definitionFile r} fid] {
	return -code error $fid
    }
    set definedList ""
    while {[gets $fid line] >= 0} {
	if {[string compare "\#" [string index $line 0]] != 0} {
	    if {[string compare [lindex $line 0] "set"] == 0} {
		global [lindex $line 1]
		lappend definedList [lindex $line 1]
	    }
	}
    }
    close $fid
    source $definitionFile
    if $useQuadConstraints {lappend requiredList quadConstraintWeight quadConstraintFile}
    if !$closedOrbit {lappend requiredList twissRefFile twissRefElement malignElement}

    #------ Looking for missing and unnecessary variables...
    set unnecList ""
    foreach var $definedList {
	set ix1 [lsearch -exact $requiredList $var]
	set ix2 [lsearch -exact $possibleList $var]
	if {$ix1 != -1} {
	    set requiredList [lreplace $requiredList $ix1 $ix1]
	}
	if {$ix1 == -1 && $ix2 == -1} {
	    lappend unnecList $var
	}
    }
    if {[llength $unnecList] && $warnings} {
	OutputStatusMessage "Warning: following variables from $definitionFile are not required: $unnecList"
    }
    if [llength $requiredList] {
	return -code error "Error: following variables are required but are not in $definitionFile: $requiredList"
    }

    #--- Checking for contradicting variables
    global options
    if {!$closedOrbit && $options(useEnergy)} {
	OutputStatusMessage "Warning: Energy fitting must be disabled when using non-closed trajectories. Disabling..."
	set options(useEnergy) 0
    }
    if !$options(useQuads) {
	if {$useQuadConstraints != 0} {
	    OutputStatusMessage "Warning: useQuadConstraints defined in $definitionFile is forced to 0 because there are no quads to fit."
	    set useQuadConstraints 0
	}
    }
    if !$options(fitDispersion) {
	if {[string compare $adjustAverageGains dispersion] == 0} {
	    OutputStatusMessage "Warning: adjustAverageGains is set to \"dispersion\" while no dispersion fitting is chosen. Will force to \"none\"."
	    set adjustAverageGains none
	}
    }
    if {$directRMCalc != 1} {
	if $directDispersionCalc {
	    OutputStatusMessage "Warning: directDispersionCalc should be disabled if directCalc!=1. Disabling..."
	    set directDispersionCalc 0
	}
    }
}

#-------------------------------------------------------------------------------------------------------------------------
# This procedure creates list of bpms which have rms reading of less than the threshold.
proc Fit_GetZeroBpms { args } {
    set deleteFiles ""
    set abovebelow below
    APSParseArguments {filename threshold column abovebelow dispColumn}
    if {[lsearch -exact [join [exec sddsquery -col $filename] ] $column] == -1} {
	set filename1 [APSTmpString]-zeros
	exec sddstranspose $filename $filename1 -oldColumnNames=$column
	set filename $filename1
	lappend deleteFiles $filename1
    }
    switch -exact -- $abovebelow {
	below {set zeroBpms [join [exec sddsconvert $filename -pipe=out -del=col,$dispColumn \
				       | sddsrowstats -pipe -rms=Rms,* \
				       | sddsprocess -pipe -proc=Rms,rms,RmsRms \
				       | sddsprocess -nowarning -pipe "-test=col,Rms RmsRms $threshold * <" \
				       | sdds2stream -pipe=in -col=$column] ]
	}
	above {
	    if [catch {exec sddsconvert $filename -pipe=out -del=col,$dispColumn \
			   | sddsrowstats -pipe -rms=Rms,* \
			   | sddsoutlier -pipe -col=Rms -stdev=$threshold -passes=3 -inv \
			   | sdds2stream -pipe=in -col=$column} result] {
		set zeroBpms ""
	    } else {
		set zeroBpms [join $result ]
	    }
	}
	default {
	    return -code error "Wrong abovebelow argument: $abovebelow"
	}
    }
    if [llength $deleteFiles] {eval file delete $deleteFiles}
    return $zeroBpms
}

#-------------------------------------------------------------------------------------------------------------------------
# This procedure makes one-column file from a response matrix file (keeps 2 pages if matrixFile is 2-page).
proc Fit_MakeColumnFromMatrix {args} {
    set rootnameColumn Rootname
    APSParseArguments {matrixFile columnFile columnName rootnameColumn rowNameColumn}
    exec sddsmatrix2column $matrixFile $columnFile -rowNameColumn=$rowNameColumn -rootnameColumn=$rootnameColumn -dataColumn=$columnName -major=row
}
#-------------------------------------------------------------------------------------------------------------------------
# This procedure splits list into several lists. Useful for queuing elegant tasks.

proc Fit_SplitList { args } {
    
    APSParseArguments { List splitTasks }
    
    if {$splitTasks == 0} {
	return $List
    }
    set listLength [llength $List]
    if {$listLength < $splitTasks} {
	set split $listLength
    } else {
	set split $splitTasks
    }
    set N [expr $listLength / $split]
    set reminder [expr $listLength - $N \* $split]
    if {$reminder > $N} {
	while {$reminder > $N} {
	    incr split -1
	    set N [expr $listLength / $split]
	    set reminder [expr $listLength - $N \* $split]
	}
    }
    set ListOut ""
    for { set J 0 } { $J < $split } { incr J } {
	set L1 [expr $J \* $N]
	set L2 [expr \( $J + 1 \) \* $N]
	lappend ListOut [lrange $List $L1 [expr $L2 - 1]]
    }
    if {$reminder != 0} {
	if {$reminder < [expr $N / 4]} {
	    #--- If reminder is very small, append the rest to the last list from above (first delete the last list, then append):
	    set ListOut [lreplace $ListOut [expr $split - 1] [expr $split - 1]]
	    lappend ListOut [lrange $List $L1 $listLength]
	} else {
	    lappend ListOut [lrange $List $L2 [expr $listLength - 1]]
	}
    }
    return $ListOut
} 

#-----------------------------------------------------------------------------------------------------------------------
#------ Example of call
#if [catch {Fit_GenerateElegantFileFromLTE -eleOutputFile $eleOutputFile \
#	       -run_setup [list "lattice aps.lte use_beamline RING rootname test parameters %s.param"] \
#	       -load_parameters [list "filename_list \"$paramFileList\"" "filename sextScan.param change_defined_values 0"] \
#	       -alter_elements [list "name * type MAXAMP item X_MAX value 0" "name * type MAXAMP item Y_MAX value 0"] \
#	       -correct [list "mode trajectory n_iterations 10 n_xy_cycles 3"] \
#	       -correction_matrix_output [list "response \"%s.hrm %s.vrm\""] \
#	       -twiss_output [list "filename <TWIFILE> matched 0 reference_file <REFERENCEFILE> reference_element <REFERENCEELEMENT>"] \
#	       -run_control [list "n_steps 1"] \
#              -bunched_beam [list "n_particles_per_bunch 1"] \
#	   } result] {
#    puts stderr "Fit_GenerateElegantFileFromLTE: $result"
#    exit
#}
#------ load_parameters2 is used to add flexibility in order of load_parameters and alter_elements
#
#------ Example of call if you want to use variable in the argument (note {} around list command):
#if [catch {eval Fit_GenerateElegantFileFromLTE1 -eleOutputFile $eleFile2 \
#	       -run_setup {[list "lattice $lteFile2 use_beamline INJLINE default_order 2 centroid $tmpRoot-2.cen"]} \
#	       $loadParamString \
#	       -alter_elements {[list "name MALINJFIT item D$plane value <DZ0>" \
#				    "name MALINJFIT item D${plane}P value <DZP0>" \
#                                    "name S38IK1 item ANGLE value <IK1KICK>" \
#                                    "name S39IK2 item ANGLE value <IK2KICK>" \
#                                    "name S39IK3 item ANGLE value <IK3KICK>" \
#				     "name S40IK4 item ANGLE value <IK4KICK>"]} \
#	       -run_control {[list "n_steps 1"]} \
#	       -bunched_beam {[list "n_particles_per_bunch 1"]} \
#	   } result] {
#    return -code error "Fit_GenerateElegantFileFromLTE1: $result"
#}

proc Fit_GenerateElegantFileFromLTE1 { args } {
    global env
    set argList [list divide_elements global_settings run_setup load_parameters alter_elements steering_element load_parameters2 run_control correct closed_orbit \
		     correction_matrix_output rf_setup twiss_output moments_output optimization_setup optimization_term optimization_variable \
		     bunched_beam optimize track matrix_output]
    foreach arg $argList {set $arg ""}
    set global_settings {{tracking_matrix_points 5}}
    set eleOutputFile ""

    APSParseArguments [concat $argList eleOutputFile]

    array set divide_elements_Array [list name "" divisions ""]
    array set global_settings_Array [list tracking_matrix_points 5]
    array set run_setup_Array [list lattice "" use_beamline "" p_central_mev 7e3 default_order 2 rootname "" \
				   parameters "" centroid "" search_path ". /home/helios/oagData/sr/lattices/LGDDetails Multipoles"]
    array set load_parameters_Array [list filename "" filename_list "" allow_missing_elements 1 allow_missing_parameters 1 \
					 change_defined_values 1 force_occurence_data 1]
    array set alter_elements_Array [list name "" type "" item "" value "" allow_missing_elements 1]
    array set run_control_Array [list n_steps 1]
    array set correct_Array [list mode orbit method global verbose 0 n_iterations 0 n_xy_cycles 1 \
				 correction_fraction [list 1.0 1.0] corrector_tweek [list 1e-5 1e-5] fixed_length 0 \
				 fixed_length_matrix 0 closed_orbit_iteration_fraction 0.5 closed_orbit_accuracy 1e-9]
    array set closed_orbit_Array [list output "" output_monitors_only 1 fixed_length 0 iteration_fraction 0.5 closed_orbit_accuracy 1e-7 \
				      closed_orbit_accuracy_requirement 1e-5 closed_orbit_iterations 100]
    array set correction_matrix_output_Array [list response "" output_at_each_step 1 fixed_length 0 coupled 1 use_response_from_computed_orbits 1 response2 "" response3 ""]
    array set twiss_output_Array [list filename "" radiation_integrals 0 output_at_each_step 1 matched 1 reference_file "" \
				      reference_element ""]
    array set moments_output_Array [list filename "" matched 1 output_at_each_step 1 verbosity 0 radiation 1]
    array set optimization_setup_Array [list mode minimize method simplex target 1e-14 tolerance 1e-14 n_passes 1 n_restarts 1 \
					    n_evaluations 100 log_file /dev/tty verbose 0]
    array set optimization_term_Array [list term ""]
    array set optimization_variable_Array [list name ""]
    array set bunched_beam_Array [list n_particles_per_bunch 1]
    array set track_Array [list center_on_orbit 0]
    array set optimize_Array [list summarize_setup 0]
    array set matrix_output_Array [list SDDS_output ""]
    array set rf_setup_Array [list name ""]
    array set steering_element_Array [list name ""]

    if [catch {open $eleOutputFile w} fileId] {
        return -code error "Cannot open the file $eleOutputFile for writing: $fileId"
    }
    set ifTrackCommand 0
    foreach command $argList {
    if [string length [set $command]] {
	    #------ command is a list of lists of options to allows for multiple same-name commands (like load_parameters)
	    set commandList [set $command]
	    if {[string compare $command track] == 0} {set ifTrackCommand 1}
	    if {[string compare $command optimize] == 0} {set ifTrackCommand 1}
	    if {[string compare $command load_parameters2] == 0} {set command load_parameters}
	    foreach singleCommand $commandList {
		array set optionsArray $singleCommand
		array set defaultOptionsArray [array get ${command}_Array]
		foreach option [array names optionsArray] {set defaultOptionsArray($option) $optionsArray($option)}
		#------ Cannot have load_parameters with empty filename and filename_list - elegant gives error.
		if {[string compare $command load_parameters] == 0} {
		    foreach option [array names optionsArray] {set defaultOptionsArray($option) $optionsArray($option)}
		    if {![string length $defaultOptionsArray(filename)] \
			    && ![string length $defaultOptionsArray(filename_list)]} {
			unset optionsArray
			unset defaultOptionsArray
			continue
		    }
		}
		if [string match "rf_setup" $command] {
		    puts $fileId "&twiss_output radiation_integrals = 1, output_at_each_step = 0, &end"
		    puts $fileId " "
		}
		puts $fileId "&$command"
		foreach option [array names defaultOptionsArray] {
		    if [string length $defaultOptionsArray($option)] {
			if {[llength $defaultOptionsArray($option)] == 1} {
			    switch $option {
				response2 {puts $fileId "   response\[2\] = $defaultOptionsArray($option),"}
				response3 {puts $fileId "   response\[3\] = $defaultOptionsArray($option),"}
				default {puts $fileId "   $option = $defaultOptionsArray($option),"}
			    }
			} else {
			    if {[string compare $option filename_list] == 0 || [string compare $option search_path] == 0} {
				puts $fileId "   $option = \"$defaultOptionsArray($option),\""
			    } else {
				puts $fileId "   ${option}\[0\] = [join $defaultOptionsArray($option) ,],"
			    }
			}
		    }
		}
		puts $fileId "&end"
		puts $fileId " "
		unset optionsArray
		unset defaultOptionsArray
	    }
	}
    }
    if !$ifTrackCommand {
	puts $fileId "&track &end"
	puts $fileId " "
    }
    close $fileId
}

#-----------------------------------------------------------------------------------------------------------------------
# This procedure is to substitute the "echo" command

proc Fit_WriteToFile {args} {

    set usage "usage: Fit_WriteToFile -filename <filename> -accessMode <w|a> -line <string>"
    set filename ""
    set accessMode ""
    set line ""
    APSParseArguments {filename accessMode line}
    if {![string length $filename] || ![string length $accessMode] || ![string length $line]} {
        return -code error "$usage"
    }
    switch -exact -- $accessMode {
        w { 
	    if [catch {open $filename w} fid] { 
		return -code error "$fid" 
	    } 
	}
        a { 
	    if [catch {open $filename a} fid] { 
		return -code error "$fid" 
	    } 
	}
        default { return -code error "$usage" }
    }
    puts $fid $line
    close $fid
}


#-----------------------------------------------------------------------------------------------------------------------

proc Fit_EnableButtons { widgetList } {
    foreach widget $widgetList {$widget configure -state normal}
}
proc Fit_DisableButtons { widgetList } {
    foreach widget $widgetList {$widget configure -state disabled}
}

#----------------------------------------------------------------------------------------------------------------------------
# Copies inputFile into outputFile and inserts includeString after (or instead if substitute is non-zero) searchString.

proc Fit_AddLine {args} {

    set inputFile ""
    set outputFile ""
    set searchString ""
    set includeString ""
    set substitute ""
    APSParseArguments {inputFile outputFile searchString includeString substitute}
    if {![string length $inputFile] || ![string length $outputFile] || ![string length $searchString] \
	    || ![string length $includeString] || ![string length $substitute]} {
	return -code error "Wrong arguments."
    }
    catch {exec grep $searchString $inputFile | wc} result
    set ambiguity [lindex $result 0]
    if {$ambiguity < 1} {
	return -code error "No $searchString found in $inputFile."
    }
    if {$ambiguity > 1} {
	return -code error "More than one appearance of $searchString found in $inputFile."
    }
    if [catch {open $inputFile r} fileId] {
        return -code error "Cannot open the file $inputFile for reading: $fileId"
    }
    if [catch {open $outputFile w} fileId1] {
        return -code error "Cannot open the file $outputFile for writing: $fileId1"
    }
    while {[gets $fileId line] >= 0} {
        if {[string first $searchString $line] > 0} {
	    if !$substitute { puts $fileId1 $line }
	    puts $fileId1 "$includeString "
        } else {
            puts $fileId1 $line
        }
    }
    close $fileId1
    close $fileId
}

#----------------------------------------------------------------------------------------------------------------------------

proc Fit_DeleteElementsFromList { args } {
    APSParseArguments { elementList deleteElements }
    if [llength $deleteElements] {
	foreach element $deleteElements {
	    set index [lsearch -exact $elementList $element]
	    if {$index >= 0} {
		set elementList [lreplace $elementList $index $index]
	    }
	}
    }
    return $elementList
}

#-------------------------------------------------------------------------------------------------------------------------

proc Fit_LookForDoneFiles {args} {
    APSParseArguments {jobNameList completedJobList doneFileList waitTime}
    set timesToTry 20
    for {set i 0} {$i < $timesToTry} {incr i} {
	set lostJobList ""
	foreach jobName $completedJobList {
	    if ![file exists [lindex $doneFileList [lsearch -exact $jobNameList $jobName]]] {lappend lostJobList $jobName}
	}
	if ![llength $lostJobList] { return $lostJobList }
	after $waitTime
    }
    return $lostJobList
}

#-------------------------------------------------------------------------------------------------------------------------

proc Fit_ResubmitLostJobs {args} {
    APSParseArguments {lostJobList jobNameList commandList doneFileList}
    set lostCommandList ""
    set lostDoneFileList ""
    foreach lostJob $lostJobList {
	lappend lostCommandList [lindex $commandList [lsearch -exact $jobNameList $lostJob]]
	lappend lostDoneFileList [lindex $doneFileList [lsearch -exact $jobNameList $lostJob]]
    }
    if [catch {Fit_SubmitJobs -commandList $lostCommandList -jobNameList $lostJobList \
		   -doneFileList $lostDoneFileList} returnList] {
	return -code error "SubmitJobs: $returnList"
    }
    return $returnList
}

#-------------------------------------------------------------------------------------------------------------------------
#------ Procedure for FNAL heimdall cluster:

proc Fit_GetNewJobList_PBS {args} {
    APSParseArguments {jobNameList}
    set newJobList ""
    if ![catch {join [exec qstat -f | grep Job_Name | editstring -stream "-edit=a 4D"] } fullJobList] {
	foreach jobName $fullJobList {
	    if {[lsearch -exact $jobNameList $jobName] != -1} {
		lappend newJobList $jobName
	    }
	}
    }
    return $newJobList
}

#-------------------------------------------------------------------------------------------------------------------------
#------ Procedure for APS clusters:

proc Fit_GetNewJobList_SGE {args} {
    APSParseArguments {jobNameList pidList}
    set newJobList ""
    foreach pid $pidList {
	if ![catch {join [exec qstat -j $pid | grep job_name \
			      | editstring -stream "-edit=a 2D"] } runningJobName] {
				  lappend newJobList $runningJobName
			      }
    }
    return $newJobList
}

#-------------------------------------------------------------------------------------------------------------------------
#------ Procedure for multiple tasks without queue

proc Fit_GetNewJobList_PS {args} {
    APSParseArguments {jobNameList pidList}
    if [catch {join [exec ps -p [join $pidList ,] | grep -v PID | editstring -stream "-edit=a x/ /  1F 100d"] } newPidList] {
	set newPidList ""
    }
    set newJobNameList ""
    foreach pid $newPidList {
	lappend newJobNameList [lindex $jobNameList [lsearch -exact $pidList $pid]]
    }
    return $newJobNameList
}

#-------------------------------------------------------------------------------------------------------------------------

proc Fit_WaitForTasks { args } {

    global useQsub queueSystemName

    set maxNumberOfResubmissions 1

    set waitTime 1800
    set usePopupWindow 0
    set waitInterval 10
    set useQsub 1
    set verbose 0
    APSParseArguments { pidList jobNameList commandList logFileList doneFileList useQsub verbose \
			    waitTime waitInterval usePopupWindow abortFile }

    switch -exact -- $queueSystemName {
	SGE { set getNewJobsProcedure Fit_GetNewJobList_SGE }
	PBS { set getNewJobsProcedure Fit_GetNewJobList_PBS }
	PS  { set getNewJobsProcedure Fit_GetNewJobList_PS }
	default {return -code error "Your Queue System Name $queueSystemName is not recognized. Valid names are SGE, PBS, PS."}
    }

    set counter 0
    set counterMax [expr $waitTime / $waitInterval]
    set waitIntervalms [format %.0f [expr $waitInterval * 1000]]
    set listLength [llength $pidList]

    after $waitIntervalms
    set oldJobList $jobNameList
    set newJobList $jobNameList
    set newPidList $pidList
    set numberOfResubmissionsList ""
    foreach element $jobNameList { lappend numberOfResubmissionsList 0 }
    while {[llength $newJobList] != 0} {
	if $verbose {puts stdout "------> New step"}
	#----- Get New Job List (the jobs that are running or waiting in queue right now)
	if [catch {$getNewJobsProcedure -jobNameList $newJobList -pidList $newPidList} newJobList] {
	    return -code error "$getNewJobsProcedure: $newJobList"
	}
	set newPidList ""
	foreach newJob $newJobList {
	    lappend newPidList [lindex $pidList [lsearch -exact $jobNameList $newJob]]
	}
	if $verbose { puts stdout "New job list: $newJobList" }
	if $verbose { puts stdout "New pid list: $newPidList" }
	#----- Get completed job list...
	if ![llength $newJobList] {
	    set completedJobList $oldJobList
	} else {
	    set completedJobList ""
	    foreach jobName $oldJobList {
		if {[lsearch -exact $newJobList $jobName] == -1} {lappend completedJobList $jobName }
	    }
	}
	if $verbose { if [llength $completedJobList] { puts stdout "Completed job list: $completedJobList" } }
	#----- Wait for files to appear...
	after $waitIntervalms
	update
	#----- Look for doneFiles...
	if [catch {Fit_LookForDoneFiles -jobNameList $jobNameList -completedJobList $completedJobList \
		       -doneFileList $doneFileList -waitTime $waitIntervalms} lostJobList] {
	    return -code error "Fit_LookForDoneFiles: $lostJobList"
	}
	if $verbose {if [llength $lostJobList] {puts stdout "Lost job list: $lostJobList"}}
	#----- Checking waiting time. If exceeds maximum, kill all left jobs and resubmit them.
	if {$counter > $counterMax} {
	    catch {eval exec qdel [join $pidList ]}
	    after 5000
	    set lostJobList $newJobList
	    set counter 0
	} else {
	    incr counter
	}
	#----- Resubmit lost jobs and jobs with errors...
	set resubmitJobList $lostJobList
	if {[llength $resubmitJobList] && $maxNumberOfResubmissions} {
	    if $verbose { puts stdout "Resubmit job list: $resubmitJobList" }
	    if [catch {Fit_ResubmitLostJobs -lostJobList $lostJobList -jobNameList $jobNameList -commandList $commandList \
			   -doneFileList $doneFileList} resubmittedList] {
		return -code error "Fit_ResubmitLostJobs: $resubmittedList"
	    }
	    set resubmittedPidList [lindex $resubmittedList 0]
	    set resubmittedLogFileList [lindex $resubmittedList 1]
	    foreach jobName $resubmitJobList pidNumber $resubmittedPidList logFile $resubmittedLogFileList {
		set I [lsearch -exact $jobNameList $jobName]
		set pidList [lreplace $pidList $I $I $pidNumber]
		set logFileList [lreplace $logFileList $I $I $logFile]
		set numberOfResubmissionsList \
		    [lreplace $numberOfResubmissionsList $I $I [expr [lindex $numberOfResubmissionsList $I] + 1]]
	    }
	    foreach element $numberOfResubmissionsList jobName $jobNameList {
		if {$element > $maxNumberOfResubmissions} {
		    if $useQsub {
			catch {eval exec qdel [join $pidList ]}
		    } else {
			catch {eval exec kill -9 [join $pidList ]}
		    }
		    return -code error "Error: Job $jobName required resubmission $element times. Exiting and killing all remaining jobs."
		}
	    }

	}
	#----- CheckAbortStatus
	if [file exists $abortFile] {
	    if $useQsub {
		catch {eval exec qdel [join $pidList ]}
	    } else {
		catch {eval exec kill -9 [join $pidList ]}
	    }
	    return -code error "Interrupted by user."
	}
    }
    catch {eval file delete $logFileList}
}

#-------------------------------------------------------------------------------------------------------------------------

proc Fit_SubmitJobs {args} {
    global env qsubCommand useQsub qsubRespProcCommand submissionPause
    set verbose 0
    APSParseArguments { commandList jobNameList doneFileList verbose }
    set pidList ""
    set logFileList ""
    set scriptFileList ""
    foreach command $commandList jobName $jobNameList doneFile $doneFileList {
	set path [file dirname $doneFile]
	set scriptFile $path/$jobName.tcl
	if [catch {open $scriptFile w} fid] {
	    return -code error "Error opening file: $fid"
	}
	puts $fid "#!/bin/sh  "
	puts $fid " "
	puts $fid "$command"
	close $fid
	exec chmod +x $scriptFile
	catch {file delete $path/$jobName.stderr}

	if $verbose { puts stdout "submitCommand: $qsubCommand" }
	if [catch {eval $qsubCommand} qsubResponse] {
	    return -code error "Error submitting command: $qsubResponse"
	}
	if $verbose { puts stdout "submit response: $qsubResponse" }
	set pid [eval $qsubRespProcCommand]
	if $verbose { puts stdout "Job PID is $pid" }
	lappend pidList $pid
	lappend logFileList $path/$jobName.stderr
	lappend scriptFileList $scriptFile
	lappend dotOFileList $scriptFile.o$pid
	#--- Pause for submissionPause seconds (after takes milliseconds).
	if $submissionPause { after [expr $submissionPause * 1000] }
    }
    return [list $pidList $logFileList $scriptFileList $dotOFileList]
}

#-------------------------------------------------------------------------------------------------------------------------

proc Fit_CalculateResponseMatrixDerivative { args } {

    global qsubCommand useQsub submissionPause qsubRespProcCommand queueSystemName
    set verbose 0
    set deleteFilesOnExit 1
    set argCopy $args
    APSParseArguments {varList splitTasks scriptName scriptParameters matrixFile tmpDirName useQsub qsubCommand \
				 continuePrevious rootTaskName usePopupWindow waitTime waitInterval deleteFilesOnExit \
				 submissionPause abortFile verbose qsubRespProcCommand queueSystemName}
    if $verbose {puts stdout "Fit_CalculateResponseMatrixDerivative agruments: $argCopy"}

    if [catch {Fit_SplitList -List $varList -splitTasks $splitTasks} listAfterSplitting] {
	return -code error "Fit_SplitList: $listAfterSplitting"
    }
    
    if ![string length $rootTaskName] {
	set rootTaskName [string range [file rootname [file tail $scriptName]] 0 7]
    }

    set totalPathList ""
    set commandList ""
    set jobNameList ""
    set doneFileList ""
    for {set jobNumber 0} {$jobNumber < [llength $listAfterSplitting]} {incr jobNumber} {
	set elements [lindex $listAfterSplitting $jobNumber]
	set totalPath $tmpDirName/$jobNumber
	set jobName $rootTaskName$jobNumber
	lappend totalPathList $totalPath

	if $continuePrevious {
	    if [file exists $totalPath/task.completed] {
		continue
	    }
	}

	lappend jobNameList $jobName
	lappend doneFileList $totalPath/task.completed
	catch {exec mkdir $totalPath}
	catch {eval file delete -force [glob -nocomplain -- $totalPath/*]}

	set scriptParametersFile $totalPath/scriptParameters
	if [catch {open $scriptParametersFile w} fid] { 
	    return -code error "$fid" 
	}
	puts $fid "-path $totalPath -varList \"$elements\" $scriptParameters"
	close $fid

	set commandLine "$scriptName -argMode file -scriptParametersFile $scriptParametersFile -verbose $verbose -deleteFilesOnExit $deleteFilesOnExit"
	lappend commandList $commandLine
    }

    if [catch {Fit_SubmitJobs -commandList $commandList -jobNameList $jobNameList \
		   -doneFileList $doneFileList -verbose $verbose} returnList] {
	return -code error "Fit_SubmitJobs: $returnList"
    }
    set pidList [lindex $returnList 0]
    set logFileList [lindex $returnList 1]
    if $useQsub {
	if [catch {Fit_WaitForTasks -pidList $pidList -jobNameList $jobNameList -commandList $commandList \
		       -logFileList $logFileList -doneFileList $doneFileList -waitTime $waitTime \
		       -waitInterval $waitInterval -usePopupWindow $usePopupWindow -verbose $verbose \
		       -useQsub $useQsub -abortFile $abortFile} result] {
	    return -code error "Fit_WaitForTasks: $result"
	}
    }

    set listLength [llength $totalPathList]
    set matrixFileList ""
    foreach path $totalPathList {
        lappend matrixFileList $path/responseMatrix.sdds
    }
    if {[llength $matrixFileList] == 1} {
        file copy -force $matrixFileList $matrixFile
    } else {
	if [catch {eval exec nice -19 sddsxref $matrixFileList $matrixFile "-take=* -leave=Rootname"} result] {
	    return -code error "Error during final combining: (list of xrefed files is: $matrixFileList) $result"
	} else {
	    if $deleteFilesOnExit {
		for {set I 0} {$I < $listLength} {incr I} {
		    set path [lindex $totalPathList $I]
		    catch {eval file delete [glob -nocomplain -- $path/*]}
		    catch {file delete $path}
		}
	    }
	}
    }
    return 0
}

#-----------------------------------------------------------------------------------------------------------------------

proc Fit_ReadListFromFile { args } {
    set optionsList ""
    APSParseArguments { listFile optionsList }
    set mainList ""
    if [string length $optionsList] {
	array set options $optionsList
	set indexList [list useQuads useCorrs useCorrs useBPMs useBPMs useEnergy useSkew useCorrsTilt useCorrsTilt \
	    useBPMsTilt useBPMsCoef]
	set paramList [list Quad HCorr VCorr HBPM VBPM Energy Skew HCorrTilt VCorrTilt BPMTilt BPMCoef]
	foreach index $indexList param $paramList {
	    if $options($index) {
		set localList [join [exec sddsprocess $listFile -pipe=out -match=para,ListName=$param -nowarning \
					 | sdds2stream -pipe=in -col=List] ]
		lappend mainList $localList
	    } else {
		lappend mainList ""
	    }
	}
    } else {
	foreach param [list HCorr VCorr HBPM VBPM] {
	    lappend mainList [join [exec sddsprocess $listFile -pipe=out -match=para,ListName=$param -nowarning \
					| sdds2stream -pipe=in -col=List] ]
	}
    }
    return $mainList
}

#-------------------------------------------------------------------------------------------------------------------------
#--- (Xbpm)       1       (cos(theta)  sin(theta)) (1  C) ( (1+Gx)*x )
#--- (    ) = ----------  (                      ) (    ) (          )
#--- (Ybpm)   sqrt(1-C^2) (-sin(theta) cos(theta)) (C  1) ( (1+Gy)*y )
#--- Derivative with respect to Gain: matrix with only non-zero row in that plane equal to the response
#--- Derivative with respect to tilt: H: matrix with only non-zero row for that BPM in Y plane equal to negative X response
#---                                  V: matrix with only non-zero row for that BPM in X plane equal to positive Y response
#--- Derivative with respect to C:    H: matrix with only non-zero row for that BPM in Y plane equal to positive X response
#---                                  V: matrix with only non-zero row for that BPM in X plane equal to positive Y response

proc Fit_ApplyBPMCorrections { args } {
    global tmpDir dispColumn
    set dispNoise 0
    set bpmNoise 0
    set seed ""
    APSParseArguments {hrmFile vrmFile bpmGainXFile bpmGainYFile bpmTiltFile bpmCoefFile}
    set xGainFile $bpmGainXFile
    set yGainFile $bpmGainYFile
    set tiltFile $bpmTiltFile
    set coefFile $bpmCoefFile
    set tmpRoot $tmpDir/[APSTmpString]-bpmErrors

    exec sddsprocess $hrmFile -pipe=out -match=para,Plane=X | sddsconvert -pipe=in $tmpRoot.hxrm -del=col,s
    exec sddsprocess $hrmFile -pipe=out -match=para,Plane=Y | sddsconvert -pipe=in $tmpRoot.hyrm -del=col,s
    exec sddsprocess $vrmFile -pipe=out -match=para,Plane=X | sddsconvert -pipe=in $tmpRoot.vxrm -del=col,s
    exec sddsprocess $vrmFile -pipe=out -match=para,Plane=Y | sddsconvert -pipe=in $tmpRoot.vyrm -del=col,s
###
#    exec sddsprocess $hrmFile -pipe=out -match=para,Plane=X | sddsconvert -pipe -del=col,s | sddsselect -pipe=in $tiltFile $tmpRoot.hxrm -match=BPMName=ElementName
#    exec sddsprocess $hrmFile -pipe=out -match=para,Plane=Y | sddsconvert -pipe -del=col,s | sddsselect -pipe=in $tiltFile $tmpRoot.hyrm -match=BPMName=ElementName
#    exec sddsprocess $vrmFile -pipe=out -match=para,Plane=X | sddsconvert -pipe -del=col,s | sddsselect -pipe=in $tiltFile $tmpRoot.vxrm -match=BPMName=ElementName
#    exec sddsprocess $vrmFile -pipe=out -match=para,Plane=Y | sddsconvert -pipe -del=col,s | sddsselect -pipe=in $tiltFile $tmpRoot.vyrm -match=BPMName=ElementName
    lappend deleteFiles $tmpRoot.hxrm $tmpRoot.hyrm $tmpRoot.vxrm $tmpRoot.vyrm

    #--- Build cosine, sin, gainX, gainY files that have the same dimension as rm files to use in hadamard multiplication:
    #--- (gainx_BPM1 gainx_BPM1 gainx_BPM1 ...)
    #--- (gainx_BPM2 gainx_BPM2 gainx_BPM2 ...)
    #--- (gainx_BPM3 gainx_BPM3 gainx_BPM3 ...)
    #--- ( ...                                )
    #--- hrm and vrm files are treated separately because they could have different number of correctors
    #--- x and y bpm number must be the same (filtering will be done later)
    #--- ?xrm file is used everywhere (except in yGain) because we redefine all columns anyway, only need it for number of column/rows
    foreach plane [list h v] {
	foreach CosSin [list cos sin] {
	    #--- TagName in tiltFile does not have "#X" or #Y, so remove it in the first line; -fill is when BPM is not used for tilt fit; 
	    #--- -reuse to get numbers for all lines for a particular BPM: #X, #Y
	    if [catch {exec sddsprocess $tmpRoot.${plane}xrm -pipe=out  "-reedit=col,TagName,%@#X@@ %@#Y@@" \
			   | sddsxref -pipe $tiltFile -take=ParameterValue -match=TagName -fill -nowarning -reuse \
			   | sddsconvert -pipe -del=col,*Name \
			   | sddsprocess -pipe "-redef=col,%s,ParameterValue $CosSin,select=*,exclude=ParameterValue" \
			   | sddsconvert -pipe=in $tmpRoot.$plane.$CosSin -del=col,ParameterValue} result] {
		return -code error "Error calculating $CosSin matrix ($tmpRoot.${plane}xrm -- $tiltFile): $result"
	    }
	    lappend deleteFiles $tmpRoot.$plane.$CosSin
	}
	#--- GainX file
	exec sddsxref $tmpRoot.${plane}xrm $xGainFile -pipe=out -take=ParameterValue -match=TagName -fill -nowarning \
	    | sddsconvert -pipe -del=col,*Name \
	    | sddsprocess -pipe "-redef=col,%s,1 ParameterValue +,select=*,exclude=ParameterValue" \
	    | sddsconvert -pipe=in $tmpRoot.$plane.gainX -del=col,ParameterValue
	#--- GainY file
	exec sddsxref $tmpRoot.${plane}yrm $yGainFile -pipe=out -take=ParameterValue -match=TagName -fill -nowarning \
	    | sddsconvert -pipe -del=col,*Name \
	    | sddsprocess -pipe "-redef=col,%s,1 ParameterValue +,select=*,exclude=ParameterValue" \
	    | sddsconvert -pipe=in $tmpRoot.$plane.gainY -del=col,ParameterValue
	#--- C matrix:
	exec sddsprocess $tmpRoot.${plane}xrm -pipe=out  "-reedit=col,TagName,%@#X@@ %@#Y@@" \
	    | sddsxref -pipe $coefFile -take=ParameterValue -match=TagName -fill -nowarning -reuse \
	    | sddsconvert -pipe -del=col,*Name \
	    | sddsprocess -pipe "-redef=col,%s,ParameterValue,select=*,exclude=ParameterValue" \
	    | sddsconvert -pipe=in $tmpRoot.$plane.C1 -del=col,ParameterValue
	#--- 1/sqrt(1-C^2) matrix:
	exec sddsprocess $tmpRoot.${plane}xrm -pipe=out  "-reedit=col,TagName,%@#X@@ %@#Y@@" \
	    | sddsxref -pipe $coefFile -take=ParameterValue -match=TagName -fill -nowarning -reuse \
	    | sddsconvert -pipe -del=col,*Name \
	    | sddsprocess -pipe "-redef=col,%s,1 1 ParameterValue sqr - sqrt /,select=*,exclude=ParameterValue" \
	    | sddsconvert -pipe=in $tmpRoot.$plane.C2 -del=col,ParameterValue
	lappend deleteFiles $tmpRoot.${plane}.gainX $tmpRoot.${plane}.gainY $tmpRoot.${plane}.C1 $tmpRoot.$plane.C2
    }

    #--- Use formula above directly:
    foreach plane [list h v] {
	set xOrbFile $tmpRoot.${plane}xrm
	set yOrbFile $tmpRoot.${plane}yrm
	set newxFile $tmpRoot-new.${plane}xrm
 	set newyFile $tmpRoot-new.${plane}yrm
	set cosFile $tmpRoot.$plane.cos
	set sinFile $tmpRoot.$plane.sin
	set gainxFile $tmpRoot.$plane.gainX
	set gainyFile $tmpRoot.$plane.gainY
	set c1File $tmpRoot.$plane.C1
	set c2File $tmpRoot.$plane.C2
	exec sddsmatrixop $xOrbFile -pipe=out -push=$cosFile                -push=$sinFile -push=$c1File -mult=had -add -push=$gainxFile -mult=had -mult=had \
	    -push=$cosFile                -push=$c1File -mult=had -push=$sinFile -add -push=$gainyFile -mult=had -push=$yOrbFile -mult=had -add -push=$c2File -mult=had \
	    | sddsprocess -pipe "-redef=col,%s,%s,select=*,exclude=*Name,units=m/rad" \
	    | sddsxref -pipe=in $xOrbFile $newxFile -take=*Name -transfer=para,*
	exec sddsmatrixop $xOrbFile -pipe=out -push=$sinFile -scalarmult=-1 -push=$cosFile -push=$c1File -mult=had -add -push=$gainxFile -mult=had -mult=had \
	    -push=$sinFile -scalarmult=-1 -push=$c1File -mult=had -push=$cosFile -add -push=$gainyFile -mult=had -push=$yOrbFile -mult=had -add -push=$c2File -mult=had \
	    | sddsprocess -pipe "-redef=col,%s,%s,select=*,exclude=*Name,units=m/rad" \
	    | sddsxref -pipe=in $yOrbFile $newyFile -take=*Name -transfer=para,*
    }
    exec sddscombine $tmpRoot-new.hxrm $tmpRoot-new.hyrm $hrmFile -overwrite
    exec sddscombine $tmpRoot-new.vxrm $tmpRoot-new.vyrm $vrmFile -overwrite
    lappend deleteFiles $tmpRoot-new.hxrm $tmpRoot-new.hyrm $tmpRoot-new.vxrm $tmpRoot-new.vyrm
    
    eval file delete $deleteFiles 
}
#-------------------------------------------------------------------------------------------------------------------------

proc OutputStatusMessage {text args} {
    global outputStatusDevice outputStatusFile iterationsLogFile
    set logFileOnly 0
    APSParseArguments {logFileOnly}
    if [catch {Fit_WriteToFile -filename $iterationsLogFile -accessMode a -line $text} result] {
	puts stdout "Error:::::"
	puts stdout "Line: $text"
	puts stdout "End of line:::"
        return -code error "Fit_WriteToFile: $result"
    }
    if $logFileOnly { return }
    switch -exact $outputStatusDevice {
        statusScreen { APSSetVarAndUpdate status $text }
        stdout { puts stdout $text }
        file {
            if {![info exists outputStatusFile] || ![string length $outputStatusFile]} {
		#------ outputStatusFile is not defined. Send output to stdout...
		puts stdout $text
                return
            }
            if [file exists $outputStatusFile] {
                set fid [open $outputStatusFile a]
                puts $fid $text
                close $fid
            } else {
                set fid [open $outputStatusFile w]
                puts $fid $text
                close $fid
            }
        }
        default { return -code error "OutputStatusMessage: wrong outputStatusDevice: $outputStatusDevice" }
    }
}

#-------------------------------------------------------------------------------------------------------------------------
proc HandleSpecialVariableType {args} {
    global tmpDir specialParamFile workDir
    set specialTagName ""
    set specialDelta ""
    APSParseArguments {specialElementsInputFile specialElementsFile specialVarType outputFile specialTagName specialDelta}
    set tmpRoot $tmpDir/[APSTmpString]-specUpdate
    if {[string length $specialTagName] == 0} {
	exec sddsprocess $specialElementsFile $tmpRoot.$specialVarType -match=col,ElementParameter=$specialVarType
	set tagNameList [join [exec sdds2stream $tmpRoot.$specialVarType -col=TagName] ]
	set parameterValueList [join [exec sdds2stream $tmpRoot.$specialVarType -col=ParameterValue] ]
	set parameterMode [exec sddsprocess $tmpRoot.$specialVarType -pipe=out -clip=1,0,inv \
			       | sdds2stream -pipe=in -col=ParameterMode]
	file delete $tmpRoot.$specialVarType
    } else {
	set tagNameList $specialTagName
	set parameterValueList $specialDelta
	set specialVarType [exec sddsprocess $specialElementsInputFile -pipe=out -match=col,TagName=$specialTagName | sdds2stream -pipe=in -col=ElementParameter]
	set parameterMode differential
    }
    
    set fileList ""
    foreach tagName $tagNameList value $parameterValueList {
	set specialOutputFile $tmpRoot.$tagName
	lappend fileList $specialOutputFile
	switch -exact $specialVarType {
	    Shift {
		#--- Shift of elements by using 2 drifts (has to be in .lte file already) with positive and negative lengths
		foreach {elementName elementOccurence} [Fit_MakeElementNameFromTagNameSingle -tagName $tagName] {}
		set tagName1 ${elementName}_D1#$elementOccurence
		set tagName2 ${elementName}_D2#$elementOccurence
		set elementName1 ${elementName}_D1
		set elementName2 ${elementName}_D2
		set value1 $value
		set value2 [expr $value * -1.0]
		exec sddsmakedataset $specialOutputFile \
		    -col=ElementName,type=string -data=$elementName1,$elementName2 \
		    -col=TagName,type=string -data=$tagName1,$tagName2 \
		    -col=ElementParameter,type=string -data=L,L \
		    -col=ParameterMode,type=string -data=$parameterMode,$parameterMode \
		    -col=ParameterValue,type=double -data=$value1,$value2 \
		    -col=ElementOccurence,type=long -data=$elementOccurence,$elementOccurence
	    }
	    DZ {
		exec sddsmakedataset $specialOutputFile \
		    -col=TagName,type=string -data=$elementName \
		    -col=ElementParameter,type=string -data=DZ \
		    -col=ParameterMode,type=string -data=$parameterMode \
		    -col=ParameterValue,type=double -data=0
	    }
	    Script {
		set scriptName [exec sddsprocess $specialElementsInputFile -pipe=out -match=col,TagName=$elementName \
					     | sdds2stream -pipe=in -col=ScriptName]
		set scriptOptions [exec sddsprocess $specialElementsInputFile -pipe=out -match=col,TagName=$elementName \
				       | sdds2stream -pipe=in -col=ScriptOptions]
		#--- Somehow need double eval to open "" around scriptOptions
		eval eval exec $scriptName $scriptOptions >&@ stdout
	    }
	    default {return -code error "Wrong special variable type: $specialVarType"}
	}
    }
    if {[llength $fileList] == 1} {
	file copy -force $fileList $outputFile
    } else {
	eval exec sddscombine $fileList $outputFile -merge
    }
    eval file delete $fileList
}
#-------------------------------------------------------------------------------------------------------------------------
proc CalculateEmittances {args} {
    global locoBinDir
    set execLog 0
    set paramFileList ""
    set previousResultsFile ""
    APSParseArguments {workDir definitionFile lteFile paramFileList previousResultsFile resultsFile beamline rfVoltageMV rfH beamEnergyGeV execLog}
    if [catch {Fit_ReadDefinitionFile -definitionFile $definitionFile -workDir $workDir -warnings 0 -variableList "momentsFile twiMomFile"} result] {
	    return -code error "Fit_ReadDefinitionFile: $result"
	}
    if ![file exists $workDir/tmp] {exec mkdir $workDir/tmp}
    set emitCalcRoot $workDir/tmp/calcEmit
    set paramFileListDesired $paramFileList
    set paramFileListMeasured $paramFileList
    if [string length $previousResultsFile] {
	exec sddsprocess $previousResultsFile -pipe=out -nowarning "-match=para,PageID=Quad,PageID=Skew,|" \
	    | sddscombine -pipe=in $emitCalcRoot-prevRes.param -merge -overwrite
	lappend paramFileListMeasured $emitCalcRoot-prevRes.param
    }
    exec sddsprocess $resultsFile -pipe=out -nowarning "-match=para,PageID=Quad,PageID=Skew,|" \
	| sddscombine -pipe=in $emitCalcRoot-results.param -merge -overwrite
    lappend paramFileListMeasured $emitCalcRoot-results.param
    set emitArrayList [list rfVoltage [expr $rfVoltageMV * 1e6] rfH $rfH energy [expr $beamEnergyGeV * 1e3]]
    set command "$locoBinDir/calculateTwissCorrection \
                     -calcMode coupling \
                     -mode calcEmit \
                     -workDir $workDir/tmp \
                     -lteMeasured $lteFile \
                     -beamlineMeasured $beamline \
                     -paramFileListMeasured \"$paramFileListMeasured\" \
                     -lteDesired $lteFile \
                     -beamlineDesired $beamline \
                     -paramFileListDesired \"$paramFileListDesired\" \
	             -emitArrayList \"$emitArrayList\""
    if !$execLog {
	puts stdout $command
	if [catch {eval exec $command >&@ stdout} result] {
	    puts stdout "$locoBinDir/calculateTwissCorrection: $result"
	    exit 1
	}
    } else {
	if [catch {APSExecLog .locoFitting \
		       -lineLimit 2048 -width 120 \
		       -name "Response Matrix Fitting..." \
		       -unixCommand $command} pid] {
	    puts stdout "Error running calculateTwissCorrection: $pid"
	}
    }
    file copy -force $workDir/tmp/moments.measured.mom $momentsFile
    file copy -force $workDir/tmp/moments.measured.twi $twiMomFile
}
#-------------------------------------------------------------------------------------------------------------------------
#-------------------------------------------------------------------------------------------------------------------------
proc OLD_APSSRSectorButtons {widget args} {
    set parent "" 
    set rootname ""
    set label "Unknown selections"
    set description "No description"
    set itemList ""
    set command ""
    set sectorCount 40
    set missingList ""
    set missingListVar ""
    set packOption "-side left"
    set orientation vertical
    set itemLabelList ""
    set includeWeights 0
    set includeDespike 0
    set onePerSector 0
    set sectorControl 0
    set sectorList ""
    set color0 ""
    set separateCountButton 0
    APSStrictParseArguments {parent rootname label description itemList \
                               command sectorCount onePerSector sectorControl \
                               missingList missingListVar packOption orientation \
				 itemLabelList includeWeights includeDespike sectorList color0 separateCountButton}

    global ${rootname}CBWidget ${rootname}BadBPMList ${rootname}SectorList
    if {![info exists ${rootname}BadBPMList]} {
        set ${rootname}BadBPMList ""
    }
    if ![string length $color0] {
	set monoList [exec sddsprocess /home/helios/oagData/sr/BPMStatus/config.sdds -pipe=out -match=col,ElectronicsType=Monopulse \
			  | sdds2stream -pipe -col=DeviceName]
	set nbList [exec sddsprocess /home/helios/oagData/sr/BPMStatus/config.sdds -pipe=out -match=col,ElectronicsType=Narrowband \
			| sdds2stream -pipe -col=DeviceName]
	set FPGAList [exec sddsprocess /home/helios/oagData/sr/BPMStatus/config.sdds -pipe=out -match=col,ElectronicsType=FPGA \
			  | sdds2stream -pipe -col=DeviceName]
	set IDList [exec  sddsprocess /home/helios/oagData/sr/BPMStatus/config.sdds -pipe=out -match=col,ElectronicsType=Xray \
			-match=col,DeviceName=*ID* \
			| sdds2stream -pipe -col=DeviceName]
	set BMList [exec  sddsprocess /home/helios/oagData/sr/BPMStatus/config.sdds -pipe=out -match=col,ElectronicsType=Xray \
			-match=col,DeviceName=*BM* \
			| sdds2stream -pipe -col=DeviceName]
    }
#    if ![string match *C0* [set ${rootname}BadBPMList]] {
#        for {set n 1} {$n<23} {incr n} {
#            lappend ${rootname}BadBPMList S${n}C:P0
#        }
#    }
    APSFrame $widget -parent $parent -label $label \
      -packOption $packOption

    set f1 $parent$widget.frame.f1
    set command1 ""
    set maxSectorLen 3
    if [llength $sectorList] {
        set sectorCount [llength $sectorList]
	foreach text $sectorList {
	    set len [string length $text]
	    if {$len>$maxSectorLen} {
		set maxSectorLen $len
	    }
	}
    }
    set ${rootname}SectorList $sectorList
    if [string match $orientation vertical] {
        frame $parent$widget.frame.f1
        eval pack $parent$widget.frame.f1 -side top
        # make vertical column for sector labels
        frame $f1.labels
        pack $f1.labels -side left -expand 1 -fill y
        for {set n $sectorCount} {$n>=0} {incr n -1} {
            if $n {
                if [llength $sectorList] {
                    set text "[lindex $sectorList [expr $n-1]] "
                } else {
                    set text [format "%3d " $n]
                }
                label $f1.labels.sector$n -text $text \
                  -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0
                pack $f1.labels.sector$n -side bottom
            } else {
                if [llength $itemLabelList] {
                    label $f1.labels.sector$n -text "    " \
                      -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0
                    pack $f1.labels.sector$n -side bottom
                }
            }
        }

        # make vertical columns for checkbuttons vs item name
        set index -1
        foreach item $itemList {
            incr index
            set f2 $f1.item$index
            frame $f2
            pack $f2 -side left
            for {set n $sectorCount} {$n>0} {incr n -1} {
		if [llength $sectorList] {
		    set name [lindex $sectorList [expr $n-1]]$item
		} else {
		    set name  S${n}$item
		}
		#set name S${n}$item
                set nameFlag ${rootname}$name
                global $nameFlag 
                if {![info exists $nameFlag]} {
                    set $nameFlag 1
                }
		
                # add default arguments to whatever command is being passed.
                if [string length $command] {
                    set command1 "$command -sector $n -item $item -nameFlag $nameFlag"
                }
		if ![string length $color0] {
		    if {[lsearch -exact $nbList $name]>=0} {
			set color  red
		    } elseif {[lsearch -exact $FPGAList $name]>=0} {
			set color yellow
		    } elseif {[lsearch -exact $monoList $name]>=0} {
			set color blue
		    } elseif [lsearch -exact $BMList $name]>=0 {
			set color "chartreuse"
		    } elseif [lsearch -exact $IDList $name]>=0 {
			set color "dark orange"
		    } else {
			set color maroon
		    } 
		} else {
		    set color $color0
		}
                if {[set $nameFlag] == 1} {
                    set c $color
                } else {
                    set c \#d9d9d9
                }

                checkbutton $f2.sector$n -text "" -variable $nameFlag \
                  -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -fg $color \
                  -command "APSSRSectorButtonsClicked -widget $f2.sector$n -var $nameFlag -selectcolor \"$color\" ; $command1" -selectcolor $c

                set ${rootname}CBWidget\($name\) $f2.sector$n
		
                if {[llength $missingList] && [lsearch $missingList $name]!=-1} {
                    $f2.sector$n configure -state disabled -indicatoron off -borderwidth 0 -pady 1 -padx 1
                } elseif {[llength [set ${rootname}BadBPMList]] && [lsearch [set ${rootname}BadBPMList] $name]!=-1} {
                    $f2.sector$n configure -state disabled -bg Grey85 -borderwidth 1 -pady 0 -padx 0
                } else {
                    $f2.sector$n configure -state normal -indicatoron on -bg Grey85 -borderwidth 1 -pady 0 -padx 0
                }
		if {0} {
                if [string compare $n$item 20V]==0 {
		    #disable the check button for B2C9V (which is sector 20) since it does not exist
		    set $nameFlag 0
		    $f2.sector$n configure -state disabled -indicatoron off -borderwidth 0 -pady 1 -padx 1
		}
		}
                pack $f2.sector$n -side bottom
                set apsContextHelp($f2.sector$n) $name
                if {$includeWeights || $includeDespike} {
                    set weightVar ${rootname}${name}Weight
                    set despikeVar ${rootname}${name}Despike
                    global $weightVar $despikeVar
                    if ![info exists $weightVar] {
                        set $weightVar 1
                    }
                    if ![info exists $despikeVar] {
                        if [regexp {(BM)|(ID)} $item] {
                            set $despikeVar 0
                        } else {
                            set $despikeVar 1
                        }
                    }
                    if {![llength $missingList] || [lsearch $missingList $name]==-1} {
                        bind $f2.sector$n <ButtonRelease-2> \
                          "APSSRConfigWeightDialog -weight $weightVar -despike $despikeVar -item $name"
                    }
                }
            }
            # item name label
            if [llength $itemLabelList] {
                set itemLabel [lindex $itemLabelList $index]
                label $f2.label -text [join [split [format %3s $itemLabel] ""] \n] \
                  -borderwidth 0 -padx 0 -pady 0 -highlightthickness 0
                pack $f2.label -side bottom
            }
        }
        if {$sectorControl} {
            set index [llength $itemList]
            set f2 $f1.item$index
            frame $f2
            pack $f2 -side left
            for {set n $sectorCount} {$n>0} {incr n -1} {
		if [llength $sectorList] {
		    set name [lindex $sectorList [expr $n-1]]${widget}
		    set sector1 [lindex $sectorList [expr $n-1]]
		} else {
		    set name S${n}${widget}
		    set sector1 S${n}
		}
                set togVar ${rootname}${name}
                global $togVar
                set $togVar 1
                checkbutton $f2.sector$n -text "" -variable $togVar \
                  -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 \
                  -command "APSSRItemTogglePosition -rootname $rootname -sector $sector1 -itemList [list $itemList] -missingList [list $missingList] -missingListVar \"$missingListVar\" -toggleVar $togVar"
                pack $f2.sector$n -in $f2 -side bottom
                set apsContextHelp($f2.sector$n) \
                  "Toggles all buttons in this sector on or off."
                
            }
            label $f2.label -text "A\nl\n\l" \
              -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0
            pack $f2.label -side bottom
        }
    } else {
        # orientation horizontal
        frame $parent$widget.frame.f1
        pack $parent$widget.frame.f1 -side left
        if [llength $itemLabelList] {
            # make vertical column for labels using item names
            frame $f1.labels
            pack $f1.labels -side left -fill y -expand 1
            set f2 $f1.labels
            # labels for items
            if {$sectorControl} {
                set index [llength $itemList]
                label $f2.item$index -text All \
                  -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0
                pack $f2.item$index -side bottom
            }
            for {set index [llength $itemLabelList]} {$index>0} {} {
                incr index -1
                label $f2.item$index -text [lindex $itemLabelList $index] \
                  -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0
                pack $f2.item$index -side bottom 
            }
            # make vertical columns for checkbuttons vs sector number
            for {set n 1} {$n<=$sectorCount} {incr n} {
                # column for checkbuttons
                frame $f1.sector$n
                pack $f1.sector$n -side left
                set f2 $f1.sector$n
                # make sector buttons
                if {$sectorControl} {
                    set index [llength $itemList]
		    if [llength $sectorList] {
			set name [lindex $sectorList [expr $n-1]]${widget}
			set sector1 [lindex $sectorList [expr $n-1]]
		    } else {
			set name  S${n}${widget}
			set sector1 S${n}
		    }
                    set togVar ${rootname}${name}
                    global $togVar
                    set $togVar 1
                    checkbutton $f2.item$index -text "" -variable $togVar \
                      -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 \
                      -command "APSSRItemTogglePosition -rootname $rootname -sector $sector1 -itemList [list $itemList] -missingList [list $missingList] -missingListVar \"$missingListVar\" -toggleVar $togVar"
                    pack $f2.item$index -in $f2 -side bottom
                    set apsContextHelp($f2.item$index) \
                      "Toggles all buttons in this sector on or off."
                }
                for {set index [llength $itemList]} {$index>0} {} {
                    incr index -1
                    set item [lindex $itemList $index]
		    if [llength $sectorList] {
			set name [lindex $sectorList [expr $n-1]]$item
		    } else {
			set name  S${n}$item
		    }
                    #set name S${n}$item
                    set nameFlag ${rootname}$name
                    global $nameFlag
                    if {![info exists $nameFlag]} {
                        set $nameFlag 1
                    }
                    if [string length $command] {
                        set command1 "$command -sector $n -item $item -nameFlag $nameFlag"
                    }
		    if ![string length $color0] {
			if {[lsearch -exact $nbList $name]>=0} {
			    set color  red
			} elseif {[lsearch -exact $FPGAList $name]>=0} {
			    set color yellow
			} elseif {[lsearch -exact $monoList $name]>=0} {
			    set color blue
			} elseif [lsearch -exact $BMList $name]>=0 {
			    set color "chartreuse"
			} elseif [lsearch -exact $IDList $name]>=0 {
			    set color "dark orange"
			} else {
			    set color maroon
			}
		    } else {
			set color $color0
		    }
		    
                    if {[set $nameFlag] == 1} {
                        set c $color
                    } else {
                        set c \#d9d9d9
                    }

                    checkbutton $f2.item$index -text "" -variable $nameFlag \
                      -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -fg $color \
                      -command "APSSRSectorButtonsClicked -widget $f2.item$index -var $nameFlag -selectcolor \"$color\" ; $command1" -selectcolor $c
                    set ${rootname}CBWidget\($name\) $f2.item$index
                    if {[llength $missingList] && [lsearch $missingList $name]!=-1} {
                        $f2.item$index configure -state disabled -indicatoron off -borderwidth 0 -pady 1 -padx 1
                    } elseif {[llength [set ${rootname}BadBPMList]] && [lsearch [set ${rootname}BadBPMList] $name]!=-1} {
                        $f2.item$index configure -state disabled -bg Grey85 -borderwidth 1 -pady 0 -padx 0
                    } else {
                        $f2.item$index configure -state normal -indicatoron on -bg Grey85 -borderwidth 1 -pady 0 -padx 0
                    }
		    if {0} {
		    if [string compare $n$item 20V]==0 {
			#disable the check button for B2C9V (which is sector 20) since it does not exist
			set $nameFlag 0
			$f2.item$index configure -state disabled -indicatoron off -borderwidth 0 -pady 1 -padx 1
		    }
		    }
                    pack $f2.item$index -side bottom
                    set apsContextHelp($f2.item$index) $name
                    if {$includeWeights || $includeDespike} {
                        set weightVar ${rootname}${name}Weight
                        set despikeVar ${rootname}${name}Despike
                        global $weightVar $despikeVar
                        if ![info exists $weightVar] {
                            set $weightVar 1
                        }
                        if ![info exists $despikeVar] {
                            if [regexp {(BM)|(ID)} $item] {
                                set $despikeVar 0
                            } else {
                                set $despikeVar 1
                            }
                        }
                        if {![llength $missingList] || [lsearch $missingList $name]==-1} {
                            bind $f2.item$index <ButtonRelease-2> \
                              "APSSRConfigWeightDialog -weight $weightVar -despike $despikeVar -item $name"
                        }
                    }
                }
                if [llength $sectorList] {
                    set text [lindex $sectorList [expr $n -1]]
		    set len [string length $text]
		    set n1 [expr $maxSectorLen - $len]
		    set text1 ""
		    for {set x 0} {$x<$n1} {incr x} {
			append text1 "\n"
		    }
		    for {set x 0} {$x<$len} {incr x} {
			append text1 "[format %s [string index $text $x]]"
			if {$x<[expr $len-1]} {
			    append text1 "\n"
			}
		    }
		    set text $text1
                } else {
                    if $n>9 {
                        set text [format "\n%1d\n%1d" [expr int($n/10)] [expr $n-int($n/10)*10]]
                    } else {
                        set text [format "\n\n%1d" $n]  
                    }
                }
                label $f2.label -text $text \
                  -borderwidth 0 -padx 0 -pady 0 -highlightthickness 0
               # if $n>9 {
                #     label $f2.label -text \
               #       [format "\n%1d\n%1d" [expr int($n/10)] [expr $n-int($n/10)*10]] \
                #      -borderwidth 0 -padx 0 -pady 0 -highlightthickness 0
               # } else {
               #     label $f2.label -text \
               #       [format "\n\n%1d" $n] \
                #      -borderwidth 0 -padx 0 -pady 0 -highlightthickness 0
                #}
                pack $f2.label -side bottom
            }
        }
    }
    # Position toggle buttons
    APSSRSectorPositionButtons .frametog -parent $parent$widget.frame -sectorWidget $widget \
      -rootname $rootname -sectorCount $sectorCount -sectorControl $sectorControl -sectorList $sectorList \
      -description $description -itemList $itemList -missingList $missingList \
      -missingListVar $missingListVar -orientation $orientation  -maxSectorLen $maxSectorLen

    # Global buttons
    APSSRSectorGlobalButtons .frameButtonsSB -parent $parent$widget.frame  \
      -rootname $rootname -sectorCount $sectorCount \
      -description $description -itemList $itemList -missingList $missingList \
      -missingListVar $missingListVar -orientation $orientation -sectorList $sectorList -separateCountButton $separateCountButton

    APSSRSectorUnsetMissing -rootname $rootname -sectorCount $sectorCount \
      -missingList $missingList -missingListVar $missingListVar -sectorList $sectorList
}

proc OLD_APSSRSectorGlobalButtons {widget args} {
    set parent ""
    set rootname ""
    set sectorCount 40
    set description ""
    set itemList ""
    set missingList ""
    set missingListVar ""
    set orientation vertical
    set sectorList ""
    set separateCountButton 0
    APSStrictParseArguments {parent rootname sectorCount description itemList missingList orientation missingListVar sectorList separateCountButton}

    set f2 $parent$widget
    frame $f2
    if [string compare $orientation vertical]==0 {
        set side1 top
        set side2 left
    } else {
        set side1 left
        set side2 top
    }
    pack $f2 -side $side1
    APSButton .allon -parent $f2 -text "+All" \
	-command "APSSetSRSectorButtons -mode all-on -rootname $rootname -sectorCount $sectorCount -itemList [list $itemList] -missingList [list $missingList] -missingListVar \"$missingListVar\" -sectorList [list $sectorList]" \
      -size small -packOption "-side $side2" -contextHelp \
      "Sets all $description buttons on."
    APSButton .alloff -parent $f2 -text "-All" \
	-command "APSSetSRSectorButtons -mode all-off -rootname $rootname -sectorCount $sectorCount -itemList [list $itemList] -missingList [list $missingList] -missingListVar \"$missingListVar\" -sectorList [list $sectorList]" \
      -size small -packOption "-side $side2" -contextHelp \
      "Sets all $description buttons off."
    if !$separateCountButton {
	APSButton .count -parent $f2 -text "Count" -size small -packOption "-side $side2" -command \
	    "set ${rootname}ConfigStatus \"$description count is \[APSCountSRConfig -rootname $rootname -sectorCount $sectorCount -sectorList [list $sectorList] -itemList [list $itemList] -missingList [list $missingList] \]\"" \
      -contextHelp "Counts the number of $description buttons that are on."
    } else {
	#booster itemlist contains both bpm and correctors
	set bpmList ""
	set corrList ""
	foreach item $itemList {
	    if [regexp {P} $item] {
		lappend bpmList $item
	    } elseif {[regexp {H} $item] || [regexp {V} $item]} {
		lappend corrList $item
	    }
	}
	if {![llength $bpmList] || ![llength $corrList]} {
	    return -code error "No bpm or correctors provided, no need separate count button."
	}
	APSButton .count1 -parent $f2 -text "Count_bpm" -size small -packOption "-side $side2" -command \
	    "set ${rootname}ConfigStatus \"$description BPM count is \[APSCountSRConfig -rootname $rootname -sectorCount $sectorCount -sectorList [list $sectorList] -itemList [list $bpmList] -missingList [list $missingList] \]\"" \
      -contextHelp "Counts the number of bpm buttons that are on."
	APSButton .count2 -parent $f2 -text "Count_corr" -size small -packOption "-side $side2" -command \
	    "set ${rootname}ConfigStatus \"$description corrector count is \[APSCountSRConfig -rootname $rootname -sectorCount $sectorCount -sectorList [list $sectorList] -itemList [list $corrList] -missingList [list $missingList] \]\"" \
	    -contextHelp "Counts the number of corrector buttons that are on."
    }
}
proc OLD_APSSetSRSectorButtons {args} {
    set mode ""
    set rootname ""
    set sectorCount 40
    set itemList ""
    set missingList ""
    set missingListVar ""
    set sectorList ""
    APSStrictParseArguments {mode rootname sectorCount itemList missingList missingListVar sectorList}

    if [string length $missingListVar] {
        global $missingListVar
        set missingList [set $missingListVar]
    }
    switch $mode {
        all-on {
            set value 1
        }
        all-off {
            set value 0
        }
        default {
            return
        }
    }

    foreach item $itemList {
        set toggleVar ${rootname}S${item}
        global $toggleVar
        set $toggleVar $value
        APSSRSectorTogglePosition -item $item -rootname $rootname  -sectorList $sectorList \
          -sectorCount $sectorCount -missingList $missingList -toggleVar $toggleVar
    }
}

proc OLD_APSSRSectorPositionButtons {widget args} {
    set parent ""
    set description ""
    set itemList ""
    set rootname ""
    set sectorCount 40
    set missingList ""
    set missingListVar ""
    set orientation vertical
    set sectorControl 0
    set sectorWidget ""
    set sectorList ""
    set maxSectorLen ""
    APSStrictParseArguments {parent sectorWidget description itemList rootname sectorCount missingList missingListVar orientation sectorControl sectorList maxSectorLen}

    set f2 $parent$widget
    frame $f2
    if [string match $orientation vertical] {
        set side1 top
        set side2 left
    } else {
        set side1 left
        set side2 top
    }
    pack $f2 -side $side1

    if [string match $orientation vertical] {
        label $f2.label -text "All " \
          -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0
    } else {
	set text ""
	if {$maxSectorLen>3} {
	    for {set i 0} {$i<[expr $maxSectorLen -3]} {incr i} {
		append text "\n"
	    }
	    append text "A\nl\nl"
	} else {
	    set text "A\nl\n\l"
	}
        label $f2.label -text $text \
          -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0
    }
    pack $f2.label -side $side2
    
    foreach item $itemList {
        set togVar ${rootname}S${item}
        global $togVar
        if {![info exists $togVar]} {
            set $togVar 1
        }
        set w $f2.$togVar
        checkbutton $f2.$togVar -text "" -variable $togVar \
          -command "APSSRSectorTogglePosition -rootname $rootname -sectorCount $sectorCount -item $item -missingList [list $missingList] -missingListVar \"$missingListVar\" -toggleVar $togVar -sectorList \"$sectorList\"" \
          -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0
        pack $f2.$togVar -in $f2 -side $side2
        set apsContextHelp($f2.$togVar) \
          "Toggles all $description in this position for all sectors on or off."
    }
    if {$sectorControl} {
        # if more than one frame of buttons is created, say one for
        # monitors and on for correctors, then this button in the two
        # frames will share the same variable.
        set widgetPartsList [split $parent .]
        set widgetParts [llength $widgetPartsList]
        set suffix [lindex $widgetPartsList [expr $widgetParts - 2]]
        set togVar ${rootname}S${suffix}
        global $togVar
        if {![info exists $togVar]} {
            set $togVar 1
        }
        set w $f2.$togVar
        if [string length $missingListVar] {
            set command "APSSRSectorsToggle -widget $sectorWidget -rootname $rootname -itemList [list $itemList] -missingList [list $missingList] -missingListVar $missingListVar -toggleVar $togVar -sectorList [list $sectorList]"
      
        } else {
            set command "APSSRSectorsToggle -widget $sectorWidget -rootname $rootname -itemList [list $itemList] -missingList [list $missingList] -toggleVar $togVar -sectorList [list $sectorList]"
        }
        checkbutton $f2.$togVar -text "" -variable $togVar \
          -command $command \
          -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0
        pack $f2.$togVar -in $f2 -side $side2
        $f2.$togVar configure -state disable
       # set apsContextHelp($f2.$togVar) "Does nothing."
    }
}
proc OLD_APSSRSectorsToggle {args} {
    set rootname ""
    set sectorCount 40
    set itemList ""
    set missingList ""
    set missingListVar ""
    set toggleVar ""
    set widget ""
    set sectorList ""
    APSStrictParseArguments {widget rootname sectorCount itemList missingList toggleVar missingListVar sectorList}
    global $toggleVar
   
    for {set n 1} {$n<=$sectorCount} {incr n} {
	if [llength $sectorList] {
	    set name [lindex $sectorList [expr $n-1]]${widget}
	} else {
	    set name S${n}${widget}
	}
        set togVar ${rootname}${name}
        global $togVar
        set $togVar [set $toggleVar]
        if [string length $missingListVar] {
            global $missingListVar
            set missingList [set $missingListVar]
        }
    #    foreach item $itemList {
     #       set name S${n}${item}
      #      set nameFlag ${rootname}${name}
       #     global $nameFlag
        #    set $nameFlag [set $togVar]
        #}
    }
   # foreach item $itemList {
    #    set togVar ${rootname}S${item}
    #    global $togVar
     #   set $togVar [set $toggleVar]
   # }
   # APSSRSectorUnsetMissing -rootname $rootname -missingList $missingList
}
proc OLD_APSSRSectorTogglePosition {args} {
    set item ""
    set rootname ""
    set sectorCount 40
    set missingList ""
    set missingListVar ""
    set toggleVar ""
    set sectorList ""
    APSStrictParseArguments {item rootname sectorCount missingList toggleVar missingListVar sectorList}
    global $toggleVar ${rootname}CBWidget
    if [string length $missingListVar] {
        global $missingListVar
        set missingList [set $missingListVar]
    }
    for {set sector 1} {$sector<=$sectorCount} {incr sector} {
	if [llength $sectorList] {
	    set name [lindex $sectorList [expr $sector-1]]${item}
	} else {
	    set name S${sector}${item}
	}
        set nameFlag ${rootname}${name}
        global $nameFlag
#        set $nameFlag [set $toggleVar]
        if {[info exists $nameFlag]} {
            if {[set $nameFlag] != [set $toggleVar]} {
                [set ${rootname}CBWidget($name)] invoke
            }
        }
    }
    APSSRSectorUnsetMissing -rootname $rootname -missingList $missingList -sectorList $sectorList
}

proc OLD_APSSRItemTogglePosition {args} {
    # similar to APSSRSectorTogglePosition except the loop is over the
    # list of items rather than the list of sectors.
    set sector ""
    set itemList ""
    set rootname ""
    set missingList ""
    set missingListVar ""
    set toggleVar ""
    APSStrictParseArguments {sector itemList rootname missingList toggleVar missingListVar}
    global $toggleVar ${rootname}CBWidget
    if [string length $missingListVar] {
        global $missingListVar
        set missingList [set $missingListVar]
    }
   
    foreach item $itemList {
        set name ${sector}${item}
        set nameFlag ${rootname}${name}
        global $nameFlag
        #set $nameFlag [set $toggleVar]
        if {[set $nameFlag] != [set $toggleVar]} {
            [set ${rootname}CBWidget($name)] invoke
        }
    }
    APSSRSectorUnsetMissing -rootname $rootname -missingList $missingList
}

proc OLD_APSSRConfigWeightDialog {args} {
    set weight ""
    set despike ""
    set item ""
    APSStrictParseArguments {weight despike item}
    global $weight $despike
    set w .srConfigWeightDialog
    if [winfo exists $w] {destroy $w}
    APSDialogBox $w -name "Weight Dialog for $item" \
      -cancelCommand "set $weight [set $weight]; set $despike [set $despike]" 
    APSLabeledEntry .le -parent $w.userFrame -label "Weight: " \
      -textVariable $weight -type real -width 26 -contextHelp \
      "Enter the weight for $item.  Should be a positive real number."
    APSRadioButtonFrame .rb -parent $w.userFrame -label "Despike: " \
      -variable $despike -packOption "-side top" \
      -orientation horizontal -buttonList {N Y} -valueList {0 1} \
      -contextHelp \
      "Set despike flag for use in orbit correction. Xray BPMs usually have the despike flag unset (N) while SR RF bpms have despike flag set (Y)."
}

proc OLD_APSSRSectorUnsetMissing {args} {
    set rootname ""
    set missingList ""
    set missingListVar ""
    set sectorList ""
    APSParseArguments {rootname missingList missingListVar sectorList}
    if [string length $missingListVar] {
        global $missingListVar
        set missingList [set $missingListVar]
    }
    global ${rootname}CBWidget
    foreach item $missingList {
        set nameFlag ${rootname}${item}
        global $nameFlag
        if {[info exists $nameFlag] && [set $nameFlag] != 0} {
            [set ${rootname}CBWidget($item)] invoke
        }
        set $nameFlag 0
    }
}

proc OLD_APSSRSectorButtonsClicked {args} {
    APSStrictParseArguments {widget var selectcolor}
    global $var
    if {[set $var]} {
        $widget configure -selectcolor $selectcolor
    } else {
        $widget configure -selectcolor \#d9d9d9
    }
}

