#############################################################################
# CDMS: Interface to CDMS-simulator
#   (c) 1997/2000: Rolf Schrödter, DLR, Institut für Planetenerkundung
#############################################################################
# $Id: BrowseList.tcl,v 1.2 2006-11-17 16:34:46+01 rolf Exp rolf $
#############################################################################
# BrowseTest.tcl :    Test Browser functions
#############################################################################

#############################################################################
# browse::format_cdms var fmt
#############################################################################
# Return formatted frame HEADER
#############################################################################
# Parameters:
#   var         - Name of an array holding CDMS data (after browse::cdms_frame)
#   fmt         - listing format
#                    0: brief listing on 1 line
#                   -1: full listing on multiple lines
# Returns:
#   result      - formatted frame data (ALL fields) in MULTIPLE lines
#############################################################################
proc browse::format_cdms { var {fmt 0} } {
    variable BROWSE
    upvar $var X

    switch -- $fmt {
        0 { ;# short CDMS header listing
            set result [format "%-7s %-4s time=%s" $X(Unit) $X(Type) $X(Hdr.OBT)]
        }
        -1 { ;# full CDMS header listing
            foreach idx $BROWSE(CDMS.Fields) {
                append result [format "%-20s %s\n" $idx $X($idx)]
            }
        }
    }
    return $result
}

#####################################################
# AsciiText frames ComDPU
#####################################################
proc browse::ascii { data } {
    binary scan $data S* int_array          ;# scan as big endian (RTX)
    set str [binary format s* $int_array]   ;# format as litle endian (string)
    binary scan $str A* str                 ;# remove trailing BLANKS and NULLS
    set str [string trim $str]              ;# remove leading and trailing whitespaces (CR,LF)
    return "--- $str ---"
}
proc browse::tryAscii { data } {
    binary scan $data s1s1a* type count bin ;# ROLIS frame type
    if { ($type == 0x436F) && ($count == 0x6D44) } {
        # It's a ComDPU message
        return "<ComDPU>\n[ascii $data]"
    } else {
        return ""
    }
}

#############################################################################
# browse::format_data var fmt
#############################################################################
# Return formatted frame DATA
#############################################################################
# Parameters:
#   var         - Name of an array holding CDMS data (after browse::cdms_frame)
#   fmt         - listing format
#                    0: brief listing on 1 line
#                   -1: full listing on multiple lines
# Returns:
#   result      - formatted frame data (ALL fields) in MULTIPLE lines
#############################################################################
proc browse::format_data { var {fmt 0} } {
    variable BROWSE
    upvar $var X

# User callback for data interpretation
# if callback procedure exists
#
    set proc_name ::browse::[string tolower $X(Unit)]::list_[string tolower $X(Type)]

    if { [llength [info commands $proc_name]] } {
        set result [$proc_name $X(Data) $fmt]
    } else {
        set result [tryAscii $X(Data)]
    }

    return $result
}

#############################################################################
# browse::format frame fmt
#############################################################################
# Return formatted frame HEADER+DATA
#############################################################################
proc browse::format_frame { frame {fmt 0} } {
    variable BROWSE
    variable ARG

    if { [catch {browse::cdms_frame $frame X} err ] } {
        return [format "*** %s ***" $err]
    }

    set str [browse::format_cdms X $fmt]
    if { $X(ChksumErr) } {
        set result "(CHKSUM) "
    }
    append result [format "#%-4d seq#%-4d %s" $BROWSE(FrameNo) $X(Hdr.PackSeq) $str]

    set str [browse::format_data X $fmt]
    if { [string length $str] } {
#           set str [string trim $str]
        #
        # If List.Short flag then show only first data line
        #
        if { $ARG(-short) } {
            set str [lindex [split $str \n] 0]
        } else {
            set str [join [split $str \n] "\n\t"]
        }
        append result [format "\t%s" $str]
    }

    return $result
}

#############################################################################
# browse::list_file filename proc
#############################################################################
# List the whole CDMS data file
#############################################################################
# Parameters:
#   filename    - name of the file to be browsed
#   cmd         - callback
#   fmt         - listing format
#                    0: brief listing on 1 line
#                   -1: full listing on multiple lines
# Returns:
#   result      - formatted frame data (ALL fields) in MULTIPLE lines
#############################################################################
proc browse::list_file { filename {cmd "<none>"} } {
    variable BROWSE

    set BROWSE(FrameNo) 0

    set chan [browse::open_infile $filename]
    browse::detect_frame_size $chan

    while { 1 } {

        set frame [read $chan $BROWSE(Frame.Size)]
        if { [string length $frame] != $BROWSE(Frame.Size) } {
            break
        }

        set str [browse::format_frame $frame 0]

        if { [string compare $cmd "<none>"] == 0 } {   ;# no callback specified
            puts stdout $str
            update ;# idletasks
        } else {
            lappend $cmd $str
            uplevel #0 $cmd     ;# execute callback at global level
        }
        incr BROWSE(FrameNo)

    }
    close $chan
}

proc browse::one_file { fname } {
    if { [string length $fname] == 0 } {
        return
    }
    if { [file exists $fname] } {    ;# open output file only if file exists
        set out [browse::open_outfile $fname.lst]
        puts -nonewline $out [browse::list_file $fname]
        close $out
    } else {
        error "Browse: File $fname does not exist"
    }
}

proc browse::files { mask_list } {
    variable ARG

    #
    # Default: Show data listing (mainly for ASCII & ISB)
    #
    set ARG(-short) 0
    set num 0
    if { [llength $mask_list] == 0 } {
        puts stderr "List: Valid options are:
    -short filename filename ... (glob-style patterns allowed)"
        return
    }
    # allow multiple files at command line
    browse::config_stdfile stdout
    foreach mask $mask_list {
        #
        # if -nodata then set global flag
        #
        if { [string compare $mask "-short"] == 0 } {
            set ARG(-short) 1
        } else {
            #
            # treat arg as a glob-style mask
            #
            foreach fname [glob -nocomplain $mask] {
                if { [file isfile $fname] } {
                    incr num
                    puts stdout "--- $fname ---"
                    if { [catch {browse::list_file $fname} errMsg] } {
                        puts stderr $errMsg
                    }
                }
            }
        }
    }
    if { $num == 0 } {
        puts stderr "browse.tcl list: no files found: $mask_list"
    }
}
