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

#amoeba interface

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

# set env(EPICS_CA_ADDR_LIST) "164.54.48.148"
APSStandardSetup

set CVSRevisionAuthor "\$Revision: 1.6 $ \$Author: borland $"

APSApplication . -name amoebaInterface -version $CVSRevisionAuthor \
  -overview {This is the quickExperiment utility.  It provides a simple interface 
   to the amoebaOAG program, which allows varying and measuring EPICS data.}
set args $argv

set Measurements 0
set MeasurementLines 1

set Variables 0
set VariableLines 1
set doForce 1

set mainStatus \
 "Note: if the force button is checked, it forces the initial value to equal
        to the current value of PVs reading from simulator
 Press ADD to enter more PV names for parameters and variables
 Press load button to load PV names or Measurement names from a file
       An example for load PVs.. ---> ameobaTest1.sdds,
                for load Measure.. ---> booster1.h"

proc SetMainStatus {text} {
    global mainStatus
    set mainStatus $text
    update
}

APSScrolledStatus .status -parent .userFrame -textVariable mainStatus -width 80 -height 8


APSFrame .parameter1 -parent .userFrame -label "Parameters" -packOption \
  "-side top -fill x"
APSFrame .parameter2 -parent .userFrame -packOption \
  "-side top -fill x"

set Factor 1
set Iterations 5
set NumberToAverage 5
set PauseBetweenReadings 0.5
set Mode "equal"
set Target 0.0
set Tolerance 0.01
set ChangePause 1

set w1 ".userFrame.parameter1"
set w2 ".userFrame.parameter2"
$w1.frame configure -relief flat -bd 0
$w2.frame configure -relief flat -bd 0
APSLabeledEntry .iters -parent $w1.frame -label \
  "Iterations:" -textVariable Iterations -width 6 -contextHelp "Enter the number
  of iterations in this field." -packOption "-side left"
set Target 0
APSLabeledEntry .tol -parent $w1.frame -label \
  "tolerance: " -textVariable Tolerance -width 7 -packOption "-side left" \
  -contextHelp "tolerance is the converging limit"
APSLabeledEntry .tar -parent $w1.frame -label \
  "target: " -textVariable Target -width 7 -packOption "-side left"
APSLabeledEntry .average -parent $w1.frame -label \
  "Average:" -textVariable NumberToAverage -width 6 -contextHelp "Enter the
  number of average in this field." -packOption "-side left"
APSLabeledEntry .pause -parent $w1.frame -label \
  "Interval(s):" -textVariable PauseBetweenReadings -width 5 -contextHelp \
  "Enter the pause time between readings in this field." -packOption "-side left"
APSLabeledEntry .post -parent $w1.frame -label \
  "Pause(s):" -textVariable ChangePause -width 7 -contextHelp \
  "Enter the pausing time after a change is made." -packOption "-side left"

set Divisions 12
set Repeats 1
APSLabeledEntry .div -parent $w2.frame -label \
  "divisions:" -textVariable Divisions -width 5 -packOption "-side left" \
  -contextHelp "enter the maximum divisons used in simplex or 1dscan"
APSLabeledEntry .rep -parent $w2.frame -label \
  "cycles:" -textVariable Repeats -width 5 -packOption "-side left" \
  -contextHelp "enter the maximum repeated runs used in simplex or 1dscan"
set Method 0
APSRadioButtonFrame .scan -parent $w2.frame \
                     -label "" -buttonList {Simplex 1D_Simplex 1DScan squishPVs}\
                     -variable Method -valueList {0 1 2 3}\
                     -packOption {-side left} -orientation horizontal\
                     -contextHelp "if squishPVs is checked, then run squishPVs when Run is clicked.\
                      otherwise, run sddsoptimize with the method checked"
set Maximum 0
APSRadioButtonFrame .max -parent $w2.frame -label "" \
      -variable Maximum\
     -buttonList {maximum minimum}  -packOption {-side left}\
     -valueList {1 0} -orientation horizontal\
     -contextHelp "find the maximum or minimum RMS value of the measurement" 
