#############################################################################
# CDMS: Interface to CDMS-simulator
#   (c) 1997/2000: Rolf Schrödter, DLR, Institut für Planetenerkundung
#############################################################################
# $Id: BrowseWindow.tcl,v 1.1 2006-01-17 14:27:52+01 rolf Exp rolf $
#############################################################################
# BrowseWindow.tcl :    Windowing interface to browser
#############################################################################

#############################################################################
# Window option database
#############################################################################
font create browse_title_font -family {Times} -size 14 -weight normal -slant roman -underline 0 -overstrike 0
font create browse_hdr_font   -family {Times} -size 12 -weight normal -slant roman -underline 0 -overstrike 0
font create browse_view_font  -family {Times} -size 12 -weight normal -slant roman -underline 0 -overstrike 0
font create browse_data_font  -family {Courier} -size 10 -weight normal -slant roman -underline 0 -overstrike 0

option add *Browse*background       gray                startupFile

option add *BrowseTitle*background  lightblue           startupFile
option add *BrowseTitle*foreground  black               startupFile
option add *BrowseTitle*font        browse_title_font   startupFile

option add *BrowseHdr*background    gray                startupFile
option add *BrowseHdr*foreground    blue                startupFile
option add *BrowseHdr*ErrorBg       red                 startupFile
option add *BrowseHdr*ErrorFg       white               startupFile
option add *BrowseHdr*font          browse_hdr_font     startupFile

option add *BrowseView*background   gray                startupFile
option add *BrowseView*foreground   black               startupFile
option add *BrowseView*font         browse_view_font    startupFile

option add *BrowseData*background   white               startupFile
option add *BrowseData*foreground   black               startupFile
option add *BrowseData*font         browse_data_font    startupFile


#############################################################################
# Open and Seek file
#############################################################################
proc browse::close_file {} {
    variable BROWSE
    close BROWSE(File.Chan)
    set BROWSE(File.Pos) [set BROWSE(File.Size) 0]
}

