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

set auto_path [linsert $auto_path 0 /usr/local/oag/apps/lib/$env(HOST_ARCH)]
set auto_path [linsert $auto_path 0 /usr/local/oag/lib_patch/$env(HOST_ARCH)]
APSStandardSetup

set CVSRevisionAuthor "\$Revision: 1.16 $ \$Author: shang $"

APSApplication . -name optimizeInterface -version $CVSRevisionAuthor \
  -overview {This interface provides a simple interface to sddsoptimize and squishPVs
    program.}

set args $argv
set configuration ""
set run 0
APSStrictParseArguments {configuration run}

set mainStatus "ready."
proc SetMainStatus {text} {
    global mainStatus
    set mainStatus $text
    update
}

proc CreateParametersWidget {widget} {
    global Iterations Tolerance Target NumberToAverage PauseBetweenReadings Method
    global ChangePause
    set p1 ${widget}.parameter1.frame
   # set p2 ${widget}.parameter2
    APSFrame .parameter1 -parent $widget -label "" 
  #  APSFrame .parameter2 -parent $widget -label "" 
    set w 10
    APSLabeledEntry .iters -parent $p1 -label \
      "Iterations: " -textVariable Iterations -width $w -contextHelp "Enter the number
        of iterations in this field." -packOption "-side left"
    APSLabeledEntry .tol -parent $p1 -label \
      "tolerance: " -textVariable Tolerance -width $w -packOption "-side left" \
      -contextHelp "tolerance is the converging limit"
    APSLabeledEntry .tar -parent $p1 -label \
      "target:   " -textVariable Target -width $w -packOption "-side left"
   
    APSLabeledEntry .div -parent $p1 -label \
      "divisions:" -textVariable Divisions -width $w -packOption "-side left" \
      -contextHelp "enter the maximum divisons used in simplex or 1dscan"
    APSLabeledEntry .rep -parent $p1 -label \
      "cycles: " -textVariable Repeats -width $w -packOption "-side left" \
      -contextHelp "enter the maximum repeated runs used in simplex or 1dscan"
    APSFrame .parameter2 -parent $widget -label ""
    set p2 $widget.parameter2.frame
    global RCDS
    set RCDS(evals) 50
    set RCDS(cycles) 6
    set RCDS(noise) 0.001
    set RCDS(stepSize) 0.01
    APSLabeledEntry .iter -parent $p2 -label "RCDS parameters: iterations:" -textVariable RCDS(evals) \
        -width $w -packOption "-side left" -contextHelp "the maximum number of function evaluations"
    APSLabeledEntry .cycles -parent $p2 -label "  cycles:" -textVariable RCDS(cycles) \
        -width $w -packOption "-side left" -contextHelp "the maximum iterations of bracket minimization search"
    APSLabeledEntry .noise -parent $p2 -label "  noise:" -textVariable RCDS(noise) \
        -width $w -packOption "-side left" -contextHelp "the experimental noise (default 0.001)"
    APSLabeledEntry .step -parent $p2 -label "  step size:" -textVariable RCDS(stepSize) \
        -width $w -packOption "-side left" -contextHelp "step size is the normalized step size when the values of the variables are noramlized to between 0 and 1, default step size is 0.01"

    #create method frame
    APSFrame .method -parent ${widget} -label "Method"
    ${widget}.method.frame configure -relief flat -bd 0
    set m ${widget}.method.frame
    set Method Simplex
    APSRadioButtonFrame .scan -parent $m \
      -label "" -buttonList {Simplex RCDS 1D_Simplex 1DScan squishPVs}\
      -variable Method -valueList {Simplex RCDS 1D_Simplex 1DScan squishPVs}\
      -packOption {-side left} -orientation horizontal\
      -contextHelp "if squishPVs is checked, then run squishPVs when \
                            Run is clicked. otherwise, run sddsoptimize"

    APSFrame .ops -parent ${widget} -packOption "-side top" \
      -contextHelp "Actions are started in this frame."

    APSButton .ops.frame.run -parent ${widget} -text Run -command \
      "ChangeButtonState 1; RunOptimizer" \
      -contextHelp "Launches sddsoptimize to find the best position using the chosed method"
    global continueButtonWidget
    set continueButtonWidget $widget.ops.frame.continue.button
    APSButton .ops.frame.continue -parent ${widget} -text Continue -command \
      "ChangeButtonState 1; ContinueOptimizer" \
      -contextHelp "Continue to run sddsoptimize starting from the best point just obtained"

}

proc methodOptionWidget {widget} {
    set m ${widget}.methodO.frame
    global Method Maximize Repeat doMeasScript Verbose mav Test Control
    
    APSCheckButtonFrame .ver -parent $m -label "" \
      -variableList Verbose\
      -buttonList verbose  -packOption {-side left}\
      -contextHelp "print the results if checked" 
    
}

proc CreatMeasurementWidget {parent} {
    global mvScroll mvScrollFrame 
    
    APSFrame .measW -name "Measurement" -parent $parent -packOption "-side top -fill x"
    set w $parent.measW.frame
    $w configure -relief flat -bd 0
    set mvScroll [APSScroll .mvScroll -parent $w]
    set mvScrollFrame $w.mvScroll
    APSFrame .but -parent $parent -packOption "-side top -fill x"
    set w1 $parent.but.frame
    $w1 configure -relief flat -bd 0
    APSButton .add -parent $w1 -text "ADD" \
      -command "MakeNewMeasureLine $mvScroll" -contextHelp "Press to add another PV name
   entry line."
    APSButton .load -parent $w1 -text "LOAD Measurement PVs from file" \
      -command LoadMeasureData
    APSButton .save -parent $w1 -text "SAVE Measurement PVs to file" \
      -command "SaveMeasureData"
    APSButton .clear -parent $w1 -text "Clear Measurement PVs" \
      -command "ClearMeasureSettings $mvScroll"
    APSFrame .par -parent $parent -packOption "-side top -fill x"
    set w $parent.par.frame
    $w configure -relief flat -bd 0
    APSFrameGrid .grid -parent $w -yList {y1 y2}
    set w1 $w.grid.y1
    set w2 $w.grid.y2
     global PauseBetweenReadings NumberToAverage Maximize Repeat mav doMeasScript MeasScript

    APSLabeledEntry .s -parent $w1 -packOption "-side left" \
      -width 60 -label "measurement script:" -textVariable MeasScript \
      -contextHelp "Enter the script measurement here"
    APSButton .choose -parent $w1.s -packOption "-side right" -text "Choose Script File" \
      -command "ChooseScriptFile -type Meas"

    APSLabeledEntry .average -parent $w2 -label \
      "Average:" -textVariable NumberToAverage -width 10 -contextHelp "Enter the
        number of average for reading in this field." -packOption "-side left"
    APSLabeledEntry .interval -parent $w2 -label \
      "Interval(s):" -textVariable PauseBetweenReadings -width 10 -contextHelp \
      "Enter the interval between two readings in this field." -packOption "-side left"
    APSRadioButtonFrame .max -parent $w2 -label "" \
      -variable Maximize\
      -buttonList {maximize minimize}  -packOption {-side left}\
      -valueList {1 0} -orientation horizontal\
      -contextHelp "find the maximum or minimum RMS value of the measurement"
    APSCheckButtonFrame .rept -parent $w2 -label "" \
      -variableList Repeat\
      -buttonList freshReading  -packOption {-side left}\
      -contextHelp "if checked: read the measurement again if the variable PVs are set back \
                       to their previous values. It should be checked with noise exists" 
    APSRadioButtonFrame .mav -parent $w2 -label "" \
      -variable mav -packOption {-side left}\
      -buttonList {mav rms} \
      -valueList {1 0} -orientation horizontal\
      -contextHelp "specifies mean-absolute-value(mav) or RMS reduction for squishPVs.\
                       sddsoptimize always uses RMS reduction"
    
    APSCheckButtonFrame .radio -parent $w2 -label ""  -packOption {-side left} \
      -variableList doMeasScript -buttonList measScript \
      -contextHelp "run the script if measScript button is checked, otherwise, run the meas file."
    
}

