#!/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.1 $ \$Author: borland $"

#
# $Log: not supported by cvs2svn $
#

set directory /home/helios/oagData/booster/MSSetpoints
#set directory /tmp

set timingCardList {1_8 9_16 17_24 25_32 33_40 41_48 49_56 57_64 65_72 73_77 78_80}

set ControlStatus "Ready."

#Make application and status window widgets.  Returns 1 when completed.

proc MakeStatusWidget {widget args} {

    global ControlStatus CVSRevisionAuthor
    set parent ""
    APSStrictParseArguments {parent}
    APSApplication . -name "Booster Closed Orbit to Memory Scanner Setpoints Application" \
      -overview "This application measures booster closed orbit and transfers it to memory scanner setpoints." \
      -version $CVSRevisionAuthor
    
    set w $parent$widget
    APSScrolledStatus .status -parent $w -withButtons 1 -textVariable ControlStatus -width 95 -packOption {-side top}
    return 1
}

# This procedure sets up widgets for this application.  Returns 1 when completed.

proc ApplicationWidgets {widget args} {

    global directory ClosedOrbitFilename ClosedOrbitCompareFilename CombinedClosedOrbitCompareFilename 
    global ClosedOrbitFilenameTail ClosedOrbitCompareFilenameTail CombinedClosedOrbitCompareFilenameTail 
    global NDelay MDelay NTurns MTurns MSAvgFactor
    
    set parent ""
    APSStrictParseArguments {parent}
    
#    SetNMDelay
#    SetMSAvgFactor -statusCallback SetStatus

    APSFrame $widget -parent $parent \
      -height 30 \
      -packOption {-side top -expand 1}

    set w $parent$widget.frame

    APSLabeledOutput .nDelayFrame -parent $w -width 5 \
      -textVariable NDelay \
      -packOption {-side top -fill x} \
      -label "BPM delay = 4 x N x (revolution period) (ms)" \
      -contextHelp "Time to delay bpm data acquisition = 4 x N x (revolution period)."

    APSLabeledOutput .mDelayFrame -parent $w -width 5 \
      -textVariable MDelay \
      -packOption {-side top -fill x} \
      -label "MS average time = 4 x M x (revolution period) (ms)" \
      -contextHelp "Time bpm memory scanners average over = 4 x M x (revolution period)."

    APSLabeledEntry .nTurnsFrame -parent $w -width 5 \
      -textVariable NTurns \
      -packOption {-side top -fill x} \
      -label "BPM delay N (turns)" \
      -contextHelp "Time to delay bpm data acquisition = 4 x N."
    bind $w.nTurnsFrame.entry <Return> "SetNMDelay"

    APSLabeledEntry .mTurnsFrame -parent $w -width 5 \
      -textVariable MTurns \
      -packOption {-side top -fill x} \
      -label "MS average time M (turns)" \
      -contextHelp "Time bpm memory scanners average over = 4 x M."
    bind $w.mTurnsFrame.entry <Return> "SetNMDelay"

    APSLabeledEntry .msAvgFactorFrame -parent $w -width 5 \
      -textVariable MSAvgFactor \
      -packOption {-side top -fill x} \
      -label "MS average factor (2^factor)" \
      -contextHelp "BPM memory scanners average factor."
    bind $w.msAvgFactorFrame.entry <Return> "SetMSAvgFactor -statusCallback SetStatus"

    APSButton .setNMTiming -parent $w \
      -text "Set BPM Timing" \
      -command {SetTCNMValues -statusCallback SetStatus} \
      -packOption {-side top} \
      -contextHelp "This button sets the booster BPM timing defined by the integers N and M."

    APSFrame .fileOutputFrame -parent $parent \
      -height 30 \
      -packOption {-side top -expand 1}

    set filew $parent.fileOutputFrame.frame

    APSLabeledOutput .closedOrbitFileFrame -parent $filew -width 70 \
      -textVariable ClosedOrbitFilenameTail \
      -packOption {-side top -fill x} \
      -label "Closed Orbit Filename" \
      -contextHelp "Filename containing averaged closed orbit."

    APSLabeledOutput .closedOrbitCompareFileFrame -parent $filew -width 70 \
      -textVariable ClosedOrbitCompareFilenameTail \
      -packOption {-side top -fill x} \
      -label "Comparison Closed Orbit filename" \
      -contextHelp "Filename containing averaged closed orbit to compare to."

    APSLabeledOutput .combinedClosedOrbitCompareFileFrame -parent $filew -width 70 \
      -textVariable ClosedOrbitCombinedFilenameTail \
      -packOption {-side top -fill x} \
      -label "Combined Closed Orbit filename" \
      -contextHelp "Filename containing the combined (processed) closed orbit and comparison files."

    APSFrame .acquireTransferFrame -parent $parent -label "Closed Orbit Acquisition, Transfer and Comparison" \
      -height 30 \
      -packOption {-side top -expand 1}

    set buttonw $parent.acquireTransferFrame.frame

    APSButton .acquireClosedOrbitButton -parent $buttonw \
      -text "Acquire Closed Orbit" \
      -command {AcquireClosedOrbit -statusCallback SetStatus} \
      -packOption {-side left -fill x} \
      -contextHelp "This button invokes a procedure that acquires the closed orbit at time specified by the integers N and M."

    APSButton .transferClosedOrbitButton -parent $buttonw \
      -text "Transfer Closed Orbit to Memory Scanner Setpoints" \
      -command {TransferClosedOrbitToMSSetpoints -statusCallback SetStatus} \
      -packOption {-side left -fill x} \
      -contextHelp "This button invokes a procedure that transfers a previously measured closed orbit at time specified by the integers N and M to memory scanner setpoints for use with sddscontrollaw."

    APSButton .compareSelectionsFrame -parent $buttonw \
      -text "Take Difference" \
      -command {CompareClosedOrbitData -statusCallback SetStatus} \
      -packOption {-side top -fill x} \
      -contextHelp "This button plots the difference between the measured closed orbit of two user specified data files."

    APSFrame .fileSelectFrame -parent $parent  -label "File Selection" \
      -height 30 \
      -packOption {-side top -expand 1}

    set fileSelectw $parent.fileSelectFrame.frame

    APSButton .closedOrbitFileSelectionFrame -parent $fileSelectw \
      -text "Closed Orbit File..." \
      -command {GetSelectedDataFile closed -statusCallback SetStatus} \
      -packOption {-side left -fill x} \
      -contextHelp "This button pops up a dialog box to select a closed orbit data file for transfer to memory scanner setpoints \
or comparison."

    APSButton .closedOrbitComparisonFileSelectionFrame -parent $fileSelectw \
      -text "Comparison File..." \
      -command {GetSelectedDataFile compare -statusCallback SetStatus} \
      -packOption {-side left -fill x} \
      -contextHelp "This button pops up a dialog box to select a closed orbit data file for comparison."

    APSButton .closedOrbitCombinedFileSelectionFrame -parent $fileSelectw \
      -text "Difference File..." \
      -command {GetSelectedDataFile combined -statusCallback SetStatus} \
      -packOption {-side left -fill x} \
      -contextHelp "This button pops up a dialog box to select a combined (processed) closed orbit data file \
                    and comparison file."

    APSFrame .plotFrame -parent $parent -label "Plotting" \
      -height 30 \
      -packOption {-side top -expand 1}

    set plotw $parent.plotFrame.frame

    APSButton .plotSelectionFrame -parent $plotw \
      -text "Plot Closed Orbit" \
      -command {PlotClosedOrbitData closedOrbit -statusCallback SetStatus} \
      -packOption {-side left -fill x} \
      -contextHelp "This button plots the data acquired for the selected data file."

    APSButton .plotComparisonSelectionFrame -parent $plotw \
      -text "Plot Difference" \
      -command {PlotClosedOrbitData compare -statusCallback SetStatus} \
      -packOption {-side left -fill x} \
      -contextHelp "This button plots the data acquired for the selected data file."

    return 1
}

