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

APSApplication . -name SRBunchPatternGenerator -version $CVSRevisionAuthor \
  -overview {This interface provides the ability to configure the SR fill pattern with flexible sequences of bunches.}

set sequences 0
set sequenceLines 0

set mainStatus "Press ADD to place another sequence in the pattern."

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

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

set superPeriods 1
set superPeriodOffset 4
APSLabeledEntry .superperiods -parent .userFrame -label "Superperiods: " -type integer \
  -contextHelp "Enter the number of repetitions of the pattern defined above." -textVariable superPeriods
APSLabeledEntry .superoffset -parent .userFrame -label "Offset: " -type integer \
  -contextHelp "Enter the offset in buckets between superperiod repetitions." -textVariable superPeriodOffset

APSFrame .lines -parent .userFrame -label "Sequence:" -packOption "-fill x"

set sequenceScroll [APSScroll .sw -parent .userFrame.lines.frame -name "Sequence List"]
set sequenceScrollFrame .userFrame.lines.frame.sw

APSButton .sequenceScrollAdd -parent .userFrame.lines.frame -text Add -command \
  "MakeNewSequenceLine $sequenceScroll" -contextHelp "Press to add sequence entry slots."
APSButton .sequenceScrollClear -parent .userFrame.lines.frame -text Clear -command "ClearSequence $sequenceScroll" \
          -contextHelp "Clears the sequence."
APSButton .sequenceScrollSave -parent .userFrame.lines.frame -text Save -command "SaveSequence $sequenceScroll" \
          -contextHelp "Saves the sequence."
APSButton .sequenceScrollLoad -parent .userFrame.lines.frame -text Load -command "LoadSequence $sequenceScroll" \
          -contextHelp "Loads the sequence."
 
set outputDirectory [pwd]
set outputRootname [APSTmpString]
set randomOrder 1
set chargeOrder 0

APSFrame .output -parent .userFrame -label "Output:" 
APSLabeledEntry .outputDir -parent .userFrame.output.frame -label "Output directory:" -textVariable outputDirectory \
  -contextHelp "Enter a name for the output file directory." -width 80
APSButton .daily -parent .userFrame.output.frame.outputDir -packOption "-anchor e" -text "daily" -size small \
  -command {set outputDirectory [APSGoToDailyDirectory]; update}
APSLabeledEntry .root -parent .userFrame.output.frame -label "Output rootname:" -textVariable outputRootname -width 80 \
  -contextHelp "Enter a rootname for the output files to hold the sequence for later use."
APSRadioButtonFrame .rb1 -parent .userFrame.output.frame -label "Random order: " -variable randomOrder \
                    -buttonList "Yes No" -valueList "1 0" -orientation horizontal \
                    -contextHelp "Select whether to generate a sequence that fills in a random way to possibly reduce rf transients."
APSRadioButtonFrame .rb2 -parent .userFrame.output.frame -label "Charge ordered: " -variable chargeOrder \
                    -buttonList "Yes No" -valueList "1 0" -orientation horizontal \
                    -contextHelp "Select whether to generate a sequence that fills from low charge to high charge."

frame .userFrame.ops -bd 4 -relief raised
pack .userFrame.ops -side top -fill x
APSButton .ops.create -parent .userFrame -text Create -command CreateSequence \
          -contextHelp "Creates a file containing the sequence."
APSButton .ops.send -parent .userFrame -text Send -command SendSequence \
          -contextHelp "Sends the sequence to the fill pattern buffer"

proc ClearSequence {widget0} {
    global sequenceLines Pattern outputFile
    if {![APSYesNoPopUp "Really? Clear all settings?"]} { return }
    for {set i 0} {$i<$sequenceLines} {incr i} {
        if {[winfo exists $widget0.m$i]} { destroy $widget0.m$i}
        set Pattern($sequenceLines.offset) 0
        set Pattern($sequenceLines.repeats) 1
        set Pattern($sequenceLines.number) 1
        set Pattern($sequenceLines.intensity) 1
        set Pattern($sequenceLines.spacing) 4
        set Pattern($sequenceLines.gap) 0
    }
    set sequenceLines 0
    set outputFile ""
    SetMainStatus "Press ADD to place a sequence in the pattern."
}

