#!/bin/sh  
# \
exec oagwish "$0" "$@"

# Cherenkov detector setup script
# /home/helios/PHOTODIA/operations/s35apps/cherenkov/setupCherenkovSR

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)]

APSStandardSetup

# Process command line arguments
set PowerUser 0
set args $argv
APSParseArguments { PowerUser }

# Authorization setting: everyone can run it
set username [exec whoami]
set authorizedUser 1
set rootUsers { bxyang abrill }
if { [lsearch $rootUsers $username] > -1 } { set authorizedUser 11 }

# Menu 
set appName "setupCherenkovSR: Set up Cherenkov Detectors in SR"

APSApplication . -name $appName \
  -overview "Perform initial setup and measure baseline of gated integrators."

set mainStatus "For initial setup:\n"
APSScrolledStatus .status -parent .userFrame -width 132 -height 16 -textVariable mainStatus 
set mainStatus " (1) Select all sectors and the last known baseline file using \[last\]."
set mainStatus " (2) Make a temp setup file with \[tmp\] and \[Make Cherenkov Detector setup file\]."
set mainStatus " (3) Set up detectors with \[Apply setup file to selected Cherenkov detectors\]."
set mainStatus " (4) Select default baseline filename and take new baseline data."
set mainStatus " (5) Select default setup filename and push the button \[Make Cherenkov Detector setup file\]."
set mainStatus " (6) Push the button \[Make link to setup file\] to make a new link to setup file for OAG scripts. \n"
set mainStatus " (7) Push the button \[Apply setup file to selected Cherenkov detectors\] again. \n"
set mainStatus "For subsequent setup:\n"
set mainStatus " (1) Select all sectors using \[all\] button in Detector Location or click recently restarted IOCs."
set mainStatus " (2) Select the last known setup file using the \[last\] buttons for Setup File."
set mainStatus " (3) Set up detectors with \[Apply setup file to selected Cherenkov detectors\]."
set mainStatus "\n In most cases, one can \[last\] file to recall most recent setup and skip measurements/calculations."

# message window output "stdout"
proc SetMainStatus {text args} {     
    global mainStatus 
    set code ""
    APSParseArguments {code}
    set mainStatus "[clock format [clock seconds] -format %H:%M:%S] $text"
    switch $code {
        error -
        warning {
            bell
        }
        default {}
    }
    update      
}    


# Standard function for excecuting unix commands with error checking. Return 0 if no error.
proc execUnixComm {args} {
    set unixCommand " "
    set addArg1  " "
    set message  " "
    APSParseArguments {unixCommand targets message}

    if [catch {eval exec $unixCommand $addArg1} result] {
      SetMainStatus $result -code error
      if {[string length $message] > 1 } { SetMainStatus $message }
      return 1
    }
      return 0
}


if [string compare $env(HOST_ARCH) WIN32]==0 {
    set tmpPrefix c:/TEMP
} else {
    set tmpPrefix /tmp
}


