#!/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 baseDir(BPM) /adata/oagData/sr/2kHz-20kS-BPM-Logging
set baseDir(PS) /adata/oagData/sr/2kHz-20kS-PS-Logging

foreach type {BPM PS} {
    if ![file exists $baseDir($type)] {
        wm withdraw .
        APSAlertBox .oops -name "Error" -modeless 0 -beep no \
          -errorMessage "Error: $baseDir($type) not found. You must be on orthrosa to use this application."
        exit
    }
}



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

APSApplication . -name SrDaqPsdTransfer -version $CVSRevisionAuthor \
  -overview {This interface provides the ability to browse and transfer BPM and PS DAQ PSD data for the SR.}

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

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

proc MakeDateTimeFrame {frame} {
    global StartTextDay StartDay StartTextMonth StartYear 
    global StartHour StartMinute StartSecond StartTime
    global EndTextDay EndDay EndTextMonth EndYear 
    global EndHour EndMinute EndSecond EndTime

    set s [clock seconds]

    ttk::frame $frame -padding 2
    pack $frame

    ttk::frame $frame.from
    pack $frame.from 
    set f $frame.from

    ttk::label $f.label -text "From:"
    ttk::spinbox $f.textday -values "Mon Tue Wed Thu Fri Sat Sun" \
      -width 3 -wrap true -textvariable StartTextDay \
      -style Tall.TSpinbox
    bindtags $f.textday "TSpinbox . all .userFrame.date.from.textday "
    bind $f.textday <<Increment>> "TimeAdjusted Start %W up"
    bind $f.textday <<Decrement>> "TimeAdjusted Start %W down"
    ttk::spinbox $f.day -from 1 -to 31 -width 2 -wrap true \
      -textvariable StartDay \
      -validate key -validatecommand {string is integer %P} \
      -style Tall.TSpinbox
    bindtags $f.day "TSpinbox . all .userFrame.date.from.day "
    bind $f.day <<Increment>> "TimeAdjusted Start %W up"
    bind $f.day <<Decrement>> "TimeAdjusted Start %W down"
    ttk::spinbox $f.month \
      -values "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec" \
      -width 3 -wrap true -textvariable StartTextMonth \
      -style Tall.TSpinbox
    bindtags $f.month "TSpinbox . all .userFrame.date.from.month "
    bind $f.month <<Increment>> "TimeAdjusted Start %W up"
    bind $f.month <<Decrement>> "TimeAdjusted Start %W down"
    ttk::spinbox $f.year -from 1900 -to 2100 -width 4 -wrap true \
      -textvariable StartYear \
      -validate key -validatecommand {string is integer %P} \
      -style Tall.TSpinbox
    bindtags $f.year "TSpinbox . all .userFrame.date.from.year "
    bind $f.year <<Increment>> "TimeAdjusted Start %W up"
    bind $f.year <<Decrement>> "TimeAdjusted Start %W down"
    ttk::label $f.space -text " "
    ttk::spinbox $f.hour -from 0 -to 23 -width 2 -wrap true \
      -format %02.0f -textvariable StartHour \
      -validate key -validatecommand {string is integer %P} \
      -style Tall.TSpinbox
    bindtags $f.hour "TSpinbox . all .userFrame.date.from.hour "
    bind $f.hour <<Increment>> "TimeAdjusted Start %W up"
    bind $f.hour <<Decrement>> "TimeAdjusted Start %W down"
    ttk::label $f.colon1 -text ":"
    ttk::spinbox $f.minute -from 0 -to 59 -width 2 -wrap true \
      -format %02.0f -textvariable StartMinute \
      -validate key -validatecommand {string is integer %P} \
      -style Tall.TSpinbox
    bindtags $f.minute "TSpinbox . all .userFrame.date.from.minute "
    bind $f.minute <<Increment>> "TimeAdjusted Start %W up"
    bind $f.minute <<Decrement>> "TimeAdjusted Start %W down"
    ttk::label $f.colon2 -text ":"
    ttk::spinbox $f.second -from 0 -to 59 -width 2 -wrap true \
      -format %02.0f -textvariable StartSecond \
      -validate key -validatecommand {string is integer %P} \
      -style Tall.TSpinbox
    bindtags $f.second "TSpinbox . all .userFrame.date.from.second "
    bind $f.second <<Increment>> "TimeAdjusted Start %W up"
    bind $f.second <<Decrement>> "TimeAdjusted Start %W down"

    bind $f.textday <Return> "TimeAdjustedManually"
    bind $f.day <Return> "TimeAdjustedManually"
    bind $f.month <Return> "TimeAdjustedManually"
    bind $f.year <Return> "TimeAdjustedManually"
    bind $f.hour <Return> "TimeAdjustedManually"
    bind $f.minute <Return> "TimeAdjustedManually"
    bind $f.second <Return> "TimeAdjustedManually"

    set StartTextDay [clock format $s -format %a]
    set StartDay [clock format $s -format %d]
    set StartTextMonth [clock format $s -format %b]
    set StartYear [clock format $s -format %Y]
    set StartHour 00
    set StartMinute 00
    set StartSecond 00

    set StartTime [clock scan "$StartTextDay $StartTextMonth $StartDay ${StartHour}:${StartMinute}:${StartSecond} $StartYear"]

   ttk::button $f.reset -text "Reset" -command "set StartTextDay $StartTextDay ; set StartDay $StartDay ; set StartTextMonth $StartTextMonth ; set StartYear $StartYear ; set StartHour $StartHour ; set StartMinute $StartMinute ; set StartSecond $StartSecond ; set StartTime $StartTime" -style Tight.TButton

    pack $f.label $f.textday $f.day $f.month \
      $f.year $f.space $f.hour $f.colon1 \
      $f.minute $f.colon2 $f.second $f.reset -side left

    ttk::button $f.1min -text "last 1 min" -command "TimePreset -minutes 1 -past 1" -style Tight.TButton
    pack $f.1min -side left
    ttk::button $f.2min -text "last 2 min" -command "TimePreset -minutes 2 -past 1" -style Tight.TButton
    pack $f.2min -side left
    ttk::button $f.3min -text "last 3 min" -command "TimePreset -minutes 3 -past 1" -style Tight.TButton
    pack $f.3min -side left
    ttk::button $f.nmin -text "last n min" -command "TimePreset -minutes 0 -past 1 -variable nMinutes" -style Tight.TButton
    pack $f.nmin -side left

    ttk::frame $frame.to
    pack $frame.to -anchor e
    set f $frame.to

    ttk::label $f.label -text "To:"
    ttk::spinbox $f.textday -values "Mon Tue Wed Thu Fri Sat Sun" \
      -width 3 -wrap true -textvariable EndTextDay \
      -style Tall.TSpinbox
    bindtags $f.textday "TSpinbox . all .userFrame.date.to.textday "
    bind $f.textday <<Increment>> "TimeAdjusted End %W up"
    bind $f.textday <<Decrement>> "TimeAdjusted End %W down"
    ttk::spinbox $f.day -from 1 -to 31 -width 2 -wrap true \
      -textvariable EndDay \
      -validate key -validatecommand {string is integer %P} \
      -style Tall.TSpinbox
    bindtags $f.day "TSpinbox . all .userFrame.date.to.day "
    bind $f.day <<Increment>> "TimeAdjusted End %W up"
    bind $f.day <<Decrement>> "TimeAdjusted End %W down"
    ttk::spinbox $f.month \
      -values "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec" \
      -width 3 -wrap true -textvariable EndTextMonth \
      -style Tall.TSpinbox
    bindtags $f.month "TSpinbox . all .userFrame.date.to.month "
    bind $f.month <<Increment>> "TimeAdjusted End %W up"
    bind $f.month <<Decrement>> "TimeAdjusted End %W down"
    ttk::spinbox $f.year -from 1900 -to 2100 -width 4 -wrap true \
      -textvariable EndYear \
      -validate key -validatecommand {string is integer %P} \
      -style Tall.TSpinbox
    bindtags $f.year "TSpinbox . all .userFrame.date.to.year "
    bind $f.year <<Increment>> "TimeAdjusted End %W up"
    bind $f.year <<Decrement>> "TimeAdjusted End %W down"
    ttk::label $f.space -text " "
    ttk::spinbox $f.hour -from 0 -to 23 -width 2 -wrap true \
      -format %02.0f -textvariable EndHour \
      -validate key -validatecommand {string is integer %P} \
      -style Tall.TSpinbox
    bindtags $f.hour "TSpinbox . all .userFrame.date.to.hour "
    bind $f.hour <<Increment>> "TimeAdjusted End %W up"
    bind $f.hour <<Decrement>> "TimeAdjusted End %W down"
    ttk::label $f.colon1 -text ":"
    ttk::spinbox $f.minute -from 0 -to 59 -width 2 -wrap true \
      -format %02.0f -textvariable EndMinute \
      -validate key -validatecommand {string is integer %P} \
      -style Tall.TSpinbox
    bindtags $f.minute "TSpinbox . all .userFrame.date.to.minute "
    bind $f.minute <<Increment>> "TimeAdjusted End %W up"
    bind $f.minute <<Decrement>> "TimeAdjusted End %W down"
    ttk::label $f.colon2 -text ":"
    ttk::spinbox $f.second -from 0 -to 59 -width 2 -wrap true \
      -format %02.0f -textvariable EndSecond \
      -validate key -validatecommand {string is integer %P} \
      -style Tall.TSpinbox
    bindtags $f.second "TSpinbox . all .userFrame.date.to.second "
    bind $f.second <<Increment>> "TimeAdjusted End %W up"
    bind $f.second <<Decrement>> "TimeAdjusted End %W down"

    bind $f.textday <Return> "TimeAdjustedManually"
    bind $f.day <Return> "TimeAdjustedManually"
    bind $f.month <Return> "TimeAdjustedManually"
    bind $f.year <Return> "TimeAdjustedManually"
    bind $f.hour <Return> "TimeAdjustedManually"
    bind $f.minute <Return> "TimeAdjustedManually"
    bind $f.second <Return> "TimeAdjustedManually"

    set EndTextDay [clock format $s -format %a]
    set EndDay [clock format $s -format %d]
    set EndTextMonth [clock format $s -format %b]
    set EndYear [clock format $s -format %Y]
    set EndHour 23
    set EndMinute 59
    set EndSecond 59

    set EndTime [clock scan "$EndTextDay $EndTextMonth $EndDay ${EndHour}:${EndMinute}:${EndSecond} $EndYear"]

    ttk::button $f.reset -text "Reset" -command "set EndTextDay $EndTextDay ; set EndDay $EndDay ; set EndTextMonth $EndTextMonth ; set EndYear $EndYear ; set EndHour $EndHour ; set EndMinute $EndMinute ; set EndSecond $EndSecond ; set EndTime $EndTime" -style Tight.TButton

    pack $f.label $f.textday $f.day $f.month \
      $f.year $f.space $f.hour $f.colon1 \
      $f.minute $f.colon2 $f.second $f.reset -side left

    ttk::button $f.1min -text "next 1 min" -command "TimePreset -minutes 1 -past 0" -style Tight.TButton
    pack $f.1min -side left
    ttk::button $f.2min -text "next 2 min" -command "TimePreset -minutes 2 -past 0" -style Tight.TButton
    pack $f.2min -side left
    ttk::button $f.3min -text "next 3 min" -command "TimePreset -minutes 3 -past 0" -style Tight.TButton
    pack $f.3min -side left
    ttk::button $f.nmin -text "next n min" -command "TimePreset -minutes 3 -past 0 -variable nMinutes" -style Tight.TButton
    pack $f.nmin -side left

    ttk::frame $frame.other
    pack $frame.other
    set f $frame.other

    global nMinutes offsetSeconds
    set nMinutes 5
    set offsetSeconds 0
    APSLabeledEntry .le1 -parent $f -label "\"n\" minutes: " -textVariable nMinutes -type integer
    APSLabeledEntry .le2 -parent $f -label "Offset (s): " -textVariable offsetSeconds -type integer
}