proc SaveSequence {widget0} {
    global sequenceLines Pattern superPeriods superPeriodOffset randomOrder chargeOrder
    set offsetList [list]
    set repeatsList [list]
    set numberList [list]
    set intensityList [list]
    set spacingList [list]
    set gapList [list]
    for {set i 0} {$i<$sequenceLines} {incr i} {
        lappend offsetList $Pattern($i.offset)
        lappend repeatsList $Pattern($i.repeats)
        lappend numberList $Pattern($i.number)
        lappend intensityList $Pattern($i.intensity)
        lappend spacingList $Pattern($i.spacing)
        lappend gapList $Pattern($i.gap)
    }
    set filename [APSInfoDialog [APSUniqueName .] -name FileDialog \
                    -width 60 -infoMessage "Supply the name of a file to which to save the sequence configuration." ]
    set filename [string trim $filename]
    if ![string length $filename] {
        return -code error "No filename given."
    }
    if {[file exists $filename] && \
          ![APSMultipleChoice [APSUniqueName .] -question "$filename exists.  Overwrite it?" \
              -labelList {Yes No} -returnList {1 0}]} {
        return
    }

    exec sddsmakedataset $filename \
      -column=Offset,type=short -data=[join $offsetList ,] \
      -column=Repeats,type=short -data=[join $repeatsList ,] \
      -column=Number,type=short -data=[join $numberList ,] \
      -column=Intensity,type=short -data=[join $intensityList ,] \
      -column=Spacing,type=short -data=[join $spacingList ,] \
      -column=Gap,type=short -data=[join $gapList ,] \
      -parameter=SuperPeriods,type=short -data=$superPeriods \
      -parameter=SuperPeriodOffset,type=short -data=$superPeriodOffset \
      -parameter=RandomOrder,type=short -data=$randomOrder \
      -parameter=ChargeOrder,type=short -data=$chargeOrder

    SetMainStatus "Configuration saved to $filename"
    
}

proc LoadSequence {widget0} {
    global sequenceScroll sequenceLines Pattern superPeriods superPeriodOffset randomOrder chargeOrder

    set filename [APSFileSelectDialog .fsd -width 40 -checkValidity 1 -pattern "*.config" -title "Load sequence"]
    if ![string length $filename] {
        SetMainStatus "Operation canceled."
        return
    }
    if [catch {sdds load $filename dataArray} result] {
        return -code error "$result"
    }

    foreach column {Offset Repeats Number Intensity Spacing Gap} {
        if [lsearch $dataArray(ColumnNames) $column]==-1 {
            return -code error "Column $column not found in $filename"
        }
        set ${column}List [lindex $dataArray(Column.$column) 0]
    }
    foreach parameter {SuperPeriods SuperPeriodOffset} {
        if [lsearch $dataArray(ParameterNames) $parameter]==-1 {
            return -code error "Parameter $parameter not found in $filename"
        }
    }

    set newSequenceLines [llength $OffsetList]
    if {$sequenceLines>$newSequenceLines} {
        for {set i $newSequenceLines} {$i<$sequenceLines} {incr i} {
            if {[winfo exists $widget0.m$i]} { destroy $widget0.m$i}
            set Pattern($sequenceLines.offset) 0
            set Pattern($sequenceLines.repeats) 1
            set Pattern($sequenceLines.number) 1
            set Pattern($sequenceLines.intensity) 1
            set Pattern($sequenceLines.spacing) 4
            set Pattern($sequenceLines.gap) 0
        }
    } elseif {$sequenceLines<$newSequenceLines} {
        for {set i $sequenceLines} {$i<$newSequenceLines} {incr i} {
            MakeNewSequenceLine $sequenceScroll
        }
    }


    set sequenceLines $newSequenceLines
    for {set i 0} {$i<$sequenceLines} {incr i} {
        set Pattern($i.offset) [lindex $OffsetList $i]
        set Pattern($i.repeats) [lindex $RepeatsList $i]
        set Pattern($i.number) [lindex $NumberList $i]
        set Pattern($i.intensity) [lindex $IntensityList $i]
        set Pattern($i.spacing) [lindex $SpacingList $i]
        set Pattern($i.gap) [lindex $GapList $i]
    }
    set superPeriods [lindex $dataArray(Parameter.SuperPeriods) 0]
    set superPeriodOffset [lindex $dataArray(Parameter.SuperPeriodOffset) 0]
    set randomOrder 0
    catch {set randomOrder [lindex $dataArray(Parameter.RandomOrder) 0]}
    set chargeOrder 0
    catch {set randomOrder [lindex $dataArray(Parameter.ChargeOrder) 0]}
    
    SetMainStatus "Configuration loaded from $filename"
    
}