# Widgets design: Save data file
proc initialSetupFrame {widget args} {
    global abortRun authorizedUser username
    global outputDir setupFile baselineFile stdPMTvolt stdAnodeSens stdDiscrim detList detPrefixList
    global duraDay duraHour duraMin duraSeconds scanSteps numAvgs avgPause monInterval nCPerCount
    
    APSStrictParseArguments {parent}
    
    set fieldWidth 102

    set w $parent$widget.frame
    APSFrame $widget -parent $parent \
        -label "Cherenkov Detector Default Setup" 

    set cherenkovList1 { S01 S02 S03 S04 S05 S06 S07 S08 S09 S10 S11 S12 S13 S14 S15 S16 S17 S18 S19 S20}
    APSCheckButtonFrame .list1 -parent $w \
        -orientation  horizontal \
        -packOption {-side top -fill x} \
        -label "Detector    " \
        -buttonList $cherenkovList1 \
        -variableList { detList(S1) detList(S2) detList(S3) detList(S4) detList(S5) detList(S6) \
          detList(S7) detList(S8) detList(S9) detList(S10) detList(S11) detList(S12) detList(S13) \
          detList(S14) detList(S15) detList(S16) detList(S17) detList(S18) detList(S19) detList(S20) } \
        -contextHelp "Chooses cherekov detectors to test."
    APSButton .none -parent $w.list1 -packOption "-side left" \
      -text "none" -size small \
      -command {setCherenkovList -none 1 }

    set cherenkovList2 { S21 S22 S23 S24 S25 S26 S27 S28 S29 S30 S31 S32 S33 S34 S35 S36 S37 S38 S39 S00 }
    APSCheckButtonFrame .list2 -parent $w \
        -orientation  horizontal \
        -packOption {-side top -fill x} \
        -label "Location    " \
        -buttonList $cherenkovList2 \
        -variableList { detList(S21) detList(S22) detList(S23) detList(S24) detList(S25) detList(S26) \
           detList(S27) detList(S28) detList(S29) detList(S30) detList(S31) detList(S32) detList(S33) \
           detList(S34) detList(S35) detList(S36) detList(S37) detList(S38) detList(S39) detList(S0) } \
        -contextHelp "Chooses cherekov detectors to test."
    APSButton .all -parent $w.list2 -packOption "-side left" \
      -text "all" -size small \
      -command {setCherenkovList -all 1 }

    if { $authorizedUser > 1 } {
      set cherenkovList3 { M1 M2 S4A S4B S4C S4D S4E S36a S36b S36c S36d S36e Bergos }
      APSCheckButtonFrame .list3 -parent $w \
        -orientation  horizontal \
        -packOption {-side top -fill x} \
        -label "For monitor " \
        -buttonList $cherenkovList3 \
        -variableList { detList(M1)   detList(M2)   detList(S4A)  detList(S4B)  detList(S4C)  detList(S4D)    detList(S4E)  
                        detList(S36a) detList(S36b) detList(S36c) detList(S36d) detList(S36e) detList(Bergos) } \
        -contextHelp "Chooses cherekov detectors to test."
    }

    # Set up three frame boxes
    APSFrameGrid .grid -parent $w -xList {x1 x2 x3} -packOption "-side top -fill x"
    set w1 $w.grid.x1
    set w2 $w.grid.x2
    set w3 $w.grid.x3
    
    set fieldWidth1 20
    set fieldWidth2 8
    set fieldWidth3 8

    # First frame box
    set tag "pmtvolt"
    APSLabeledEntry .$tag -parent $w1 \
        -label "PMT High Voltage:" -textVariable stdPMTvolt \
        -contextHelp "Enter standard PMT HV supply voltage. default = ByAnodeSens." \
        -width $fieldWidth1 -packOption "-side top -fill x"
    APSButton .default -parent $w1.$tag -packOption "-side right" \
        -text "default" -size small \
        -command { set stdPMTvolt [defaultVar -var defPMTVolt] }
    APSButton .std -parent $w1.$tag -packOption "-side right" \
        -text "standard" -size small \
        -command { set stdPMTvolt [defaultVar -var stdPMTvolt] }

    set tag "anode"
    APSLabeledEntry .$tag -parent $w2 \
        -label "  Target Anode Sensitivity (A/lm-b):" -textVariable stdAnodeSens \
        -contextHelp "Enter target sensitivity in A/lm-b." \
        -width $fieldWidth2 -packOption "-side top -fill x"
    APSButton .default -parent $w2.$tag -packOption "-side right" \
        -text "default" -size small \
        -command { set stdAnodeSens [defaultVar -var stdAnodeSens] }

    set tag "discrim"
    APSLabeledEntry .$tag -parent $w3 \
        -label "  Discriminator:" -textVariable stdDiscrim \
        -contextHelp "Enter pause time between measurements for averaging." \
        -width $fieldWidth3 -packOption "-side top -fill x"
    APSButton .default -parent $w3.$tag -packOption "-side right" \
        -text "default" -size small \
        -command { set stdDiscrim [defaultVar -var stdDiscrim] }

    # Back to one column
    APSLabeledEntry .outputfile -parent $w \
      -label "Setup file:" -textVariable setupFile \
      -contextHelp "Enter the full name of the output file." \
      -width $fieldWidth -commandButton 1
    if { $authorizedUser > 1 } {
      APSButton .tmp -parent $w.outputfile -packOption "-side right" \
        -text "tmp" -size small \
        -command {set setupFile /tmp/$username-[defaultVar -var setupFile]}
      APSButton .daily -parent $w.outputfile -packOption "-side right" \
        -text "daily" -size small \
        -command {set setupFile [string range [APSGoToDailyDirectory -fourDigitYear 1] 0 end-2]/[defaultVar -var setupFile]}
      APSButton .defaultFile -parent $w.outputfile -packOption "-side right" \
        -text "default" -size small \
        -command {set setupFile [defaultVar -var outputDir]/[defaultVar -var setupFile]}
    }
    APSButton .last -parent $w.outputfile -packOption "-side right" \
      -text "last" -size small \
      -command {set setupFile [ lastDataFile -directory [defaultVar -var outputDir] -keyword Setup ] }
    APSButton .pick -parent $w.outputfile -packOption "-side right" -text "pick" -size small \
      -command {set setupFile [pickDataFile -inputFile $setupFile] }

    APSButton .init -parent $w \
        -text "Apply setup file to selected Cherenkov detectors"  \
        -packOption {-side left} \
        -command { setupCherenkovDetector -dryrun 0 } \
        -contextHelp "Apply new offset calculated from the baseline data."

    APSButton .make -parent $w \
        -text "Make Cherenkov detector setup file"  \
        -packOption {-side right} \
        -command { makeCherenkovSetupFile } \
        -contextHelp "Apply new offset calculated from the baseline data."
    APSButton .plot -parent $w \
        -text "Plot setup file"  \
        -packOption {-side right} \
        -command { plotCherenkovSetupFile } \
        -contextHelp "Plot Cherenkov detector setup parameters by sector."
    APSButton .link -parent $w \
        -text "Make link to setup file"  \
        -packOption {-side right} \
        -command { linkCherenkovSetupFile } \
        -contextHelp "Make a symbolic link to setup file for OAG script."
}


