#!/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

# $Log: not supported by cvs2svn $
# Revision 1.6  2011/09/23 21:42:32  shang
# changed the plot range for x/y position of linac and changed the plot description.
#
# Revision 1.5  2011/09/23 20:37:35  shang
# changed option parameters to use time and samples instead of self test number per Erwin's request, removed the histogram and average procesing and plot.
#
# Revision 1.4  2011/09/21 19:58:07  shang
# changed the PV names for data collections, now using XPOS, YPOS and VAL for x, y and sum data.
#
# Revision 1.3  2011/09/19 20:07:30  shang
# added missing $ sign before "processFlag" variable, and initialized "processFlag" variable.
#
# Revision 1.2  2011/09/19 16:13:28  shang
# added system arguments to MakeLabelledEntryWidgets to be able to change the entry labels for linac systems.
#
# Revision 1.1  2011/09/15 19:54:28  shang
# first version, for linac, LTP, PTB, Booster bypass, and BTS bpm self testing.
#
set mainDir  /home/helios/oagData/linac/bpmSelfTest

# This procedure sets the status variable used by the status widget.

proc SetStatus {text} {
    global ControlStatus
    set ControlStatus $text
    update
}

#Disable buttons once one is pressed.

proc DisableSelfTestButton {} {
    APSDisableButton .userFrame.selfTestWidgets.frame.selfTestButton.button
  #  APSDisableButton .userFrame.selfTestWidgets.frame.fileSelectionFrame.button
  #  APSDisableButton .userFrame.selfTestWidgets.frame.processSelectionFrame.button
    APSDisableButton .userFrame.plotFrame.frame.plotSelectionFrame.button
    APSDisableButton .userFrame.selfTestWidgets.frame.cleanupSelectionFrame.button
    APSDisableButton .userFrame.selfTestWidgets.frame.updateContentsFrame.button
}

#Enable buttons once one is pressed and its associated procedure finishes.

proc EnableSelfTestButton {} {
    APSEnableButton .userFrame.selfTestWidgets.frame.selfTestButton.button
  #  APSEnableButton .userFrame.selfTestWidgets.frame.fileSelectionFrame.button
  #  APSEnableButton .userFrame.selfTestWidgets.frame.processSelectionFrame.button
    APSEnableButton .userFrame.plotFrame.frame.plotSelectionFrame.button
    APSEnableButton .userFrame.selfTestWidgets.frame.cleanupSelectionFrame.button
    APSEnableButton .userFrame.selfTestWidgets.frame.updateContentsFrame.button
}

# Checks the SR BPM local bus addresses for errors.  If errors are
# detected, an sddsfile is made in $directory and sddsprintout is used
# to display the specific BPMs with errors, sector number, and IOC
# number.  Returns 0 if there are errors; 1 if there are no errors.

#Perform the BPM self-test.  Returns a 1 if the test was successful; 
#returns a 0 if not.

proc PerformBPMSelfTest {args} {

    global ControlStatus selectedBPMList SelfTestDataFileName SelfTestDataFileRootName
    global MostRecentFileName directory contentsString system

    DisableSelfTestButton
    APSParseArguments {statusCallback}
    
    set selectedBPMList ""
    set selectedBPMList [MakeSelectedBPMList]
    if {$selectedBPMList==""} {
        $statusCallback "No BPMs Selected."
        EnableSelfTestButton
        bell
        return 0
    }
    scan [DetermineMostRecentFileIndex $SelfTestDataFileRootName] %ld fileIndex
    incr fileIndex
    set fileIndex [format %03ld $fileIndex]
    if {$MostRecentFileName==""} {
        set fileIndex [DetermineMostRecentFileIndex $SelfTestDataFileRootName]
    }
    set SelfTestDataFileName ${SelfTestDataFileRootName}.${fileIndex}.sdds
    SetStatus "setup ..."
    if [catch {PerformBPMSelfTestSetup -statusCallback SetStatus} result] {
	SetStatus "Error in setting up selft test: $result"
	EnableSelfTestButton
	return
    }
    SetStatus "Perform self test..."
    if [catch {AcquireBPMSelfTestData -statusCallback SetStatus} result] {
	SetStatus "Error in acquiring data: $result"
	EnableSelfTestButton
	return
    }
    SetStatus "restore setup ..."
    if [catch {RestoreBPMSetup -statusCallback SetStatus} result] {
	SetStatus "Error in restoring setup: $result"
	EnableSelfTestButton
	return
    }
    bell
    EnableSelfTestButton
    SetStatus "data collected."
    #process
    SetStatus "Processing data ..."
    if [catch {RegroupAndHistogramSelfTestData} result] {
	SetStatus "Error in processing data: $result"
	EnableSelfTestButton
	return
    }
    SetStatus "done."
    return 1
}

# Make a list of BPMs selected using the checkbuttons.  Procedure returns the list.

proc MakeSelectedBPMList {} {

    global bpmList 
    eval global $bpmList
    set selectedList ""
    foreach bpm $bpmList {
	if [set $bpm] {
	    lappend selectedList $bpm
	}
    }
    return $selectedList
}

proc MakeMonitorFile {args} {
    set filename ""
    APSParseArguments {filename}
    global suffixList orbitFile
    set selectedBPMList [MakeSelectedBPMList]
    
    set tmpRoot /tmp/[APSTmpString]
    if [catch {exec sddsmakedataset $tmpRoot.1 -col=Name,type=string -data=[join $selectedBPMList ,]} result] {
	return -code error "Error in making monitor file1; $result"
    }
    if [catch {exec sddsselect $orbitFile $tmpRoot.1 -reuse -match=BPMName=Name $filename} result] {
	return -code error "Error in making monitor file2: $result"
    }
}