set offset 0
set MeasurementLines 1
proc MakeNewMeasureLine {widget0 args} {
    global mvScrollFrame
    global MeasurementLines VarMeasurementName VarOffsetPVName ReadbackUnits
    global OffsetValue Weight

    APSFrame .m$MeasurementLines -parent $widget0 -packOption "-anchor w -fill x"
    set widget $widget0.m$MeasurementLines.frame
    $widget configure -relief flat -bd 0
    APSFrame .op  -parent $widget -packOption "-side left" 
    $widget.op.frame configure -relief flat -bd 0
    APSFrame .data  -parent $widget -height 1
    $widget.data.frame configure -relief flat -bd 0

    if {$MeasurementLines==1} {
        set measurementName ""
        set offsetValue 0
        set offsetPVName ""
        set readbackUnits ""
        set weight 1
    } else {
        set lastVar [expr $MeasurementLines - 1]
        set measurementName $VarMeasurementName($lastVar)
        set offsetValue $OffsetValue($lastVar)
        set offsetPVName $VarOffsetPVName($lastVar)
        set readbackUnits $ReadbackUnits($lastVar)
        set weight $Weight($lastVar)
    }        
    APSParseArguments {measurementName offsetValue offsetPVName readbackUnits weight}

    APSButton .delete -parent $widget.op.frame -text "DELETE" \
      -command "DeleteMeasurementLine $widget0 $MeasurementLines" \
      -contextHelp "Press to delete the corresponding PV name entry line." 
    $widget.op.frame.delete configure -bd 0
    $widget.op.frame.delete.button configure -font -adobe-courier-medium-r-normal-*-12-*-*-*-*-*-*-*

    APSButton .clear -parent $widget.op.frame -text "CLEAR" \
      -command "ClearMeasurementLine $widget0 $MeasurementLines" \
      -contextHelp "Press to clear the corresponding PV name entry line." 
    $widget.op.frame.clear configure -bd 0
    $widget.op.frame.clear.button configure -font -adobe-courier-medium-r-normal-*-12-*-*-*-*-*-*-*
    
    set VarMeasurementName($MeasurementLines) $measurementName
    APSLabeledEntry .x -parent $widget.data.frame -label "PV:" -textVariable \
      VarMeasurementName($MeasurementLines) -width 20 \
      -contextHelp "Enter the name of a variable process variable (PV) in this field." \
      -packOption "-side left"
    $widget.data.frame.x configure -bd 0
    set ReadbackUnits($MeasurementLines) $readbackUnits
     APSLabeledEntry .unit -parent $widget.data.frame -label "Units:" \
        -textVariable ReadbackUnits($MeasurementLines) -width 5 \
      -contextHelp "Enter the units for the variable process variable (PV)
       in this field." -packOption "-side left"
    $widget.data.frame.x configure -bd 0
    set VarOffsetPVName($MeasurementLines) $offsetPVName
    APSLabeledEntry .off -parent $widget.data.frame -label "OffsetPV:" -textVariable \
      VarOffsetPVName($MeasurementLines) -width 20 \
      -contextHelp "Enter the name of a variable process variable (PV) in this field that will \
       substracting from corresponding measurement PV or the readbackName." \
      -packOption "-side left"
    
    $widget.data.frame.unit configure -bd 0
    set OffsetValue($MeasurementLines) $offsetValue
    APSLabeledEntry .y -parent $widget.data.frame -label "offset:" \
        -textVariable OffsetValue($MeasurementLines) -width 8 \
      -contextHelp "Enter the offset value for the variable process variable (PV)
       in this field." -packOption "-side left"
    $widget.data.frame.y configure -bd 0
    set Weight($MeasurementLines) $weight
    APSLabeledEntry .back -parent $widget.data.frame -label "weight:" \
        -textVariable Weight($MeasurementLines) -width 7 \
      -contextHelp "Enter the weight for the variable process variable (PV)
       in this field." -packOption "-side left"
    $widget.data.frame.back configure -bd 0
    
    incr MeasurementLines
    .userFrame.main.frame.tn select 1
    tkwait visibility $widget.data.frame.back
    APSScrollAdjust $mvScrollFrame -numVisible 5

}

proc DeleteMeasurementLine {widget0 number} {
    global VarMeasurementName mvScrollFrame
    if {$number} {
        destroy $widget0.m$number
        set VarMeasurementName($number) ""
        APSScrollAdjust $mvScrollFrame -scrollIncrement 35
    } else {
        bell
    }
}
proc ClearMeasurementLine {widget0 number} {
    global VarMeasurementName OffsetValue OffsetPVName ReadbackUnits Weight
    set VarMeasurementName($number) ""
    set OffsetPVName($number) ""
    set ReadbackUnits($number) ""
    set OffsetValue($number) 0
    set Weight($number) 1
}

proc LoadMeasureData {args} {
    global env mvScroll homeDir measDir home
    global InputOrbitFile MeasurementLines PauseBetweenReadings NumberToAverage
    set filename ""
    APSParseArguments {filename}
    if {![string compare $measDir $home]} {
         if [string compare $homeDir $home] {
            set measDir $homeDir
         }
    }
    if ![string length $filename] {
        set filename [APSFileSelectDialog .chooseInputFile -listDir $measDir]
    }
    set filename [string trim $filename]
    if [string length $filename] {
        set measDir [file dirname $filename]
        set homeDir $measDir
    }

    set InputOrbitFile $filename
    
    if [string first " " $filename]!=-1 {
        SetMainStatus "Filename may not have spaces in it."
        bell
        return
    }
    if {![APSCheckSDDSFile -fileName $filename]} {
        bell
        SetMainStatus "$filename is not an SDDS file."
        return
    }
    set colNames [APSGetSDDSNames -fileName $filename -class column]
    if {[llength $colNames]<1} {
        SetMainStatus "$filename doesn't contain any data columns from which
          to get PV names."
        bell
        return 
    }
    if {[lsearch -exact $colNames "ControlName"]!=-1} {
        set columnName ControlName
    } else {
        SetMainStatus "$filename doesn't contain any data columns from which to
           get PV names."
        bell
        return
    }
    set names [APSGetSDDSColumn -fileName $filename -column $columnName -page 0]
    if {[llength $names]==0} {
        SetMainStatus "$filename has no process variable names."
        bell
        return
    }
    set PVCount [llength $names]
    if {[lsearch -exact $colNames "ReadbackName"]!=-1} {
        set backNames [APSGetSDDSColumn -fileName $filename -column ReadbackName -page 0]
    } else {
       set backNames [lindex $names 0]
       for {set i 1} {$i < $PVCount} {incr i} {
       lappend backNames [lindex $names $i]
       }
    }
    if {[lsearch -exact $colNames "DesiredValue"]!=-1} {
        set values [APSGetSDDSColumn -fileName $filename -column DesiredValue -page 0]
    } else {
        set values 0
        for {set i 1} {$i < $PVCount} {incr i} {
        lappend values 0
       }
    }
    if {[lsearch -exact $colNames "Weight"]!=-1} {
        set weight [APSGetSDDSColumn -fileName $filename -column Weight -page 0]
    } else {
        set weight 1
        for {set i 1} {$i < $PVCount} {incr i} {
        lappend weight 1
       }
    }
    if {[lsearch -exact $colNames "ReadbackUnits"]!=-1} {
        set units [APSGetSDDSColumn -fileName $filename -column ReadbackUnits -page 0]
    } else {
        set units ""
        for {set i 1} {$i < $PVCount} {incr i} {
          lappend units ""        
        }
    }
    set paramList [APSGetSDDSNames -fileName $filename -class parameter]
    if { [lsearch $paramList "pauseBetweenReadings"] != -1 } {
       set PauseBetweenReadings [APSGetSDDSParameter -fileName $filename -parameter \
           PauseBetweenReadings -page 0 ]
    } 
    if {[lsearch $paramList "numberToAverage"] !=-1 } {
       set NumberToAverage [APSGetSDDSParameter -fileName $filename -parameter \
            NumberToAverage -page 0]
    }
    if {[lsearch $paramList "tolerance"] != -1 } {
       set Tolerance [APSGetSDDSParameter -fileName $filename -parameter Tolerance -page 0]
    } else {
       set Tolerance 0.01
    } 
    ClearMeasureSettings $mvScroll 0
    set i 0
    foreach name $names {
       MakeNewMeasureLine $mvScroll -measurementName $name \
         -offsetValue [format %.4f [lindex $values $i]] \
         -offsetPVName [lindex $backNames $i]  \
         -readbackUnits [lindex $units $i] \
         -weight [format %.4f [lindex $weight $i]]
       incr i
    }
  #  SetMainStatus "Measurement data loaded from $filename."
}
proc ClearMeasureSettings {widget0 {popUp 1}} {
    global MeasurementLines VarMeasureName OffsetValue OffsetPVName ReadbackUnits
    global mvScrollFrame
    if {$MeasurementLines>1} {
      if {$popUp} {
        if {![APSYesNoPopUp "Really? Clear Measurement settings?"]} { return }
      }
 
     for {set i $MeasurementLines} {$i>0} {incr i -1} {
        if {[winfo exists $widget0.m$i]} { destroy $widget0.m$i}
        set VarMeasurementName($i) ""
        set OffsetValue($i) 0
        set OffsetPVName($i) ""
        set ReadbackUnits($i) ""
        set Weight($i) 1
     }
     set MeasurementLines 1
     APSScrollAdjust $mvScrollFrame -scrollIncrement 35
   }
}