set Repeat 0
APSCheckButtonFrame .rept -parent $w2.frame -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" 
set MeasScript ""
APSFrame .script -parent .userFrame -packOption "-side top -fill x"
APSLabeledEntry .s -parent .userFrame.script.frame -packOption "-side left" \
         -width 50 -label "meas. script:" -textVariable MeasScript \
         -contextHelp "Enter the script measurement here"
.userFrame.script.frame configure -relief flat -bd 0
set doScript 0
APSRadioButtonFrame .radio -parent .userFrame.script.frame -label "" \
      -variable doScript -packOption {-side left}\
     -buttonList {measScript measFile} \
     -valueList {1 0} -orientation horizontal\
     -contextHelp "run the script if measScript button is checked, otherwise, run the meas." 

set Verbose 1
APSCheckButtonFrame .ver -parent .userFrame.script.frame -label "" \
      -variableList Verbose\
     -buttonList verbose  -packOption {-side left}\
     -contextHelp "print the results if checked" 
set mav 1
APSRadioButtonFrame .mav -parent .userFrame.script.frame -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"

set InputOrbitFile ""
set OutputOrbitFile ""
set OutTmp 0
set tmpFile ""
set tmpFile1 ""
set tmpFile2 ""
set OutputFile ""
set InputConfigFile ""
set LogFile ""

APSFrame .pvMeasurement -parent .userFrame -label "Measurement" -packOption \
  "-side top -fill x" -contextHelp \
  "Enter data for measurement PVs in this frame."
set mvScroll [APSScroll .mvScroll -parent .userFrame.pvMeasurement.frame]
set mvScrollFrame .userFrame.pvMeasurement.frame.mvScroll

APSButton .add -parent .userFrame.pvMeasurement.frame -text "ADD" \
  -command "MakeNewMeasureLine $mvScroll" -contextHelp "Press to add another PV name
   entry line."
APSButton .load -parent .userFrame.pvMeasurement.frame -text "LOAD Measurement PVs..." \
  -command LoadMeasureData
APSButton .save -parent .userFrame.pvMeasurement.frame -text "SAVE Measurement..." \
  -command "SaveMeasureData 0"
APSButton .clear -parent .userFrame.pvMeasurement.frame -text "Clear Measurement..." \
  -command "ClearMeasureSettings $mvScroll"



APSFrame .pvVariable -parent .userFrame -label "PV Variables" -packOption \
  "-side top -fill x" -contextHelp \
  "Enter data for parameters and PVs in this frame."

set pvScroll [APSScroll .pvScroll -parent .userFrame.pvVariable.frame]
set pvScrollFrame .userFrame.pvVariable.frame.pvScroll

APSButton .add -parent .userFrame.pvVariable.frame -text "ADD" \
  -command "MakeNewPVLine $pvScroll" -contextHelp "Press to add another variable PV name
   entry line."
APSButton .load -parent .userFrame.pvVariable.frame -text "LOAD PVs..." \
  -command "LoadConfigData 0"
APSButton .save -parent .userFrame.pvVariable.frame -text "SAVE CONFIG..." \
  -command "SaveConfigData 0"
APSButton .clear -parent .userFrame.pvVariable.frame -text "Clear CONFIG..." \
  -command "ClearVarSettings $pvScroll"
APSRadioButtonFrame .check -parent .userFrame.pvVariable.frame -label "" \
      -variable doForce\
     -buttonList {start_from_present start_from_given_values} \
     -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." 

APSFrame .knob1 -parent .userFrame -contextHelp "knob files frame."  \
               -packOption "-anchor w -fill x" 

set KnobFiles ""
set w ".userFrame.knob1.frame"
$w configure -relief flat -bd 0
APSButton .open -parent $w -command "OpenKnobFile" -text "choose" -packOption "-side left"\
   -contextHelp "Press to open the knob files list and choose the knob file"