proc browse::seek_frame { n } {
    variable BROWSE

    if {$n >= $BROWSE(File.Size)} {
        set n $BROWSE(File.Size)
    } elseif {$n < 1} {
        set n 1
    }
    set BROWSE(File.Pos) $n     ;# n=1..Max.Frame
    if { $BROWSE(File.Size) } {
        seek $BROWSE(File.Chan) [expr {($n-1) * $BROWSE(Frame.Size) }] start
        browse::show_frame [read $BROWSE(File.Chan) $BROWSE(Frame.Size)]
        # Reflect new position in scrollbar
        set to [expr {double($BROWSE(File.Pos))/$BROWSE(File.Size)}]
        set from [expr {$to - 1.0/$BROWSE(File.Size)}]
        $BROWSE(Win.SB) set $from $to
    }
}
proc browse::scroll_frame { direction } {
    variable BROWSE
    switch -exact -- $direction {
        home    { browse::seek_frame 1 }
        end     { browse::seek_frame $BROWSE(File.Size) }
        prior   { browse::seek_frame [expr {$BROWSE(File.Pos) - 1}] }
        next    { browse::seek_frame [expr {$BROWSE(File.Pos) + 1}] }
    }
    return -code break
}
proc browse::scroll_command { cmd args } {
    variable BROWSE
    switch -exact -- $cmd {
        moveto  {
            set fraction $args  ;# 0..1
            set frameNo [expr {int($fraction * $BROWSE(File.Size) + 1.0)}]
            browse::seek_frame $frameNo
        }
        scroll  {
            foreach {incr unit} $args {}
            browse::seek_frame [expr {$BROWSE(File.Pos) + $incr}]
        }
        default { ;# ignore }
    }
}

#############################################################################
# Search file for Rolis/Civa/HK/Text data frames
#############################################################################
proc browse::search_frame {pattern {back 0} } {
    variable BROWSE

    set startPos $BROWSE(File.Pos)      ;# original starting position
    set n $startPos             ;# n=1..Max.Frame
    set i [expr {$back ? -1 : +1}]  ;# increment: back=-1

    if { $BROWSE(File.Size) == 0 } {
        return -1   ;# not found
    }
    set found 0
    while { ! $found } {
        incr n $i   ;# go one frame forward/backward
        if { ($n <= 0) || ($n > $BROWSE(File.Size)) } {
            set BROWSE(File.Pos) $startPos
            return -1   ;# not found
        }
        # Show some progress in the title bar
        set BROWSE(File.Pos) $n
        update idletasks
        
        seek $BROWSE(File.Chan) [expr {($n-1) * $BROWSE(Frame.Size) }] start
        catch {unset X}
        browse::cdms_frame [read $BROWSE(File.Chan) $BROWSE(Frame.Size)] X
        
        set unit [string tolower $X(Unit)]
        set fType [string tolower $X(Type)]
        if { [string compare $unit "rolis"] != 0 } {
            continue
        }
        
        binary scan $X(Data) @0s1 ident
        set dev     [expr {($ident & 0xF000) >> 12}]
        set rType   [expr {($ident & 0x0F00) >> 8}]
        
        switch -exact -- $pattern {
            hk {
                if { [string compare $fType "hk"] == 0 } {
                    set found 1
                }
            }
            data {
                if { [string compare $fType "data"] == 0 } {
                    set found 1
                }
            }
            rolis {
                if { ([string compare $fType "data"] == 0) && ($dev == 5) } {
                    set found 1
                }
            }
            civa {
                if { ([string compare $fType "data"] == 0) && ($dev == 12) } {
                    set found 1
                }
            }
            text {
                if { ([string compare $fType "data"] == 0) && ($ident == 0x5000) } {
                    set found 1
                }
            }
            isb {
                if { ([string compare $fType "data"] == 0) && ($ident == 0x5300) } {
                    set found 1
                }
            }
        }
    }
    browse::seek_frame $n
    return $n
}
proc browse::do_search {pattern} {
    variable BROWSE
    search_frame $pattern $BROWSE(Win.SearchBack)
}

#############################################################################
# Select new file
#############################################################################
proc browse::select_file { {fname ""} } {
    variable BROWSE

    if { [string length $fname] == 0 } {    ;#interactive file selection
        set fname [tk_getOpenFile -filetypes $BROWSE(File.Types) -initialdir $BROWSE(File.Dir)]
        if { [string length $fname] == 0 } {    ;# File selection aborted
            return
        }
    }
    if { ! [file isfile $fname] } {
        tk_messageBox -message "$fname does not exists or is not a regular file" -icon error
        return
    }
    if { [catch {browse::open_infile $fname} result] } {
        tk_messageBox -message $result -icon error
        return
    }

    catch { browse::close_file }
    set BROWSE(File.Chan)       $result
    set BROWSE(File.Dir)        [file dirname $fname]
    set BROWSE(File.Name)       [file tail $fname]
    set BROWSE(File.FullName)   $fname

    browse::detect_frame_size $result
    browse::check_file_size
    browse::seek_frame 0

    wm title $BROWSE(Win) $BROWSE(File.Name)
    focus -force $BROWSE(Win)
}

#############################################################################
# Show the current data frame
#############################################################################
proc browse::show_frame { frame } {
    variable BROWSE
    variable DATA

    browse::cdms_frame $frame DATA
    set DATA(Dump) [browse::dump $DATA(Data)]   ;# because it is trace'd (viewer.tcl)

    set unit [string tolower $DATA(Unit)]
    set type [string tolower $DATA(Type)]
    set cmd ::browse::${unit}::ascii_${type}
    if { [llength [info commands $cmd]] } { ;# if command exists
        set DATA(Ascii) [$cmd $DATA(Data)]
    } else {
        set DATA(Ascii) {}
    }
    switch -exact -- $type {
        hk {
            set DATA(AnalogHK) [browse::hk::analog_hk $DATA(Data)]
            set DATA(SoftHK)   [browse::hk::soft_hk $DATA(Data)]
            set BROWSE(Win.Message) "(*** Not all SoftHK values are valid before Rolis-SW version xx.12.2001 ***)"
            set DATA(Ascii)    "For HK listing go to AnalogHK/SoftHK display"
        }
        data {
            set DATA(AnalogHK)  ""
            set DATA(SoftHK)    ""
            set BROWSE(Win.Message) ""
        }
    }
    if { $DATA(ChksumErr) } {
        set bg [option get $BROWSE(Win.Hdr) ErrorBg ErrorBg]
        set fg [option get $BROWSE(Win.Hdr) ErrorFg ErrorFg]
    } else {
        set bg [option get $BROWSE(Win.Hdr) background Background] 
        set fg [option get $BROWSE(Win.Hdr) foreground Foreground] 
    }
    $BROWSE(Win.Hdr).lab10 configure -bg $bg -fg $fg
    $BROWSE(Win.Hdr).dat10 configure -bg $bg -fg $fg
}

#############################################################################
# Check filesize: it may be changed by other applications
#############################################################################
proc browse::check_file_size {} {
    variable BROWSE

    set size [file size $BROWSE(File.FullName)]
    set size [expr {$size / $BROWSE(Frame.Size)}]

    # Did the file size change ?
    if { $size != $BROWSE(File.Size) } {

        # Were we originally displaying End-Of-File ?
        set endFlag [expr {($BROWSE(File.Size) > 1) && ($BROWSE(File.Pos) == $BROWSE(File.Size))}]
        set BROWSE(File.Size) $size
        if { $endFlag } {
            browse::seek_frame $size
        }
    }
    after $BROWSE(Latency) browse::check_file_size
}

#############################################################################
# Readonly text widget displaying DATA
#############################################################################
proc browse::data_changed { txt name idx op } {
    upvar #0 [namespace current]::$name X
    $txt configure -state normal
    $txt delete 1.0 end
    if { [string length $idx] } {
        $txt insert end $X($idx)
    } else {
        $txt insert end $X
    }
    $txt configure -state disabled
}
proc browse::data_view { txt varname args } {
    eval text $txt -state disabled $args
    trace variable $varname w [list browse::data_changed $txt]
    # Enable Copy & Paste
     bind $txt <Button-1> {focus %W}
     return $txt
}

#############################################################################
# Different sub-windows
#############################################################################
proc browse::win_title { win } {
    variable BROWSE
    
    frame $win -class BrowseTitle

    label $win.unit  -textvariable ::browse::DATA(Unit) -width 7
    label $win.type  -textvariable ::browse::DATA(Type) -width 5 -anchor w
    label $win.no    -textvariable ::browse::BROWSE(File.Pos) -width 10 -anchor e
    label $win.delim -text "/"
    label $win.size  -textvariable ::browse::BROWSE(File.Size)

    label $win.version -text "Version $BROWSE(VersionNo) ($BROWSE(VersionDate))"

    pack $win.unit $win.type -side left 
    pack $win.size $win.delim $win.no -side right
    pack $win.version -anchor c -expand no -fill none
}

proc browse::win_hdr { win } {
    variable BROWSE

    frame $win -class BrowseHdr

    label $win.title -text "CDMS header:"
    pack $win.title -side top -anchor w

    frame $win.indent -width 20
    pack $win.indent -side left

    set f [frame $win.data]
    pack $f -side right -anchor n
    set BROWSE(Win.Hdr) $f

        set i 0
        foreach field $BROWSE(CDMS.Fields) {
            set isHdr [regexp {^Hdr\.(.*)} $field x name]
            if { $isHdr } {
                label $f.lab$i -text $name:
                label $f.dat$i -textvariable ::browse::DATA($field)
                grid    $f.lab$i     x    $f.dat$i  -sticky nw
                incr i
            }
        }
        grid columnconfigure $f 1 -minsize 5
        grid columnconfigure $f 2 -minsize 150

    return $win
}

proc browse::win_selector { win name } {
    variable BROWSE
    radiobutton $win -indicatoron 0 -width 8 \
        -variable ::browse::BROWSE(Win.Page) \
        -highlightthickness 0 -pady 1 \
        -text $name -value $name \
        -command [list notebook_display $BROWSE(Win.NB) $name]
}
proc browse::win_view { win } {
    variable BROWSE

    frame $win -class BrowseView

    set BROWSE(Win.NB) [set nb $win.nb]     ;# notebook pages
    set BROWSE(Win.SB) [set sb $win.sb]     ;# scrollbar

    notebook_create $nb

    set f [frame $win.status]
    pack $f -side bottom -fill x
    
        label $f.msg -textvariable ::browse::BROWSE(Win.Message) -fg red1
        pack $f.msg -side top
    
    set f [frame $win.select]
    pack $f -side top -fill x

        browse::win_selector $f.dump Dump
        browse::win_selector $f.ascii Ascii
        browse::win_selector $f.analog_hk AnalogHK
        browse::win_selector $f.soft_hk SoftHK
        pack $f.dump $f.ascii $f.analog_hk $f.soft_hk -side left

        frame $f.delim -width 10
        image create photo imgOpen -file [ file join $::LIBDIR open.gif]
        button $f.open -image imgOpen -command ::browse::select_file
        pack $f.open $f.delim -side right -fill y

    # notebook pages
    #
    pack $nb -side left -expand yes -fill both

    ################### Dump #######################
        set page [notebook_page $nb Dump]
        set f [frame $page.f -class BrowseData]
        pack $f -expand yes -fill both

            browse::data_view $f.data ::browse::DATA(Dump) -width 64 -height 16 -wrap word
            pack $f.data -expand yes -fill both

    ################### Ascii #######################
        set page [notebook_page $nb Ascii]
        set f [frame $page.f -class BrowseData]
        pack $f -expand yes -fill both

            browse::data_view $f.data ::browse::DATA(Ascii) -width 64 -height 16 -wrap word
            pack $f.data -expand yes -fill both

    ################### AnalogHK #######################
        set page [notebook_page $nb AnalogHK]
        set f [frame $page.f -class BrowseData]
        pack $f -expand yes -fill both
        
            browse::data_view $f.data ::browse::DATA(AnalogHK) -width 64 -height 16 -wrap word
            pack $f.data -expand yes -fill both
        
    ################### SoftHK #######################
        set page [notebook_page $nb SoftHK]
        set f [frame $page.f -class BrowseData]
        pack $f -expand yes -fill both
        
            browse::data_view $f.data ::browse::DATA(SoftHK) -width 80 -height 39 -wrap word
            pack $f.data -expand yes -fill both


    # Scrollbar for fast frame access
    #
    scrollbar $sb -orient vertical -command ::browse::scroll_command
    pack $sb -side right -expand no -fill y

}
proc browse::win_search { win } {
    variable BROWSE

    frame $win -class BrowseView

    label $win.title -text "Search:"
    pack $win.title -side top -anchor w

    frame $win.indent -width 20
    pack $win.indent -side left

    set f [frame $win.f]
    pack $f -side right -anchor n

        radiobutton $f.fwd  -text "Forward"  -variable ::browse::BROWSE(Win.SearchBack) -value 0
        radiobutton $f.back -text "Backward" -variable ::browse::BROWSE(Win.SearchBack) -value 1
        label $f.help1 -text "H-HK frame"
        label $f.help2 -text "D-Data frame"
        label $f.help3 -text "C-Civa data"
        label $f.help4 -text "R-Rolis data"
        label $f.help5 -text "T-Rolis text"
        label $f.help6 -text "I-Rolis ISB"
        
        grid    $f.fwd    $f.back             -sticky nw
        grid    $f.help1  $f.help2  $f.help3  -sticky nw
        grid    $f.help4  $f.help5  $f.help6  -sticky nw
        
    return $win
}

#############################################################################
# Main window
#############################################################################
proc browse::window { {win "."} } {
    variable BROWSE

    set BROWSE(Win) $win
    catch {toplevel $win -class Browse}
    wm title $win $BROWSE(File.Name)

    if { [string compare $win "."] == 0 } {
        set win ""
    }

    browse::win_title $win.title
    pack $win.title -side top -fill x -anchor c

    set f [frame $win.left]
    pack $f -side left -anchor n -expand no -fill both

        browse::win_hdr $f.hdr
        pack $f.hdr -side top -expand no -fill both

        browse::win_search $f.search
        pack $f.search -side bottom -expand no -fill both

    browse::win_view $win.view
    pack $win.view -side left -expand yes -fill both

    bind all <Home>    [list browse::scroll_frame home]
    bind all <End>     [list browse::scroll_frame end]
    bind all <Prior>   [list browse::scroll_frame prior]
    bind all <Next>    [list browse::scroll_frame next]
    
    bind all <Key-b> { set browse::BROWSE(Win.SearchBack) 1 }
    bind all <Key-c> { browse::do_search civa  }
    bind all <Key-d> { browse::do_search data  }
    bind all <Key-f> { set browse::BROWSE(Win.SearchBack) 0 }
    bind all <Key-h> { browse::do_search hk    }
    bind all <Key-r> { browse::do_search rolis }
    bind all <Key-t> { browse::do_search text  }
    bind all <Key-i> { browse::do_search isb  }
}

#############################################################################
# Browser procedure
#############################################################################
proc browse::browse { {fname ""} } {
        browse::window .
#        update
        after idle [list browse::select_file $fname]
        tkwait window .
}