proc SaveMeasureData {args} {
    global MeasurementLines VarMeasurementName OffsetValue VarOffsetPVName ReadbackUnits
    global OutputMeasFile Weight PauseBetweenReadings
    global NumberToAverage Tolerance

    set PVcount 0
    for {set i 1} {$i<$MeasurementLines} {incr i} {
        if [string length $VarMeasurementName($i)]!=0 {
            incr PVcount
        }
    }

    if {$PVcount == 0} {
        SetMainStatus "SaveMeasureData: No PV variables specified for saving."
        return 0 
    }
    set filename ""
    APSStrictParseArguments {filename}
    if [string length $filename] {
        if [file exist $filename] {
            if ![APSMultipleChoice [APSUniqueName .] -question "$filename exists. \
               Overwrite it?" -labelList {Yes No} -returnList {1 0}] {
               return 0
            }
        }
    }

    while {![string length $filename]} {
      set filename [APSInfoDialog [APSUniqueName .] -name FileDialog \
                    -width 60 \
                    -infoMessage "Supply the name of a file to which to \
                     save the measurement data." ]
      set filename [string trim $filename]
      if ![string length $filename] {
         return -code error "No filename given."
      }
      if {[file exists $filename] && \
         ![APSMultipleChoice [APSUniqueName .] -question "$filename exists.\
           Overwrite it?" -labelList {Yes No} -returnList {1 0}]} {
             set filename ""
      }
    }
    set units 0
    for {set i } {$i<$MeasurementLines} {incr i} {
        if {$ReadbackUnits($i)!=""} {
           set units 1
        }
        if {$units && $ReadbackUnits($i)==""} {
            SetMainStatus "the unit of $VarMeasurementName($i) is not given"
            bell
            return 0
        }
    }
    set fid [open $filename w]
    puts $fid "SDDS1"
    puts $fid "&parameter name=NumberToAverage type=long &end"
    puts $fid "&parameter name=PauseBetweenReadings type=double &end"
    puts $fid "&parameter name=Tolerance type=double &end"
    puts $fid "&column name=ControlName type=string &end"
    puts $fid "&column name=ReadbackName type=string &end"
    if $units {
       puts $fid "&column name=ReadbackUnits type=string &end"
    }
    puts $fid "&column name=DesiredValue type=double &end"
    puts $fid "&column name=Weight type=double &end"
    puts $fid "&data mode=ascii no_row_counts=1 &end"
    puts $fid "$NumberToAverage"
    puts $fid "$PauseBetweenReadings"
    puts $fid "$Tolerance"
    for {set i 1} {$i<$MeasurementLines} {incr i} {
      if [string length $VarMeasurementName($i)]==0 continue
      if $units {
        puts $fid "\"$VarMeasurementName($i)\" \"$VarOffsetPVName($i)\" \"$ReadbackUnits($i)\" \"$OffsetValue($i)\" \"$Weight($i)\"" 
      } else {
        puts $fid "\"$VarMeasurementName($i)\" \"$VarOffsetPVName($i)\" \"$OffsetValue($i)\" \"$Weight($i)\""
      }
    }
    close $fid
    set OutputMeasFile $filename
   # SetMainStatus "Save completed to file $filename."
    return 1
}
set KnobFiles ""
set startFromPresent 1
proc CreatVariableWidget {parent} {
    global pvScroll pvScrollFrame KnobFiles startFromPresent
    
    APSFrame .varW -name "PV Variables" -parent $parent -packOption "-side top -fill x"
    set w $parent.varW.frame
    set pvScroll [APSScroll .mvScroll -parent $w]
    set pvScrollFrame $w.mvScroll
    APSFrame .button -parent $parent -packOption "-side top -fill x"
    set w1 $parent.button.frame
    APSButton .add -parent $w1 -text "ADD" -packOption "-side left" \
      -command "MakeNewVariableLine $pvScroll" -contextHelp "Press to add another PV name
   entry line."
    APSButton .load -parent $w1 -text "Load Variable PVs from file" \
      -command LoadVariableData
    APSButton .save -parent $w1 -text "SAVE variable PVs to file" \
      -command "SaveVariableData"
    APSButton .clear -parent $w1 -text "Clear variables..." \
      -command "ClearVariableSettings $pvScroll"
    APSFrame .knob -parent $parent -packOption "-side top -fill x"
    set w $parent.knob.frame
    $w configure -relief flat -bd 0
    global ChangePause
    APSLabeledEntry .post -parent $w -label \
      "Pause(s):  " -textVariable ChangePause -width 10 -contextHelp \
      "Enter the pausing time in seconds after a control change is made." -packOption "-side left"
    
    APSLabeledEntry .file -parent $w -label \
      "  KnobFiles: " -textVariable KnobFiles -width 60 -packOption "-side left"\
      -contextHelp "Enter the knob file names here, use ',' to separate different files\
      If the file has different directory from the above dir, \
      give the directory together here"
    
    APSButton .open -parent $w.file -command "OpenKnobFile" -text "choose" \
      -packOption "-side right"\
      -contextHelp "Press to open the knob files list and choose the knob file"
    global VarScript
    APSLabeledEntry .s -parent $parent  \
      -width 75 -label "variable script:" -textVariable VarScript \
      -contextHelp "Enter the variable script here"
    APSButton .choose -parent $parent.s -packOption "-side right" -text "Choose Script File" \
      -command "ChooseScriptFile -type Var"
    APSRadioButtonFrame .check -parent $parent -label "" \
      -variable startFromPresent -packOption "-side top" \
      -buttonList {start_from_present start_from_given_values} \
      -commandList {"GetPVValues -read 1" "GetPVValues -read 0"} \
      -valueList {1 0} -orientation horizontal\
      -contextHelp "PV start from present values \
      if start_from_present button is checked, or start from the given values if \
      start_from_given_values button is checked." 
    global doVarScript
    APSCheckButtonFrame .radio -parent $parent.check -label "" -packOption "-side left" \
      -variableList doVarScript -buttonList varScript \
      -contextHelp "run the var script if varScript button is checked" \
      -commandList {ResetDoForce}
}
proc ResetDoForce {args} {
    global startFromPresent doVarScript
    if $doVarScript {
        set startFromPresent 0
    }
}   

set KnobDir "/home/helios/oagData/sr/knobs"
proc OpenKnobFile {} {
   global KnobFiles KnobDir

   set filename [APSFileSelectDialog .chooseInputFile -listDir $KnobDir \
         -contextHelp "Select a knob configuration file" \
         -title "Select Knob Configuration File:"]
   set filename [string trim $filename]
   set KnobDir [file dirname $filename]

   if {$KnobFiles ==""} {
      set KnobFiles $filename
   } else {
     if {![string match *${filename}* $KnobFiles]} {
        set KnobFiles "$KnobFiles,$filename"
     } else {
        APSAlertBox .existFile -errorMessage \
           "This file has alrady been chosen: $filename"
        return
     }   
   }
}

set InitExist 0
proc LoadVariableData {args} {
    global env pvScroll startFromPresent
    global VariableLines ChangePause varDir homeDir home VarPVname InitialValue
    global Iterationts Target Mode PauseBetweenReading NumberToAverage Tolerance
    global PauseAfterChange InitialSettings InitExist
    if {![string compare $varDir $home] && [string compare $homeDir $home]} {
        set varDir $homeDir
    }
    set filename ""
    APSParseArguments {filename}
    if ![string length $filename] {
        set filename [APSFileSelectDialog .chooseInputFile -listDir $varDir]
    }
    set filename [string trim $filename]
    if [string length $filename] {
        set varDir [file dirname $filename]
        set homeDir $varDir
    }

    if {![APSCheckSDDSFile -fileName $filename]} {
        SetMainStatus "$filename is not an SDDS file."
        bell
        return
    }
    set colNames [APSGetSDDSNames -fileName $filename -class column]
    if {[llength $colNames]<1} {
        SetMainStatus "$filename doesn't contain any data columns from which
          to get PV names."
        bell
        return 
    }
    if {[lsearch -exact $colNames "ControlName"]!=-1} {
        set columnName ControlName
    } else {
        SetMainStatus "$filename doesn't contain controlPV data column."
        bell
        return
    }
    set names [APSGetSDDSColumn -fileName $filename -column $columnName -page 0]
    if {[llength $names]==0} {
        SetMainStatus "$filename has no process variable names."
        bell
        return
    }
    
    set paramList [APSGetSDDSNames -fileName $filename -class parameter]

   if {[lsearch $paramList "PauseAfterChange"] != -1 } {
       set ChangePause [format %.3f [APSGetSDDSParameter -fileName $filename -parameter\
                                       PauseAfterChange -page 0]]
    } else {
       set ChangePause 1
    }
    set nInit {}
    set PVCount [llength $names]
    if {[lsearch -exact $colNames InitialValue] !=-1} {
       set nInit [APSGetSDDSColumn -fileName $filename -column "InitialValue" -page 0]
       set InitExit 1
    }

    if {[lsearch -exact $colNames LowerLimit] == -1} {
        bell
        set nLower -25.0
       for {set i 1} {$i < $PVCount} {incr i} {
       lappend nLower -25.0
       }
    } else {
      set nLower [APSGetSDDSColumn -fileName $filename -column "LowerLimit" -page 0]
    }

    if {[lsearch -exact $colNames UpperLimit] ==-1} {
       set nUpper 25.0
       for {set i 1} {$i < $PVCount} {incr i} {
       lappend nUpper 25.0
       }
    } else {
       set nUpper [APSGetSDDSColumn -fileName $filename -column "UpperLimit" -page 0]
    }

    if {[lsearch -exact $colNames InitialChange] == -1} {
       set nInitC 0.2
       for {set i 1} {$i < $PVCount} {incr i} {
       lappend nInitC 0.2
       }
    } else {
      set nInitC [APSGetSDDSColumn -fileName $filename -column "InitialChange" -page 0]
    }
    ClearVariableSettings $pvScroll 0
    set i 0
    foreach name $names {
        set init [lindex $nInit $i]
        if [string length $init] {
            set init [format %.4f $init]
        }
       MakeNewVariableLine $pvScroll -pvName $name \
         -lowerLimit [format %.4f [lindex $nLower $i]] \
         -upperLimit [format %.4f [lindex $nUpper $i]]  \
         -initialValue $init \
         -initialChange [format %.4f [expr [lindex $nInitC $i]]] \
             -gain 1
       incr i
    }
   # if $startFromPresent {
   #     GetPVValues -read 1
   # }
 #   SetMainStatus "PV data loaded from $filename."
}