proc TimePreset {args} {
    set minutes 0
    set past 1
    set variable ""
    if [APSStrictParseArguments {minutes past variable}] {
        return -code error "TimePreset: invalid arguments: $args"
    }
    global offsetSeconds
    if [string length $variable] {
        global $variable
        set minutes [set $variable]
    }
    foreach var "Start End" {
        global ${var}TextDay ${var}Day ${var}TextMonth ${var}Year 
        global ${var}Hour ${var}Minute ${var}Second ${var}Time
    }
    set s [clock seconds]

    if $past {
        set s1 [expr $s - $minutes*60 + $offsetSeconds]
        set s2 [expr $s + $offsetSeconds]
    } else {
        set s1 [expr $s + $offsetSeconds]
        set s2 [expr $s + $minutes*60 + $offsetSeconds]
    }
    
    set EndTextDay [clock format $s2 -format %a]
    set EndDay [clock format $s2 -format %d]
    set EndTextMonth [clock format $s2 -format %b]
    set EndYear [clock format $s2 -format %Y]
    set EndHour [clock format $s2 -format %H]
    set EndMinute [clock format $s2 -format %M]
    set EndSecond [clock format $s2 -format %S]
    set EndTime [clock scan "$EndTextDay $EndTextMonth $EndDay ${EndHour}:${EndMinute}:${EndSecond} $EndYear"]

    set StartTextDay [clock format $s1 -format %a]
    set StartDay [clock format $s1 -format %d]
    set StartTextMonth [clock format $s1 -format %b]
    set StartYear [clock format $s1 -format %Y]
    set StartHour [clock format $s1 -format %H]
    set StartMinute [clock format $s1 -format %M]
    set StartSecond [clock format $s1 -format %S]
    set StartTime [clock scan "$StartTextDay $StartTextMonth $StartDay ${StartHour}:${StartMinute}:${StartSecond} $StartYear"]
}