# Execute commands to configure each BPM for the self-test.  Returns 1 after executing the BPM configuration commands.

proc PerformBPMSelfTestSetup {args} {

    global ControlStatus gain MSavg oldMSavg system gain testMode VMIN MSavg samples
    global averagingState

    APSParseArguments {statusCallback}
    if {$statusCallback!=""} {
        $statusCallback "Configuring Selected BPMs for the self-test..."
    }       
    global selectedBPMList
    if !$gain {
	set gainval 1
    } else {
	set gainval 0
    }
    switch $testMode {
	SelfTest {
	    set test 1
	}
	NoiseTest {
	    set test 0
	    #set VMIN to 0
	    if [catch {exec cavput -list=[join $selectedBPMList ,] -list=:BPM.VMIN=0 -pend=10} valList] {
		return -code error "Error in setting VMINs: $result"
	    }
	}
    }
    if [catch {exec cavput -list=[join $selectedBPMList ,] -list=:GainC=$gainval,:TestC=$test,:BPM.CAVG=$MSavg -pend=10 } result] {
	return -code error "Error in setting up BPM self testing: $result"
    }
    
    if {$statusCallback!=""} {
        $statusCallback "Selected BPMs configured for the self-test."
    }       
    return 1
}

proc RestoreBPMSetup {args} {

    global ControlStatus gain MSavg oldMSavg system VMIN testMode AVG
    global averagingState
    set gain 0
    
    APSParseArguments {statusCallback}
    if {$statusCallback!=""} {
        $statusCallback "Restoring standard BPM configuration..."
    } 
     global selectedBPMList
    if [catch {exec cavput -list=[join $selectedBPMList ,] -list=:GainC=1,:TestC=0 -pend=10 } result] {
	return -code error "Error in restoring BPM self testing: $result"
    }
    if {$testMode=="NoiseTest"} {
	foreach bpm $selectedBPMList {
	    lappend putList ${bpm}:BPM.VMIN=$VMIN($bpm)
	}
	if [catch {exec cavput -list=[join $putList ,] -pend=10} result] {
	    return -code error "Error in restoring BPM VMIN: $result"
	}
    }
    set putList ""
    foreach bpm $selectedBPMList {
	lappend putList ${bpm}:BPM.CAVG=$AVG($bpm)
    }
    if [catch {exec cavput -list=[join $putList ,] -pend=10} result] {
	return -code error "Error in restoring BPM VMIN: $result"
    }
    
    if {$statusCallback!=""} {
        $statusCallback "BPM standard configuration restored."
    }       
    return 1
}

# Compose the SDDS self-test data file header.  Returns 1 when finished.


# Acquire the self-test data: compose required cavput and cavget commands and run the self-test.  Returns 1 when finished.
proc AcquireBPMSelfTestData {args} {

    global ControlStatus selectedBPMList SelfTestDataFileRootName SelfTestDataFileName time samples
    global number multiplier MSavg gain abortFlag directory processFlag contentsString system gain

    set number [expr int(pow(2,$MSavg) * $multiplier)]

    APSParseArguments {statusCallback}
    
    set SelfTestSddsmonitorFileName $SelfTestDataFileRootName.[lindex [split $SelfTestDataFileName {.}] 1].mon

    set AcquireDataCommandList ""
    set AcquireDataCommand ""

    if {$statusCallback!=""} {
        $statusCallback "Performing the BPM self-test and acquiring data for selected BPMs..."
    }
    
    #
    if [catch {MakeMonitorFile -filename $SelfTestSddsmonitorFileName} result] {
	return -code error $result
    }
    # for loop to execute $number of self-tests.
    set number [format %.0f [expr $time*60]]
    set sddsMonitorErrorLog /tmp/[APSTmpString]
    set sddsMonitorFileID [open "|sddsmonitor $SelfTestSddsmonitorFileName \
           $SelfTestDataFileName \
           -erase -single=stdout -time=[expr $time * 60] -interval=1 -update=1 2> $sddsMonitorErrorLog" r+]
    set processFlag 1
    set abortFlag 0
    fileevent $sddsMonitorFileID readable \
      "sddsmonitorCallback $sddsMonitorFileID processFlag -statusCallback SetStatus"
    for {set i 0} {$i < $number} {incr i 1} {
        if {$processFlag==1 && $abortFlag==0} {
            tkwait variable processFlag
        }
        set processFlag 1
        update
        after 1000
        update
        if {$abortFlag==1 || $processFlag==-1} {
            set abortNumber [expr $i + 1]
            bell
            break
        } elseif {[expr fmod($i + 1,10)]==0} { 
            if {$statusCallback!=""} {
                $statusCallback "[expr $i + 1] self-tests completed."
            }
            bell
        }
        if {$abortFlag==0} {
            puts $sddsMonitorFileID "y"
            flush $sddsMonitorFileID
        }
        update
    }
    close $sddsMonitorFileID
    if [file size $sddsMonitorErrorLog]!=0 {
        APSFileDisplayWindow [APSUniqueName .] \
          -fileName $sddsMonitorErrorLog -comment "Errors from sddsmonitor process" \
          -deleteOnClose 1 -width 132 -height 30 -printCommand "enscript -r" 
    } else {
        catch {file delete $sddsMonitorErrorLog}
    }
    set PWD [exec pwd]
    cd $directory

    # Record memory scanner average factor and gain mode here.
    # Also, convert to binary to "fix" bug in processing segment of the script.
    if {!$gain} {
        set gainMode "Low"
    } else {set gainMode "High"}
   
    if [catch  {exec sddsprocess $SelfTestDataFileName -nowarning \
		    -print=param,GainMode,$gainMode \
		    -define=par,CollectTime,$time,units=minutes\
		    -define=param,Samples,$samples,type=long \
		    "-print=par,GainModeString,Gain Mode = $gainMode" \
		    "-print=par,CollectTimeString,collecting time = $time minutes" \
		    "-print=par,SamplesString,Samples = $samples" \
		    -print=param,Contents,[APSMakeSafeQualifierString $contentsString]} result] {
        return -code error "$result"
    }
    catch {file delete ${SelfTestDataFileName}~ $SelfTestSddsmonitorFileName}
    exec gzip $SelfTestDataFileName
    set SelfTestDataFileName ${SelfTestDataFileName}.gz
    cd $PWD
    if {$statusCallback!="" && $abortFlag==0} {
        $statusCallback "BPM self-test data acquisition completed.  $number self-tests completed."
    } elseif {$statusCallback!="" && $abortFlag==1} {
        $statusCallback "BPM self-test data acquisition aborted.  $abortNumber self-tests completed."
    }
    return 1
}