# Widgets design: Save data file
proc takeBaselineDataFrame {widget args} {
    global abortRun outputDir setupFile baselineFile stdPMTvolt stdAnodeSens stdDiscrim detList detPrefixList
    global duraDay duraHour duraMin duraSeconds scanSteps numAvgs avgPause monInterval nCPerCount
    
    APSStrictParseArguments {parent}
    
    set fieldWidth 100

    set w $parent$widget.frame
    APSFrame $widget -parent $parent \
        -label "Cherenkov Detector Integrator Baseline Measurements"

    # Set up three frame boxes
    APSFrameGrid .grid -parent $w -xList {x1 x2 x3} -packOption "-side top -fill x"
    set w1 $w.grid.x1
    set w2 $w.grid.x2
    set w3 $w.grid.x3
    
    set fieldWidth1 12
    set fieldWidth2 12
    set fieldWidth3 12

    # First frame box
    APSLabeledEntry .steps -parent $w1 \
        -label "Number of data points for baseline measurement:" -textVariable scanSteps \
        -contextHelp "Enter scan STEPS." \
        -width $fieldWidth1 -packOption "-side top -fill x"
    APSButton .default -parent $w1.steps -packOption "-side right" \
        -text "calculate" -size small \
        -command { set scanSteps [calMonSteps] }

    APSLabeledEntry .interval -parent $w2 \
        -label "   Interval:" -textVariable monInterval \
        -contextHelp "Enter interval between monitor data points." \
        -width $fieldWidth2 -packOption "-side top -fill x"
    APSButton .default -parent $w2.interval -packOption "-side right" \
        -text "default" -size small \
        -command { set monInterval [defaultVar -var monInterval] }

    APSLabeledEntry .count -parent $w3 \
        -label "   nC per Count:" -textVariable nCPerCount \
        -contextHelp "Enter pause time between measurements for averaging." \
        -width $fieldWidth3 -packOption "-side top -fill x"
    APSButton .default -parent $w3.count -packOption "-side right" \
        -text "default" -size small \
        -command { set nCPerCount [defaultVar -var nCPerCount] }

    APSLabeledEntry .outputfile -parent $w \
      -label "Baseline file:   " -textVariable baselineFile \
      -contextHelp "Enter the full name of the output file." \
      -width $fieldWidth -commandButton 1
    APSButton .tmp -parent $w.outputfile -packOption "-side right" \
      -text "tmp" -size small \
      -command {set baselineFile /tmp/$username-[defaultVar -var baselineFile]}
    APSButton .last -parent $w.outputfile -packOption "-side right" \
      -text "last" -size small \
      -command {set baselineFile [ lastDataFile -directory [defaultVar -var outputDir] -keyword Baseline ] }
#    APSButton .daily -parent $w.outputfile -packOption "-side right" \
      -text "daily" -size small \
      -command {set baselineFile [string range [APSGoToDailyDirectory -fourDigitYear 1] 0 end-2]/[defaultVar -var baselineFile]}
    APSButton .defaultFile -parent $w.outputfile -packOption "-side right" \
      -text "default" -size small \
      -command {set baselineFile [defaultVar -var outputDir]/[defaultVar -var baselineFile]}
    APSButton .pick -parent $w.outputfile -packOption "-side right" -text "pick" -size small \
      -command {set baselineFile [pickDataFile -inputFile $baselineFile] }

    # Start SDDS Waveform Monitor 
    APSButton .scan -parent $w \
        -text "Take baseline data"  \
        -command { takeBaselineData } \
        -contextHelp "Save baseline data ."

    APSButton .calc -parent $w \
        -text "Calculate OFFSET"  \
        -command { calIntOffset -printOffset 1 -setOffset 0 } \
        -contextHelp "Calculate new offset from the baseline data."

    APSButton .apply -parent $w \
        -text "Apply new OFFSET"  \
        -command { calIntOffset -printOffset 0 -setOffset 1 } \
        -contextHelp "Apply new offset calculated from the baseline data."

#    APSButton .print -parent $w \
        -text "Show Selection"  \
        -packOption {-side right} \
        -command { SetMainStatus "cherenkovList = [getCherenkovList]" } \
        -contextHelp "Show selected detectors."

#    APSButton .mon -parent $w \
        -text "Make MON file"  \
        -packOption {-side right} \
        -command { makeMonitorFile -fileName "/tmp/$username-junkFile.mon" } \
        -contextHelp "Make monitor files for sddsmonitor."

    APSButton .del -parent $w \
        -text "Delete file"  \
        -packOption {-side right} \
        -command { deleteDataFile -file $baselineFile } \
        -contextHelp "Delete bunch purity waveform file."

    APSButton .cleandir -parent $w \
        -text "Clean up directory"  \
        -command { cleanUpDirectory -directory $baselineFile } \
        -contextHelp "Delete junk files and put away monitor and experiment files." \
        -packOption {-side right} 
}


#################################
#	File operations		#
#################################

proc deleteDataFile {args} {
    set directory ""
    set file ""
    APSParseArguments {directory file}
    if { [string length $directory]>0 } {
      set filename $directory/$file
    } else {
      set filename $file
    }
    if ![file exists $filename] {
        return -code error "Can't find file $filename to delete."
    }
    if [APSYesNoPopUp "Are you sure to delete file $filename?"] {
        exec rm -f "$filename"
        SetMainStatus "$filename was deleted"
    }
    return
}


proc cleanUpDirectory {args} {
    global VERBOSE
    set directory ""
    APSParseArguments {directory}
    
    if $VERBOSE {SetMainStatus "cleanUpDirectory: directory = $directory"}
    set cleanDir [file dirname $directory]
    SetMainStatus "cleanUpDirectory: cleanDir = $cleanDir"
    
    #Check whether the directory exists
    if ![file exists $cleanDir] {
        return -code error "Can't find file $cleanDir for clean up."
    }

    # get file names in cleanDir
    set fileList [exec ls $cleanDir]
    if $VERBOSE { SetMainStatus "deleteJunkFiles: fileList = $fileList" }

    # delete junk and temp files 
    SetMainStatus "cleanUpDirectory: delete junk* and temp* files." 
    foreach oneFile $fileList {
      if { ( [ string first "junk" $oneFile ] == 0 ) || ( [ string first "temp" $oneFile ] == 0 ) } {
        if $VERBOSE { SetMainStatus "cleanUpDirectory: delete $oneFile" }
        if [execUnixComm -unixCommand "rm -r $cleanDir/$oneFile"] { return }
      }
    }

    # delete *.mon~ and *.exp~ files 
    SetMainStatus "cleanUpDirectory: delete *.mon~ and *.exp~ files." 
    foreach oneFile $fileList {
      if { ( [ string first ".mon~" $oneFile ] > 0 ) || ( [ string first ".exp~" $oneFile ] > 0 ) } {
        if $VERBOSE { SetMainStatus "cleanUpDirectory: delete $oneFile" }
        if [execUnixComm -unixCommand "rm -r $cleanDir/$oneFile"] { return }
      }
    }

    # make mon directory if not exist already 
    SetMainStatus "cleanUpDirectory: put away *.mon and *.exp files." 
    if ![file exists $cleanDir/mon] {
      SetMainStatus "cleanUpDirectory: make monitor directory: $cleanDir/mon." 
      if [execUnixComm -unixCommand "mkdir $cleanDir/mon"] { return }
    }
    
    # put away monitor files and exp files 
    foreach oneFile $fileList {
      if { ( [file extension $oneFile] == ".exp" ) || ( [file extension $oneFile] == ".mon" ) } {
        if $VERBOSE { SetMainStatus "cleanUpDirectory: move $oneFile" }
        if [execUnixComm -unixCommand "mv $cleanDir/$oneFile $cleanDir/mon"] { return }
      }
    }

    SetMainStatus "cleanUpDirectory: done." 
    return
}


proc pickDataFile {args} { 
    global VERBOSE pickDir pickFile baselineFile

    set inputFile NOARG
    APSParseArguments {inputFile}

    # determine whether to use old value in pickDir
    if { $inputFile == "NOARG" } {
      if { [string length $pickDir] < 8 } { set pickDir [file dirname $baselineFile] }
    } else {
      if { [string length $inputFile] < 8 } { 
        set pickDir [file dirname $inputFiles(0)] 
      } else {
	set pickDir [file dirname $inputFile]
      }      
    }

	# Pick a file name
    set fileName [APSFileSelectDialog .[APSTmpString] -listDir $pickDir -width 90 \
                       -contextHelp "File select box for linear fit scan data file."]
    
	#check validity of filename
    if { [string length $fileName]==0 } { return }

	# Save pick file sirectory and filename separately	
    set pickDir [file dirname $fileName]
    set pickFile [file tail $fileName]

    if $VERBOSE { SetMainStatus "pickDataFile: \n pickDir = $pickDir \n pickFile = $pickFile" }
    return $pickDir/$pickFile
}