proc TimeAdjustedManually {args} {
    foreach var "Start End" {
        global ${var}TextDay ${var}Day ${var}TextMonth ${var}Year 
        global ${var}Hour ${var}Minute ${var}Second ${var}Time
        
        set ${var}Time [clock scan "[set ${var}TextMonth] [set ${var}Day] [set ${var}Hour]:[set ${var}Minute]:[set ${var}Second] [set ${var}Year]"]
        set ${var}Minute [clock format [set ${var}Time] -format %M]
        set ${var}Hour [clock format [set ${var}Time] -format %H]
        set ${var}TextDay [clock format [set ${var}Time] -format %a]
        set ${var}Day [clock format [set ${var}Time] -format %d]
        set ${var}TextMonth [clock format [set ${var}Time] -format %b]
        set ${var}Year [clock format [set ${var}Time] -format %Y]
    }
}

proc TimeAdjusted {var widget direction} {
    global ${var}TextDay ${var}Day ${var}TextMonth ${var}Year 
    global ${var}Hour ${var}Minute ${var}Second ${var}Time

    if {[lindex [split $widget .] end] == "second"} {
        if {$direction == "up"} {
            set direction "+"
        } else {
            set direction "-"
        }
        set ${var}Time [expr "[set ${var}Time] $direction (1)"]
        set ${var}Second [clock format [set ${var}Time] -format %S]
        set ${var}Minute [clock format [set ${var}Time] -format %M]
        set ${var}Hour [clock format [set ${var}Time] -format %H]
        set ${var}TextDay [clock format [set ${var}Time] -format %a]
        set ${var}Day [clock format [set ${var}Time] -format %d]
        set ${var}TextMonth [clock format [set ${var}Time] -format %b]
        set ${var}Year [clock format [set ${var}Time] -format %Y]
    } elseif {[lindex [split $widget .] end] == "minute"} {
        if {$direction == "up"} {
            set direction "+"
        } else {
            set direction "-"
        }
        set ${var}Time [expr "[set ${var}Time] $direction (60)"]
        set ${var}Minute [clock format [set ${var}Time] -format %M]
        set ${var}Hour [clock format [set ${var}Time] -format %H]
        set ${var}TextDay [clock format [set ${var}Time] -format %a]
        set ${var}Day [clock format [set ${var}Time] -format %d]
        set ${var}TextMonth [clock format [set ${var}Time] -format %b]
        set ${var}Year [clock format [set ${var}Time] -format %Y]
    } elseif {[lindex [split $widget .] end] == "hour"} {
        if {$direction == "up"} {
            set direction "+"
        } else {
            set direction "-"
        }
        set ${var}Time [expr "[set ${var}Time] $direction (60 * 60)"]
        set ${var}Hour [clock format [set ${var}Time] -format %H]
        set ${var}TextDay [clock format [set ${var}Time] -format %a]
        set ${var}Day [clock format [set ${var}Time] -format %d]
        set ${var}TextMonth [clock format [set ${var}Time] -format %b]
        set ${var}Year [clock format [set ${var}Time] -format %Y]
    } elseif {[lindex [split $widget .] end] == "textday"} {
        if {$direction == "up"} {
            set direction "+"
        } else {
            set direction "-"
        }
        set ${var}Time [expr "[set ${var}Time] $direction (24 * 60 * 60)"]
        set initTextDay [set ${var}TextDay]
        set ${var}TextDay [clock format [set ${var}Time] -format %a]
        if {$initTextDay != [set ${var}TextDay]} {
            #This is needed for the transition to daylight savings time.
            set ${var}Time [expr "[set ${var}Time] $direction (1 * 60 * 60)"]
            set ${var}TextDay [clock format [set ${var}Time] -format %a]
        }
        set ${var}Day [clock format [set ${var}Time] -format %d]
        set ${var}TextMonth [clock format [set ${var}Time] -format %b]
        set ${var}Year [clock format [set ${var}Time] -format %Y]
    } elseif {[lindex [split $widget .] end] == "day"} {
        if {$direction == "up"} {
            set direction "+"
        } else {
            set direction "-"
        }
        set ${var}Time [expr "[set ${var}Time] $direction (24 * 60 * 60)"]
        set initTextDay [set ${var}TextDay]
        set ${var}TextDay [clock format [set ${var}Time] -format %a]
        if {$initTextDay == [set ${var}TextDay]} {
            #This is needed for the transition to daylight savings time.
            set ${var}Time [expr "[set ${var}Time] $direction (1 * 60 * 60)"]
            set ${var}TextDay [clock format [set ${var}Time] -format %a]
        }
        set ${var}Day [clock format [set ${var}Time] -format %d]
        set ${var}TextMonth [clock format [set ${var}Time] -format %b]
        set ${var}Year [clock format [set ${var}Time] -format %Y]
    } elseif {[lindex [split $widget .] end] == "month"} {
        set month [clock format [set ${var}Time] -format %b]
        set year [clock format [set ${var}Time] -format %Y]
        set s1 [clock scan "$month 01 00:00:00 $year"]
        if {$direction == "up"} {
            if {$month == "Dec"} {
                incr year
            }
        } else {
            if {$month == "Jan"} {
                incr year -1
            }
        }
        set s2 [clock scan "[set ${var}TextMonth] 01 00:00:00 $year"]
        set s [expr {$s2 - $s1 + (60 * 60)}]
        set ${var}Time [expr "[set ${var}Time] + $s"]
        while {[set ${var}TextMonth] != [clock format [set ${var}Time] -format %b]} {
            if {$month == [clock format [set ${var}Time] -format %b]} {
                if {$direction == "up"} {
                    set ${var}Time [expr "[set ${var}Time] + (12 * 60 * 60)"]
                } else {
                    set ${var}Time [expr "[set ${var}Time] - (12 * 60 * 60)"]
                }
            } else {
                if {$direction == "up"} {
                    set ${var}Time [expr "[set ${var}Time] - (12 * 60 * 60)"]
                } else {
                    set ${var}Time [expr "[set ${var}Time] + (12 * 60 * 60)"]
                }
            }
        }
        set ${var}TextDay [clock format [set ${var}Time] -format %a]
        set ${var}Day [clock format [set ${var}Time] -format %d]
        set ${var}TextMonth [clock format [set ${var}Time] -format %b]
        set ${var}Year [clock format [set ${var}Time] -format %Y]
    } elseif {[lindex [split $widget .] end] == "year"} {
        if {([set ${var}Day] == "29") && ([set ${var}TextMonth] == "Feb")} {
            set ${var}Day 28
        }
        set ${var}Time [clock scan "[set ${var}TextMonth] [set ${var}Day] [set ${var}Hour]:[set ${var}Minute]:[set ${var}Second] [set ${var}Year]"]
        set ${var}TextDay [clock format [set ${var}Time] -format %a]
    }
    set ${var}Time [clock scan "[set ${var}TextMonth] [set ${var}Day] [set ${var}Hour]:[set ${var}Minute]:[set ${var}Second] [set ${var}Year]"]

}

