#!/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)]
APSDebugPath

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

APSApplication . -name quickDaqAggregator -version $CVSRevisionAuthor \
  -overview {This is the quickDaqMonitor utility.  It provides a simple interface to the PvAggregator  program, which allows logging EPICS data to an SDDS file base on changes of pv values including traditional CA pvs and new EPIC7 pva channels.  The data can be plotted after it is collected, or during collection.  You can also manipulate and display the data offline using the SDDS toolkit programs.}

set monitors 0
set monitorLines 0

set mainStatus "Press ADD to enter more PV names for monitoring"

proc SetMainStatus {text} {
    global mainStatus
    set mainStatus "[exec date]: $text"
    update
}

APSScrolledStatus .status -parent .userFrame -textVariable mainStatus -width 120

frame .userFrame.lines  -bd 4  -relief raised
pack .userFrame.lines -side top -fill x

set pvScroll [APSScroll .sw -parent .userFrame.lines -name "PV List"]
set pvScrollFrame .userFrame.lines.sw

#APSButton .pvScrollAdd -parent .userFrame.lines -text ADD -command \
#  "MakeNewMonitorLine $pvScroll" \
# -contextHelp "Press to add PV name entry slots."
APSButton .pvScrollAdd -parent .userFrame.lines -text ADD -command "addNewPV"


set runTime 60
set outputDir [APSGoToDailyDirectory -subdirectory daqMon]
set rootname DAQtest-000
APSLabeledEntry .dir -parent .userFrame -label "Output Directory: " \
  -textVariable outputDir -width 80 \
  -contextHelp "Enter a name for the output directory to hold the data. "
APSButton .pick -parent .userFrame.dir \
  -text F -packOption  "-side right" \
  -command "findDir -dirVariable outputDir" \
  -contextHelp "Bring up a directory selection dialog box to choose the directory."
APSButton .daily -parent .userFrame.dir \
  -text Daily -packOption "-side right"  \
  -command "set outputDir  [APSGoToDailyDirectory -subdirectory daqMon]"

APSLabeledEntry .rootname -parent .userFrame -label "Rootname:" \
  -textVariable rootname -width 80 -contextHelp "enter a rootname for the output file."
APSFrameGrid .grid -parent .userFrame -xList {x1 x2}

set w1 .userFrame.grid.x1
set w2 .userFrame.grid.x2
set width 20
set aggName AGGTest
set aggUpdate 0
set runTime 60
set delay 1.0
set timeTolerance 1e-6
set keepTimeStamp 0
set nDispose 1
set logLevel DEBUG

APSLabeledEntry .name -parent $w1 -label "Aggregate channel name:" -textVariable aggName -width $width \
  -contextHelp "provide the aggregate channel name, which will be the single PV data object for the provided channels."
APSLabeledEntry .update -parent $w2 -label "Aggregate update period (seconds):" \
  -textVariable aggUpdate -width $width \
  -contextHelp "aggregate record update period in seconds. 0 indicates that aggregate record is updated every time a PV is processed."
APSLabeledEntry .time -parent $w1 -label "Run time (seconds):" -textVariable runTime -width $width \
  -contextHelp "aggregator runtime."
APSLabeledEntry .delay -parent $w2 -label "PV processing delay (second):" -width $width -textVariable delay \
  -contextHelp "delay for procssing pvs."
APSLabeledEntry .tol -parent $w1 -label "Time stamp tolerance (seconds):" -width $width \
  -textVariable timeTolerance \
  -contextHelp "all pvs generated with timestamps within the tolerance period will be considered to be part of the same aggregate object (default: 1.0e-6 seconds)."
APSLabeledEntry .pvs -parent $w2 -textVariable nDispose -width $width \
  -label "number of initial pv values to be discarded:" \
  -contextHelp "number of initial pv values that should be discarded from each channel before aggregator starts collecting updates (default: 1)."
APSRadioButtonFrame .keep -parent $w1 -label "Keep timestamp of individual pvs?" -buttonList {Yes No} \
  -variable keepTimeStamp -valueList {1 0} -orientation horizontal
APSRadioButtonFrame .debug -parent $w2 -label "Log level:" -buttonList {DEBUG INFO WARN ERROR} \
  -valueList   {DEBUG INFO WARN ERROR} -variable logLevel -orientation horizontaol