# This procedure sets the timing card NTurns and MTurns values which define at what time in the ramp to take the closed
# orbit and how many turns to average respectively.  Returns 1 when completed.

proc SetTCNMValues {args} {

    global ControlStatus NTurns MTurns NDelay MDelay
    APSStrictParseArguments {statusCallback}
    
    set NTurns [expr int($NTurns)]
    set MTurns [expr int($MTurns)]

    SetNMDelay

# Set global timing card variables to the "golden" values.

    set Glb36 0.29588
    set Glb94 0.29720

    exec cavput -list=It:Ddg3chan6.DLY=$Glb36 -pendIoTime=3
    exec cavput -list=It:Ddg9chan4.DLY=$Glb94 -pendIoTime=3

    if {$statusCallback!=""} {
        $statusCallback "Setting N delay to $NTurns turns (actual delay is [expr 4 * $NTurns] turns).  This corresponds to [format %0.3f $NDelay] ms after the booster IP..."
    }

    if {[catch {eval exec [ComposeTCCavputCavgetCommand cavput Delay_count_lo $NTurns]}]} {
        $statusCallback "Channel access error(s) occurred while setting N to $NTurns.  Checking timing card N parameters..."
        set NTurnsValueList [eval exec [ComposeTCCavputCavgetCommand cavget Delay_count_lo $NTurns]]
        PrintTCListNotSetProperly N $NTurns $NTurnsValueList -statusCallback SetStatus
    } else {
        $statusCallback "Checking each timing card to see that N is set to $NTurns..."
        set NTurnsValueList [eval exec [ComposeTCCavputCavgetCommand cavget Delay_count_lo $NTurns]]
        PrintTCListNotSetProperly N $NTurns $NTurnsValueList -statusCallback SetStatus
    }

    if {$statusCallback!=""} {
        $statusCallback "Setting M to $MTurns...  The bpm memory scanners will average [expr 4 * $MTurns] turns or [format %0.3f $MDelay] ms..."
    }

    if {[catch {eval exec [ComposeTCCavputCavgetCommand cavput Cycle_count_lo $MTurns]}]} {
        $statusCallback "Channel access error(s) occurred while setting M to $MTurns.  Checking timing card M parameters..."
        set MTurnsValueList [eval exec [ComposeTCCavputCavgetCommand cavget Cycle_count_lo $MTurns]]
        PrintTCListNotSetProperly M $MTurns $MTurnsValueList -statusCallback SetStatus
    } else {
        $statusCallback "Checking each timing card to see that M is set to $MTurns..."
        set MTurnsValueList [eval exec [ComposeTCCavputCavgetCommand cavget Cycle_count_lo $MTurns]]
        PrintTCListNotSetProperly M $MTurns $MTurnsValueList -statusCallback SetStatus
    }
    return 1
}