APSLabeledEntry .file -parent $w -label \
  "KnobFiles: " -textVariable KnobFiles -width 80 -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"


APSFrame .ops -parent .userFrame \
  -contextHelp "Actions are started in this frame."


APSButton .ops.frame.run -parent .userFrame -text Run -command \
   "ChangeButtonState 1; RunAmoeba" \
  -contextHelp "Launches Amoeba to find the best position using simplex"
APSButton .ops.frame.continue -parent .userFrame -text Continue -command \
    "ChangeButtonState 1; ContinueAmoeba 2" \
   -contextHelp "continuely run amoebaOAG starting from the best point just obtained"
APSButton .ops.frame.clear -parent .userFrame -text "CLEAR ALL" \
  -command "ClearVarSettings $pvScroll;ClearParSettings;ClearMeasureSettings $mvScroll" \
  -contextHelp "Clears all of the settings."
APSButton .ops.frame.restore -parent .userFrame -text "RestoreInitialSettings" \
  -command "RestoreInitialSettings" \
  -contextHelp "Restore the initial PV settings."

proc OpenKnobFile {} {
   global KnobFiles
   set KnobDir "/home/helios/oagData/sr/knobs"
   set filename [APSFileSelectDialog .chooseInputFile -listDir $KnobDir \
         -contextHelp "Select a knob configuration file" \
         -title "Select Knob Configuration File:"]
   if {$KnobFiles ==""} {
      set KnobFiles $filename
   } else {
     if {![string match $KnobFiles $filename]} {
        set KnobFiles "$KnobFiles,$filename"
     } else {
        APSAlertBox .existFile -errorMessage \
           "This file has alrady been chosen: $filename"
        return
     }   
   }
}


proc ChangeButtonState {state} {
    if $state {
        APSDisableButton .userFrame.ops.frame.continue.button
    } else {
        APSEnableButton .userFrame.ops.frame.continue.button
    }
}

proc RestoreInitialSettings {} {
    global VariableLines InitialValue VarPVname pvList
    global tclVarList pvList IV InitialSettings
    if {[llength $tclVarList]==0} {
       for {set i 1} {$i < $VariableLines} {incr i} {
         if {[string length $VarPVname($i)]>0} {
            addToLists $VarPVname($i) IV($i)
         }     
       }
    }
    if [pv linkw $tclVarList $pvList] {
       SetMainStatus "Unable to link PVs"
       bell
       set tclVarList {}
       set pvList {}
       return
    }
    set num $VariableLines
    SetMainStatus "VariableLines=$VariableLines"
    for {set i 1} {$i < $num } {incr i} {
       set IV($i) $InitialSettings($i)
    }
    if {![pv putw $tclVarList]} {
      for {set i 1} {$i < $num } {incr i} {
        set InitialValue($i) $InitialSettings($i)      
      }
      SetMainStatus "Successfully the PVs to the original settings!"
    }
}

proc SetCurrentPV {} {
    global VariableLines InitialValue VarPVname pvList
    global tclVarList pvList IV InitialSettings
    if {[llength $tclVarList]==0} {
       for {set i 1} {$i < $VariableLines} {incr i} {
         if {[string length $VarPVname($i)]>0} {
            addToLists $VarPVname($i) IV($i)
         }     
       }
    }
    if [pv linkw $tclVarList $pvList] {
       SetMainStatus "Unable to link PVs"
       bell
       set tclVarList {}
       set pvList {}
       return
    }
#    SetMainStatus "VariableLines=$VariableLines"
    for {set i 1} {$i < $VariableLines} {incr i} {
       set IV($i) $InitialValue($i)
    }
    if {![pv putw $tclVarList]} {
      SetMainStatus "Successfully set the PVs to current value!"
    }
}