# Callback routine for sddsmonitor subprocess in single-shot mode written by M. Borland.

proc sddsmonitorCallback {fid flagVariable args} {
    
    global ControlStatus
    APSParseArguments {statusCallback}
    gets $fid input
    global $flagVariable
    #        puts stderr "[subst \$$flagVariable]  $input"
    if [string compare $input "Type <cr> to read, q to quit:"]==0 {
        set $flagVariable 0
        #                puts stderr "[subst \$$flagVariable]  $input"
        return
    }
    if [string compare $input "Done."]==0 {
        set $flagVariable 2
        #                puts stderr "[subst \$$flagVariable]  $input"
        return
    }
    if [string length $input] {
        # unknown string returned
        set $flagVariable -1
        if {$statusCallback!=""} {
            $statusCallback "Unknown response from sddsmonitor while acquiring data..."
            $statusCallback "$input"
        }
    }
}

# Determines the proper file index for the self test data file based on the most recent version of the file.

proc DetermineMostRecentFileIndex {fileRootName} {

    global MostRecentFileName
    set MostRecentFileName [lindex [lsort -decreasing [glob -nocomplain ${fileRootName}.*]] 0]

    if {$MostRecentFileName!=""} {
        set index [lindex [split $MostRecentFileName .] 1]
    } else {set index [format %03ld 0]}
    return $index
}

# Gets the selected data file using APSFileSelectDialog.  If no file is selected (Cancel is pressed) the procedure
# gets the most recent existing data file.
set CompareDataFileName ""
proc GetSelectedDataFile {args} {
    set compareData 0
    set statusCallback ""

    global SelfTestDataFileName contentsString directory ControlStatus bpmList CompareDataFileName contentsString1 system testMode
    APSParseArguments {statusCallback compareData}
    
    if {$compareData} {
        set fileVar CompareDataFileName
        set contentVar contentsString1
    } else {
        set fileVar  SelfTestDataFileName
        set contentVar contentsString
    }
    set files [lsort -decreasing [glob -nocomplain $directory/${testMode}Data-*.sdds.gz]]
    
    regsub -all $directory/ $files "" files0
    regsub -all {.gz} $files0 "" files
    global fileSelection
    set fileSelection ""
    APSScrolledListWindow .display$system -name "$system file selection" \
        -label "Select a flile"  -acceptButton 0 \
        -itemList $files -selectionVar fileSelection \
        -directory $directory -appendDescription 1 \
        -rootnameOnly 1 -descriptionName Contents 
    tkwait variable fileSelection
    if ![string length $fileSelection] {
        SetStatus "No file is chosen."
        return
    }
    set fileSelection [lindex [lindex $fileSelection 0] 0]
    set $fileVar $directory/${fileSelection}.gz
   
    set file [set $fileVar]
    set ProcessedDataFileFlag [lindex [split $file {.}] 2]
    if {$file!=""} {
        if {$ProcessedDataFileFlag=="Reg" || $ProcessedDataFileFlag=="Hist" || \
                $ProcessedDataFileFlag=="MeanRaw" || $ProcessedDataFileFlag=="FBHist" || \
                $ProcessedDataFileFlag=="FBMeanRaw" || $ProcessedDataFileFlag=="FBReg" || \
                $ProcessedDataFileFlag=="mon"} {
            set $fileVar [join "[lindex [split $file {.}] 0] \
                                                        [lindex [split $file {.}] 1] sdds gz" {.}]
        } else {set $fileVar $file}
    }
   
    if {!$compareData} {
        GetBPMNamesFromSelectedFile -file $file
    }
    if [catch {exec sddsprintout $file -param=Contents} result] {
        if {$statusCallback!=""} {
            $statusCallback "No contents string defined in $file."
        }
        return 0
    } else {
        set $contentVar [exec sdds2stream $file -noquotes -parameter=Contents]
        return 1
    }
}

# This procedure gets bpm names from a selected file
# and selects the bpms on the bpm select widget.
# Returns 1 when completed.