set VariableLines 1
proc SaveVariableData {args} {
    global VariableLines VarPVname NumberToAverage PauseBetweenReadings Iterations InitExist
    global Mode Target Tolerance OutputOrbitFile OutputFile tmpFile OutTmp ChangePause
    global InitialValue LowerLimit UpperLimit InitialChange OutputVarFile InitExist startFromPresent
    set PVcount 0 
    for {set i 1} {$i<$VariableLines} {incr i} {
        if [string length $VarPVname($i)]!=0 {
            incr PVcount
        }
    }

    if {$PVcount == 0} {
        SetMainStatus "SaveVariableData: No PV variables specified for saving."
        return 0
    }
    set filename ""
    APSParseArguments {filename}
    if [string length $filename] {
        if [file exist $filename] {
            if ![APSMultipleChoice [APSUniqueName .] -question "$filename exists. \
               Overwrite it?" -labelList {Yes No} -returnList {1 0}] {
               return 0
            }
        }
    }
    while {![string length $filename]} {
       set filename [APSInfoDialog [APSUniqueName .] -name FileDialog \
                     -width 60 \
                     -infoMessage "Supply the name of a file to which to save \
                      the configureation data." ]
       set filename [string trim $filename]
       if ![string length $filename] {
            return -code error "No filename given."
        }
        if {[file exists $filename] && \
             ![APSMultipleChoice [APSUniqueName .] -question "$filename exists. \
               Overwrite it?" -labelList {Yes No} -returnList {1 0}]} {
            set filename ""
        }
    }
    set fid [open $filename w]
    puts $fid "SDDS1"
    puts $fid "&parameter name=PauseAfterChange type=double &end"
    puts $fid "&column name=ControlName type=string &end"
    if {$InitExist} {
        puts $fid "&column name=InitialValue type=double &end" }
    puts $fid "&column name=LowerLimit type=double &end"
    puts $fid "&column name=UpperLimit type=double &end"
    puts $fid "&column name=InitialChange type=double &end"
    puts $fid "&data mode=ascii no_row_counts=1 &end"

    puts $fid "$ChangePause"
    for {set i 1} {$i<$VariableLines} {incr i} {
        if [string length $VarPVname($i)]==0 continue 
        if {$InitExist} {
            if {$InitialValue($i) !="" } {
                puts $fid "$VarPVname($i) $InitialValue($i) $LowerLimit($i) \
             $UpperLimit($i) $InitialChange($i)" 
            } else {
                bell
                SetMainStatus "Please give the initial value of $VarPVname($i)"
                return
            }
        } else {
            puts $fid "$VarPVname($i) $LowerLimit($i) \
             $UpperLimit($i) $InitialChange($i)"
        }
    }
    close $fid
    set OutputVarFile $filename
    return 1
}

proc MakeNewVariableLine {widget0 args} {
    global pvScrollFrame 
    global VariableLines VarPVname startFromPresent 
    global LowerLimit UpperLimit InitialChange InitialValue InitialSettings Gain
   
    APSFrame .m$VariableLines -parent $widget0 -packOption "-anchor w -fill x"
    set widget $widget0.m$VariableLines.frame
    $widget configure -relief flat -bd 0
    APSFrame .op  -parent $widget -packOption "-side left" 
    $widget.op.frame configure -relief flat -bd 0
    APSFrame .data  -parent $widget -height 1
    $widget.data.frame configure -relief flat -bd 0

    if {$VariableLines==1} {
        set pvName ""
        set lowerLimit -25
        set upperLimit 25
        set initialChange 0.2
        set initialValue 0.0
        set gain 1
    } else {
        set lastVar [expr $VariableLines - 1]
        set pvName $VarPVname($lastVar)
        set lowerLimit $LowerLimit($lastVar)
        set upperLimit $UpperLimit($lastVar)
            set initialChange $InitialChange($lastVar)
        set initialValue $InitialValue($lastVar)
        set gain $Gain($lastVar)
    }        
    APSParseArguments {pvName lowerLimit upperLimit initialChange initialValue gain}

    APSButton .delete -parent $widget.op.frame -text "DELETE" \
      -command "DeletePVLine $widget0 $VariableLines" \
      -contextHelp "Press to delete the corresponding PV name entry line." 
    $widget.op.frame.delete configure -bd 0
    $widget.op.frame.delete.button configure -font -adobe-courier-medium-r-normal-*-12-*-*-*-*-*-*-*

    APSButton .clear -parent $widget.op.frame -text "CLEAR" \
      -command "ClearPVLine $widget0 $VariableLines" \
      -contextHelp "Press to clear the corresponding PV name entry line." 
    $widget.op.frame.clear configure -bd 0
    $widget.op.frame.clear.button configure -font -adobe-courier-medium-r-normal-*-12-*-*-*-*-*-*-*
    
    set VarPVname($VariableLines) $pvName
    APSLabeledEntry .x -parent $widget.data.frame -label "PV:" -textVariable \
      VarPVname($VariableLines) -width 20 \
      -contextHelp "Enter the name of a variable process variable (PV) in this field." \
      -packOption "-side left"
    $widget.data.frame.x configure -bd 0
    set LowerLimit($VariableLines) $lowerLimit
    APSLabeledEntry .lower -parent $widget.data.frame -label "lower:" -textVariable \
      LowerLimit($VariableLines) -width 8\
      -contextHelp "Enter the lower limit for the variable process variable (PV)
       in this field." -packOption "-side left"
    $widget.data.frame.lower configure -bd 0
    set UpperLimit($VariableLines) $upperLimit
    APSLabeledEntry .upper -parent $widget.data.frame -label "upper:" -textVariable \
      UpperLimit($VariableLines) -width 8 \
      -contextHelp "Enter the upper limit for the variable process variable (PV)
       in this field." -packOption "-side left"
    $widget.data.frame.upper configure -bd 0
    set InitialChange($VariableLines) $initialChange
    APSLabeledEntry .initchange -parent $widget.data.frame -label "change:" \
      -textVariable InitialChange($VariableLines) -width 7 \
      -contextHelp "Enter the change for the variable process variable (PV)
       in this field." -packOption "-side left"   
    $widget.data.frame.initchange configure -bd 0
     set InitialValue($VariableLines) $initialValue
    APSLabeledEntry .initval -parent $widget.data.frame -label "initial:" \
      -textVariable InitialValue($VariableLines) -width 8 \
      -contextHelp "Enter the initial value for the variable process variable (PV)
       in this field." -packOption "-side left"
    $widget.data.frame.initval configure -bd 0
    set Gain($VariableLines) $gain
    APSLabeledEntry .gain -parent $widget.data.frame -label "gain:" \
      -textVariable Gain($VariableLines) -width 6 \
      -contextHelp "Enter the gain value for the variable process variable (PV)
       in this field." -packOption "-side left"
    $widget.data.frame.gain configure -bd 0
    incr VariableLines
    .userFrame.main.frame.tn select 0
    tkwait visibility $widget.data.frame.initval
    APSScrollAdjust $pvScrollFrame -numVisible 5
}


proc DeletePVLine {widget0 number} {
    global VariableLines VarPVname tclVarList pvList 
    global pvScrollFrame
    global LowerLimit UpperLimit InitialValue InitialChange
    if {$number} {
       destroy $widget0.m$number
       set VarPVname($number) ""
       set tclVarList {}
       set pvList {}
    APSScrollAdjust $pvScrollFrame -scrollIncrement 35
    } else {
        bell
    }
}