# This procedure sets the status variable used by the status widget. Returns 1 when completed.

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

# Procedure sets the N and M delay variables used in the labelled output boxes. Returns 1.

proc SetNMDelay {} {

    global NTurns MTurns NDelay MDelay

    set NDelay [expr $NTurns * 4 * 0.001228]                 
    set MDelay [expr $MTurns * 4 * 0.001228]                 
    return 1
}

# This procedure sets the average factor for the bpms.  Returns 0 if the factor is not between
# 2 and 11 inclusive.

proc SetMSAvgFactor {args} {

    global MSAvgFactor ControlStatus
    APSStrictParseArguments {statusCallback}

    if {$MSAvgFactor < 2 || $MSAvgFactor > 11} {
        if {$statusCallback!=""} {
            $statusCallback "The MS avgerage factor must be an integer from 2 to 11 inclusive."
            return 0
        }
    } else {
        exec cavput -list=B:bpm:memscan_wt_ao.VAL=$MSAvgFactor -pendIOTime=20
        return 1
    }
}

# Composes a cavput (cavget) command for bpm timing card delay variables specified by integers N and M.
# Returns the command.

proc ComposeTCCavputCavgetCommand {action pvNameString pvCommand} {

    global timingCardList 
    if {$action=="cavput"} {
        set Command "cavput -list=B:bpmT -list=[join $timingCardList ,] -list=:$pvNameString=$pvCommand -pendIOTime=10"
    } elseif {$action=="cavget"} {
        set Command "cavget -list=B:bpmT -list=[join $timingCardList ,] -list=:$pvNameString -pendIOTime=10 -errorValue=-999"
    }
    return $Command
}

# This procedure checks to see if a list of values (valueList) contains identical values given by valueToCheck.
# Returns an error list for each item in valueList if errors are detected.  If no errors are detected it returns 0. 
# Used to make sure N and M timing card delay values were all set to the same, specified value.

proc CheckListOfValues {valueToCheck valueList} {

    set error 0
    set errorList ""
    foreach value $valueList {
        if {![string compare $value $valueToCheck]} {
            lappend errorList 0
        } else {
            set error 1
            lappend errorList 1
        }
    }
        if {$error} {
            return $errorList
        } else {return 0}
}