proc GetBPMNamesFromSelectedFile {args} {
    set file ""
    APSParseArguments {file}
    global SelfTestDataFileName directory bpmList system
    set tmpFile /tmp/[APSTmpString]
    APSAddToTempFileList $tmpFile
    if [catch {exec sddsconvert $file -pipe=out -toPage=1 \
                   | sddscollect -pipe=in $tmpFile -collect=suffix=:BPM.VAL } result] {
        return -code error "GetBPMNamesFromSelectedFile: $result while processing $file"
    }
    
    if [catch {APSGetSDDSColumn -fileName $tmpFile -column Rootname} fileBPMList] {
        return -code error "GetBPMNamesFromSelectedFile: $fileBPMList while getting column names"
    }
    catch {file delete $tmpFile}

  
    foreach bpm $bpmList {
	global $bpm
	set $bpm 1
    }
    return 1
}

# This procedure regroups, histograms and collapses the self-test data.  Returns a 1 when finished.  Returns 0 if the
# self-test data file does not exist.

proc RegroupAndHistogramSelfTestData {args} {
    set compareData 0 
    set statusCallback SetStatus
    APSParseArguments {compareData statusCallback}
    
    global SelfTestDataFileName directory system suffixList CompareDataFileName orbitFile system
    
    if $compareData {
        set file $CompareDataFileName
    } else {
        set file $SelfTestDataFileName 
    }
    if {![file exists $file]} {
        SetStatus "Pease select an existing self-test data file." 
        return 0
    }    
    
    set RegroupedDataFileName  \
        [join "[lindex [split $file {.}] 0] . \
             [lindex [split $file {.}] 1] .Reg.sdds" {}]
    
    if {$statusCallback!=""} {
        $statusCallback "Processing $file self-test data file..."
    }       
    
    foreach suffix $suffixList {
        lappend collectOpt -collect=suffix=$suffix
        lappend procOpt -process=$suffix,average,Mean[string range $suffix 1 end]
    }
    if {$system=="linac" || $system=="BB"} {
	#each bpm has corresponding X,Y and SUM
	eval exec sddscollect -pipe=out $file  $collectOpt \
	    | sddsxref -pipe $orbitFile -match=Rootname=BPMName \
	    -take=Index \
	    -reuse=page \
	    | sddsconvert -pipe -rename=col,Index=BPMIndex \
	    | sddssort -pipe -col=BPMIndex,increasing \
	    | sddsregroup -pipe -newParameter=BPMIndex,Rootname \
	    -newColumn=Step \
        | sddsxref -pipe=in $file -nowarnings -transfer=par,* -leave=* $RegroupedDataFileName 
	if {$statusCallback!=""} {
	    $statusCallback "Self-test data file $file processed."
	}
    } else {
	#H bpm only have X and SUM, V bpm only have Y and SUM
	exec sddsconvert $file -pipe=out -retain=col,Step,CAErrors,Time,TimeOfDay,DayofMonth,*H*:BPM* \
	    | sddscollect -pipe -collect=suffix=:BPM.XPOS -collect=suffix=:BPM.VAL \
	    | sddsxref -pipe $orbitFile -match=Rootname=BPMName \
	    -take=Index \
	    -reuse=page \
	    | sddsconvert -pipe -rename=col,Index=BPMIndex \
	    | sddssort -pipe -col=BPMIndex,increasing \
	    | sddsregroup -pipe -newParameter=BPMIndex,Rootname \
	    -newColumn=Step \
	    | sddsxref -pipe=in $file -nowarnings -transfer=par,* -leave=* ${RegroupedDataFileName}.x
	exec  sddsconvert $file -pipe=out -retain=col,Step,CAErrors,Time,TimeOfDay,DayofMonth,*V*:BPM* \
	    | sddscollect -pipe -collect=suffix=:BPM.YPOS -collect=suffix=:BPM.VAL \
	    | sddsxref -pipe $orbitFile -match=Rootname=BPMName \
	    -take=Index \
	    -reuse=page \
	    | sddsconvert -pipe -rename=col,Index=BPMIndex \
	    | sddssort -pipe -col=BPMIndex,increasing \
	    | sddsregroup -pipe -newParameter=BPMIndex,Rootname \
	    -newColumn=Step \
	    | sddsxref -pipe=in $file -nowarnings -transfer=par,* -leave=* ${RegroupedDataFileName}.y
	exec  sddsconvert $file -pipe=out -retain=col,Step,CAErrors,Time,TimeOfDay,DayofMonth,*:BPM.VAL \
	    | sddscollect -pipe  -collect=suffix=:BPM.VAL \
	    | sddsxref -pipe $orbitFile -match=Rootname=BPMName \
	    -take=Index \
	    -reuse=page \
	    | sddsconvert -pipe -rename=col,Index=BPMIndex \
	    | sddssort -pipe -col=BPMIndex,increasing \
	    | sddsregroup -pipe -newParameter=BPMIndex,Rootname \
	    -newColumn=Step \
	    | sddsxref -pipe=in $file -nowarnings -transfer=par,* -leave=* ${RegroupedDataFileName}.sum
	if {$statusCallback!=""} {
	    $statusCallback "Self-test data file $file processed."
	}
    }
    return
    exec sddsmultihist $RegroupedDataFileName -pipe=out \
        -column=:BPM.*       \
        -sizeOfBins=1       \
        -abscissa=RawCounts \
        | sddsxref -pipe=in $RegroupedDataFileName \
        $HistogramDataFileName \
        -transfer=param,BPMIndex,Rootname,Mean*,SelfTestNumber,GainMode \
        -leave=*

    exec sddscollapse $HistogramDataFileName  -pipe=out -nowarnings \
	| sddsprocess -pipe=in $MeanRawDataFileName \
	"-print=param,SelfTestNumberString,Self-Test Number = $SelfTestNumber,type=string" \
	"-print=param,MSBoxAvgWtString,Memory Scanner Avg = $MSBoxCarAverage,type=string" \
	"-print=param,MultiplierString,Self-Test Multiplier = $MultFactor,type=string" \
	"-print=param,GainModeString,Gain Mode = $GainMode,type=string"
    
   
    if {$statusCallback!=""} {
        $statusCallback "Self-test data file $file processed."
    }       
    bell
    return 1
}       