proc ClearPVLine {widget0 number} {
    global VariableLines VarPVname Gain
    global LowerLimit UpperLimit InitialChange InitialValue

    set VarPVname($number) ""
    set LowerLimit($number) 0
    set UpperLimit($number) 0
    set InitialChange($number) 0
    set InitialValue($number) 0
    set Gain($number) 1
}

proc ClearVariableSettings {widget0 {popUp 1}} {
    global VariableLines VarPVname InitialValue LowerLimit UpperLimit InitialChange
    global pvScrollFrame
    if {$popUp} {
	if {![APSYesNoPopUp "Really? Clear variable settings?"]} { return }
    }
    for {set i $VariableLines} {$i>0} {incr i -1} {
        if {[winfo exists $widget0.m$i]} { destroy $widget0.m$i}
        set VarPVname($i) ""
        set InitialValue($i) 0
        set LowerLimit($i) 0
        set UpperLimit($i) 0
        set InitialChang($i) 0
    }
    set VariableLines 1
    APSScrollAdjust $pvScrollFrame -scrollIncrement 30
}

set Limit 3
proc CreatTestWidget {parent} {
  global testScroll testScrollFrame Limit
  
  APSFrame .testW -name "TEST Variables" -parent $parent -packOption "-side top -fill x"
  set w1 $parent.testW.frame
  set testScroll [APSScroll .mvScroll -parent $w1]
  set testScrollFrame $w1.mvScroll
  APSFrame .lim -parent $parent -packOption "-side top -fill x"
  set ww $parent.lim.frame
  $ww configure -relief flat -bd 0
  APSLabeledEntry .limit -parent $ww  -packOption "-side left" -textVariable Limit \
    -label "limited fail times:" -width 8 -contextHelp "This field specifies the 
     the maximum times for each failed test"
  APSFrame .but -parent $parent -packOption "-side top -fill x"
  set w2 $parent.but.frame
  $w2 configure -relief flat -bd 0
  APSButton .add -parent $w2 -text "ADD" -packOption "-side left" \
   -command "MakeNewTestLine $testScroll" -contextHelp "Press to add another TEST
   entry line."
  APSButton .load -parent $w2 -text "Load tests from file" \
    -command LoadTestData
  APSButton .save -parent $w2 -text "SAVE tests to file" \
    -command "SaveTestData"
  APSButton .clear -parent $w2 -text "Clear tests..." \
    -command "ClearTestSettings $testScroll"
  
}

set TestLines 1
proc MakeNewTestLine {widget0 args} {
    global testScrollFrame 
    global TestLines TestPVname SleepTime
    global Minimum Maximum 
   
    APSFrame .m$TestLines -parent $widget0 -packOption "-anchor w -fill x"
    set widget $widget0.m$TestLines.frame
    $widget configure -relief flat -bd 0
    APSFrame .op  -parent $widget -packOption "-side left" 
    $widget.op.frame configure -relief flat -bd 0
    APSFrame .data  -parent $widget -height 1
    $widget.data.frame configure -relief flat -bd 0

    if {$TestLines==1} {
        set testName ""
        set minimum -2
        set maximum 2
        set sleeptime ""
    } else {
        set lastVar [expr $TestLines - 1]
        set testName $TestPVname($lastVar)
        set minimum $Minimum($lastVar)
        set maximum $Maximum($lastVar)
        set sleeptime $SleepTime($lastVar)
    }        
    APSParseArguments {testName minimum maximum sleeptime}

    APSButton .delete -parent $widget.op.frame -text "DELETE" \
      -command "DeleteTestLine $widget0 $TestLines" \
      -contextHelp "Press to delete the corresponding TEST name entry line." 
    $widget.op.frame.delete configure -bd 0
    $widget.op.frame.delete.button configure -font -adobe-courier-medium-r-normal-*-12-*-*-*-*-*-*-*

    APSButton .clear -parent $widget.op.frame -text "CLEAR" \
      -command "ClearTestLine $widget0 $TestLines" \
      -contextHelp "Press to clear the corresponding TEST name entry line." 
    $widget.op.frame.clear configure -bd 0
    $widget.op.frame.clear.button configure -font -adobe-courier-medium-r-normal-*-12-*-*-*-*-*-*-*
    
    set TestPVname($TestLines) $testName
    APSLabeledEntry .x -parent $widget.data.frame -label "TestPV:" -textVariable \
      TestPVname($TestLines) -width 20 \
      -contextHelp "Enter the name of a test PV in this field." \
      -packOption "-side left"
    $widget.data.frame.x configure -bd 0
    set Minimum($TestLines) $minimum
    APSLabeledEntry .lower -parent $widget.data.frame -label "minimum:" -textVariable \
      Minimum($TestLines) -width 8\
      -contextHelp "Enter minimum value for the test process variable
       in this field." -packOption "-side left"
    $widget.data.frame.lower configure -bd 0

    set Maximum($TestLines) $maximum
    APSLabeledEntry .upper -parent $widget.data.frame -label "maximum" -textVariable \
      Maximum($TestLines) -width 8 \
      -contextHelp "Enter the maximum value for the test process variable 
       in this field." -packOption "-side left"
    $widget.data.frame.upper configure -bd 0
    set SleepTime($TestLines) $sleeptime
    APSLabeledEntry .sleep -parent $widget.data.frame -label "sleeptime:" \
      -textVariable SleepTime($TestLines) -width 8 \
      -contextHelp "Enter the sleeping time for the test process variable
       in this field if test fails." -packOption "-side left"
    $widget.data.frame.sleep configure -bd 0
    incr TestLines

    .userFrame.main.frame.tn select 2
    tkwait visibility $widget.data.frame.sleep
    APSScrollAdjust $testScrollFrame -numVisible 5
}

proc DeleteTestLine {widget0 number} {
    global TestLines TestPVname 
    global testScrollFrame
    global Maximum Minimum SleepTime
    if {$number} {
       destroy $widget0.m$number
       set TestPVname($number) ""
    APSScrollAdjust $testScrollFrame -scrollIncrement 35
    } else {
        bell
    }
}
proc ClearTestLine {widget0 number} {
    global TestLines TestPVname
    global Maximum Minimum SleepTime
    if {$number} {
       set TestPVname($number) ""
       set Maximum($number) ""
       set Minimum($number) ""
       set SleepTime($number) ""
    } else {
        bell
    }
}
proc ClearTestSettings {widget0 {popUp 1}} {
    global TestLines TestPVname
    global Maximum Minimum SleepTime
    global testScrollFrame
    if {$popUp} {
	if {![APSYesNoPopUp "Really? Clear Measurement settings?"]} { return }
    }
    for {set i $TestLines} {$i>0} {incr i -1} {
        if {[winfo exists $widget0.m$i]} { destroy $widget0.m$i}
        set TestPVName($i) ""
        set Maximum($i) ""
        set Minimum($i) ""
        set SleepTime($i) ""
    }
    set TestLines 1
    APSScrollAdjust $testScrollFrame -scrollIncrement 35
}

set SleepExist 0
proc LoadTestData {args} {
    global env testScroll 
    global TestLines SleepExist homeDir testDir home
    if {![string compare $testDir $home]} {
        if [string compare $homeDir $home] {
            set testDir $homeDir
        } 
    }
    set filename ""
    APSParseArguments {filename}
    if ![string length $filename] {
        set filename [APSFileSelectDialog .chooseInputFile -listDir $testDir]
    }
    set filename [string trim $filename]
    if [string length $filename] {
        set testDir [file dirname $filename]
        set homeDir $testDir
    }

    if {![APSCheckSDDSFile -fileName $filename]} {
        SetMainStatus "$filename is not an SDDS file."
        bell
        return
    }
    set colNames [APSGetSDDSNames -fileName $filename -class column]
    if {[llength $colNames]<1} {
        SetMainStatus "$filename doesn't contain any data columns from which
          to get PV names."
        bell
        return 
    }
    if {[lsearch -exact $colNames "ControlName"]!=-1} {
        set columnName ControlName
    } else {
        SetMainStatus "$filename doesn't contain controlPV data column."
        bell
        return
    }
    set names [APSGetSDDSColumn -fileName $filename -column $columnName -page 0]
    if {[llength $names]==0} {
        SetMainStatus "$filename has no process variable names."
        bell
        return
    }
    
    set nSleep {}
    set PVCount [llength $names]
    if {[lsearch -exact $colNames SleepTime] !=-1} {
       set nSleep [APSGetSDDSColumn -fileName $filename -column "SleepTime" -page 0]
       set SleepExist 1
    }

    if {[lsearch -exact $colNames MinimumValue] == -1} {
        bell
        set MainStatus "The test file should contain \"MinimumValue\" column";
        return
    } else {
      set nLower [APSGetSDDSColumn -fileName $filename -column "MinimumValue" -page 0]
    }

    if {[lsearch -exact $colNames MaximumValue] ==-1} {
       SetMainStatus "The test file should contain MaximumValue column."
       bell
       return
    } else {
       set nUpper [APSGetSDDSColumn -fileName $filename -column "MaximumValue" -page 0]
    }

    if {[lsearch -exact $colNames SleepTime] == -1} {
       set SleepExist 0
    } else {
      set nSleep [APSGetSDDSColumn -fileName $filename -column "SleepTime" -page 0]
      set SleepExist 1
    }
    ClearTestSettings $testScroll 0
    set i 0
    foreach name $names {
       if {$SleepExist} {
         MakeNewTestLine $testScroll -testName $name \
           -minimum [format %.4f [lindex $nLower $i]] \
           -maximum [format %.4f [lindex $nUpper $i]]  \
           -sleeptime [format %.3f [lindex $nSleep $i]]
       } else {
         MakeNewTestLine $testScroll -testName $name \
           -minimum [format %.4f [lindex $nLower $i]] \
           -maximum [format %.4f [lindex $nUpper $i]] 
       }
       incr i
    }
#    SetMainStatus "Test data loaded from $filename."
}