# This procedure makes a list of timing cards which were not properly set to the requested N or M value.
# Returns 1 when completed.

proc PrintTCListNotSetProperly {variable valueToCheck valueList args} {

    global timingCardList ControlStatus
    APSStrictParseArguments {statusCallback}
    set errorList [CheckListOfValues $valueToCheck $valueList]
    set TCErrorList ""
    set index 0
    foreach value $errorList {
        if {![string compare $value 1]} {
            lappend TCErrorList [lindex $timingCardList $index]
        }
        incr index
    }
    
    if {$statusCallback!="" && [llength $TCErrorList]!=0} {
        $statusCallback "Timing Cards $TCErrorList not set for desired value of ${variable}."
        APSAlertBox .alert -errorMessage "Error:  timing card $variable values for timing cards $TCErrorList not set properly."
    } else {
        $statusCallback "Timing cards are set to the desired value of ${variable}."
    }
    return 1
}

# This procedure composes the name of the closed orbit filename available for data acquisition.  Returns 1 when
# completed.

proc SetClosedOrbitOutputFilename {whichIndex} {

    global directory ClosedOrbitFilename CollectedClosedOrbitFilename ClosedOrbitFileRootName 
    global ClosedOrbitFilenameTail 
    global ClosedOrbitXBurtFilename ClosedOrbitYBurtFilename ClosedOrbitBurtFilename

    set todayDate [APSOffsetDateInfo -today 1 -dateFormat Y-M-D]

    set ClosedOrbitFileRootName ${directory}/ClosedOrbit-${todayDate}
    if {![string compare $whichIndex MostRecent]} {
        set fileIndex [DetermineMostRecentFileIndex $ClosedOrbitFileRootName]
        set ClosedOrbitFilename ${ClosedOrbitFileRootName}.${fileIndex}.sdds
        set ClosedOrbitFilenameTail [file tail $ClosedOrbitFilename]
        set CollectedClosedOrbitFilename ${ClosedOrbitFileRootName}.Col.${fileIndex}.sdds
        set ClosedOrbitXBurtFilename ${ClosedOrbitFileRootName}.XBurt.${fileIndex}.sdds
        set ClosedOrbitYBurtFilename ${ClosedOrbitFileRootName}.YBurt.${fileIndex}.sdds
        set ClosedOrbitBurtFilename ${ClosedOrbitFileRootName}.Burt.${fileIndex}.snp
    } elseif {![string compare $whichIndex Next]} {
        set fileIndex [DetermineFirstFreeFileIndex $ClosedOrbitFileRootName]
        set ClosedOrbitFilename ${ClosedOrbitFileRootName}.${fileIndex}.sdds
        set ClosedOrbitFilenameTail [file tail $ClosedOrbitFilename]
        set CollectedClosedOrbitFilename ${ClosedOrbitFileRootName}.Col.${fileIndex}.sdds
        set ClosedOrbitXBurtFilename ${ClosedOrbitFileRootName}.XBurt.${fileIndex}.sdds
        set ClosedOrbitYBurtFilename ${ClosedOrbitFileRootName}.YBurt.${fileIndex}.sdds
        set ClosedOrbitBurtFilename ${ClosedOrbitFileRootName}.Burt.${fileIndex}.snp
    }        
    return 1
}

# Determines the proper file $index for the most recent version of the closed orbit data file.

proc DetermineMostRecentFileIndex {fileRootName} {

    global MostRecentFilename
    set MostRecentFilename [lindex [lsort -decreasing [glob -nocomplain ${fileRootName}.*]] 0]
    
    if {$MostRecentFilename!=""} {
        set fileIndex [lindex [split $MostRecentFilename .] 2]
    } else {set fileIndex [format %03ld 0]}
    return $fileIndex
}

# Determines the proper file $index for the closed orbit data file which is used by sddsstatmon.

proc DetermineFirstFreeFileIndex {fileRootName} {

    scan [DetermineMostRecentFileIndex $fileRootName] %ld fileIndex
    incr fileIndex
    set fileIndex [format %03ld $fileIndex]
    return $fileIndex
}

# Procedure transfers the closed orbit specified in $ClosedOrbitFilename to memory scanner setpoint process variables.
# Returns 1 when completed.  Returns 0 if file does not exist.