proc lastDataFile {args} {
    set directory [defaultVar -var outputDir]
    set keyword   "Baseline"
    APSParseArguments { directory keyword }
    if ![file exists $directory]      { return -code error "Can't find directory $directory." } 
    if ![file isdirectory $directory] { set directory [file dirname $directory] } 
    
    # Select baseline files
    set fileList [exec ls $directory]
    set baselineFileList ""
    # SetMainStatus "lastDataFile: fileList = $fileList"
    foreach oneFile $fileList {
      if { [string first $keyword $oneFile] > -1 } { lappend baselineFileList $oneFile }
    }
    # SetMainStatus "lastDataFile: baselineFileList = $baselineFileList"
    
    # Select last file
    set baselineFileList [lsort -decreasing $baselineFileList]
    set oneFile "$directory/[lindex $baselineFileList 0]"
    return $oneFile
}


#########################################
#	Setup Cherenkov Boards		#
#########################################

proc getCherenkovBoard {args} {
    global VERBOSE nToalDetectors detList detPrefixList installList boardList
    
    set detector S1
    APSParseArguments { detector }

    return $detector
}


proc setCherenkovList {args} {
    global VERBOSE nToalDetectors detList detPrefixList installList boardList
    
    set none 1
    set all  0
    APSParseArguments { all none }

    # clear all settings
    
    if $none {
        if $VERBOSE { SetMainStatus "setCherenkovList: clear detList" }    
        foreach detector $detPrefixList { set detList($detector) 0 }
    }
    
    # set all installed detectors/ boards
    if $all {
        if $VERBOSE { SetMainStatus "setCherenkovList: installList = $installList" }    
        foreach detector $boardList { set detList($detector) 1 }
    }
}


proc getCherenkovList {args} {
    global VERBOSE nToalDetectors detList detPrefixList installList boardList 
    
    set cherenkovList { }
    foreach detector $detPrefixList {
     if $detList($detector) { 
       if { [lsearch $installList $detector] >= 0 } {
         lappend cherenkovList $detector
       } else {
         SetMainStatus "getCherenkovList: Cherenkov detector in $detector is not installed."
       }
     }
    }
    
    if $VERBOSE { SetMainStatus "getCherenkovList: cherenkovList = $cherenkovList" }    
    return $cherenkovList   
}


proc printSelection {args} {
    SetMainStatus "cherenkovList = [getCherenkovList]"
}


proc makeCherenkovSetupFile {args} {
    global abortRun VERBOSE username
    global outputDir setupFile baselineFile stdPMTvolt stdAnodeSens stdDiscrim detList detPrefixList
    global duraDay duraHour duraMin duraSeconds scanSteps numAvgs avgPause monInterval nCPerCount

    set overwrite 0
    APSParseArguments { overwrite }

    # Check for existing file
    if [file exists $setupFile] {
        if $overwrite { 
          execUnixComm -unixCommand "rm $setupFile" 
        } else {
          SetMainStatus "Output file $setupFile exists. No action."
          return "ERROR"
        }
    }

    # default application directory
    set appsDir /home/helios/PHOTODIA/operations/s35apps/cherenkov/
    
    # temp files
    set junkFile0 /tmp/$username-junkSetupFile0.sdds
    set junkFile1 /tmp/$username-junkSetupFile1.sdds
    set junkFile2 /tmp/$username-junkSetupFile2.sdds
    
    # calculate integrator offset
    SetMainStatus " "
    SetMainStatus "makeCherenkovSetupFile: Calculating gated integrator offsets..."
    calIntOffset -printOffset 0 -setOffset 0 -outputFile $junkFile0

    # Make setup data sector by sector
    set firstSite 1
    set cherenkovList [getCherenkovList]
    foreach detector $cherenkovList {
      # Calculate PMT gain for site
      set site "${detector}"
      set msg [exec $appsDir/onePMTGain -site $site -targetSensitivity $stdAnodeSens -outputFile $junkFile1 ]
      SetMainStatus "$msg"
      # Find the Cherenkov board connected to the PMT
      set board [getCherenkovBoard -detector $detector]
      # Determin the setting of the Cherenkov board
      set targetPMTVolt  [format %0.0f [lindex [APSGetSDDSColumn -fileName $junkFile1 -column targetPMTVolt] 0] ]
      set Adc0AIOffset  -[format %0.0f [APSGetSDDSParameter -fileName $junkFile0 -parameter "$board:cerenkov:Adc0M.Offset" -page 1] ]
      set Adc1AIOffset  -[format %0.0f [APSGetSDDSParameter -fileName $junkFile0 -parameter "$board:cerenkov:Adc1M.Offset" -page 1] ]
      SetMainStatus "Detector $site is connected to board at $board, targetPMTVolt = Cherenkov detector $targetPMTVolt \n \
                     Gated integrator offsets: Adc0AIOffset = $Adc0AIOffset, Adc1AIOffset = $Adc1AIOffset"

      exec sddsprocess $junkFile1 $junkFile2 \
        -def=col,Adc0AIOffset,$Adc0AIOffset -def=col,Adc1AIOffset,$Adc1AIOffset \
        -def=col,Discriminator,$stdDiscrim  -print=col,Sector,$board
      if $firstSite {
        set firstSite 0
        exec sddsprocess $junkFile2 $setupFile
      } else {
        exec sddscombine $setupFile $junkFile2 $junkFile1 -overWrite -merge
        exec sddsprocess $junkFile1 $setupFile
      }
    }
    
    # Print the setup file contents
    setupCherenkovDetector -dryrun 1

    SetMainStatus "makeCherenkovSetupFile: Done."
    return
}