APSButton .run -parent .userFrame -text RUN -command RunMonitor \
  -contextHelp "Launches a monitoring subprocess to collect the data."
APSButton .new -parent .userFrame -text "NEW..." -command "exec quickDaqMonitor &" \
  -contextHelp "Launches a new instance of the quickMonitor screen"
APSButton .clear -parent .userFrame -text "CLEAR ALL" -command "ClearAllSettings $pvScroll" \
  -contextHelp "Clears all of the settings for quickMonitor, including PV names and filenames."
APSButton .save -parent .userFrame -text "SAVE CONFIG..." -command SaveMonitorList \
  -contextHelp "Allows you to save the configuration, which includes the list of PVs, the interval, and the number of steps"
APSButton .load -parent .userFrame -text "LOAD CONFIG..." -command LoadExistingInput \
  -contextHelp "Loads PV names and run parameters from a previously saved configuration file." 
APSButton .namecap -parent .userFrame -text "NAME CAPTURE..." -command \
  "catch {exec namecapture &}" -contextHelp \
  "Launches an instance of the name capture utility, which is useful in making lists of process variable names for use with quickMonitor.  Use the center mouse button on any MEDM screen to get the process variable name of whatever you point at.  Hold the mouse button down and drag the name into the name capture window.  You can drop the name from there into a quickMonitor entry box, or have name capture put names in a file that you can load into quickMonitor using LOAD INPUT..."

APSButton .plot -parent .userFrame -text "Plot..." -command PlotFileChoice
frame .userFrame.review -bd 4 -relief raised
pack .userFrame.review -side top -fill x

set fileSelListDir $env(HOME)

proc PlotFileChoice {args} {
    global outputDir rootname selectFile
    cd $outputDir
    set files1 [glob -nocomplain *.sdds]
    set files2 [glob -nocomplain *.wf]
    set files [concat $files1 $files2]
    if ![llength $files] {
        SetMainStatus "No files found for plot"
        return
    }
    set selectFile ""
     APSScrolledListWindow .scrollFile -name "Select A File" \
      -label "Select fields" -itemList $files -selectionVar selectFile 
    tkwait variable selectFile
    if ![string length $selectFile] {
        return
    }
    foreach file $selectFile {
        PlotFile -file $file
    }
}

proc PlotFile {args} {
    set file ""
    global outputDir
    APSParseArguments {file}
    if ![file exist $outputDir/$file] {
        SetMainStatus "$outputDir/$file does not exist"
        return
    }
    if [string match *.sdds $file] {
        exec sddsplot $outputDir/$file -grap=line,vary  -col=Time,* -yexclude=Time,OnjectId $outputDir/$file &

    } elseif [string match *.wf $file] {
        if ![file exist $outputDir/$file.proc] {
            exec sddsprocess $outputDir/$file $outputDir/$file.proc -define=col,Index,i_row,type=long 
              
        }
        set col [exec sddsquery -col $outputDir/$file]
        exec sddsplot -grap=line,vary -split=page -col=Index,$col $outputDir/$file.proc &
    }
}


proc LoadExistingInput {args} {
    set filename ""
    if {[APSStrictParseArguments {filename}]} {
        return -code error "LoadExistingInput: invalid arguments"
    }
    global pvScroll fileSelListDir
    global monitorLines PVname Steps Interval
    if ![string length $filename] {
        set filename [APSFileSelectDialog .chooseInputFile \
                        -listDir $fileSelListDir]
        if {$filename==""} { 
            return 
        }
    }
    set fileSelListDir [file dirname $filename]
    if {![APSCheckSDDSFile -fileName $filename]} {
        SetMainStatus "$filename is not an SDDS file."
        return
    }
    set names [APSGetSDDSNames -fileName $filename -class column]
    if {[llength $names]<1} {
        SetMainStatus "$filename is not a valid sddsmonitor input file."
        return 
    }
    if {[lsearch -exact $names "ControlName"]!=-1} {
        set columnName ControlName
    } elseif {[lsearch -exact $names "Device"]!=-1} {
        set columnName Device
    } else {
        SetMainStatus "$filename is not a valid sddsmonitor input file."
        return
    }
    if {[lsearch -exact $names "ReadbackName"]!=-1} {
         set columnNameRB ReadbackName
    } else {
         set columnNameRB $columnName
    }
    if [lsearch -exact $names "CaType"]>=0 {
        set caTypes [exec sdds2stream -col=CaType $filename]
    } else {
        set caTypes ""
    }
    if [lsearch -exact $names "Scalar"] {
        set scalars [exec sdds2stream -col=Scalar $filename]
    } else {
        set scalars ""
    }
    set names [APSGetSDDSColumn -fileName $filename -column $columnName -page 0]
    set namesRB [APSGetSDDSColumn -fileName $filename -column $columnNameRB -page 0]
    
    if {[llength $names]==0} {
        SetMainStatus "$filename has no process variable names."
        return
    }
    if {$monitorLines==1 && [string length $PVname(0.PV)]==0} {
        incr monitorLines -1
    }
    set i 0
    foreach namePV $names nameRB $namesRB {
        if [llength $caTypes] {
            set caType [lindex $caTypes $i]
        } else {
            set caType CA
        }
        if [llength $scalars] {
            set scalar [lindex $scalars $i]
        } else {
            set scalar 1
        }
        MakeNewMonitorLine $pvScroll -pvNamePV $namePV -pvNameRB $nameRB -caType $caType -scalar $scalar
        incr i
        update
    }
    set pars [exec sddsquery -par $filename]
    for par $pars{
        global $par
        set $par [exec sdds2stream -par=$pars $filename]
    }
    SetMainStatus "Loaded configuration from file $filename"
}


