#############################################################################
# CDMS: Interface to CDMS-simulator
#   (c) 1997/2000: Rolf Schrödter, DLR, Institut für Planetenerkundung
#############################################################################
# $Id: BrowseSort.tcl,v 1.1 2006-01-17 14:27:53+01 rolf Exp rolf $
#############################################################################
# BrowseSort.tcl : Sort frames by CDMS onboard time (OBT)
#############################################################################

proc browse::sort { args } {
    variable BROWSE

    if { [llength $args] == 0 } {
        errorMsg "Sort: Sort the data by CDMS header fields:
    -from num       - sort from record number (def=0)
    -to num         - sort to record number (def=end)
    -file filename  - filename to extract
    -out filename   - name of output file (def=stdout)
    -type type      - sort criterium: uid,cat,seq,obt (default=obt)
                      uid: Sorts by CDMS UnitPID
                      cat: sorts by CDMS category
                      seq: Sorts by CDMS sequence counter
                      obt: Sorts by CDMS onboard time
                      seq,cat: sorts first by seq, then by cat"
    }

    # default parameters
    set ARG(From)       0
    set ARG(To)         [expr {0x7FFFFFFF}]
    set ARG(File)       {}
    set ARG(Out)        {}
    set ARG(Type)       obt

    # parse command parameters
    foreach {opt val} $args {
        set opt [string tolower $opt]
        switch -glob -- $opt {
            -from       { set ARG(From)     $val }
            -to         { set ARG(To)       $val }
            -file       { set ARG(File)     $val }
            -out        { set ARG(Out)      $val }
            -type       { set ARG(Type)     $val }
            default { errorMsg "Sort: invalid option $opt" }
        }
    }
    if { [string length $ARG(File)] } {
        set fin [browse::open_infile $ARG(File)]
    } else {
        errorMsg "Sort: no data file specified (-file filename)"
    }
    if { [string length $ARG(Out)] == 0 } {
        set fout stdout
        browse::config_stdfile $fout
    } else {
        set fout [browse::open_outfile $ARG(Out)]
    }
    browse::detect_frame_size $fin

    seek $fin [expr {$ARG(From)*$BROWSE(Frame.Size)}]
    set BROWSE(FrameNo) $ARG(From)

    #
    # 1. Scan the complete input file, creating a list of frame parameters: 
    #    {FrameNum UnitPID Category PackSeq OBT.Num}
    # 2. Sort list by specified criterium
    # 3. Reread the input data in sorted order and write the output file
    #
    set FrameList {}
    
    while { 1 } {
        set frame [read $fin $BROWSE(Frame.Size)]
        if { [string length $frame] != $BROWSE(Frame.Size) } {
            break
        }
        if { [catch {browse::cdms_frame $frame X} err ] } {
            puts stderr [format "*** %s ***" $err]
        }
        #
        # 1. Scan the complete input file, creating a list of frame parameters: 
        #    {FrameNum UnitPID Category PackSeq OBT.Num}
        #
        lappend FrameList [list $BROWSE(FrameNo) $X(Hdr.UnitPID) $X(Hdr.Category) $X(Hdr.PackSeq) $X(Hdr.OBT.Num)]
        
        incr BROWSE(FrameNo)
        if { $BROWSE(FrameNo) > $ARG(To) } {
            break
        }
    }
    #
    # 2. Sort list by specified criterium
    #
    foreach type [split $ARG(Type) ","] {
        switch -- $type {
            uid     { set FrameList [lsort -integer -index 1 $FrameList] }
            cat     { set FrameList [lsort -integer -index 2 $FrameList] }
            seq     { set FrameList [lsort -integer -index 3 $FrameList] }
            obt     { set FrameList [lsort -real -index 4 $FrameList] }
            default { errorMsg "Sort: invalid sort type $type" }
        }
    }
    #
    # 3. Reread the input data in sorted order and write the output file
    #
    foreach entry $FrameList {
        set num [lindex $entry 0]
        seek $fin [expr {$num*$BROWSE(Frame.Size)}]
        set frame [read $fin $BROWSE(Frame.Size)]
        puts -nonewline $fout $frame
    }
    
    close $fin

}