proc CompareBPMSelfTestData {args} {
    
    global SelfTestDataFileRootName SelfTestDataFileName system CompareDataFileName
    global dataFlag histFlag averageFlag xMin xMax yMin yMax sumMin sumMax

    if ![string length $CompareDataFileName] {
        return -code error "Compare data file is not provided."
    }
    if {([regexp {SelfTest} $CompareDataFileName] && ![regexp {SelfTest} $SelfTestDataFileName]) || \
	    ([regexp {NoiseTest} $CompareDataFileName] && ![regexp {NoiseTest} $SelfTestDataFileName])} {
	return -code error "Two different test mode files selected."
    }
    
    foreach file [list $CompareDataFileName $SelfTestDataFileName] flag {1 2} {
        set fileIndex$flag [lindex [split $file {.}] 1]
        set rootname$flag [lindex [split $file {.}] 0]
        
        set RegroupedFileName$flag \
            [join "[lindex [split $file {.}] 0] . [lindex [split $file {.}] 1] .Reg.sdds" {}]
	
	foreach type {X Y Sum} chan {x y sum} {
	    if [file exists [set RegroupedFileName$flag].$chan] {
		set ${type}File$flag [set RegroupedFileName$flag].$chan
	    } elseif [file exists [set RegroupedFileName$flag]] {
		set ${type}File$flag [set RegroupedFileName$flag]
	    } else {
		SetStatus "Self-test data file $file must be processed\n(or collected) \
                                         before plotting."
		return
	    }
	}
	
    }
    
    SetStatus "Plotting self-test data file $SelfTestDataFileName with $CompareDataFileName ..."
    set sumscale 0
   
    foreach flag {1 2} color {0 1} coord {0.05 0.5} {
	set stringOpt$flag "-string=@CollectTimeString,p=$coord,q=0.9,line=$color -string=@SamplesString,p=$coord,q=0.85,line=$color -string=@GainMode,p=$coord,q=0.8,line=$color"
    }
    set plotOpt "-layout=3,3 -labelsize=0.03 -enumeratedScales=interval=9 \
            -legend=file,edit=1Z-%/.FBReg.sdds//%/.Reg.sdds//  -split=page -groupby=page -sep=page \
            -graph=line,vary -ylabel=edit=%/:BPM.YPOS/Y/%/:BPM.XPOS/X/%/:BPM.VAL/SUM/"
   
    set plotOptX $plotOpt
    set plotOptY $plotOpt
    set plotOptSum $plotOpt
    foreach col {:BPM.XPOS :BPM.YPOS :BPM.VAL} {
	if [regexp {XPOS} $col] {
	    set type X
	} elseif [regexp {YPOS} $col] {
	    set type Y
	} elseif [regexp {VAL} $col] {
	    set type Sum
	} else {
	    continue
	}
	lappend plotOpt$type \"-topline=BPM $type Position vs. Self-Test Number\"
	lappend plotOpt$type "-col=Step,$col [set ${type}File1] $stringOpt1" 
	lappend plotOpt$type "-col=Step,$col [set ${type}File2] $stringOpt2" 
	lappend plotOpt$type -end
    }
    eval exec sddsplot -title=@Rootname -scale=0,0,$xMin,$xMax [join $plotOptX] &
    eval exec sddsplot -title=@Rootname -scale=0,0,$yMin,$yMax [join $plotOptY] &
    eval exec sddsplot -title=@Rootname -scale=0,0,$sumMin,$sumMax [join $plotOptSum] &
    
}

# Plot out the results of a given self-test data file.  Returns 0 if the required processed data files do not 
# exist or all plotting flags are set to 0.  and gives an error message.  Returns 1 if the processed data files 
# exist and plots the results.
# Before returning, the procedure sets the plot request flags to their default.