proc plotCherenkovSetupFile {args} {
    global abortRun VERBOSE
    global outputDir setupFile baselineFile stdPMTvolt stdAnodeSens stdDiscrim detList detPrefixList
    global duraDay duraHour duraMin duraSeconds scanSteps numAvgs avgPause monInterval nCPerCount

    set plotType 0
    APSParseArguments { plotType }
    
    # Check for existing file
    if ![file exists $setupFile] {
      SetMainStatus "plotCherenkovSetupFile: Output file no found \n   $setupFile."
      return "ERROR"
    }

    set columnList [APSGetSDDSNames -fileName $setupFile -class column]
    if { [lsearch $columnList $plotType] > -1 } {
      SetMainStatus "plotCherenkovSetupFile: plotType = $plotType."
    } else {
      SetMainStatus "plotCherenkovSetupFile: Default plot."
      exec sddsplot -layout=1,3 -separate \
        -col=Sector,targetPMTVolt -graph=symb $setupFile \
        -col=Sector,AnodeSensitivity -graph=symb $setupFile \
        -col=Sector,LogGainSlope -graph=symb $setupFile \
        &
    }
    
    SetMainStatus "plotCherenkovSetupFile: Done"
    return
}


proc linkCherenkovSetupFile {args} {
    global abortRun VERBOSE
    global outputDir setupFile baselineFile stdPMTvolt stdAnodeSens stdDiscrim detList detPrefixList
    global duraDay duraHour duraMin duraSeconds scanSteps numAvgs avgPause monInterval nCPerCount

    # contains serial number (SN), so calibration of year 2015 can follow the isntrument.
    # column Site would be incorrect for APS-U
    set setupFileLink "/home/helios/PHOTODIA/DeviceData/SR/Cherenkov/cherenkovSetup.sdds"
    
    # Check for existing file
    if ![file exists $setupFile] {
      SetMainStatus "linkCherenkovSetupFile: Setup file no found \n   $setupFile."
      return "ERROR"
    }

    # delete existing link
    if [file exists $setupFileLink] {
      SetMainStatus "linkCherenkovSetupFile: Remove existing link \n   $setupFileLink."
      file delete -force $setupFileLink
    }
    
    # Make a new link
    SetMainStatus "linkCherenkovSetupFile: \n Make new link $setupFileLink \n To $setupFile."
    exec ln -s $setupFile $setupFileLink
    
    SetMainStatus "plotCherenkovSetupFile: Done"
    return
}


proc setupCherenkovDetector {args} {
    global abortRun VERBOSE mainStatus username
    global outputDir setupFile baselineFile stdPMTvolt stdAnodeSens stdDiscrim detList detPrefixList
    global duraDay duraHour duraMin duraSeconds scanSteps numAvgs avgPause monInterval nCPerCount

    set dryrun 0
    APSParseArguments { dryrun }

    # check input directory for existence
    if ![file exists $setupFile] {
      SetMainStatus "setupCherenkovDetector: Setup parameter file $setupFile not found."
      return "ERROR"
    }

    # temp files
    set junkFile0 /tmp/$username-junkSetupFile0.sdds
    
    # Get list of detectors to set
    set cherenkovList [getCherenkovList]
    if { $dryrun==0 } { SetMainStatus "setupCherenkovDetector: Initializing these Cherenkov detector boards: \n $cherenkovList" }
    
    foreach detector $cherenkovList { 
      set site "${detector}"
      set board [getCherenkovBoard -detector $detector]
      # SetMainStatus "setupCherenkovDetector: Initializing Cherenkov detector $site connect to Board $board "
      exec sddsprocess $setupFile $junkFile0 -match=column,Site=$site
      set targetPMTVolt [format %0.1f [lindex [APSGetSDDSColumn -fileName $junkFile0 -column targetPMTVolt] 0] ]
      set Adc0AIOffset  [format %0.0f [lindex [APSGetSDDSColumn -fileName $junkFile0 -column Adc0AIOffset]  0] ]
      set Adc1AIOffset  [format %0.0f [lindex [APSGetSDDSColumn -fileName $junkFile0 -column Adc1AIOffset]  0] ]
      set Discriminator [format %0.3f [lindex [APSGetSDDSColumn -fileName $junkFile0 -column Discriminator] 0] ]
      set mainStatus "Site = $site, board = $board, targetPMTVolt = $targetPMTVolt, Adc0AIOffset = $Adc0AIOffset, Adc1AIOffset = $Adc1AIOffset, Discriminator = $Discriminator"

      if { $dryrun==0 } {
        if [catch  exec setupCherenkovOneSector -sector [format %02ld $board] \
              -integratorOffset0 $Adc0AIOffset -integratorOffset1 $Adc1AIOffset -pmtHV $targetPMTVolt -discriminator $Discriminator \
          } result] {
          SetMainStatus $result -code error
          return 1
        }
      SetMainStatus "\n$result \n"
      SetMainStatus "setupCherenkovDetector: Complete initializing Cherenkov detector boards at $board."
      }
    }
    
    SetMainStatus "."
    SetMainStatus "setupCherenkovDetector: Completed."
    return
}



#################################################
#	Take Cherenkov integrator data		#
#################################################

proc makeMonitorFile {args} {
    global VERBOSE DRYRUN inputDir detList detPrefixList

    set fileName  ERR
    set overwrite 1
    APSParseArguments { fileName overwrite }

    if $VERBOSE { SetMainStatus "makeMonitorFile: Make monitor file: $fileName." }

	# check output directory existence
    if [file exists $fileName] {
        if $overwrite { 
          execUnixComm -unixCommand "rm $fileName" 
        } else {
          SetMainStatus "Output file $fileName exists. No action."
          return "ERROR"
        }
    }

	# check input directory existence
    set inputFile monOneVarTemplate.mon
    if ![file exists $inputDir/$inputFile] {
        SetMainStatus "Can't find input monitor file $inputFile at $inputDir."
        return "ERROR"
    }

	# start basic monitor file
    set ctrlName1 S-DCCT:CurrentM
    set rdbkName1 srCurrent
    set unit1     mA
    exec replaceText $inputDir/$inputFile $fileName \
       -original=<ctrlName1>,<rdbkName1>,<unit1> \
       -replace=$ctrlName1,$rdbkName1,$unit1
#    execUnixComm -unixCommand "cp $inputDir/$inputFile $fileName"

	# Add Sxx files one by 1
    set cherenkovList [getCherenkovList]
    foreach detector $cherenkovList { 
      if $VERBOSE {SetMainStatus "makeMonitorFile: add monitor for detector = $detector." }
      addOneMonFile -fileName $fileName -detector $detector
    }

    SetMainStatus "makeMonitorFile: Done"
    return $fileName
}