proc FindFiles {args} {
    set type ""
    if {[APSStrictParseArguments {type}] || ![string length $type] || [lsearch -exact [list BPM PS] $type]==-1} {
        return -code error "FindFiles: invalid arguments: $args"
    }
    global baseDir 
    global StartYear StartHour StartMinute StartSecond StartTextDay StartDay StartTextMonth 
    global EndYear EndHour EndMinute EndSecond EndTextDay EndDay EndTextMonth 

    set StartTime [clock scan "$StartTextDay $StartTextMonth $StartDay ${StartHour}:${StartMinute}:${StartSecond} $StartYear"]
    set EndTime [clock scan "$EndTextDay $EndTextMonth $EndDay ${EndHour}:${EndMinute}:${EndSecond} $EndYear"]
    scan [clock format $StartTime -format %d] %d startDay
    scan [clock format $StartTime -format %m] %d startMonth
    scan [clock format $EndTime -format %d] %d endDay
    scan [clock format $EndTime -format %m] %d endMonth

    set fileList [list]
    set origDir [pwd]
    cd $baseDir($type)
    for {set year $StartYear} {$year<=$EndYear} {incr year} {
        for {set month $startMonth} {$month<=$endMonth} {incr month} {
            for {set day $startDay} {$day<=$endDay} {incr day} {
                set candidateFileList [glob -nocomplain [format %4d/%02d/%02d/PSD-??:??:??.gz $year $month $day]]
                foreach candidate $candidateFileList {
                    regexp {(.*)/(.*)/(.*)/PSD-(..):(..):(..).gz} $candidate all yyyy mo dd hh mm ss
                    #puts stderr "Checking $candidate: $yyyy $mo $dd $hh $mm $ss"
                    set candidateTime [clock scan "$yyyy/$mo/$dd $hh:$mm:$ss" -format "%Y/%m/%d %T"]
                    if [expr $candidateTime>=$StartTime && $candidateTime<=$EndTime] {
                        lappend fileList $candidate
                    }
                }
            }
        }
    }
    set fileList [lsort $fileList]
    cd $origDir
    return $fileList
}

