
#variableList: the control PV list for sddsoptimize.
#startValueList: the initial values of the cotnrol PVs.
#stepList: the changing step of the control PVs.
#lowerList: the lower limit of the control PVs.
#upperList: the upper limit of the control PVs.
#the above list should has the same size or empty.
#readbackList: the measurement PVs for sddsoptimize.
#maximize=1 do maximize, if not given, do minimize.

proc APSQuickOptimize {args} {
    global optDone

    set optDone 0
    set variableList ""
    set startValueList ""
    set stepList ""
    set lowerList ""
    set upperList ""
    set readbackList ""
    set tolerance 0.1
    set average 5
    set interval 1
    set pauseChange 1
    set maximize 0
    set interactive 0
    set destroyWindow 0

    set usage "Usage: APSQuickOptimize -variableList <list of control PVs> -startValueList \
       <values> -stepList <values> -lowerList <lower limits> -upperList <upper limits> \
       -readbackList <measurement PVs> -tolerance <value> -average <number> -interval \
       <value in seconds> -pauseChange <pause time in seconds> -maximize {1: maximize;\
       default: minize} -interactive <0 or 1> -destroyWindow <0 or 1>"
    APSParseArguments {variableList startValueList stepList lowerList upperList \
       readbackList tolerance average interval pauseChange minimize interactive destroyWindow}

    if {$variableList=="" || $readbackList==""} {
        return -code error "APSQuickOptimize: no variables or readback!"
    }

    if {$lowerList=="" || $upperList=="" || $stepList=="" } {
        set result "the lower and upper limit of control pv should be given\n"
        set result "${result}the change step of the control PV should be given"
        return -code error "APSQuickOptimize: $result"
    }

    set size [llength $variableList]
    set sizeL [llength $lowerList]
    set sizeU [llength $upperList]
    set sizeS [llength $stepList]
    if {$size!=$sizeL || $size!=$sizeU || $size!=$sizeS} {
       return -code error "APSQuickOptimize: The size of variabeList, stepList, lowerList and upperList should be the same"
    }

    if {$startValueList!=""} {
        set size1 [llength $startValueList]
        if {$size!=$size1} {
            return -code error "APSQuickOptimize: The size of variableList and startValueList should be the same"
        }
    }


    set tmpInput /tmp/[APSTmpString]
    set tmpMeas /tmp/[APSTmpString]
    #save variable data into file
    set fid [open $tmpInput w]
    puts $fid "SDDS1"
    puts $fid "&parameter name=pauseAfterChange type=double &end"
    puts $fid "&column name=ControlName type=string &end"
    if {$startValueList!=""} {
        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 "$pauseChange"
    if {$startValueList!=""} {
        foreach var $variableList start $startValueList step $stepList \
          low $lowerList up $upperList {
              puts $fid "$var $start $low $up $step"
          }
    } else {
        foreach var $variableList step $stepList \
          low $lowerList up $upperList {
              puts $fid "$var $low $up $step"
          }
    }
    close $fid
    #save measurement data into file
    set fid [open $tmpMeas 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 "&data mode=ascii no_row_counts=1 &end"
    puts $fid "$average"
    puts $fid "$interval"
    puts $fid "$tolerance"
    foreach name $readbackList {
        puts $fid "$name"
    }
    close $fid

    set optimize ""
    set optDone 0
    if $maximize {
        set optimize -maximize
    }
    set log /tmp/[APSTmpString]
    if $interactive {
        set win [APSUniqueName .]
        APSExecLog $win -width 60 -unixCommand "sddsoptimize \
           -varFile=$tmpInput -logFile=$log $optimize \
           -measFile=$tmpMeas -verbose -simplex=restarts=1,cycles=1,evaluations=200" \
          -callback "set optDone done" -abortCallback "set optDone abort" \
          -cancelCallback "set optDone cancel"
        tkwait variable optDone
        set filelist [list $tmpInput $tmpMeas $log]
        APSAddToTmpFileList -ID 1 -fileList $filelist
        switch $optDone {
            cancel -
            abort {
                if $destroyWindow {
                    destroy $win
                }
                return -code error "APSQuickOptimize: sddsoptimize is canceled or aborted"
            }
            done {
                if $destroyWindow {
                    destroy $win
                }
                return
            }
            default {
                if $destroyWindow {
                    destroy $win
                }
                return
                return
            }
        }
    } else {
        if [catch {eval exec sddsoptimize -varFile=$tmpInput -logFile=$log $optimize \
            -measFile=$tmpMeas -verbose -simplex=restarts=1,cycles=1,evaluations=200} result] {
            return -code error "APSQuickOptimize: $result"
        }
    }
}