proc TransferClosedOrbitToMSSetpoints {args} {
    
    global ClosedOrbitFilename ClosedOrbitFilenameTail
    APSStrictParseArguments {statusCallback}

    set ClosedOrbitFileExistsFlag [file exists $ClosedOrbitFilename]
    set ClosedOrbitBurtFilename [join "[lindex [split $ClosedOrbitFilename .] 0] Burt \
                                   [lindex [split $ClosedOrbitFilename .] 1] snp" {.}]

    if {$ClosedOrbitFileExistsFlag==1} {
        if {$statusCallback!=""} {
            $statusCallback "Transferring closed orbit data in $ClosedOrbitFilenameTail to memory scanner setpoints..."
        }
        exec sddscasr -restore $ClosedOrbitBurtFilename
        if {$statusCallback!=""} {
            $statusCallback "Done."
        }
        bell
        return 1
    } else {
        if {$statusCallback!=""} {
            $statusCallback "File $ClosedOrbitFilenameTail does not exist.  Closed orbit data acquisition must occur before setpoint transfer is performed."
        }
        bell
        return 0
    }
}

# Procedure acquires the closed orbit specified by NTurns and MTurns using sddsstatmon.  Ten orbits are averaged.
# Files created are stored in $directory.

proc AcquireClosedOrbit {args} { 

    global ClosedOrbitFilename CollectedClosedOrbitFilename ClosedOrbitFileRootName NTurns MTurns
    global ClosedOrbitFilenameTail directory
    global ClosedOrbitXBurtFilename ClosedOrbitYBurtFilename ClosedOrbitBurtFilename ControlStatus
    APSStrictParseArguments {statusCallback}

    set ClosedOrbitFileExistsFlag [file exists $ClosedOrbitFilename]
    if {$ClosedOrbitFileExistsFlag==1} {
        SetClosedOrbitOutputFilename Next
    } else {SetClosedOrbitOutputFilename MostRecent}

    if {$statusCallback!=""} {
        $statusCallback "Acquiring closed orbit data in $ClosedOrbitFilenameTail, averaging over 10 orbits and collecting..."
        } 
    bell
    set wait 0
    APSExecLog .sddsstatmonWidget -unixCommand "sddsstatmon ${directory}/BBPMs.stmon $ClosedOrbitFilename \
      -steps=1 -samples=10 -includeStatistics=mean -interval=1,seconds -update=10 -verbose" \
      -callback {set wait 1}

    tkwait variable wait
        
    set ClosedOrbitFilenameRoot [file tail $ClosedOrbitFilename]

    exec sddscollect -pipe=out $ClosedOrbitFilename \
      -collect=suffix=:ms:x:AdjustedCCMean \
      -collect=suffix=:ms:y:AdjustedCCMean \
      | sddsconvert -pipe \
      -rename=col,:ms:x:AdjustedCCMean=:ms:x:AdjustedCC,:ms:y:AdjustedCCMean=:ms:y:AdjustedCC \
      | sddsprocess -pipe=in $CollectedClosedOrbitFilename \
      -define=param,N,$NTurns \
      -define=param,M,$MTurns \
      "-print=param,NString,N = %.0f,N" \
      "-print=param,MString,M = %.0f,M" \
      "-print=param,ClosedOrbitFilenameString,$ClosedOrbitFilenameRoot"

    exec sddsprocess -pipe=out $CollectedClosedOrbitFilename  \
      -edit=col,ControlName,Rootname,6f/i/:ms:x:SetpointAO/ \
      -print=parameter,SnapType,Absolute \
      -print=col,ControlType,pv \
      -print=col,Lineage,- \
      -print=col,ValueString,%.4f,:ms:x:AdjustedCC \
     "-define=col,Count,1 abs,type=long" \
      | sddsconvert -pipe=in $ClosedOrbitXBurtFilename -delete=col,:ms:x:AdjustedCC,:ms:y:AdjustedCC,Rootname

    exec sddsprocess -pipe=out $CollectedClosedOrbitFilename  \
      -edit=col,ControlName,Rootname,6f/i/:ms:y:SetpointAO/ \
      -print=parameter,SnapType,Absolute \
      -print=col,ControlType,pv \
      -print=col,Lineage,- \
      -print=col,ValueString,%.4f,:ms:y:AdjustedCC \
     "-define=col,Count,1 abs,type=long" \
      | sddsconvert -pipe=in $ClosedOrbitYBurtFilename -delete=col,:ms:x:AdjustedCC,:ms:y:AdjustedCC,Rootname

    exec sddscombine $ClosedOrbitXBurtFilename $ClosedOrbitYBurtFilename $ClosedOrbitBurtFilename -merge

    exec rm $ClosedOrbitXBurtFilename $ClosedOrbitYBurtFilename

    if {$statusCallback!=""} {
        $statusCallback "Done."
    }
    bell
    return 1
}