proc PlotBPMSelfTestData {args} {

    global SelfTestDataFileRootName SelfTestDataFileName system sumMin sumMax xMin xMax yMin yMax
    global dataFlag histFlag averageFlag

    APSParseArguments {statusCallback}

    set fileIndex [lindex [split $SelfTestDataFileName {.}] 1]
    set CurrentSelfTestDataFileRootName [lindex [split $SelfTestDataFileName {.}] 0]

    set SelfTestRegroupedDataFileName \
      [join "[lindex [split $SelfTestDataFileName {.}] 0] . \
      [lindex [split $SelfTestDataFileName {.}] 1] .Reg.sdds" {}]
   
    if {[glob -nocomplain $CurrentSelfTestDataFileRootName.${fileIndex}.Reg.sdds*]==""} {
        if {$statusCallback!=""} {
            $statusCallback "Self-test data file $SelfTestDataFileName must be processed\n(or collected) \
                                         before plotting."
        } 
        return 0
    }
    if [file exist ${SelfTestRegroupedDataFileName}.x] {
	set xFile ${SelfTestRegroupedDataFileName}.x
    } elseif [file exist $SelfTestRegroupedDataFileName] {
	set xFile $SelfTestRegroupedDataFileName
    } else {
	if {$statusCallback!=""} {
            $statusCallback "Self-test data file $SelfTestDataFileName must be processed\n(or collected) \
                                         before plotting."
        } 
        return 0
    }
    if [file exist ${SelfTestRegroupedDataFileName}.y] {
	set yFile ${SelfTestRegroupedDataFileName}.y
    } elseif [file exist $SelfTestRegroupedDataFileName] {
	set yFile $SelfTestRegroupedDataFileName
    } else {
	if {$statusCallback!=""} {
            $statusCallback "Self-test data file $SelfTestDataFileName must be processed\n(or collected) \
                                         before plotting."
        } 
        return 0
    }
    if [file exist ${SelfTestRegroupedDataFileName}.sum] {
	set sumFile ${SelfTestRegroupedDataFileName}.sum
    } elseif [file exist $SelfTestRegroupedDataFileName] {
	set sumFile $SelfTestRegroupedDataFileName
    } else {
	if {$statusCallback!=""} {
            $statusCallback "Self-test data file $SelfTestDataFileName must be processed\n(or collected) \
                                         before plotting."
        } 
        return 0
    }
    if {$statusCallback!=""} {
        $statusCallback "Plotting self-test data file $SelfTestDataFileName..."
    }
    set sumscale 0
    set filenameString [file tail $SelfTestRegroupedDataFileName]
    set clip 0
   
    catch {exec sddsplot -labelsize=0.03 -layout=2,2  -clip=$clip,$clip -legend=yname,edit=%/:BPM.XPOS/X/ \
	       -scale=0,0,$xMin,$xMax \
	       -split=page -groupby=page -sep=page "-title=@Rootname" \
	       -graph=line,vary $xFile \
	       -col=Step,*XPOS \
	       -string=@CollectTimeString,p=0.05,q=0.9 \
	       -string=@SamplesString,p=0.05,q=0.85 \
	       -string=@GainModeString,p=0.05,q=0.8 \
	       -string=[file tail $xFile],p=0.05,q=0.76 \
	       "-topline=BPM X Position vs Self-Test Number" \
	       "-ylabel=RawCounts" &} result
    
    catch {exec sddsplot -labelsize=0.03 -layout=2,2  -clip=$clip,$clip -legend=yname,edit=%/:BPM.YPOS/Y/ \
	       -scale=0,0,$yMin,$yMax \
	       -split=page -groupby=page -sep=page "-title=@Rootname" \
	       -graph=line,vary $yFile \
	       -col=Step,*YPOS \
	       -string=@CollectTimeString,p=0.05,q=0.9 \
	       -string=@SamplesString,p=0.05,q=0.85 \
	       -string=@GainModeString,p=0.05,q=0.8 \
	       -string=[file tail $yFile],p=0.05,q=0.76 \
	       "-topline=BPM Y Position vs Self-Test Number" \
	       "-ylabel=RawCounts" &} result
    
    catch {exec sddsplot -labelsize=0.03 -layout=3,3  -clip=$clip,$clip -scale=0,0,0,$sumscale \
	       -scale=0,0,$sumMin,$sumMax \
	       -legend=spec=SUM \
	       -split=page -groupby=page -sep=page "-title=@Rootname" \
	       -graph=line,vary $sumFile \
	       -col=Step,*VAL \
	       -string=@CollectTimeString,p=0.05,q=0.9 \
	       -string=@SamplesString,p=0.05,q=0.85 \
	       -string=@GainModeString,p=0.05,q=0.8 \
	       -string=[file tail $sumFile],p=0.05,q=0.76 \
	       "-topline=BPM Sum Data vs Self-Test Number" \
	       "-ylabel=RawCounts" &} result
    
    if {$statusCallback!=""} {
        $statusCallback "Plotting for data file $SelfTestDataFileName completed."
    }
    return 1
}


# This procedure removes processed data files (*Reg*, *Hist*, and *MeanRaw*) for a given self-test measurement.
# Returns 0 if no such files are found, returns 1 after removing the files.

proc CleanupProcessedBPMDataFiles {args} {

    global SelfTestDataFileRootName SelfTestDataFileName

    APSParseArguments {statusCallback}

    set fileIndex [lindex [split $SelfTestDataFileName {.}] 1]
    
    set SelfTestRegroupedDataFileName \
      [join "[lindex [split $SelfTestDataFileName {.}] 0] . \
      [lindex [split $SelfTestDataFileName {.}] 1] .Reg.sdds" {}]
    set SelfTestMeanRawDataFileName \
      [join "[lindex [split $SelfTestDataFileName {.}] 0] . \
      [lindex [split $SelfTestDataFileName {.}] 1] .MeanRaw.sdds" {}]

    # Check to see that the file contains more bpm pvs than the A:P2s.  The A:P2s do not have feedback PVs
    # defined so the following processing would generate an error.

    set colList [APSGetSDDSNames -fileName ${SelfTestDataFileName} -class column]
    set onlyAP2Flag [lsearch -glob $colList *FBMS*]


    if {$statusCallback!=""} {
        $statusCallback "Deleting processed files and sddsmonitor input file for data file \
                                 $SelfTestDataFileName..."
    }
    
    if {[glob -nocomplain $SelfTestDataFileRootName.${fileIndex}.Reg.sdds]=="" && 
        [glob -nocomplain $SelfTestDataFileRootName.${fileIndex}.Hist.sdds]=="" && 
        [glob -nocomplain $SelfTestDataFileRootName.${fileIndex}.MeanRaw.sdds]==""} {
        if {$statusCallback!=""} {
            $statusCallback "No processed files and/or sddsmonitor input file found for \
                                         $SelfTestDataFileName."
        }
        bell
        return 0
    }

    catch {file delete $SelfTestRegroupedDataFileName $SelfTestHistogramDataFileName \
             $SelfTestMeanRawDataFileName}
    
   
    if {$statusCallback!=""} {
        $statusCallback "Processed data files and/or sddsmonitor input file for $SelfTestDataFileName deleted."
    }

    bell
    return 1
}