proc MakeNewSequenceLine {widget0 args} {
    global sequenceScrollFrame
    global sequenceLines Pattern
    set pvNamePV ""
    set pvNameRB ""
    APSParseArguments {pvNamePV pvNameRB}

    set widget $widget0.m$sequenceLines
    if ![winfo exists $widget] {
        frame $widget -bd 1
        pack $widget -fill x
        frame $widget.op 
        frame $widget.data
        pack $widget.op $widget.data -side left

        APSButton .delete -parent $widget.op -text "DELETE" -size small \
          -command "DeleteSequenceLine $widget0 $sequenceLines" \
          -contextHelp "Press to delete the corresponding PV name entry line."
        APSButton .clear -parent $widget.op -text "CLEAR" -size small \
          -command "ClearSequenceLine $widget0 $sequenceLines" \
          -contextHelp "Press to clear the corresponding PV name entry line."
        set Pattern($sequenceLines.offset) 0
        set Pattern($sequenceLines.repeats) 0
        set Pattern($sequenceLines.number) 0
        set Pattern($sequenceLines.intensity) 1
        set Pattern($sequenceLines.spacing) 4
        set Pattern($sequenceLines.gap) 0
        APSLabeledEntry .offset -parent $widget.data -label "Offset:" -type integer \
          -textVariable Pattern($sequenceLines.offset) -width 4 -packOption "-side left" \
          -contextHelp "Enter the offset from the end of the previous pattern."
        APSLabeledEntry .repeats -parent $widget.data -label " Repeats:" -type integer \
          -textVariable Pattern($sequenceLines.repeats) -width 4 -packOption "-side left" \
          -contextHelp "Enter the number of repeats."
        APSLabeledEntry .number -parent $widget.data -label " (Number:" -type integer \
          -textVariable Pattern($sequenceLines.number) -width 4 -packOption "-side left" \
          -contextHelp "Enter the number of bunches in the sub-sequence."
        APSLabeledEntry .intensity -parent $widget.data -label " (Intensity:" -type integer \
          -textVariable Pattern($sequenceLines.intensity) -width 4 -packOption "-side left" \
          -contextHelp "Enter relative intensity of bunches in the sub-sequence."
        APSLabeledEntry .spacing -parent $widget.data -label " Spacing:" -type integer \
          -textVariable Pattern($sequenceLines.spacing) -width 4 -packOption "-side left" \
          -contextHelp "Enter the spacing of the bunches in the sub-sequence."
        APSLabeledEntry .gap -parent $widget.data -label ") Gap:" -type integer \
          -textVariable Pattern($sequenceLines.gap) -width 4 -packOption "-side left" \
          -contextHelp "Enter the gap at the end of the sub-sequence."
        APSLabel .paren -parent $widget.data -text ")"
    }

    incr sequenceLines
    APSScrollAdjust $sequenceScrollFrame -numVisible 10
}

proc DeleteSequenceLine {widget0 number} {
    global sequenceLines Pattern 
    destroy $widget0.m$number
    set Pattern($number.offset) 0
    set Pattern($number.repeats) 0
    set Pattern($number.number) 0
    set Pattern($number.intensity) 1
    set Pattern($number.spacing) 4
    set Pattern($number.gap) 0
}

proc ClearSequenceLine {widget0 number} {
    global sequenceLines Pattern 
    set Pattern($number.offset) 0
    set Pattern($number.repeats) 0
    set Pattern($number.number) 0
    set Pattern($number.intensity) 1
    set Pattern($number.spacing) 4
    set Pattern($number.gap) 0
}