# Procedure gets a selected closed orbit or closed orbit comparison file and renames it to the root filename 
# if necessary.  Returns 1 when completed.

proc GetSelectedDataFile {whichfile args} {

    global directory ClosedOrbitFilename ClosedOrbitCompareFilename ClosedOrbitCombinedFilename SetStatus
    global ClosedOrbitFilenameTail ClosedOrbitCompareFilenameTail ClosedOrbitCombinedFilenameTail
    APSStrictParseArguments {statusCallback}

    if {![string compare $whichfile closed]} {
        if {$statusCallback!=""} {
            $statusCallback "Select closed orbit file..."
        }
        set ClosedOrbitFilename [APSFileSelectDialog .chooseClosedOrbitFile -path ${directory} \
                                   -pattern "ClosedOrbit-????-??-??.???.sdds"]
        set ClosedOrbitFilenameTail [file tail $ClosedOrbitFilename]
        set ClosedOrbitFileFlag [lindex [split $ClosedOrbitFilename {.}] 1]
        if {[string compare $ClosedOrbitFileFlag Col]==0} {        
            set ClosedOrbitFilename [join "[lindex [split $ClosedOrbitFilename {.}] 0] \
                                           [lindex [split $ClosedOrbitFilename {.}] 2] sdds" {.}]
        }
        if {$statusCallback!=""} {
            $statusCallback "Done."
        }
        return 1
    } elseif {![string compare $whichfile compare]} {
        if {$statusCallback!=""} {
            $statusCallback "Select closed orbit comparison file..."
        }
        set ClosedOrbitCompareFilename [APSFileSelectDialog .chooseClosedOrbitFile -path ${directory} \
                                          -pattern "ClosedOrbit-????-??-??.???.sdds"]
        set ClosedOrbitCompareFilenameTail [file tail $ClosedOrbitCompareFilename]
        set ClosedOrbitCompareFileFlag [lindex [split $ClosedOrbitCompareFilename {.}] 1]
        if {[string compare $ClosedOrbitCompareFileFlag Col]==0} {        
            set ClosedOrbitCompareFilename [join "[lindex [split $ClosedOrbitCompareFilename {.}] 0] \
                                           [lindex [split $ClosedOrbitCompareFilename {.}] 2] sdds" {.}]
        }
        if {$statusCallback!=""} {
            $statusCallback "Done."
        }       
        return 1
    } elseif {![string compare $whichfile combined]} {
        if {$statusCallback!=""} {
            $statusCallback "Select closed orbit combined file..."
        }
        set ClosedOrbitCombinedFilename [APSFileSelectDialog .chooseClosedOrbitFile -path ${directory} \
                                         -pattern "ClosedOrbit*-*ClosedOrbit*.sdds"]
        set ClosedOrbitCombinedFilenameTail [file tail $ClosedOrbitCombinedFilename]
        if {$statusCallback!=""} {
            $statusCallback "Done."
        }
    }
}


# Plots the closed orbit data in file given by $ClosedOrbitFilename.  Returns 1 if the closed orbit file exists.
# Returns 0 if the file selected does not exist.