proc MakeNewPVLine {widget0 args} {
    global pvScrollFrame 
    global VariableLines VarPVname doForce 
    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
    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 
    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 InitExist 0
proc LoadConfigData {flag {fid log} args} {

    global env pvScroll 
    global InputConfigFile VariableLines Factor ChangePause
    global Iterationts Target Mode PauseBetweenReading NumberToAverage Tolerance
    global PauseAfterChange InitialSettings InitExist
    if { $flag == 0} {
       set filename [APSFileSelectDialog .chooseInputFile -listDir $env(HOME)]
    } else {
        if [file exists $fid] {
          set filename $fid
        } else {
          SetMainStatus "File $fid does not exit. Please try again"
          return
        }
    }
    set filename [string trim $filename]
    set InputConfigFile $filename

    if {![APSCheckSDDSFile -fileName $filename]} {
        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."
        return 
    }
    if {[lsearch -exact $colNames "ControlName"]!=-1} {
        set columnName ControlName
    } else {
        SetMainStatus "$filename doesn't contain controlPV data column."
        return
    }
    set names [APSGetSDDSColumn -fileName $filename -column $columnName -page 0]
    if {[llength $names]==0} {
        SetMainStatus "$filename has no process variable names."
        return
    }
    
    set paramList [APSGetSDDSNames -fileName $filename -class parameter]

   if {[lsearch $paramList "pauseAfterChange"] != -1 } {
       set ChangePause [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]
    }
    ClearVarSettings $pvScroll 0
    set i 0
    foreach name $names {
       MakeNewPVLine $pvScroll -pvName $name \
             -lowerLimit [lindex $nLower $i] \
             -upperLimit [lindex $nUpper $i]  \
             -initialValue [lindex $nInit $i] \
             -initialChange [expr [lindex $nInitC $i]/$Factor] \
             -gain 1
       incr i
    }
    
  
    SetMainStatus "PV data loaded from $filename."
}


proc ClearVarSettings {widget0 {popUp 1}} {
    global VariableLines VarPVname InitialValue LowerLimit UpperLimit InitialChange
    global pvScrollFrame
    if {$popUp} {
	if {![APSYesNoPopUp "Really? Clear variable settings?"]} { return }
    }
#    ClearParSettings
    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
    SetMainStatus "Press ADD to enter measurement or variable PV names
       for sddsexperiment"
}

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

    if {$PVcount == 0} {
        SetMainStatus "No PV variables specified--can't save."
        return
    }
    if {$flag == 0} {
       set filename ""
       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 sourceFile $OutputOrbitFile
    } else {
       if {$OutTmp==0 || $OutTmp ==1 } {
          set tmpFile /tmp/[APSTmpString]
          set OutTmp 1
       }
       set filename $tmpFile
       set sourceFile $tmpFile2
    }
    set fid [open $filename w]
    puts $fid "SDDS1"
#    puts $fid "&parameter name=figureOfMerit type=string &end"
#    puts $fid "&parameter name=tolerance type=double &end"
    puts $fid "&parameter name=pauseAfterChange type=double &end"
#    set fig [concat "-script getPVAve -sourceFile" $sourceFile \
            "-numOfReadings" $NumberToAverage "-pauseBetweenReading" $PauseBetweenReadings]

    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 "$fig"
#    puts $fid "$Tolerance"
    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)"
               set saveSuccess 0
           }
        } else {
           puts $fid "$VarPVname($i) $LowerLimit($i) \
             $UpperLimit($i) $InitialChange($i)"
        }
    }
    close $fid
    if {!$flag} { 
       set OutputFile $filename 
       SetMainStatus "Save completed to file $filename."
    } else {
#      SetMainStatus "[ exec sddsprintout $filename -column=controlPV]"
      set tmpFile1 $filename
    }
}


proc ClearParSettings {} {
    global Iterations NumberToAverage PauseBetweenReadings Mode Target Tolerance
    global InputOrbitFile InputConfigFile OutputFile doForce
    set Iterations 0
    set NumberToAverage 0
    set PauseBetweenReadings 0
    set Mode ""
    set Target 0
    set Tolerance 0
    set InputOrbitFile ""
    set InputConfigFile ""
    set OutputFile ""
    set doForce 1
}