set outputListLength 0
proc CreateSequence {args} {
    global sequenceLines Pattern superPeriods superPeriodOffset outputDirectory outputRootname randomOrder chargeOrder

    set count 0
    for {set i 0} {$i<$sequenceLines} {incr i} {
        if {$Pattern($i.repeats)>0 && $Pattern($i.number)>0} {
            incr count
        }
    }
    if {!$count} {
        return -code error "No valid sub-sequences given."	
    }
  
    set filename [file join $outputDirectory $outputRootname.sdds]
    if {[file exists $filename] && \
          ![APSMultipleChoice [APSUniqueName .] -question "$filename exists.  Overwrite it?" \
              -labelList {Yes No} -returnList {1 0}]} {
        set filename ""
    }


    set dataArray(ColumnNames) "BucketNumber Intensity SequenceNumber RepeatNumber"
    set dataArray(ColumnInfo.BucketNumber) "type SDDS_SHORT"
    set dataArray(ColumnInfo.Intensity) "type SDDS_SHORT"
    set dataArray(ColumnInfo.SuperPeriod) "type SDDS_SHORT"
    set dataArray(ColumnInfo.SequenceNumber) "type SDDS_SHORT"
    set dataArray(ColumnInfo.RepeatNumber) "type SDDS_SHORT"

    set bucketNumber 0
    set BucketNumberList [list]
    set IntensityList [list]
    set SuperPeriodList [list]
    set SequenceNumberList [list]
    set RepeatNumberList [list]
    for {set super 0} {$super<$superPeriods} {incr super} {
        for {set seq 0} {$seq<$sequenceLines} {incr seq} {
            set intensity $Pattern($seq.intensity)
            set spacing $Pattern($seq.spacing)
            set gap $Pattern($seq.gap)
            set offset $Pattern($seq.offset)
            set bucketNumber [expr $bucketNumber+$offset]
            for {set repeat 0} {$repeat<$Pattern($seq.repeats)} {incr repeat} {
                for {set b 0} {$b<$Pattern($seq.number)} {incr b} {
                    lappend BucketNumberList $bucketNumber
                    lappend IntensityList $intensity
                    lappend SuperPeriodList $super
                    lappend SequenceNumberList $seq
                    lappend RepeatNumberList $repeat
                    set lastBucketNumber $bucketNumber
                    set bucketNumber [expr $bucketNumber+$spacing]
                }
                set bucketNumber [expr $bucketNumber+$gap]
            }
        }
        if $lastBucketNumber>1295 {
            return -code error "Bucket number exceeded 1295 in superperiod $super"
        }
        set bucketNumber [expr $bucketNumber+$superPeriodOffset]
    }
    
    foreach column [list BucketNumber Intensity SuperPeriod SequenceNumber RepeatNumber] {
        set dataArray(Column.$column) [list [set ${column}List]]
    }
    if [catch {sdds save $filename dataArray} result] {
        return -code error "unable to save pattern: $result"
    }
    SetMainStatus "Pattern saved to $filename"
    exec sddsplot -column=BucketNumber,Intensity $filename -filename -graph=impulse,vary -unsuppress=y \
      -split=column=SequenceNumber &

    set filename [file join $outputDirectory $outputRootname.putMe]
    if {[file exists $filename] && \
          ![APSMultipleChoice [APSUniqueName .] -question "$filename exists.  Overwrite it?" \
              -labelList {Yes No} -returnList {1 0}]} {
        set filename ""
    }
    set ControlNameList [list]
    set ValueStringList [list]
    set index 0
    foreach bucketNumber $BucketNumberList intensity $IntensityList {
        lappend ControlNameList [format S-INJ:BucketFillQueue%03dC $index]
        lappend ValueStringList $bucketNumber 
        lappend ControlNameList [format S-INJ:ChargeFillQueue%03dC $index]
        lappend ValueStringList $intensity
        incr index
    }
    lappend ControlNameList S-INJ:FillQueueNumberOfBunchesC
    lappend ValueStringList $index
    if [catch {exec sddsmakedataset $filename \
                 -column=ControlName,type=string -data=[join $ControlNameList ,] \
                 -column=ValueString,type=string -data=[join $ValueStringList ,]} result] {
        return -code error "$result"
    }
    if {$randomOrder || $chargeOrder} {
        if [catch {MakeRandomOrder -filename $filename -randomOrder $randomOrder -chargeOrder $chargeOrder} result] {
            return -code error "$result"
        }
    }
    
    SetMainStatus "File $filename ready to be sent"
}