proc ClearAllSettings {widget0} {
    global monitorLines PVname outputFile logplot
    if {![APSYesNoPopUp "Really? Clear all settings?"]} { return }
    for {set i 0} {$i<$monitorLines} {incr i} {
        if {[winfo exists $widget0.m$i]} { destroy $widget0.m$i}
        set PVname($i.PV) ""
        set PVname($i.RB) ""
    }
    set monitorLines 0
    set outputFile ""
    set logplot 0
    SetMainStatus "Press ADD to enter PV names for monitoring"
}

proc CheckPVType {args} {
    set pvName ""
    APSParseArguments {pvName}
    
    set elementCount 1
    if [catch {exec cainfo $pvName} caResult] {
        #not CA
        if [catch {exec pvinfo $pvName } pvInfoResult] {
            return -code error "Error: did not find $pvName, please check the pv name!"
        } else {
            set caType PVA
        }
    } else {
        set b [split $caResult "\n"]
        set elementCount [scan [string trim [lindex $b end]] "Element count:   %d"]
        set caType CA
    }
    return "$caType $elementCount"
}

proc MakeNewMonitorLine {widget0 args} {
    global pvScrollFrame
    global monitorLines PVname
    set pvNamePV ""
    set pvNameRB ""
    set caType CA
    set scalar 1
    APSParseArguments {pvNamePV pvNameRB caType scalar}

    
    for {set i 0} {$i<$monitorLines} {incr i} {
        if [string compare $pvNamePV $PVname($i.PV)]==0 {
            SetMainStatus "$pvNamePV already added."
            return
        }
    }
    set widget $widget0.m$monitorLines
    if ![winfo exists $widget] {
        frame $widget -bd 1
        pack $widget -fill x
        frame $widget.data
        frame $widget.op 
        frame $widget.op1
        pack $widget.data $widget.op $widget.op1 -side left

        APSButton .delete -parent $widget.op -text "DELETE" \
          -command "DeleteMonitorLine $widget0 $monitorLines" \
          -contextHelp "Press to delete the corresponding PV name entry line."
        $widget.op.delete configure -bd 0
        $widget.op.delete.button configure -font -adobe-courier-medium-r-normal-*-12-*-*-*-*-*-*-*
        APSButton .clear -parent $widget.op -text "CLEAR" \
          -command "ClearMonitorLine $widget0 $monitorLines" \
          -contextHelp "Press to clear the corresponding PV name entry line."
        
        $widget.op.clear configure -bd 0
        $widget.op.clear.button configure -font -adobe-courier-medium-r-normal-*-12-*-*-*-*-*-*-*
        set PVname($monitorLines.caType) $caType
        set PVname($monitorLines.scalar) $scalar
        APSLabeledEntry .x -parent $widget.data -label " PV name:" \
          -textVariable PVname($monitorLines.PV) -width 30 -packOption "-side left" \
          -contextHelp "Enter the name of a process variable (PV) to be monitored in this field."
        bind $widget.data.x.entry <Return> "CheckPVType -number $monitorLines -widget $widget.data.x "
        
        APSRadioButtonFrame .type -parent $widget.op -label "PV type:" -buttonList "CA PVA" \
            -valueList {CA PVA} -variable PVname($monitorLines.caType) -orientation horizontal \
            -contextHelp "please provide the PV type, tradidional pvs use CA otherwise choose PVA"
        APSRadioButtonFrame .count -parent $widget.op1 -label "" -buttonList {Scalar Array} \
          -valueList {1 0} -variable PVname($monitorLines.scalar) -orientation horizontal
        
       # APSLabeledEntry .y -parent $widget.data -label " PV readback:" \
       #   -textVariable PVname($monitorLines.RB) -width 30 -packOption "-side right" \
       #   -contextHelp "Enter the name of the column in the output file for this PV.  Defaults to the PV name."
       
        
        
    }
    
    set PVname($monitorLines.PV) $pvNamePV
    if [string length $pvNameRB] {
        set PVname($monitorLines.RB) $pvNameRB
    } else { 
        set PVname($monitorLines.RB) $pvNamePV
    }
    
    incr monitorLines
    #tkwait visibility $widget.data.x
    APSScrollAdjust $pvScrollFrame -numVisible 10
    tkwait visibility $widget.data.x
}