proc RunAmoeba {} {
    global Iterations OutputFile OutputOrbitFile global LogFile tmpFile1 tmpFile2
    global VarPVname VarMeasurementName MeasurementLines VariableLines OutTmp
    global MeasScript doScript Method KnobFiles InitExist Tolerance InitialValue
    global doForce saveSuccess Target Divisions Repeats Verbose Maximum Repeat
    global tmpFile mav NumberToAverage PauseBetweenReadings ChangePause Step
#    GetInitial
    # make a PV list for later checking, sorting and finding duplicates
    set PVlist {}
    set count 0
    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)]
       #     SetMainStatus "$PVlist"
            incr count
        }
    }

    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
            }  
            set PVlist [linsert $PVlist 0 $VarPVname($i)]
            incr count
        }
    }
    if {!$count} {
        SetMainStatus "No variable PV names given."
        bell
        return
    }
    if {!$doForce} {
       for {set i 1} {$i<$VariableLines} {incr i} {
            if {$InitialValue($i)==""} {
                bell
                APSInfoWindow .info -name "Invalid IntialValue" \
                   -infoMessage "The initialValue of $VarPVname($i) is not given"
                return
            }
            if {$InitialValue($i)>$UpperLimit($i) || \
               $InitialValue($i)<$LowerLimit($i)} {
                bell
                APSInfoWindow .info -name "Invalid IntialValue" \
                   -infoMessage "The initialValue of $VarPVname($i) is out of range"
                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 Ameoba not started." 
            set FoundDuplicate 1
            return
        }
    }
    if {$FoundDuplicate} { return}

    set other ""
    if {$Maximum} {
       if {$Verbose} {
          set other "-maximize -verbose"
       } else {
          set other "-maximize"
       }
    } else {
      if {$Verbose} {
         set other "-verbose"
      } 
    }
    set log /tmp/[APSTmpString]
    
    if {$Method==3} { #run squishPVs
       saveSquishData
       if {$mav} {
          set criterion ""
       } else {
          set criterion "-criterion=rms"
       }
       APSExecLog .jon -unixCommand "squishPVs $tmpFile \
            -averages=$NumberToAverage,$PauseBetweenReadings -stepsize=$Step \
            -repeat=number=$Repeats -settlingTime=$ChangePause $other $criterion"
    } else { #run sddsoptimize
        #if the "force" button is checked, then force the initial value to be the current value
        if {$doForce} { 
            set InitExist 0
        } 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
                }
            }
       }
       SaveConfigData 1
       set fileScript ""
       if {$doScript} {
          if {$MeasScript==""} {
            APSInfoWindow .info -name "script non-exist" \
                -infoMessage "the script is not given" 
            return
          } else {
            set fileScript "\"-measScript=$MeasScript\" -tolerance=$Tolerance"
          }
       } else {
          SaveMeasureData 1
          set fileScript "-measFile=$tmpFile2"
       }
       if {!$saveSuccess} {return}
       if {!$OutTmp} {
          set sourceFile $OutputFile
       } else {
          set sourceFile $tmpFile1
       }
       if {$Method==0} {
           set simplex "-simplex=restarts=1,cycles=$Repeats,evaluations=$Iterations,no1dscan"
           set logFile "$log.SimplexNo1D"
       } elseif {$Method==1} {
           set simplex "-simplex=restarts=1,cycles=$Repeats,evaluations=$Iterations"
           set logFile "$log.SimplexWith1D"
       } else {
           SetMainStatus "repeat=$Repeat"
           if {$Repeat} { 
              set simplex "-1dscan=divisions=$Divisions,cycles=$Repeats,evaluations=$Iterations,refresh" 
           } else {
              set simplex "-1dscan=divisions=$Divisions,cycles=$Repeats,evaluations=$Iterations"
           }
           set logFile "$log.1DScan"
       }
       set knobs ""
       if {$KnobFiles !=""} {
          set knobs "-knobFiles=$KnobFiles" 
       }
       APSExecLog .jon -unixCommand "sddsoptimize $fileScript -varFile=$sourceFile $knobs \
                    $simplex -target=$Target $other -logFile=$logFile"
    }
    if { $OutTmp } {
       APSAddToTmpFileList -ID 1 -fileList {$file1 $file2 $logFile $tmpFile}
    }
    ChangeButtonState 0
}