proc addOneMonFile {args} {
    global VERBOSE inputDir scanVar username

    APSStrictParseArguments { fileName detector }
    
    if $VERBOSE {SetMainStatus "addOneMonFile: detector = $detector, fileName = $fileName" }
    set tempFile /tmp/$username-junkMonitorFile.mon

	# check output directory existence
    if ![file exists $fileName] {
      SetMainStatus "addOneMonFile: Basic monitor file $fileName not found."
      return "ERROR"
    }
	# check input file existence
    set inputFile "$inputDir/extraThreeVar.mon"
    if ![file exists $inputFile] {
        SetMainStatus "Can't find input monitor file $inputFile."
        return "ERROR"
    }
    
    set ctrlName1 $detector:cerenkov:Adc0AI.RVAL
    set rdbkName1 $detector:cerenkov:Adc0AI.Raw
    set unit1     cnts
    set ctrlName2 $detector:cerenkov:Adc1AI.RVAL
    set rdbkName2 $detector:cerenkov:Adc1AI.Raw
    set unit2     cnts
    set ctrlName3 $detector:cerenkov:CountAI
    set rdbkName3 $detector:cerenkovCount
    set unit3     cnts

	# combine files and replace video frame grabber PV
    exec cat $fileName $inputFile > $tempFile
    exec replaceText $tempFile $fileName \
       -original=<ctrlName1>,<rdbkName1>,<unit1>,<ctrlName2>,<rdbkName2>,<unit2>,<ctrlName3>,<rdbkName3>,<unit3> \
       -replace=$ctrlName1,$rdbkName1,$unit1,$ctrlName2,$rdbkName2,$unit2,$ctrlName3,$rdbkName3,$unit3
    exec rm -f $tempFile

    return $fileName
}


proc takeBaselineData {args} {
    global abortRun VERBOSE
    global outputDir baselineFile scanVar scanVarStart scanVarStop scanSteps monInterval

    if [file exists $baselineFile] { return -code error "takeBaselineData: file $baselineFile exists." }

    # File root
    if { [string first . $baselineFile] < 0 } { 
      set monRoot $baselineFile
    } else {
      set monRoot [string range $baselineFile 0 [expr [string last . $baselineFile] - 1] ]
    }
    
    # Check directory   
    set outputDir [file dirname $baselineFile]
    if ![file exist $outputDir] {
        exec mkdir $outputDir
        #exec setfacl -m mask:rwx $outputDir
        exec /home/helios/OAG/bin/setFACL-oagPlus \
            emery,borland,shang,oag,bxyang,sr,asdops,sereno,cyao $outputDir
    }
    
    # set scanVar for monitor application
    set scanVar Time
    
    # Make monitor file
    set monFile  $monRoot.mon
    makeMonitorFile -fileName $monFile -overwrite 1
    
    #####   Take data  #####
    # start fast scan 
    SetMainStatus "Experiment started. File = \n $baselineFile"
    APSExecLog .job \
        -unixCommand "sddsmonitor $monFile $baselineFile -steps=$scanSteps -interval=$monInterval,sec -verbose" \
        -contextHelp "This window is running a cherenkovMonitor process."  

    SetMainStatus "takeBaselineData: Started...."
    return
}