set pvName ""
set caType ""
proc AddNewMonitor {args} {
    global pvScroll
    set pvNamePV ""
    APSParseArguments {pvNamePV}
    
    if [catch {CheckPVType -pvName $pvNamePV} typeList] {
        SetMainStatus "Error checking pv type: $typeList; $pvNamePV was not added."
        return
    }
    set type [lindex $typeList 0]
    set count [lindex $typeList 1]
    
    if [string match "*.VAL" $pvNamePV] {
        set pvNamePV [file root $pvNamePV]
    }
    if {$type=="CA"} {
        if $count>1 {
            set scalar 0
        } else {
            set scalar 1
        }
        MakeNewMonitorLine $pvScroll -pvNamePV $pvNamePV -caType CA -scalar $scalar
        return
    }
    
    set answer  [APSMultipleChoice .info -name "Monitor $pvNamePV" \
                       -question "Do you want to monitor all the fields of $pvNamePV or part of it?" \
                       -returnList {All Part} -labelList {All Part} ]
    if {$answer=="All"} {
        MakeNewMonitorLine $pvScroll -pvNamePV $pvNamePV -caType PVA -scalar 0
        return
    }
    if [catch {exec pvinfo $pvNamePV} pvInfoResult] {
        SetMainStatus "Error getting $pvNamePV structure: $pvInfoResult"
        return
    }
    global selectPVA
    set alist [split $pvInfoResult "\n"]
    set itemList ""
    foreach a $alist {
        set spaces [expr [string length $a] - [string length [string trim $a]]]
        if {$spaces==8} {
            #only consider one level of the structure and ignore the nested structure
            if [regexp "structure" $a] {
                continue
            }
            set b [string trim $a]
            if [string length $b] {
                lappend itemList $b
            }
        }
    }
    set selectPVA ""
    APSScrolledListWindow .scrollPVA -name "Select field of $pvNamePV" \
      -label "Select fields" -itemList $itemList -selectionVar selectPVA 
    tkwait variable selectPVA
    if ![string length $selectPVA] {
        return
    }
    foreach a $selectPVA {
       # puts $a
        if [regexp {\[\]} $a] {
            set scalar 0
        } else {
            set scalar 1
        }
        set name $pvNamePV.[lindex [split $a " "] 1]
        
        MakeNewMonitorLine $pvScroll -pvNamePV $name -caType PVA -scalar $scalar
    }
}

proc addNewPV {} {
    
    global pvName caType pvScroll
    
    set okCommand {AddNewMonitor -pvNamePV $pvName \
                       -caType $caType}
    APSDialogBox .pv -name "Add PV Box" -width 30 \
      -cancelCommand "" -okCommand $okCommand
   # APSDialogBoxAddButton .help -parent .pv -text "Help" -command "HelpDialog -box PVBox"
    APSDialogBoxAddButton .clear -parent .pv -text "Clear" \
      -contextHelp "clear the existing settings in this dialog." \
      -command {set pvName "";set caType ""}
    APSLabeledEntry .addVar -parent .pv.userFrame \
      -label "PV name: " -textVariable pvName -width 30 \
      -contextHelp "Enter a PV name of your choice."
    bind .pv.userFrame.addVar.entry <Return> "CheckPVType"
   # APSRadioButtonFrame .type -parent .pv.userFrame -label "PV type:" -buttonList \
   #   {CA PVA} -valueList {CA PVA} -variable caType \
    #  -commandList {CheckPVType CheckPVType}  -orientation horizontal
      
}