proc ReallyTransferFiles {args} {
    set overwrite 0
    set type ""
    global includeMedian includeMean includeMin includeMax
    if [APSStrictParseArguments {overwrite type}] {
        return -code error "ReallyTransferFiles: invalid arguments: $args"
    }

    global StartYear StartHour StartMinute StartSecond StartTextDay StartDay StartTextMonth 
    set StartTime [clock scan "$StartTextDay $StartTextMonth $StartDay ${StartHour}:${StartMinute}:${StartSecond} $StartYear"]
    scan [clock format $StartTime -format %d] %d startDay
    scan [clock format $StartTime -format %m] %d startMonth
    global deviceList
    set localDeviceList [split $deviceList($type) " ,"]
    global outputDirectory baseDir description
    if ![string length $outputDirectory($type)] {
        SetMainStatus "Give a $type output directory"
        return
    }
    if {[file exists $outputDirectory($type)] && ![file isdir $outputDirectory($type)]} {
        SetMainStatus "$outputDirectory($type) is not a directory."
        return
    }
    if {![file exists $outputDirectory($type)]} {
        SetMainStatus "$outputDirectory($type) is not a directory. Try the mkdir button."
        return
    }
    SetMainStatus "Searching for $type files..."
    set fileList [FindFiles -type $type]
    if ![llength $fileList] {
        SetMainStatus "No files found"
        return
    }
    SetMainStatus "[llength $fileList] files found"
    global ${type}List ${type}VarList ${type}PatternList ${type}GroupNameList 
    set matchOpt ""
    set nSelected 0
    set groupList [list]
    set groupPatternList [list]
    foreach part [set ${type}List] var [set ${type}VarList] pattern [set ${type}PatternList] groupName [set ${type}GroupNameList] {
        global $var
        if [set $var] {
            incr nSelected
            #SetMainStatus "$part $var $pattern $groupName"
            if ![string length $matchOpt] {
                set matchOpt -match=parameter,${type}Name=$pattern
            } else {
                set matchOpt ${matchOpt},${type}Name=$pattern,|
            }
            if [lsearch -exact $groupList $groupName]==-1 {
                lappend groupList $groupName
                lappend groupPatternList $pattern
            }
        }
    }
    #SetMainStatus $matchOpt
    set successes 0
    set failures 0
    set skipped 0
    set destinationList [list]
    # Need these two statements in case of month or day like "08" or "09"
    scan $startMonth %d month
    scan $startDay %d day
    set destYMDTag [format "%d-%02d-%02d" ${StartYear} ${month} ${day}]
    foreach filename $fileList {
        SetMainStatus "$filename ..."
        set destination $outputDirectory(${type})/${type}-${destYMDTag}-[file tail $filename]
        if {[file exists $destination] && [file mtime $destination]>[file mtime $baseDir(${type})/$filename] && !$overwrite} {
            SetMainStatus "File exists, not overwriting"
            lappend destinationList $destination
            incr skipped
        } else {
            if {$nSelected==[llength [set ${type}List]]} {
                if [catch {file copy -force $baseDir(${type})/$filename $destination} result] {
                    SetMainStatus "$result"
                    incr failures
                } else {
                    incr successes
                    lappend destinationList $destination
                }
            } else {
                if [catch {exec sddsprocess $baseDir(${type})/$filename $destination $matchOpt} result] {
                    SetMainStatus "$result"
                    incr failures
                } else {
                    incr successes
                    lappend destinationList $destination
                }
            }
        }
    }
    SetMainStatus "Successfully copied $successes files. Failed to transfer $failures files. Preserved $skipped files."
    if [llength $destinationList] {
        eval set firstTag [os editstring 5Z-%/.gz// [file tail [lindex $destinationList 0]]]
        eval set lastTag [os editstring 5Z-%/.gz// [file tail [lindex $destinationList end]]]
        set tag ${destYMDTag}-${firstTag}-${lastTag}
        if {$includeMedian || $includeMean || $includeMin || $includeMax} {
            set stats1OptList [list]
            set stats2OptList [list]
            if $includeMedian {
                lappend stats1OptList -median=Sqrt*
                lappend stats2OptList -median=Sqrt*Median
            }
            if $includeMean {
                lappend stats1OptList -mean=Sqrt*
                lappend stats2OptList -mean=Sqrt*Mean
            }
            if $includeMin {
                lappend stats1OptList -min=Sqrt*
                lappend stats2OptList -min=Sqrt*Min*
            }
            if $includeMax {
                lappend stats1OptList -max=Sqrt*
                lappend stats2OptList -max=Sqrt*Max*
            }
            foreach device $localDeviceList {
                SetMainStatus "Creating $device statistical summary of [llength $destinationList] files..."
                set device [string trim $device]
                set summaryFile $outputDirectory($type)/${device}-PSD-$tag.sdds
                if [catch {eval exec sddscombine $destinationList -pipe=out \
                             | sddsprocess -pipe -match=parameter,${type}Name=$device \
                             | sddsenvelope -pipe=in -copy=f $stats1OptList $summaryFile} result] {
                    SetMainStatus "$result"
                }
            }
            SetMainStatus "Creating per-type statistical summary of [llength $destinationList] files..."
            foreach group $groupList groupPattern $groupPatternList {
                SetMainStatus "Working on $group ($groupPattern)"
                set statsFileList [list]
                foreach datafile $destinationList {
                    set problem 0
                    if [file exists $datafile.proc.$group] {
                        SetMainStatus "$datafile already processed."
                    } else {
                        SetMainStatus "Processing $datafile"
                        if [catch {eval exec sddsprocess $datafile -pipe=out -match=param,${type}Name=$groupPattern \
                                     | sddsenvelope -pipe=in $datafile.proc.$group -copy=f $stats1OptList} result] {
                            SetMainStatus "$result"
                            file delete $datafile.proc.$group 
                            set problem 1
                        }
                    }
                    if !$problem {
                        set nr [exec sdds2stream $datafile.proc.$group -rows=bare]
                        if {$nr != 10001 } {
                            SetMainStatus "Wrong number of rows"
                            file delete $datafile.proc.$group 
                        } else {
                            lappend statsFileList $datafile.proc.$group
                        }
                    }
                }
                if ![llength $statsFileList] {
                    SetMainStatus "No good results for $group"
                } else {
                    set summaryFile [file dirname $datafile]/$group-PSD-$tag.sdds
                    SetMainStatus "Creating summary file $summaryFile"
                    if [catch {eval exec sddscombine $statsFileList -pipe=out \
                                 | sddsenvelope -pipe -copy=f $stats2OptList \
                                 | sddsprocess -pipe=in $summaryFile \
                                 "{-print=parameter,Description,[APSMakeSafeQualifierStringForEval $description]}"} result] {
                        SetMainStatus "$result"
                    }
                    eval file delete $statsFileList
                }
            }
            SetMainStatus "Finished making statistical output files."
        }
        exec sddsmakedataset $outputDirectory(${type})/$type-PSD-$tag.sdds \
          -parameter=Description,type=string "-data=[APSMakeSafeQualifierString $description]"
    }
}

proc TransferFiles {args} {
    global includeBPMs includePS 
    set overwrite 0
    if [APSStrictParseArguments {overwrite}] {
        return -code error "TransferFiles: invalid arguments: $args"
    }

    global StartYear StartHour StartMinute StartSecond StartTextDay StartDay StartTextMonth 
    global EndYear EndHour EndMinute EndSecond EndTextDay EndDay EndTextMonth 

    set StartTime [clock scan "$StartTextDay $StartTextMonth $StartDay ${StartHour}:${StartMinute}:${StartSecond} $StartYear"]
    set EndTime [clock scan "$EndTextDay $EndTextMonth $EndDay ${EndHour}:${EndMinute}:${EndSecond} $EndYear"]
    set NowTime [clock seconds]
    if [expr $StartTime>$NowTime] {
        if ![APSYesNoPopUp "Starting time is in the future. Proceed?"] return
    }
    if [expr $EndTime>$NowTime] {
        if ![APSYesNoPopUp "Ending time is in the future. Proceed?"] return
    }
    if $includeBPMs {
        ReallyTransferFiles -overwrite $overwrite -type BPM
    }
    if $includePS {
        ReallyTransferFiles -overwrite $overwrite -type PS
    }
}

MakeDateTimeFrame .userFrame.dt
set includeBPMs 1
set includePS 1
APSCheckButtonFrame .cb1 -parent .userFrame -label "Include: " -orientation horizontal \
                    -buttonList "BPM PS" -variableList "includeBPMs includePS" 

APSLabeledEntry .file1 -parent .userFrame -label "BPM output directory: " -fileSelectButton 1  \
                -fileSelectDirectory 1 -textVariable outputDirectory(BPM) -width 80
APSButton .daily -parent .userFrame.file1 -packOption "-anchor e" -text "daily" -size small \
  -command {set outputDirectory(BPM) [APSGoToDailyDirectory]}
APSButton .make -parent .userFrame.file1 -packOption "-anchor e" -text "mkdir" -size small \
  -command {file mkdir $outputDirectory(BPM)}
APSLabeledEntry .dl1 -parent .userFrame -label "BPM device list (optional): " -textVariable deviceList(BPM) -width 80

APSLabeledEntry .file2 -parent .userFrame -label "PS output directory: " -fileSelectButton 1 \
                -fileSelectDirectory 1 -textVariable outputDirectory(PS) -width 80
APSButton .daily -parent .userFrame.file2 -packOption "-anchor e" -text "daily" -size small \
  -command {set outputDirectory(PS) [APSGoToDailyDirectory]}
APSButton .make -parent .userFrame.file2 -packOption "-anchor e" -text "mkdir" -size small \
  -command {file mkdir $outputDirectory(PS)}
APSLabeledEntry .dl2 -parent .userFrame -label "PS device list (optional): " -textVariable deviceList(PS) -width 80

set BPMList {A:P0 A:P3 B:P6 B:P5 B:P3 B:P0 IDSlope IDPosition}
set BPMPatternList [eval os editstring %/A:/*:/%/B:/*:/%/ID/ID*/ $BPMList]
set BPMGroupNameList [eval os editstring Z: $BPMList]
set BPMVarList [eval os editstring i/include/%/:// $BPMList]
foreach var $BPMVarList {
    set $var 1
}

APSCheckButtonFrame .bpmcb -parent .userFrame -orientation horizontal -buttonList $BPMList -variableList $BPMVarList \
  -allNone 1 -label "BPM selections" -limitPerRow 8

set fastPSList {A:FH1 A:FV1 A:FH2 A:FV2 B:FH2 B:FV2 B:FH1 B:FV1}
set fastPSVarList [eval os editstring i/include/%/:// $fastPSList]
foreach var $fastPSVarList {
    set $var 1
}

APSCheckButtonFrame .fastPScb -parent .userFrame -orientation horizontal -buttonList $fastPSList -variableList $fastPSVarList \
  -allNone 1 -label "Fast PS selections" 

set BPSList {A:H1 A:V1 A:H7 A:V7 A:V8 B:V8 B:V7 B:H7 B:V1 B:H1 \
                  A:Q4T A:Q5T A:M3T A:Q8T A:M4T B:M4T B:Q8T B:M3T B:Q5T B:Q4T \
                  A:SQ1 A:SQ2 B:SQ2 B:SQ1}
set BPSVarList [eval os editstring i/include/%/:// $BPSList]
foreach var $BPSVarList {
    set $var 1
}

APSCheckButtonFrame .bPScb -parent .userFrame -orientation horizontal -buttonList $BPSList -variableList $BPSVarList \
  -allNone 1 -label "Slow bipolar PS selections" -limitPerRow 11

set UPSList {A:Q1 A:Q2 A:Q3 A:Q6 A:Q7 B:Q7 B:Q6 B:Q3 B:Q2 B:Q1  \
                  A:Q4 A:Q5 A:M3 A:Q8 A:M4 B:M4 B:Q8 B:M3 B:Q5 B:Q4 \
                  A:S1 A:S2 A:S3 B:S3 B:S2 B:S1}
set UPSVarList [eval os editstring i/include/%/:// $UPSList]
foreach var $UPSVarList {
    set $var 1
}

APSCheckButtonFrame .uPScb -parent .userFrame -orientation horizontal -buttonList $UPSList -variableList $UPSVarList \
  -allNone 1 -label "Unipolar PS selections" -limitPerRow 11

set PSList [concat $fastPSList $BPSList $UPSList]
set PSVarList [concat $fastPSVarList $BPSVarList $UPSVarList]
set PSPatternList [eval os editstring %/A:/*:/%/B:/*:/ $PSList]
set PSGroupNameList [eval os editstring Z: $PSList]

set includeMedian 1
set includeMean 1
set includeMax 1
set includeMin 1
APSCheckButtonFrame .cb2 -parent .userFrame -label "Statistics: " -orientation horizontal \
                    -buttonList "Median Mean Minimum Maximum" -variableList "includeMedian includeMean includeMin includeMax" 

set description ""
APSLabeledEntry .le1 -parent .userFrame -label "Description: " -textVariable description -width 100

APSButton .transferPreserve -parent .userFrame -text "Transfer (Preserve)" -command "TransferFiles -overwrite 0" \
  -contextHelp "Transfer files, preserving any desination files with the same name"
APSButton .transferOverwrite -parent .userFrame -text "Transfer (Overwrite)" -command "TransferFiles -overwrite 1" \
  -contextHelp "Transfer files, overwriting any desination files with the same name"