proc MakeRandomOrder {args} {
    set filename ""
    set randomOrder 0
    set chargeOrder 0
    if {[APSStrictParseArguments {filename randomOrder chargeOrder}] || ![string length $filename]} {
        return -code error "MakeRandomOrder: invalid arguments"
    }

    if {!$randomOrder && !$chargeOrder} {
        return
    }
    
    set tmpRoot /tmp/[APSTmpString]
    
    # Make a file with the desired bucket number and charge in columns
    # - First, extract the (QueuePosition, BucketNumber) pairs
    if [catch {exec sddsprocess $filename $tmpRoot.bn -match=col,ControlName=S-INJ:BucketFillQueue???C \
                 -edit=column,QueuePosition,ControlName,%/S-INJ:BucketFillQueue// \
                 -scan=col,BucketNumber,ValueString,%hd,type=short} result] {
        return -code error "MakeRandomOrder (1): $result"
    }
    
    # - Second, extract the (QueuePosition, Charge) pairs, then combine with the (QueuePosition, BucketNumber) pairs
    #   and sort in desired order.
    set sortOptList [list]
    if $chargeOrder {
        lappend sortOptList -column=Charge,incr
    }
    if $randomOrder {
        lappend sortOptList -column=RN
    }
    if [catch {eval exec sddsprocess $filename -pipe=out -match=col,ControlName=S-INJ:ChargeFillQueue???C \
                 -edit=column,QueuePosition,ControlName,%/S-INJ:ChargeFillQueue// \
                 -scan=col,Charge,ValueString,%le \
                 "{-define=column,RN,i_row 0 == ? -1 : rnd $ }" \
                 | sddsxref -pipe $tmpRoot.bn -match=QueuePosition -take=BucketNumber \
                 | sddssort -pipe $sortOptList \
                 | sddsconvert -pipe=in $tmpRoot.table -retain=col,Charge,BucketNumber} result] {
        return -code error "MakeRandomOrder (2): $result"
    }
    file delete -force $tmpRoot.bn

    # Make the new .putMe file
    # - First, the bucket numbers
    if [catch {exec sddsprocess $tmpRoot.table $tmpRoot.buckets -redefine=col,Index,i_row,type=short \
                    "-print=col,ControlName,S-INJ:BucketFillQueue%03hdC,Index" \
                    "-print=col,ValueString,%hd,BucketNumber"} result] {
        return -code error "MakeRandomOrder (3): $result"
    }
    
    # - Second, the charge values
    if [catch {exec sddsprocess $tmpRoot.table $tmpRoot.charge -redefine=col,Index,i_row,type=short \
                    "-print=col,ControlName,S-INJ:ChargeFillQueue%03hdC,Index" \
                    "-print=col,ValueString,%le,Charge"} result] {
        return -code error "MakeRandomOrder (4): $result"
    }
    # - Combine these
    if [catch {exec sddscombine $tmpRoot.buckets $tmpRoot.charge -merge -pipe=out \
                 | sddssort -pipe=in $tmpRoot.both -column=Index -column=ControlName} result] {
        return -code error "MakeRandomOrder (5): $result"
    }

    # Add extra PVs not in the combined file
    if [catch {exec sddsselect $filename $tmpRoot.both $tmpRoot.extra -match=ControlName -invert} result] {
        return -code error "MakeRandomOrder (6): $result"
    }
    if [catch {exec sddscombine  $tmpRoot.both $tmpRoot.extra -merge -overwrite $filename} result] {
        return -code error "MakeRandomOrder (7): $result"
    }

    file delete -force $tmpRoot.both $tmpRoot.extra $tmpRoot.buckets $tmpRoot.charge $tmpRoot.table
}


MakeNewSequenceLine $sequenceScroll

proc SendSequence {} {
    global outputDirectory outputRootname

    set filename $outputDirectory/$outputRootname.putMe
    if ![file exists $filename] {
        SetMainStatus "Not found: $filename"
    }
    
    if {![APSMultipleChoice [APSUniqueName .] -question "Send configuration to active fill pattern?" \
            -labelList {Yes No} -returnList {1 0}]} {
        SetMainStatus "Operation canceled."
        return
    }

    if [catch {exec sddscasr -restore $filename} result] {
        return -code error "Error sending fill pattern: $result"
    }
    if [catch {exec cavput -list=S-INJ:LoadNewActiveFillPatternC=1} result] {
        return -code error "Error transferring fill pattern: $result"
    }
    SetMainStatus "Configuration $filename sent to active fill pattern."
}