proc calIntOffset {args} {
    global abortRun VERBOSE username
    global outputDir baselineFile scanVar scanVarStart scanVarStop scanSteps monInterval nCPerCount

    set printOffset  1
    set setOffset    0
    set outputFile   NONE
    APSParseArguments { printOffset setOffset outputFile }

    set junkFile0 /tmp/$username-junkBaselineFile0.sdds
    set junkFile1 /tmp/$username-junkBaselineFile1.sdds
    
    if [catch { exec \
         sddsprocess $baselineFile -pipe=out  "-define=col,pIndex,i_row 120 / int" \
       | sddsbreak   -pipe -changeOf=pIndex,amount=0.99 \
       | sddsprocess -pipe \
          "-process=S*-CBLM:CDET:Adc0M.Raw,maximum,%sMax" \
          "-process=S*-CBLM:CDET:Adc1M.Raw,maximum,%sMax" \
          "-process=S*-CBLM:CDET:Adc0M.Raw,average,%sAve0" \
          "-process=S*-CBLM:CDET:Adc1M.Raw,average,%sAve0" \
          "-process=S*-CBLM:CDET:Adc1M.Raw,sigma,%sSigma0" \
          "-process=S*-CBLM:CDET:Adc0M.Raw,sigma,%sSigma0" \
          "-process=S*:cerenkovCount,maximum,%sMax" \
          "-process=S*:cerenkovCount,average,%sAve0" \
       | sddsprocess -pipe=in $junkFile0 \
          "-def=par,%s-CBLM:CDET:Adc0M.RawAve,%s-CBLM:CDET:Adc0M.RawAve0 1 1 n_rows / - / %s-CBLM:CDET:Adc0M.RawMax n_rows 1 - / -,select=*-CBLM:CDET:Adc0M.RawMax,edit=%/-CBLM:CDET:Adc0M.RawMax//" \
          "-def=par,%s-CBLM:CDET:Adc1M.RawAve,%s-CBLM:CDET:Adc1M.RawAve0 1 1 n_rows / - / %s-CBLM:CDET:Adc1M.RawMax n_rows 1 - / -,select=*-CBLM:CDET:Adc1M.RawMax,edit=%/-CBLM:CDET:Adc1M.RawMax//" \
          "-def=par,%s-CBLM:CDET:Adc0M.RawSigma,%s-CBLM:CDET:Adc0M.RawSigma0 n_rows 1 - sqrt *,select=*-CBLM:CDET:Adc0M.RawMax,edit=%/-CBLM:CDET:Adc0M.RawMax//" \
          "-def=par,%s-CBLM:CDET:Adc1M.RawSigma,%s-CBLM:CDET:Adc1M.RawSigma0 n_rows 1 - sqrt *,select=*-CBLM:CDET:Adc1M.RawMax,edit=%/-CBLM:CDET:Adc1M.RawMax//" \
          "-def=par,%s:cerenkovCountAve,%s:cerenkovCountAve0 1 1 n_rows / - / %s:cerenkovCountAve0 n_rows 1 - / -,select=*:cerenkovCountMax,edit=%/:cerenkovCountMax//" \
       } result] {
      SetMainStatus $result -code error
      return 1
    }
    
    set factor0 [expr $nCPerCount / 50.0 * 65536]
    set factor1 [expr $nCPerCount / 1000.0 * 65536]
    if [catch { exec \
         sddscollapse $junkFile0 -pipe=out \
       | sddsprocess -pipe \
          "-process=S*-CBLM:CDET:Adc0M.RawAve,average,%s" \
          "-process=S*-CBLM:CDET:Adc1M.RawAve,average,%s" \
          "-process=S*-CBLM:CDET:Adc0M.RawSigma,average,%s" \
          "-process=S*-CBLM:CDET:Adc1M.RawSigma,average,%s" \
          "-process=S*:cerenkovCountAve,average,%s" \
       | sddsprocess -pipe=in $junkFile1 \
          "-def=par,%s-CBLM:CDET:Adc0M.Offset,%s-CBLM:CDET:Adc0M.RawAve %s:cerenkovCountAve $factor0 * -,select=*-CBLM:CDET:Adc0M.RawAve,edit=%/-CBLM:CDET:Adc0M.RawAve//" \
          "-def=par,%s-CBLM:CDET:Adc1M.Offset,%s-CBLM:CDET:Adc1M.RawAve %s:cerenkovCountAve $factor0 * -,select=*-CBLM:CDET:Adc1M.RawAve,edit=%/-CBLM:CDET:Adc1M.RawAve//" \
       } result] {
      SetMainStatus $result -code error
      return 1
    }

	# Calculate Sxx one by one
    set cntOffset  0
    set sumOffset0 0
    set sumOffset1 0
    set cherenkovList [getCherenkovList]
    set detectorList3 { S4A S4B S4C S4D S4E S36a S36b }
    set boardList3    { S3  S5  S6  S7  S8  S36a S36b }
    foreach detector $cherenkovList { 
      SetMainStatus "detector = $detector"
      # Find the Cherenkov board connected to the PMT
      set detectorIndex [lsearch $detectorList3 $detector]
      if { $detectorIndex > -1 } {
        set board [lindex $boardList3 $detectorIndex]
      } else {
        set board $detector
      }
      set oldOffset0    [getVar -var Offset0 -extraVar $board]
      set oldOffset1    [getVar -var Offset1 -extraVar $board]
      set newOffset0   -[format %0.0f [APSGetSDDSParameter -fileName $junkFile1 -parameter "$board-CBLM:CDET:Adc0M.Offset" -page 1] ]
      set newOffset1   -[format %0.0f [APSGetSDDSParameter -fileName $junkFile1 -parameter "$board-CBLM:CDET:Adc1M.Offset" -page 1] ]
      set sigmaOffset0  [format %0.0f [APSGetSDDSParameter -fileName $junkFile1 -parameter "$board-CBLM:CDET:Adc0M.RawSigma" -page 1] ]
      set sigmaOffset1  [format %0.0f [APSGetSDDSParameter -fileName $junkFile1 -parameter "$board-CBLM:CDET:Adc1M.RawSigma" -page 1] ]
      set offsetChange0 [format %0.0f [expr $newOffset0 - $oldOffset0] ]
      set offsetChange1 [format %0.0f [expr $newOffset1 - $oldOffset1] ]
      if $printOffset {
        SetMainStatus "calIntOffset: Detector $detector Offset0 (new/old) = $newOffset0 / $oldOffset0; sigmaOffset0 = $sigmaOffset0; Change = $offsetChange0"
        SetMainStatus "calIntOffset: Board $board,    Offset1 (new/old) = $newOffset1 / $oldOffset1; sigmaOffset0 = $sigmaOffset1; Change = $offsetChange1"
      }
      set cntOffset  [expr $cntOffset  + 1]
      set sumOffset0 [expr $sumOffset0 + $newOffset0]
      set sumOffset1 [expr $sumOffset1 + $newOffset1]
      if $setOffset {
        SetMainStatus "calIntOffset: Set Detector $detector, Board $board, Offset0 = $newOffset0; Offset1 = $newOffset1"
        setVar -var Offset0 -extraVar $board -value $newOffset0
        setVar -var Offset1 -extraVar $board -value $newOffset1
      }
    }
    
    # CALCULATE AVERAGE 
    if { $cntOffset > 0 } {
      set avgOffset0 [expr $sumOffset0 / $cntOffset]
      set avgOffset1 [expr $sumOffset1 / $cntOffset]
    } else {
      set avgOffset0 0
      set avgOffset1 0
    }
    SetMainStatus "calIntOffset: For Sectors $cherenkovList \n avgOffset0 = $avgOffset0, avgOffset1 = $avgOffset1"
    
    # Save offset file
    if { $outputFile!="NONE" } { exec sddsprocess $junkFile1 $outputFile }

    SetMainStatus "calIntOffset: Done."

    return
}



proc getPV {args} {
    global VERBOSE

    APSParseArguments {pv}

    if {[string length $pv] < 5} {
        if {$VERBOSE} {APSSetVarAndUpdate mainStatus "getPV: PV is not valid: $pv, return 0!"}
        set value 0
    } else {
        set value [caget $pv]
        if {$VERBOSE} {APSSetVarAndUpdate mainStatus "getPV: $pv has value of $value"}
        if [string match *Error* $value] {set value 0}
    }
    
    return $value
}



proc setPV {args} {
    global VERBOSE
    global authorizedUser
    global DRYRUN
    
    set readback 0
    APSParseArguments {pv value readback}

    if {[string length $pv] < 5} {
        APSSetVarAndUpdate mainStatus "setPV: PV is not valid: $pv, No action taken!"
        return
    }
    
    if { ($DRYRUN!=0) || ($authorizedUser==0) } {
        APSSetVarAndUpdate mainStatus "pretend setting $pv to $value"
    } else {
        if $VERBOSE { APSSetVarAndUpdate mainStatus "Setting $pv to $value" }
        exec caput $pv $value
    }   

    if !$readback { return 0 }
    set newValue [getPV -pv $pv]
    return $newValue 
}