proc SaveTestData {args} {
    global TestLines TestPVname  OutputTestFile 
    global SleepTime Minimum Maximum SleepExist
    set PVcount 0 
    for {set i 1} {$i<$TestLines} {incr i} {
        if [string length $TestPVname($i)]!=0 {
            incr PVcount
        }
    }

    if {$PVcount == 0} {
        SetMainStatus "SaveTestData: No test variables specified for saving."
        return 0
    }
    set filename ""
    APSParseArguments {filename}
    if [string length $filename] {
        if [file exist $filename] {
            if ![APSMultipleChoice [APSUniqueName .] -question "$filename exists. \
               Overwrite it?" -labelList {Yes No} -returnList {1 0}] {
               return 0
            }
        }
    }
    while {![string length $filename]} {
       set filename [APSInfoDialog [APSUniqueName .] -name FileDialog \
                     -width 60 \
                     -infoMessage "Supply the name of a file to which to save \
                      the configureation data." ]
       set filename [string trim $filename]
       if ![string length $filename] {
            return -code error "No filename given."
        }
        if {[file exists $filename] && \
             ![APSMultipleChoice [APSUniqueName .] -question "$filename exists. \
               Overwrite it?" -labelList {Yes No} -returnList {1 0}]} {
            set filename ""
        }
    }
    for {set i 1} {$i<$TestLines} {incr i} {
      if [string length $TestPVname($i)] {  
        if {$SleepTime($i)!=""} {
           set SleepExist 1
        } else {
           bell
           SetMainStatus "found a test PV whose sleeptime is not given, the saved file will not contain SleepTime column"
           set SleepExist 0
        } 
        break 
      } 
    }
    set fid [open $filename w]
    puts $fid "SDDS1"
    puts $fid "&column name=ControlName type=string &end"
    if {$SleepExist} {
       puts $fid "&column name=SleepTime type=double &end" }
    puts $fid "&column name=MinimumValue type=double &end"
    puts $fid "&column name=MaximumValue type=double &end"
    puts $fid "&data mode=ascii no_row_counts=1 &end"

    for {set i 1} {$i<$TestLines} {incr i} {
        if [string length $TestPVname($i)]==0 continue  
        if {$SleepExist} {
           if {$SleepTime($i) !="" } {
             puts $fid "$TestPVname($i) $SleepTime($i) $Minimum($i) $Maximum($i)" 
           } else {
               bell
               SetMainStatus "Please give the sleep time of $TestPVname($i) as others"
               return -code error "The sleep time of $TestPVname($i) is not given"
           }
        } else {
           puts $fid "$TestPVname($i) $Minimum($i) $Maximum($i)"
        }
    }
    close $fid
    set OutputTestFile $filename
    return 1
}

set ControlPV ""
set ControlPVPar ""
set ControlDes ""
set ControlDesPar ""
set PingTimeout 30
set PingInterval 2

proc CreatControlWidget {parent} {
   global ControlPV ControlPVPar ControlDes ControlDesPar PingTimeout PingInterval
 
   APSFrame .conW -name "runControlPV" -parent $parent 
   set w $parent.conW.frame
  $w configure -relief flat -bd 0
   APSLabeledEntry .name -parent $w -label \
         "Run Control PV:" -textVariable ControlPV -width 40 -contextHelp "Enter the name \
          of run Control PV in this field. " 
  
   APSLabeledEntry .des -parent $w -label \
         "Run Control Description:" -textVariable ControlDes -width 40 \
         -contextHelp "Enter the name of runControlDecription in this field." 
 
   APSLabeledEntry .out -parent $w -label \
         "pingTimeout (seconds):" -textVariable PingTimeout -width 8 -contextHelp "Enter the ping \
          time out for the runControlPV in this field." 
   APSLabeledEntry .int -parent $w -label \
         "pingInterval (seconds):" -textVariable PingInterval -width 8 -contextHelp "Enter the ping
          interval for the runControlPV in this field." 
  
}

set logFile ""
set LogDir ""
set Suffix 0
proc CreatLogFileWidget {parent} {
   global logFile LogDir Suffix
   APSFrame .conW -name "logFile" -parent $parent 
   set w $parent.conW.frame
  $w configure -relief flat -bd 0
   APSLabeledEntry .dir -parent $w -label \
         "LogFile directory:" -textVariable LogDir -width 70 -contextHelp "Enter the directory\
          of log file to review or to save (the filename will be generated by APSTmpString).
          if you leave this entry empty, the log file is created under /tmp, and will be deleted
          when program exits"  
  APSFrame .but -parent $parent
  set w1 $parent.but.frame
  APSRadioButtonFrame .suffix -parent $w1 -label "suffix" -packOption "-side left" \
    -variable Suffix -buttonList {SimplexAnd1DScan All} -valueList {0 1} \
    -orientation horizontal \
    -contextHelp "Please select the suffix of the log file that will be displayed,\
      SimplexAnd1DScan represents those log files created by optimize, all \
      represents selectiong all the files under the above given directory"
    APSButton .view -parent $w1 -text "Review and Plot Log File ..." -command "PlotLogFile"
}