set offset 0
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
    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
    set VarMeasurementName($number) ""
    set OffsetPVName($number) ""
    set ReadbackUnits($number) ""
    set OffsetValue($number) 0
}

proc LoadMeasureData {} {
    global env mvScroll
    global InputOrbitFile MeasurementLines PauseBetweenReadings NumberToAverage
    
    set filename [APSFileSelectDialog .chooseInputFile -listDir $env(HOME)]
    set InputOrbitFile $filename
    if [string length $filename]==0 { 
        return 
    }
    if [string first " " $filename]!=-1 {
        SetMainStatus "Filename may not have spaces in it."
        return
    }
    if {![APSCheckSDDSFile -fileName $filename]} {
        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."
        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."
        return
    }
    set names [APSGetSDDSColumn -fileName $filename -column $columnName -page 0]
    if {[llength $names]==0} {
        SetMainStatus "$filename has no process variable names."
        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 [lindex $values $i] \
             -offsetPVName [lindex $backNames $i]  \
             -readbackUnits [lindex $units $i] \
             -weight [lindex $weight $i]
       incr i
    }   
#    .userFrame.pvMeasurement.frame.mvScroll.frame.canvas config -scrollregion "0 0 0 0"
    SetMainStatus "PV data loaded from $filename."
}

proc ClearMeasureSettings {widget0 {popUp 1}} {
    global MeasurementLines VarMeasureName OffsetValue OffsetPVName ReadbackUnits
    global mvScrollFrame
    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
    SetMainStatus "Press ADD to enter measurement or variable PV names
       for sddsexperiment"

}


proc SaveMeasureData {flag} {
    global MeasurementLines VarMeasurementName OffsetValue VarOffsetPVName ReadbackUnits
    global OutputOrbitFile OutTmp tmpFile tmpFile2 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 "No PV variables specified--can't save."
        return
    }
    if {!$flag} {
       set filename ""
    
       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 ""
           }
       }
    } else {
       if {$OutTmp == 0 || $OutTmp==1} {
          set tmpFile /tmp/[APSTmpString]
          set OutTmp 1
       }
       set filename $tmpFile
    }
    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"
    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
        puts $fid "\"$VarMeasurementName($i)\" \"$VarOffsetPVName($i)\" \"$ReadbackUnits($i)\" \"$OffsetValue($i)\" \"$Weight($i)\""
    }
    close $fid
    if {!$flag} {
       set OutputOrbitFile $filename
       SetMainStatus "Save completed to file $filename."
    } else {
#      SetMainStatus "[exec sddsprintout $filename -column=ControlName]"
      set tmpFile2 $filename
    }
}

proc ContinueAmoeba {factor {popUp 1}} {
   global LogFile Factor doForce VariableLines InitialChange 
   if {$popUp} {
	if {[APSYesNoPopUp "Do you want to reduce change of PVs by a factor of $factor?"]} {
             set Factor $factor
             for {set i 1} {$i < $VariableLines} {incr i} { 
               set InitialChange($i) [expr $InitialChange($i)/$factor]
             }
        }
    }
      
#then, run "RunAmoeba" continuously
    RunAmoeba

} 