proc GetPVAStructure {args} {
    set contents ""
    APSParseArguments {contents}

    set pvaList ""
    set itemList ""
    forach nm $contexts {
        

    }
}

proc DeleteMonitorLine {widget0 number} {
    global monitorLines PVname 
    destroy $widget0.m$number
    set PVname($number.PV) ""
    set PVname($number.RB) ""
}

proc ClearMonitorLine {widget0 number} {
    global monitorLines PVname 
    set PVname($number.PV) ""
    set PVname($number.RB) ""
}

set outputListLength 0
proc SaveMonitorList {args} {
    set filename ""
    APSStrictParseArguments {filename}
    global monitorLines PVname 
    global Interval Steps 
    global outputDir
    global aggName aggUpdate runTime delay timeTolerance nDispose logLevel rootname keepTimeStamp

    set count 0
    for {set i 0} {$i<$monitorLines} {incr i} {
        if {[string length $PVname($i.PV)]} {
            incr count
        }
    }
    if {!$count} {
        return -code error "No PV names given."	
    }
    set userMode 0
    while {![string length $filename]} {
        set userMode 1
        set filename [APSInfoDialog [APSUniqueName .] -name FileDialog \
                        -width 60 \
                        -infoMessage "Supply the name of a file to which to save the 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 origNameList ""
    set readbackNameList ""
    set caTypeList ""
    set scalarList ""
    global plotList
    set plotList ""
    for {set i 0} {$i<$monitorLines} {incr i} {
        if {[string length $PVname($i.PV)]} {
	    set origName [string trim $PVname($i.PV)]
	   
            lappend caTypeList $PVname($i.caType)
            lappend origNameList $origName
            lappend scalarList $PVname($i.scalar)
            set readbackName $origName
            lappend readbackNameList $readbackName
           # puts $readbackName
            if $PVname($i.scalar) {
                if {[string length $plotList]==0} {
                    set plotList $readbackName
                } else {
                    set plotList "$plotList,$readbackName"
                }
            }
        }
    }
   ### puts $plotList
    if [catch {exec sddsmakedataset $filename -col=ControlName,type=string -data=[join $origNameList ,] \
                 -col=ReadbackName,type=string -data=[join $readbackNameList ,] \
                 -col=CaType,type=string -data=[join $caTypeList ,] \
                 -col=Scalar,type=short -data=[join $scalarList ,] \
                 -par=keepTimeStamp,type=short -data=$keepTimeStamp \
                 -par=aggName,type=string -data=$aggName \
                 -par=aggUpdate,type=double -data=$aggUpdate \
                 -par=runTime,type=double -data=$runTime \
                 -par=delay,type=double -data=$delay \
                 -par=timeTolerance,type=double -data=$timeTolerance \
                 -par=nDispose,type=long -data=$nDispose \
                 -par=logLevel,type=string -data=$logLevel \
                 -par=rootname,type=string -data=$rootname } result] {
        return -code error "Error saving config file: $result"
    }
    if $userMode {
        SetMainStatus "Configuration saved to $filename"
    }
}

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
     }
}