proc PlotClosedOrbitData {whichPlot args} {

    global ClosedOrbitFilename ClosedOrbitCompareFilename ClosedOrbitCombinedFilename SetStatus
    global ClosedOrbitFilenameTail ClosedOrbitCompareFilenameTail ClosedOrbitCombinedFilenameTail
    APSStrictParseArguments {statusCallback}

    set ClosedOrbitFileVarExistsFlag [info exists ClosedOrbitFilename]
    if {${ClosedOrbitFileVarExistsFlag}==1} {
        set ClosedOrbitFileExistsFlag [file exists $ClosedOrbitFilename]
    } else {
        set ClosedOrbitFileExistsFlag 0
    }
    
    set ClosedOrbitCombinedFileVarExistsFlag [info exists ClosedOrbitCombinedFilename]
    if {${ClosedOrbitCombinedFileVarExistsFlag}==1} {
        set ClosedOrbitCombinedFileExistsFlag [file exists $ClosedOrbitCombinedFilename]
    } else {
        set ClosedOrbitCombinedFileExistsFlag 0
    }

    if {![string compare $whichPlot closedOrbit]} {

        if {![string compare $ClosedOrbitFileExistsFlag 1]} {
            if {$statusCallback!=""} {
                $statusCallback "Plotting closed orbit data in $ClosedOrbitFilenameTail..."
            }       
            set ProcessedFilename [join "[lindex [split $ClosedOrbitFilename {.}] 0] \
                                 Col [lindex [split $ClosedOrbitFilename {.}] 1] sdds" {.}]
            catch {exec sddsplot $ProcessedFilename -legend=ysymbol,editCommand=5f/1D \
                     -labelsize=0.03 -graph=line,vary -enum=interval=2 \
                     "-topline=Horizontal and Vertical Adjusted Closed Orbits" \
                     -string=@ClosedOrbitFilenameString,p=0.05,q=0.93 \
                     -string=@NString,p=0.05,q=0.87 \
                     -string=@MString,p=0.05,q=0.81 \
                     -col=Rootname,(:ms:x:AdjustedCC,:ms:y:AdjustedCC) \&}
            if {$statusCallback!=""} {
                $statusCallback "Done."
            }        
            bell
            return 1
        } else {
            if {$statusCallback!=""} {
                $statusCallback "Please select a valid closed orbit file to plot."
            }
            bell
            return 0
        }
    } elseif {![string compare $whichPlot compare]} {
        if {![string compare $ClosedOrbitCombinedFileExistsFlag 1]} {
            if {$statusCallback!=""} {
                $statusCallback "Plotting closed orbit data in $ClosedOrbitCombinedFilenameTail..."
            }        
            catch {exec sddsplot $ClosedOrbitCombinedFilename -legend=ySymbol,editCommand=9d5f1D \
                 -labelsize=0.03 -graph=line,vary -enum=interval=2 \
                 "-topline=Horizontal and Vertical Adjusted Closed Orbit Differences" \
                 -string=@ClosedOrbitFilenameRootString,p=0.05,q=0.93 \
                 -string=@ClosedOrbitFileNString,p=0.05,q=0.87 \
                 -string=@ClosedOrbitFileMString,p=0.05,q=0.81 \
                 -string=@ClosedOrbitCompareFilenameString,p=0.05,q=0.16 \
                 -string=@ClosedOrbitCompareFileNString,p=0.05,q=0.10 \
                 -string=@ClosedOrbitCompareFileMString,p=0.05,q=0.04 \
                 "-col=Rootname,(ChangeIn:ms:x:AdjustedCC,ChangeIn:ms:y:AdjustedCC)" \&}
            bell
            if {$statusCallback!=""} {
                $statusCallback "Done."
            }        
            return 1
        } else {
            if {$statusCallback!=""} {
                $statusCallback "Please select a valid difference file containing the difference between two closed orbit files to plot."
            }
            bell
            return 0
        }
    }
}

# Procedure is used to compare two closed orbit files by taking the difference between them.  Plots the result.
# Returns 1 if plotting is successful.  Returns 0 if two valid files were not selected.