proc PlotLogFile {} {
    global LogDir Suffix FileSelection
    if {$LogDir==""} {
        SetMainStatus "Please enter the directory of the log file you wish to review!"
        bell
        return
    }
    set files ""
    if !$Suffix {
        if [catch {set files [glob $LogDir/*.Simplex*]} result] {
            SetMainStatus "$result"
        }
        if [catch {set files1 [glob $LogDir/*.1DScan]} result] {
            SetMainStatus "$result"
        }
    } else {
        if [catch {set files [glob $LogDir/*]} result] {
            SetMainStatus "$result"
            return
        }
    }
    if ![string length $files] {
        SetMainStatus "No such files contained in $LogDir directory!"
        return
    }
    set FileSelection ""
    APSScrolledListWindow .choose -name "Log Data file Selection" \
      -label "Select a log file" \
      -itemList $files -selectionVar FileSelection
    tkwait variable FileSelection
    if ![string length $FileSelection] {
        SetMainStatus "No files chosen!"
        return
    }
    set colNames [APSGetSDDSNames -fileName $FileSelection -class column]
    if {[lsearch -exact $colNames currentValue]==-1 || \
          [lsearch -exact $colNames EvalIndex]==-1} {
        SetMainStatus "$FileSelection does not contain EvalIndex and currentValue columns, 
                     can not be plotted"
        return
    }
    #the columns of the log File are placed as: currentValue, EvalIndex, ....(defined in sddsoptimize.c)
    #here we pick up the third one to the end
    set variables [lrange $colNames 2 end]
    lappend options -legend
    lappend options -col=EvalIndex,([join $variables ,]) -graph=sym,conn=sub,vary=sub,sca=3 -sep=nameindex
    lappend options -col=EvalIndex,currentValue -graph=sym,conn=sub,sub=1,sca=3 -omni -yscale=id=value
    eval exec sddsplot $FileSelection $options &
}

proc ChangeButtonState {state} {
    global continueButtonWidget
    if $state {
        APSDisableButton $continueButtonWidget
    } else {
        APSEnableButton $continueButtonWidget
    }
}

proc RunOptimizer {} {
    global Iterations doVarScript
    global VarPVname VarMeasurementName MeasurementLines VariableLines VarScript
    global MeasScript doMeasScript Method KnobFiles InitExist Tolerance InitialValue
    global startFromPresent Target Divisions Repeats Verbose Maximize Repeat
    global mav NumberToAverage PauseBetweenReadings ChangePause Step 
    global TestPVname Maximum Minimum TestLines SleepTime tmpFile
    global Control Limit logFile options LogDir
    global ControlPV ControlPVPar ControlDes ControlDesPar PingTimeout PingInterval RCDS
    # make a PV list for later checking, sorting and finding duplicates
    set PVlist {}
    set count 0
    #check for the measurement variables if measFile is checked
    set tmpRoot /tmp/[APSTmpString]
    set optOptions ""
    if {!$doMeasScript} {
       for {set i 1} {$i<$MeasurementLines} {incr i} {
          if {[string length $VarMeasurementName($i)]} {
              if {[string first " " $VarMeasurementName($i)]!=-1} {
                 SetMainStatus "Space found in PV name:$MeasPVname($i)"
                 bell
                 return
              }
    
            set PVlist [linsert $PVlist 0 $VarMeasurementName($i)]
            incr count
          }
      }
      if !$count {
         SetMainStatus "No measurement variable is given!"
         bell
         return
      }
   }
    #check for variable PVs
    set variables ""
    set count 0
    for {set i 1} {$i<$VariableLines} {incr i} {
        if {[string length $VarPVname($i)]} {
            if {[string first " " $VarPVname($i)]!=-1} {
                SetMainStatus "Space found in PV name:$VarPVname($i)"
                bell
                return
            }
            lappend variables $VarPVname($i)  
            set PVlist [linsert $PVlist 0 $VarPVname($i)]
            incr count
        }
    }
    if {!$count} {
        SetMainStatus "No variable PVs given."
        bell
        return
    }
  
    #check for duplicate PVs
    set FoundDuplicate 0
    set PVlist [lsort -ascii $PVlist]
    for {set i 1; set j 0} {$i<[llength $PVlist]} {incr i; incr j} {
        if {![string compare [set PV [lindex $PVlist $j]] [lindex $PVlist $i]] } { 
            APSInfoWindow .info -name "Duplicate PV $PV" \
              -infoMessage "Found two PV of the same name. Check both lists of measurement \n\
                            and variable PVs.\n Optimizer not started." 
            set FoundDuplicate 1
            return
        }
    }
    if {$FoundDuplicate} { return}
    
    set other ""
    if $Maximize {
        lappend optOptions "-maximize"
    }
    if $Verbose {
        lappend optOptions "-verbose"
    }
    set deleteLog 0
    if {$LogDir==""} {
       set logFile $tmpRoot
       set deleteLog 1
    } else {
       set logFile $LogDir/[APSTmpString]
    }
    
    if {[string length $ControlPV] && [string length $ControlDes]} {
        lappend optOptions "-runControlPV=string=$ControlPV,pingTimeout=$PingTimeout"
        lappend optOptions "-runControlDesc=string=\"[APSMakeSafeQualifierString $ControlDes]\""
    }
    
    if {$Method=="squishPVs"} {
        if {![saveSquishData $tmpRoot.squish]} {
            bell
            return
        }
        if {$mav} {
            set criterion ""
        } else {
            set criterion "-criterion=rms"
        }
        APSExecLog .jon -width 80 -unixCommand "squishPVs $tmpRoot.squish \
            -averages=$NumberToAverage,$PauseBetweenReadings -stepsize=$Step \
            -repeat=number=$Repeats -settlingTime=$ChangePause $other $criterion \
            $controlpv \"$controldesc\"" -closeInput 0
    } else { 
        #run sddsoptimize
        #if the "force" button is checked, then force the initial value to be the current value
        if {$startFromPresent} { 
            if $doVarScript {
                set InitExist 1
            } else {
                set InitExist 0
            }
            GetPVValues -read 1
        } else {
            set InitExist 1
            #check whether the initial value of PV is given
            for {set i 1} {$i<$VariableLines} {incr i} {
                if [string length $VarPVname($i)]==0 continue      
                if {$InitialValue($i) =="" } {
                    bell
                    SetMainStatus "Please give the initial value of $VarPVname($i)"
                    return
                }
            }
        }
        # SetMainStatus "testlines: $TestLines"
        if {$TestLines>1} {
            set tmpTest $tmpRoot.test
            if [catch {SaveTestData -filename $tmpTest} result] {
                SetMainStatus "Error saving tests file: $result"
                return
            } else {
                lappend optOptions "-testValues=file=$tmpTest,limit=$Limit"
            }
        }
        if {![SaveVariableData -filename $tmpRoot.var]} {
	    bell
            return
        }
        lappend optOptions "-varFile=$tmpRoot.var"
        set varScript ""
        if $doVarScript {
            if ![string length $VarScript] {
                APSInfoWindow .info -name "script non-exist" \
                  -infoMessage "the variable script is not given"  
                return 
            }
            if ![file exist [lindex [split $VarScript]] 0] {
                APSInfoWindow .info -name "script non-exist" \
                  -infoMessage "the variable script $VarScript does not exist"  
                return 
            }
         #   lappend optOptions \\"-varScript=$VarScript\\"
            set varScript \"-varScript=$VarScript\"
        }
        set measScript ""
        if $doMeasScript {
            if ![string length $MeasScript] {
                APSInfoWindow .info -name "script non-exist" \
                  -infoMessage "the measurement script is not given" 
                return
            }
            if ![file exist [lindex [split $MeasScript] 0]] {
                APSInfoWindow .info -name "script non-exist" \
                  -infoMessage "the measurement script $MeasScript does not exist" 
                return
            }
           # lappend optOptions \\"-measScript=$MeasScript\\"
            set measScript \"-measScript=$MeasScript\"
            lappend optOptions "-tolerance=$Tolerance"
        } else {
            if ![SaveMeasureData -filename $tmpRoot.meas] {
                bell
                return
            }
          lappend optOptions "-measFile=$tmpRoot.meas"
        }
        if {$Method=="Simplex"} {
            lappend optOptions "-simplex=restarts=1,cycles=$Repeats,evaluations=$Iterations,no1dscan"
            set logFile "${logFile}.SimplexNo1D"
        } elseif {$Method=="1D_Simplex"} {
            lappend optOptions "-simplex=restarts=1,cycles=$Repeats,evaluations=$Iterations"
            set logFile "${logFile}.SimplexWith1D"
        } elseif {$Method=="RCDS"} {
            lappend optOptions "-rcds=evaluations=$RCDS(evals),cycles=$RCDS(cycles),noise=$RCDS(noise),step=$RCDS(stepSize)"
            
        } else {
            if {$Repeat} { 
                lappend optOptions "-1dscan=divisions=$Divisions,cycles=$Repeats,evaluations=$Iterations,refresh" 
            } else {
                lappend optOptions "-1dscan=divisions=$Divisions,cycles=$Repeats,evaluations=$Iterations"
            }
            set logFile "${logFile}.1DScan"
        }
        lappend optOptions "-logFile=$logFile"
        if {$KnobFiles !=""} {
            lappend optOptions "-knobFiles=$KnobFiles" 
        }
        APSExecLog .jon -width 80 -closeInput 0 \
          -unixCommand "sddsoptimize $optOptions $varScript $measScript"
        set options -legend 
        lappend options -col=EvalIndex,([join $variables ,]) -graph=sym,conn=sub,vary=sub,sca=3 -sep=nameindex
        lappend options -col=EvalIndex,currentValue -graph=sym,conn=sub,sub=1,sca=3 -omni -yscale=id=value
        #set p1 .[APSUniqueName plot1]
        if [winfo exist .jon.buttonRow.plot] {
            destroy .jon.buttonRow.plot
        }
        APSDialogBoxAddButton .plot -parent .jon \
          -text "Plot Log File... " -command {eval exec sddsplot  -repeat \"-device=motif,-movie true -keep 1\" $logFile $options &}
    }
    set fileList [glob ${tmpRoot}*]
    APSAddToTmpFileList -ID 1 -fileList $fileList
    ChangeButtonState 0
}

proc GetPVValues {args} {
    global VariableLines VarPVname InitialValue
    set read 1
    APSParseArguments {read}
    if !$read {
        return
    }
    for {set i 1} {$i<$VariableLines} {incr i} {
        if ![string length $VarPVname($i)] continue  
        if [catch {APScavget -list=$VarPVname($i) -pend=30} InitialValue($i)] {
            SetMainStatus "Can not get value of $VarPVname($i)"
            return
        }
    }
}
proc saveSquishData {filename} {
    global Gain mav LowerLimit UpperLimit VariableLines VarPVname InitialChange
    global MeasurementLines VarMeasurementName VarOffsetPVName OffsetValue ReadbackUnits
    global Step Weight 

    #get the number of measurement PVs
    set MVcount 0 
    for {set i 1} {$i<$MeasurementLines} {incr i} {
        if [string length $VarMeasurementName($i)]!=0 {
            incr MVcount
        }
    }
    #get the number of corrector PVs (i.e. variable PVs)
    set PVcount 0
    for {set i 1} {$i<$VariableLines} {incr i} {
        if [string length $VarPVname($i)]!=0 {
            incr PVcount
            set Step $InitialChange($i)
        }
    }
    if {$PVcount == 0 || $MVcount==0} {
        SetMainStatus "No PV variables or measurements specified--can't save."
        return 0
    }
    #get the number of offset pvs, if 0, do not save it
    set Offset 0
    for {set i 1} {$i<$MeasurementLines} {incr i} {
        if {[string length $VarOffsetPVName($i)]!=0 && $OffsetValue($i)!=0} {
            incr Offset
        }
    }
    set fid [open $filename w]
    puts $fid "SDDS1"
    puts $fid "&parameter name=CorrectorPV type=string &end"
    puts $fid "&parameter name=Gain type=double &end"
    puts $fid "&parameter name=LowerLimit type=double &end"
    puts $fid "&parameter name=UpperLimit type=double &end"
    puts $fid "&column name=BpmPV type=string &end"
    if {$Offset} {
       puts $fid "&column name=OffsetPV type=string &end"
       puts $fid "&column name=OffsetValue type=double &end"
    }
    puts $fid "&column name=Weight type=double &end"
    puts $fid "&data mode=ascii no_row_counts=1 &end"
    for {set i 1} {$i<$VariableLines} {incr i} {
        #write to each page
        if [string length $VarPVname($i)]==0 continue
        puts $fid "$VarPVname($i)"
        puts $fid "$Gain($i)"
        puts $fid "$LowerLimit($i)"
        puts $fid "$UpperLimit($i)"
        for {set j 1} {$j<$MeasurementLines} {incr j} {
           if [string length $VarMeasurementName($j)]==0 continue
           if {$Offset} {
              puts $fid "\"$VarMeasurementName($j)\" \"$OffsetPVName($j)\"  \"$OffsetValue($j)\" \"$Weight($j)\""
           } else {
              puts $fid "\"$VarMeasurementName($j)\" \"$Weight($j)\""
           }
        }
        puts $fid " "
   }
   close $fid
   return 1
}


APSScrolledStatus .status -parent .userFrame -textVariable mainStatus \
  -width 110 -height 5
set sectionList [list Variables Measurements "Test Values" "Run Control" "Log File" "Parameters"]

set tabFrameWidgetList [APSTabFrame .main -parent .userFrame -label "" \
    -labelList $sectionList -width 1050 -height 500 -packOption "-expand true"]

CreatVariableWidget [lindex $tabFrameWidgetList 0]
CreatMeasurementWidget [lindex $tabFrameWidgetList 1]
CreatTestWidget [lindex $tabFrameWidgetList 2]
CreatControlWidget [lindex $tabFrameWidgetList 3]
CreatLogFileWidget [lindex $tabFrameWidgetList 4]
CreateParametersWidget [lindex $tabFrameWidgetList 5]

#set home $env(HOME)
set home [pwd]
set measDir $home
set varDir $home
set homeDir $home
set testDir $home
set readDir $home
set saveDir $home
set Iterations 50
set NumberToAverage 5
set PauseBetweenReadings 0.5
set Target 0.0
set Tolerance 0.01
set ChangePause 1
set Divisions 12
set Repeats 1
set VarScript ""
proc ChooseScriptFile {args} {
    global scriptDir MeasScript VarScript
    APSParseArguments {type}
    set script [APSFileSelectDialog .chooseInputFile -listDir $scriptDir]
    set scriptDir [file dirname $script]
    switch $type {
        Var {
            set VarScript $script
        }
        Meas {
            set MeasScript $script
        }
    }
}
proc ContinueOptimizer {} {
  global startFromPresent
  set startFromPresent 1
  RunOptimizer
}

proc saveAll {} {
    global saveDir readDir home
    if {![string compare $saveDir $home]} {
        set defaultDir $readDir
    }  else {
        set defaultDir $saveDir
    }
    set dir ""
    set dir [APSFileSelectDialog .choosedir -selectDir 1 \
                   -listDir $defaultDir -checkValidity 0]
    
    if ![string length $dir] {
        SetMainStatus "Save Configuration was cancelled."
        return
    }
    set saveDir $dir
    set readDir $saveDir
    if ![file isdirectory $saveDir] {
        SetMainStatus "A new directory $saveDir is being created"
        if [catch {exec mkdir $saveDir} result] {
            SetMainStatus "$result"
            return
        }
   }
   SetMainStatus "saving ....."
   SaveVariableData -filename ${saveDir}/variables
   SaveMeasureData -filename ${saveDir}/measurements
   SaveTestData -filename ${saveDir}/testValues
   SaveParameterData -filename ${saveDir}/logFile -option log
   SaveParameterData -filename ${saveDir}/runControl -option control
   SaveParameterData -filename ${saveDir}/parameters -option parameter
   SetMainStatus "saving done"
}
proc SaveParameterData {args} {
    global LogDir
    
    set filename ""
    set option ""
    set controlList [list ControlPV ControlDes PingTimeout PingInterval]
    set parameterList [list Iterations Tolerance Target NumberToAverage \
        PauseBetweenReadings ChangePause Maximize Method Repeat doVarScript doMeasScript \
        Verbose mav VarScript MeasScript Test Control Limit Divisions Repeats KnobFiles]

    APSParseArguments {filename option}
    if ![string length $option] {
        SetMainStatus "SaveLogFileData: No option is given for saving!"
        bell
        return 0
    }
    if ![string length $filename] {
        SetMainStatus "SaveLogFileData: No file name is given for saving!"
        bell
        return 0
    }
    if {[file exists $filename] && \
       ![APSMultipleChoice [APSUniqueName .] -question "$filename exists.\
         Overwrite it?" -labelList {Yes No} -returnList {1 0}]} {
         SetMainStatus "$filename is not updated!"
         return 0
    }
    set fid [open $filename w]
    puts $fid "SDDS1"
    puts $fid "&column name=TclVariableName type=string &end"
    puts $fid "&column name=TclVariableValue type=string &end"
    puts $fid "&data mode=ascii no_row_counts=1 &end"
    set list ""
    switch $option {
        log {
            puts $fid "LogDir \"$LogDir\""
            close $fid
            return 1
        }
        control {
            set list $controlList
        }
        parameter {
            set list $parameterList
        }
        default {
            SetMainStatus "wrong options!"
            close $fid
            return 0
        }
    }
    foreach name $list {
        global $name
        puts $fid "$name \"[set $name]\""
    }
    close $fid
    return 1
}

proc Read {args} {
    global saveDir readDir home tabFrameWidgetList doMeasScript
    set configuration ""
    APSParseArguments {configuration}
    
    if ![string length $configuration] {
        if {![string compare $readDir $home]} {
            set defaultDir $saveDir
        } else {
            set defaultDir $readDir
        }
        set dir ""
        set dir [APSFileSelectDialog .choosedir -selectDir 1 -listDir $defaultDir]
        if ![string length $dir] {
            SetMainStatus "Load configuration was cancelled."
            return
        }
    } else {
        set dir $configuration
    }
    set readDir $dir
    set saveDir $readDir
    SetMainStatus "reading..."
    #read logFile paramter, controlPV parameter and other parameters
    set files [list ${readDir}/logFile ${readDir}/runControl ${readDir}/parameters]
    foreach file $files {
        if [file exist $file] {
            set variables [APSGetSDDSColumn -fileName $file -column TclVariableName -page 0]
            set values [APSGetSDDSColumn -fileName $file -column TclVariableValue -page 0]
            foreach name $variables value $values {
                global $name
                set $name $value
                puts "$name $value"
            }
        } else {
            SetMainStatus "$file does not exist!"
        }
    }
    if [info exist Method] {
        switch $Method {
            0 {
                set Method Simplex
            }
            1 {
                set Method 1D_Simplex
            }
            2 {
                set Method 1DScan
            }
            3 {
                set Method squishPVs
            }
            4 {
                set Method RCDS
            }
        }
    }
    
    if [info exist doScript] {
        set doMeasScript $doScript
    }
    ResetDoForce
    #load pv variables, measurement and testValues
    if [file exist ${readDir}/variables] {
        LoadVariableData -filename ${readDir}/variables
    } else {
        SetMainStatus "${readDir}/variables does not exist!"
    }
    if [file exist ${readDir}/measurements] {
        LoadMeasureData -filename ${readDir}/measurements
    } else {
        SetMainStatus "${readDir}/measurements does not exist!"
    }
    if [file exist ${readDir}/testValues] {
        LoadTestData -filename ${readDir}/testValues
    } else {
        SetMainStatus "${readDir}/testValues does not exist!"
    }
    SetMainStatus "reading Done"
}


set Method Simplex
set Maximize 1
set Repeat 0
set doMeasScript 0
set doVarScript 0
set Verbose 1
set mav 1
set MeasScript ""
set Test 0
set Control 0
set MeasScript ""
set scriptDir $home

.menu.file.menu insert 1 command -label "Save..." -underline 0 \
      -command saveAll
.menu.file.menu insert 1 command -label "Read..." -underline 0 \
      -command Read

ChangeButtonState 1
if [string length $configuration] {
    Read -configuration $configuration
    if $run {
        RunOptimizer
    }
}