proc findDir {args} {
    # General purpose directory selection
    # args is passed to APSFileSelectDialog
    set dirVariable ""
    set trim 0
    APSParseArguments {dirVariable trim}
    global $dirVariable
     set choosedfile [APSFileSelectDialog .chooseInputFile -listDir ./  -selectDir 1]
    if [string length $choosedfile] {
        set $dirVariable $choosedfile
    }
    
}
proc RunMonitor {} {
    global monitorLines outputDir rootname outputFile PVname monitorLines
    global logplot
    global outputList plotComList plotLogScale outputListLength
    global plotList
    global aggName aggUpdate runTime delay timeTolerance nDispose logLevel keepTimeStamp
    
    
    if {[string length $rootname]==0} {
        SetMainStatus "Supply an output rootname."
        bell
        return
    }
    
    set outputFile $outputDir/${rootname}.sdds
    if {[file exists $outputFile]} {
        bell
        set ok [APSYesNoPopUp "Delete existing $outputFile?"]
        if {!$ok} {
            SetMainStatus "Supply a new output rootname"
            return
        }
    }

    set inputFile $outputDir/${rootname}.mon
    if [catch {SaveMonitorList -filename $inputFile} result] {
	bell
        APSAlertBox [APSUniqueName .] -errorMessage $result
        SetMainStatus "Searching is stopped."
        return
    }
    set caList ""
    set pvaList ""
    for {set i 0} {$i<$monitorLines} {incr i} {
        if [string length $PVname($i.PV)] {
            switch $PVname($i.caType) {
                CA {
                    lappend caList $PVname($i.PV)
                }
                PVA {
                    lappend pvaList $PVname($i.PV)
                }
            }
        }
    }
    if {![llength $caList] && ![llength $pvaList]} {
        SetMainStatus "No pvs provided!"
        return
    }
    set pvOpt ""
    if [llength $caList] {
        append pvOpt " --ca-channels [join $caList ,]"
    }
    if [llength $pvaList] {
        append pvOpt " --pva-channels [join $pvaList ,]"
    }
    if $keepTimeStamp {
        append pvOpt " --keep-timestamps"
    }
    append pvOpt " --aggregate-channel $aggName --aggregate-record-update-period $aggUpdate --runtime $runTime"
    append pvOpt " --pv-processing-delay $delay --timestamp-tolerance $timeTolerance"
    append pvOpt " --sdds-file-prefix $rootname --output-directory $outputDir --n-disposable-pv-values $nDispose -d $logLevel"
    SetMainStatus "running..."
    set outputList($outputListLength) $outputFile
    set plotComList($outputListLength) "sddsplot -ticks=xtime -column=Time,($plotList) -graph=line,vary -legend $outputFile"
    APSExecLog .job$outputListLength -unixCommand "daq-aggregate $pvOpt" \
      -contextHelp "This window is running a quickAggegateMonitor subprocess."  \
      -callback "AddPlotCommandToFile $outputFile $plotComList($outputListLength)"
    if [llength $plotList] {
        AddReplotButton .job$outputListLength $outputListLength
    }
    incr outputListLength
}


proc AddPlotCommandToFile {outputFile args} {
    set command [APSMakeSafeQualifierString [join $args]]
    set tmpFile [file dirname $outputFile]/[APSTmpString]
    exec sddsprocess $outputFile $tmpFile -nowarning \
      "-print=param,sddsplotCommand01,$command" 
    exec mv $tmpFile $outputFile
}

proc AddReplotButton {parent index} {
    global outputList plotComList plotLogScale plotSeparately plotSameScale
    set w $parent.rprow$index
    pack [frame $w -relief raised -bd 2] -side bottom

    set plotLogScale($index) 0
    set plotSeparately($index) 0
    set plotSameScale($index) 0
    APSButton .plot -parent $w \
      -text "Plot $outputList($index)" \
      -command "ReplotData $index" \
      -contextHelp "This button replots the data in file $outputList($index)"
    checkbutton $w.log -text "Log plot" \
      -variable plotLogScale($index) -relief ridge
    checkbutton $w.separ -text "Separate plots" \
      -variable plotSeparately($index) -relief ridge
    checkbutton $w.same -text "Same scale" \
      -variable plotSameScale($index) -relief ridge
    pack $w.log  $w.separ $w.same -side left
}

proc ReplotData {index} {
    global outputList plotComList plotLogScale plotSeparately plotSameScale
    SetMainStatus "Plotting  $outputList($index)"
    set extraArgs ""
    if $plotSameScale($index) {
        set extraArgs "$extraArgs -samescale=y"
    }
    if $plotSeparately($index) {
        set extraArgs "$extraArgs -separate"
    }
    if {$plotLogScale($index)} {
        eval exec "$plotComList($index)  -mode=y=log \"-ylabel=edit=i/Log\\\$b10\\\$n /\" $extraArgs &"
    } else {
        eval exec "$plotComList($index) $extraArgs &"
    }                
}

#MakeNewMonitorLine $pvScroll

if [llength $argv] {
    set args $argv
    set fileName ""
    if {[APSStrictParseArguments {fileName}] || ![string length $fileName]} {
        return -code error {usage: quickMonitor [-fileName <string>]}
    }
    if ![file exists $fileName] {
        return -code error "not found: $fileName"
    }
    LoadExistingInput -filename $fileName
}