proc CompareClosedOrbitData {args} {

    global directory ClosedOrbitFilename ClosedOrbitCompareFilename ClosedOrbitCombinedFilename SetStatus
    global ClosedOrbitFilenameTail ClosedOrbitCompareFilenameTail ClosedOrbitCombinedFilenameTail 
    APSStrictParseArguments {statusCallback}

    set ClosedOrbitFileVarExistsFlag [info exists ClosedOrbitFilename]
    if {${ClosedOrbitFileVarExistsFlag}==1} {
        set ClosedOrbitFileExistsFlag [file exists $ClosedOrbitFilename]
    } else {
        set ClosedOrbitFileExistsFlag 0
    }

    set ClosedOrbitCompareFileVarExistsFlag [info exists ClosedOrbitCompareFilename]
    if {${ClosedOrbitCompareFileVarExistsFlag}==1} {
        set ClosedOrbitCompareFileExistsFlag [file exists $ClosedOrbitCompareFilename]
    } else {
        set ClosedOrbitCompareFileExistsFlag 0
    }

    if {${ClosedOrbitFileExistsFlag}==1 && ${ClosedOrbitCompareFileExistsFlag}==1} {

        if {$statusCallback!=""} {
            $statusCallback "Comparing $ClosedOrbitFilenameTail and $ClosedOrbitCompareFilenameTail..."
        }

        set ClosedOrbitCollectedFilename [join "[lindex [split $ClosedOrbitFilename {.}] 0] \
                                     Col [lindex [split $ClosedOrbitFilename {.}] 1] sdds" {.}]
        set ClosedOrbitCompareCollectedFilename [join "[lindex [split $ClosedOrbitCompareFilename {.}] 0] \
                                            Col [lindex [split $ClosedOrbitCompareFilename {.}] 1] sdds" {.}]

        set OriginalCombinedFileRootNames [join "[lindex [split $ClosedOrbitFilename {.}] 0]  \
                                                 [lindex [split $ClosedOrbitFilename {.}] 1]  \
                                                 [lindex [split [file tail $ClosedOrbitCompareFilename] {.}] 0] \
                                                 [lindex [split $ClosedOrbitCompareFilename {.}] 1]" \
                                                 {-}]
        set CombinedFileRootname [join "$OriginalCombinedFileRootNames Comb" {.}]

        set ClosedOrbitCombinedFilename [join "$CombinedFileRootname sdds" {.}]
        set ClosedOrbitCombinedFilenameTail [file tail $ClosedOrbitCombinedFilename]
        set ClosedOrbitCombinedFileExistsFlag [file exists $ClosedOrbitCombinedFilename]

        if {${ClosedOrbitCombinedFileExistsFlag}==1} {
            PlotClosedOrbitData compare -statusCallback SetStatus
            bell
            return 1
        }

        set ClosedOrbitFileN [format %.0f [APSGetSDDSParameter -fileName $ClosedOrbitCollectedFilename -parameter N]]
        set ClosedOrbitFileM [format %.0f [APSGetSDDSParameter -fileName $ClosedOrbitCollectedFilename -parameter M]]
        set ClosedOrbitCompareFileN [format %.0f [APSGetSDDSParameter -fileName $ClosedOrbitCompareCollectedFilename -parameter N]]
        set ClosedOrbitCompareFileM [format %.0f [APSGetSDDSParameter -fileName $ClosedOrbitCompareCollectedFilename -parameter M]]
        set ClosedOrbitFilenameRoot [file tail $ClosedOrbitFilename]
        set ClosedOrbitCompareFilenameRoot [file tail $ClosedOrbitCompareFilename]
        exec sddscombine -pipe=out $ClosedOrbitCollectedFilename $ClosedOrbitCompareCollectedFilename \
          | sddschanges -pipe -copy=Rootname \
          -changesIn=:ms:x:AdjustedCC,:ms:y:AdjustedCC \
          | sddsprocess -pipe=in $ClosedOrbitCombinedFilename \
          "-print=param,ClosedOrbitFilenameRootString,${ClosedOrbitFilenameRoot}" \
          "-print=param,ClosedOrbitCompareFilenameString,${ClosedOrbitCompareFilenameRoot}" \
          "-print=param,ClosedOrbitFileNString,N = ${ClosedOrbitFileN}" \
          "-print=param,ClosedOrbitFileMString,M = ${ClosedOrbitFileM}" \
          "-print=param,ClosedOrbitCompareFileNString,N = ${ClosedOrbitCompareFileN}" \
          "-print=param,ClosedOrbitCompareFileMString,M = ${ClosedOrbitCompareFileM}"

        if {$statusCallback!=""} {
            $statusCallback "Done."
        }
        PlotClosedOrbitData compare -statusCallback SetStatus
        return 1
    } else { 
        if {$statusCallback!=""} {
            $statusCallback "Please select two existing files to compare."
        }
        bell
        return 0
    }
}

# Build application and set timing defaults.

set NTurns 400
set MTurns 1024
set MSAvgFactor 11

SetClosedOrbitOutputFilename MostRecent
MakeStatusWidget .userFrame 
ApplicationWidgets .applicationWidgets -parent .userFrame