# Procedure to update data file contents description.  Returns 1 when completed.
# Returns 0 if file does not exists.

proc UpdateDataFileContents {args} {

    global SelfTestDataFileName directory contentsString
    APSParseArguments {statusCallback}

    if {![file exists $SelfTestDataFileName]} {
        if {$statusCallback!=""} {
            $statusCallback "Please select an existing self-test data file."
        }
        bell
        return 0
    }

    if [catch {exec sddsprocess $SelfTestDataFileName ${directory}/tmpFile -reprint=param,Contents,[APSMakeSafeQualifierString $contentsString]
        exec gzip ${directory}/tmpFile
        eval file delete ${SelfTestDataFileName} ${directory}/tmpFile
        file rename ${directory}/tmpFile.gz $SelfTestDataFileName} result] {
        return -code error "$result"
    }
    
    if {$statusCallback!=""} {
        $statusCallback "File $SelfTestDataFileName contents string updated."
    }
    return 1
}

# Procedure to set the abortFlag to 1 when the abort button is pressed.  It also sets the processFlag to 0 in 
# case the loop is hung up on the tkwait command with processFlag stuck at a value of 1.
# returns 1 when completed
set processFlag -1
proc SetFlagsOnAbort {} {

    global abortFlag processFlag

    set abortFlag 1

    if {$processFlag==1} {
        set processFlag 0
    } elseif {$processFlag==0} {
        set processFlag 1
    } elseif {$processFlag==-1} {
        set processFlag 0
    }
    return 1
}

proc SelectAll {args} {
    set all 1
    APSParseArguments {all}
    global bpmList
    eval global $bpmList
    foreach bpm $bpmList {
	set $bpm $all
    }
}

set testMode SelfTest
proc UpdateTestMode {args} {
    global testMode SelfTestDataFileRootName MostRecentFileName SelfTestDataFileName directory fileWidth
    set SelfTestDataFileRootName $directory/${testMode}Data-[clock format [clock seconds] -format %Y-%m-%d]
    scan [DetermineMostRecentFileIndex $SelfTestDataFileRootName] fileIndex
    incr fileIndex
    set fileIndex [format %03ld $fileIndex]
    if {$MostRecentFileName==""} {
        set fileIndex [DetermineMostRecentFileIndex $SelfTestDataFileRootName]
    }
    set SelfTestDataFileName ${SelfTestDataFileRootName}.${fileIndex}.sdds
    
}

proc MakeBPMSelectionWidget {widget args} {
    set parent ""
    set limitPerRow 5
    APSParseArguments {parent limitPerRow}
    APSFrame $widget -parent $parent
    set w1 $parent$widget.frame
    global bpmList fileWidth
    eval global $bpmList
    APSCheckButtonFrame .bpmsel -parent $w1 -label "Select BPM:" -allNone 1 \
	-buttonList $bpmList -variableList $bpmList -orientation vertical \
	-limitPerRow $limitPerRow
    
   # APSButton .all1 -parent $w1 -text "Select All" -command "SelectAll -all 1"
  #  APSButton .none -parent $w1 -text "Select None" -command "SelectAll -all 0" 
}