proc setVar {args} {
    global VERBOSE

    set var error
    set extraVar error
    set value 0
    set readback 0
    APSParseArguments {var extraVar value readback}
    if {$VERBOSE} {APSSetVarAndUpdate mainStatus "(defaultVar) var=$var, extraVar=$extraVar"}
    if {$var == "error"} { return error }

    set pv [getPVName -var $var -extraVar $extraVar]
    if {$pv == 0} { return error }
    set newValue [setPV -pv $pv -value $value -readback $readback]
    return $newValue
}




proc getVar {args} {
    global VERBOSE

    set var error
    set extraVar error
    APSParseArguments {var extraVar}
    if {$VERBOSE} {APSSetVarAndUpdate mainStatus "getVar: var=$var, extraVar=$extraVar"}
    if {$var == "error"} { return error }

    set pv [getPVName -var $var -extraVar $extraVar]
    if {$var == 0} { return error }
    set value [getPV -pv $pv]
    return $value
}



proc getPVName {args} {
    global VERBOSE
    
    set var error
    set extraVar error
    APSStrictParseArguments {var extraVar}
    
    if {$VERBOSE} {APSSetVarAndUpdate mainStatus "var=$var, extraVar=$extraVar"}
    switch $var {
        PMT-HV     	{ set pv [format "%s-BLM:CDET:HighVoltageC" $extraVar] }
        Discriminator	{ set pv [format "%s-BLM:CDET:DacC" $extraVar] }
        CountTime	{ set pv [format "%s-BLM:CDET:ClearRateC" $extraVar] }
        Offset0		{ set pv [format "%s-BLM:CDET:Adc0M.ROFF" $extraVar] }
        Offset1		{ set pv [format "%s-BLM:CDET:Adc1M.ROFF" $extraVar] }
    }
    return $pv
}



proc defaultVar {args} {
    global VERBOSE scanVar inputFile scheduleRun
    global hourStart dayStart monthStart yearStart
    set var error
    APSParseArguments {var}

    set timeStamp [clock format [clock seconds] -format %Y-%m%d-%H%M]
    set value ERROR
    if {$VERBOSE} {APSSetVarAndUpdate mainStatus "var = $var, value = $value"}
    switch $var {
        scanSteps      { set value 300 }
        monInterval    { set value 1 }
        nCPerCount     { set value 0.0 }
        stdPMTvolt     { set value 800 }
        defPMTvolt     { set value "ByAnodeSensitivity" }
        stdAnodeSens   { set value 5.0 }
        stdDiscrim     { set value 0.50 }
        inputDir       { set value /home/helios/PHOTODIA/operations/s35apps/inputFiles }
        outputDir      { set value [clock format [clock seconds] -format /home/helios/PHOTODIA/DeviceData/SR/Cherenkov/%Y/Setup] }
        baselineFile   { set value cherenkovBaseline-$timeStamp.sdds }
        setupFile      { set value cherenkovSetup-$timeStamp.sdds }
    }
    if {$VERBOSE} {APSSetVarAndUpdate mainStatus "var = $var, value = $value"}

    return $value
}


#########################################################
#	Define and initialize important global vars	#
#########################################################

set abortRun 0
set VERBOSE  0
set DRYRUN   0


set scanVar        Time
set scanVarStart   1
set scanVarStop    1
set duraDay        6
set duraHour       0
set duraMin        0
set scanSteps      [defaultVar -var scanSteps]
set monInterval    [defaultVar -var monInterval]
set nCPerCount	   [defaultVar -var nCPerCount]
set stdPMTvolt     [defaultVar -var defPMTvolt]
set stdAnodeSens   [defaultVar -var stdAnodeSens]
set stdDiscrim	   [defaultVar -var stdDiscrim]
set inputDir       [defaultVar -var inputDir]
set baselineFile   [defaultVar -var outputDir]/[defaultVar -var baselineFile]
set setupFile      [lastDataFile -directory [defaultVar -var outputDir] -keyword Setup]

# a list of good cherenkov detectors
set nToalDetectors 41
set detPrefixList  { S01 S02 S03 S04 S05 S06 S07 S08 S09 S10 S11 S12 S13 S14 S15 S16 S17 S18 S19 S20 \
	S21 S22 S23 S24 S26 S27 S28 S29 S30 S31 S32 S33 S34 S35 S36 S37 S38 S39 S40}
# List of installed detectors as of 11/3/09
set boardList    { S01 S02 S03 S04 S05 S06 S07 S08 S09 S10 S11 S12 S13 S14 S15 S16 S17 S18 S19 S20 \
	S21 S22 S23 S24 S26 S27 S28 S29 S30 S31 S32 S33 S34 S35 S36 S37 S38 S39 S40 }
set installList  { S01 S02 S03 S04 S05 S06 S07 S08 S09 S10 S11 S12 S13 S14 S15 S16 S17 S18 S19 S20 \
	S21 S22 S23 S24 S26 S27 S28 S29 S30 S31 S32 S33 S34 S35 S36 S37 S38 S39 S40}
setCherenkovList -all 1

#########################################
#	START INPUT / OUTPUT FRAMES	#
#########################################

initialSetupFrame      .init   -parent .userFrame
if { $authorizedUser > 1 } { takeBaselineDataFrame  .base   -parent .userFrame }
update

.menu.help.menu add command -label "HTML info file" -command {
    exec netscape "/home/helios/PHOTODIA/DeviceInfo/SR/Sector35/36AM/BunchPurity/BunchPurityMonitor.html" &
    # exit
}
.menu.help.menu insert 5 separator

.menu.help.menu add command -label "Toggle verbose mode" -command {
    set VERBOSE [expr 1 - $VERBOSE]
    SetMainStatus "VERBOSE = $VERBOSE"
}
.menu.help.menu add command -label "Toggle DRYRUN mode" -command {
    set DRYRUN [expr 1 - $DRYRUN]
    SetMainStatus "DRYRUN = $DRYRUN"
}
.menu.help.menu insert 7 separator