proc SearchPVName {args} {
     set pvnameList ""
     set useCA 0
     if [APSStrictParseArguments {pvnameList useCA}] {
         return -code error "SearchPVName: bad arguments"
     }
     if $useCA {
         if [catch {exec cavget -list=[join $pvnameList ,]} dataList] {
             return -code error "SearchPVName: $result"
         }
         set pvNotFoundList ""
         foreach pv $pvnameList value $dataList {
             if [string compare $value ?]==0 {
                 lappend pvNotFoundList $pv
             }
         }
         if [llength $pvNotFoundList] {
             return -code error "PVs not found: [join $pvNotFoundList]"
         }
     } else {
         set pvdata_path "/home/helios/iocinfo/pvdata"
         set origDir [pwd]
         if {[file isdirectory $pvdata_path] != 1} {
             return -code error "Cannot open or locate directory $pvdata_path"
         }

         cd $pvdata_path
         set pvdata_file_list [glob -nocomplain *]
         set findFlag 0
         foreach variable $pvnameList {
             set findFlag 0
             set variable [string trim $variable]
             set cmd "grep \"$variable\" $pvdata_file_list /dev/null"
             set catchlist [list open |$cmd r]
             catch $catchlist fp
             while {[gets $fp line] >= 1} {
                 set breakpoint [string first : $line]
                 set ematch [string range $line [expr $breakpoint+1] end]
                 
                 if {[string compare $ematch $variable] == 0} {
                     set findFlag 1
                     break
                 }
             }
             if !$findFlag {
                 cd $origDir
                 return -code error "Unable to find PV $variable."
             }
         }
         cd $origDir
     }
}

set tclVarList {}
set pvList {}
proc addToLists {args} {
    global pvList tclVarList
    APSAddToParallelLists -listNames {pvList tclVarList} \
      -listItems $args
}

proc ForceInitial {} {
    global VariableLines InitialValue VarPVname pvList InitialSettings
    global tclVarList pvList doForce pvScrollFrame IV
    global env pvScroll 
    global InitialChange UpperLimit LowerLimit Factor
    if {[llength $tclVarList]==0} {
       for {set i 1} {$i < $VariableLines} {incr i} {
         if {[string length $VarPVname($i)]>0} {
             addToLists $VarPVname($i) IV($i)
          }     
       }
    }
    if [pv linkw $tclVarList $pvList] {
       SetMainStatus "Unable to link PVs"
       bell
       set tclVarList {}
       set pvList {}
       return
    }
    SetMainStatus "VariableLines=$VariableLines"
    if {![pv getw $tclVarList]} {
      for{set i 1} {$i < $VariableLines } {incr i} {
         set InitialValue($i) $IV($i) 
         set InitialSettings($i) $IV($i)
      #   SetMainStatus "$InitialValue($i)"
      }
      SetMainStatus "Start from the present Value!"
    }
}

proc GetInitial {} {
    global VariableLines InitialSettings VarPVname pvList
    global tclVarList pvList doForce pvScrollFrame IV
    global env pvScroll 
    global InitialChange UpperLimit LowerLimit Factor
    if {[llength $tclVarList]==0} {
       for {set i 1} {$i < $VariableLines} {incr i} {
         if {[string length $VarPVname($i)]>0} {
             addToLists $VarPVname($i) IV($i)
          }     
       }
    }
    if [pv linkw $tclVarList $pvList] {
       SetMainStatus "Unable to link PVs"
       bell
       set tclVarList {}
       set pvList {}
       return
    }
    SetMainStatus "VariableLines=$VariableLines"
    if {![pv getw $tclVarList]} {
      for {set i 1} {$i < $VariableLines } {incr i} {
         set InitialSettings($i) $IV($i) 
         SetMainStatus "$InitialSettings($i)"
      }
  #    SetMainStatus "Start from the present Value!"
    }
}

  
proc saveSquishData {} {
    global Gain mav LowerLimit UpperLimit VariableLines VarPVname InitialChange
    global MeasurementLines VarMeasurementName VarOffsetPVName OffsetValue ReadbackUnits
    global tmpFile 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
    }
    #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 tmpFile /tmp/[APSTmpString]
    set fid [open $tmpFile 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
   SetMainStatus "Save completed to file $tmpFile."
}

MakeNewPVLine $pvScroll
MakeNewMeasureLine $mvScroll
ChangeButtonState 1