set time 2
set samples 2
proc MakeOptionsWidget {widget args} {
    set parent ""
    APSParseArguments {parent}
    APSFrame $widget -parent $parent
    set w1 $parent$widget.frame
    global time samples SelfTestDataFileName SelfTestDataFileRootName gain MostRecentFileName directory testMode gain
    set fileWidth 80
    APSRadioButtonFrame .type -parent $w1 -label "Test mode:" -buttonList {Self_Test Noise_Test} \
	-variable testMode -valueList {SelfTest NoiseTest} -orientation horizontal -commandList {UpdateTestMode UpdateTestMode}  \
	-contextHelp "for self_test, the BPM gain is set to low, and mode in Test mode; for Noise_test, bpm gain is low, but mode is Normal."
    APSLabeledEntry .time -parent $w1 -label "Collecting time (minutes):" -textVariable time -width 30
    APSLabeledEntry .sample -parent $w1 -label "Samples:" -textVariable samples -width 30
    APSRadioButtonFrame .gainFrame -parent $w1 -label "BPM Gain Mode" \
      -packOption {-side top} \
	-variable gain \
	-buttonList {Low High} \
	-valueList {0 1} \
	-orientation horizontal \
	-contextHelp "This button selects the BPM gain mode.  In High gain mode smaller position changes  can be detected than in Low gain mode."
    APSLabeledEntryFrame .x -parent $w1 -label "X plot range start/end" -variableList {xMin xMax} -orientation horizontal -width 20
    APSLabeledEntryFrame .y -parent $w1 -label "Y plot range start/end" -variableList {yMin yMax} -orientation horizontal -width 20
    APSLabeledEntryFrame .sum -parent $w1 -label "Sum plot range start/end" -variableList {sumMin sumMax} -orientation horizontal -width 20
    set year ""
    set month ""
    set day ""
    APSDateBreakDown -monthVariable month -yearVariable year -twoDigitYear 0 -dayVariable day   
    
    set SelfTestDataFileRootName ${directory}/${testMode}Data-$year-$month-${day}
    set fileIndex [DetermineMostRecentFileIndex $SelfTestDataFileRootName]
    set SelfTestDataFileName ${SelfTestDataFileRootName}.${fileIndex}.sdds
    
    APSLabeledOutput .data1 -parent $parent -width $fileWidth \
        -textVariable CompareDataFileName \
        -packOption {-side top -fill x} \
		-label "Comparing Data Filename:" \
        -contextHelp "Filename for comparing with following file in the plot."
    APSButton .sel -parent $parent.data1 -text "Select" -size small \
        -packOption "-side right" \
        -command "GetSelectedDataFile -compareData 1"
    APSButton .proc -parent $parent.data1 -text "Process" -size small \
        -packOption "-side right" \
        -command "RegroupAndHistogramSelfTestData -compareData 1"
    
    APSLabeledEntry .dataContentsFrame1 -parent $parent -width $fileWidth \
      -textVariable contentsString1 \
      -packOption {-side top -fill x} \
		-label "Compare Data Description:  " \
      -contextHelp "Filename contents containing a description of the self-test data present in the compare data file."


    APSLabeledOutput .dataFileFrame -parent $parent -width $fileWidth \
        -textVariable SelfTestDataFileName \
        -packOption {-side top -fill x} \
		-label "Self Test Data Filename:  " \
        -contextHelp "Filename containing the SCDU, MS, and BPLD self test data."

    APSButton .sel1 -parent $parent.dataFileFrame -text "Select" -size small \
        -packOption "-side right" \
        -command "GetSelectedDataFile -compareData 0"
    APSButton .proc1 -parent $parent.dataFileFrame -text "Process" -size small \
        -packOption "-side right" \
        -command "RegroupAndHistogramSelfTestData -compareData 0"
    
    APSLabeledEntry .dataContentsFrame -parent $parent -width $fileWidth \
      -textVariable contentsString \
      -packOption {-side top -fill x} \
		-label "Self Test Data Description:  " \
      -contextHelp "Filename contents containing a description of the self-test data present in the file."

   
    APSFrame .plotFrame -parent $parent \
        -height 30 \
        -packOption {-side top -expand 1}
    APSButton .compare -parent $parent.plotFrame.frame \
        -text "Compare" \
        -command {CompareBPMSelfTestData -statusCallback SetStatus} \
        -packOption {-side left -fill x} \
        -contextHelp "This button compares the self test data file with compare data file with plots."
    APSButton .plotSelectionFrame -parent $parent.plotFrame.frame \
      -text "Plot" \
      -command {PlotBPMSelfTestData -statusCallback SetStatus} \
      -packOption {-side left -fill x} \
      -contextHelp "This button plots the data acquired for the selected data file."

}


#execution starts here
set system linac
set args $argv
APSStrictParseArguments {system}
set sumMin 0
set sumMax 0.5
set xMin -2
set xMax 2
set yMin -2
set yMax 2
set fileWidth 80
switch $system {
    linac {
	set sumMin 0
	set sumMax 0.5
	set xMin -3
	set xMax 3
	set yMin -3
	set yMax 3
    }
    BTS {
	set sumMin 0
	set sumMax 20
	set xMin -2
	set xMax 2
	set yMin -2
	set yMax 2
    }
    PTB {
	set sumMin 0
	set sumMax 0.5
	set xMin -5
	set xMax 5
	set yMin -6
	set yMax 6
    }
    LTP {
	set sumMin 0
	set sumMax 20
	set xMin -5
	set xMax 5
	set yMin -6
	set yMax 6
    }
    BB {
	set sumMin 0
	set sumMax 20
	set xMin -2
	set xMax 2
	set yMin -2
	set yMax 2
	#ok
    }
    default {
	puts stderr "Unknowm system - $system provided."
	exit 1
    }
}
set limitPerRow 2
set suffixList {:BPM.YPOS :BPM.XPOS :BPM.VAL}

set directory $mainDir/$system
set orbitFile $mainDir/${system}.req

MakeSRBPMCheckoutStatusWidget .userFrame  -system $system

if [catch {exec sddsprocess $orbitFile -pipe=out -match=col,ControlName=*BPM.VAL \
	       | sdds2stream -pipe -col=BPMName} bpmList] {
    puts stderr $bpmList
    exit 1
}
set bpmList [join $bpmList]

foreach bpm $bpmList {
    set $bpm 1
}
if [catch {exec cavget -list=[join $bpmList ,] -list=:BPM.VMIN -pend=10} valList] {
    puts stderr "Error in reading VMIN: $result"
    exit 1
}

foreach bpm $bpmList val $valList {
    set VMIN($bpm) $val
}
if [catch {exec cavget -list=[join $bpmList ,] -list=:BPM.CAVG -pend=10} valList] {
    puts stderr "Error in reading VMIN: $result"
    exit 1
}
foreach bpm $bpmList val $valList {
    set AVG($bpm) $val
}

    
MakeBPMSelectionWidget .bpmSel -parent .userFrame -limitPerRow $limitPerRow 
MakeOptionsWidget .opt -parent .userFrame
#MakeLabelledEntryWidgets .labelledEntries -parent .userFrame -fileWidth $fileWidth -system $system
#APSRadioButtonFrame .type -parent .userFrame -label "Test mode:" -buttonList {Self_Test Noise_Test} \
#	-variable testMode -valueList {SelfTest NoiseTest} -orientation horizontal -commandList {UpdateTestMode UpdateTestMode}  \
#	-contextHelp "for self_test, the BPM gain is set to low, and mode in Test mode; for Noise_test, bpm gain is low, but mode is Normal."
MakeSRBPMSelfTestWidget .selfTestWidgets -parent .userFrame -system $system

# Local Variables:
# mode: tcl
# End:
