
#-------------------------------------------------------------------------------
# Module:     messenger.tk
# Activation: Loaded during GOBLET startup
# Scope:      Display structured logging information
#             Searching a logfile
#             Logfile upload from GOBLIN messenger
#
# Updated:
#-------------------------------------------------------------------------------



# Data Initialization

set LogFile [file join $env(HOME) "gosh.log"]
set LogSearchMode 0
set LogSearchDir 0
set LogSearchString "-nocase"
set LogSelection ""


proc ViewMessenger {} {
    global InternalWindowing Log CanvasRegion \
        LogFile LogView LogText LogXScroll LogYScroll LogBar
    
    if {![info exists Log] || ![winfo exists $Log] || ![winfo exists $CanvasRegion]} {
        if {!$InternalWindowing && [winfo exists $CanvasRegion]} {
            set Log .log
            destroy $Log
            toplevel $Log
            wm title $Log "GOBLIN Messenger"
            wm protocol $Log WM_DELETE_WINDOW DestroyLogFile
        } else {
            global Workspace InternalLog CanvasRegion DialogRegion \
                BrowserBalance DialogBalance
            destroy .log
            set Log $InternalLog
            destroy $InternalLog
            frame $Log
            if {[winfo exists $CanvasRegion] || [winfo exists $DialogRegion]} {
                SplitWorkspace
            } else {
                pack $Log -side top -fill both -expand yes -padx 1m -pady 1m
            }
        }

        set LogBar $Log.bar
        frame $LogBar -relief raised -borderwidth 1
        pack $LogBar -side left -fill y
        MakeLogBar

        set LogView $Log.view
        frame $LogView
        pack $LogView -side top -fill both -expand yes

        set LogText $LogView.text
        set LogXScroll $LogView.xscroll
        set LogYScroll $LogView.yscroll
        set LogDelete $LogView.delete
        text $LogText -bg ivory  -font {courier 12} \
            -padx 2m -pady 2m -takefocus 1 \
            -relief sunken -borderwidth 2 -wrap none \
            -xscrollcommand "$LogXScroll set" \
            -yscrollcommand "$LogYScroll set"
            
        bind $LogText <Control-f> SearchLogFile
        bind $LogText <Button-1> {focus $LogText}
        bind $Log <Configure> MakeLogBar

        $LogText see end
        $LogText tag configure tag0 -foreground red -font {courier 12 bold}
        $LogText tag configure tag1 -foreground red -font {courier 12 bold}
        $LogText tag configure tag2 -foreground red -font {courier 12 bold}
        $LogText tag configure tag3 -foreground red -font {courier 12 bold}
        $LogText tag configure tag4 -foreground red -font {courier 12 bold}
        $LogText tag configure tag5 -foreground red -font {courier 12 bold}
        $LogText tag configure tag7 -foreground red3
        $LogText tag configure tag8 -foreground blue
        $LogText tag configure tag9 -foreground blue
        $LogText tag configure tag10 -foreground brown3 -font {courier 12 bold}
        $LogText tag configure tag11 -foreground brown3 -font {courier 12 bold}
        $LogText tag configure tag12 -foreground magenta3 -font {courier 12 bold}
        $LogText tag configure tag13 -foreground darkGrey -font {courier 12 bold}
        $LogText tag configure tag14 -foreground darkGrey -font {courier 12 bold}
        $LogText tag configure tag15 -foreground darkGrey -font {courier 12 bold}
        $LogText tag configure tag16 -foreground green4 -font {courier 12 bold}
        $LogText tag configure tag17 -foreground darkGreen
        $LogText tag configure tag18 -foreground blue3 -font {courier 12 bold}
        $LogText tag configure tag19 -foreground blue2 -font {courier 12}
        $LogText tag configure tag20 -foreground blue
        $LogText tag configure tag21 -foreground blue
        $LogText tag configure tag22 -foreground black -font {courier 12 bold}

        scrollbar $LogXScroll -orient horiz -command "$LogText xview" -width 3.5m
        scrollbar $LogYScroll -command "$LogText yview" -width 3.5m
        button $LogDelete -command DestroyLogFile -padx 0 -pady 0 -image delbutton 

        grid $LogText -in $LogView \
            -row 0 -column 0 -rowspan 1 -columnspan 1 -sticky news
        grid $LogXScroll \
            -row 1 -column 0 -rowspan 1 -columnspan 1 -sticky news
        grid $LogYScroll \
            -row 0 -column 1 -rowspan 1 -columnspan 1 -sticky news
        grid $LogDelete \
            -row 1 -column 1 -rowspan 1 -columnspan 1 -sticky news
        grid rowconfig    $LogView 0 -weight 1 -minsize 0
        grid columnconfig $LogView 0 -weight 1 -minsize 0

        LoadLogFile
    } else {
        LoadLogFile
        $LogText see end
        MakeLogBar
    }
}


image create photo log_first -file [file join $GoblinTclPath logFirst.gif]
image create photo log_prev -file [file join $GoblinTclPath logPrev.gif]
image create photo log_next -file [file join $GoblinTclPath logNext.gif]
image create photo log_last -file [file join $GoblinTclPath logLast.gif]
image create photo log_search -file [file join $GoblinTclPath logSearch.gif]
image create photo log_see -file [file join $GoblinTclPath logSee.gif]

proc MakeLogBar {} {
    global GoblinTclPath Log LogBar ThisGraph
    
    set height [winfo height $Log]

    MakeArrowUp LogBar $LogBar.up $height 5

    MakeIcon LogBar $LogBar.search log_search SearchLogFile \
        {search messages} $height 1 5

    MakeIcon LogBar $LogBar.first log_first LogFindFirst \
        {find first} $height 2 5

    MakeIcon LogBar $LogBar.prev log_prev LogFindPrev \
        {find previous} $height 3 5

    MakeIcon LogBar $LogBar.next log_next LogFindNext \
        {find next} $height 4 5

    MakeIcon LogBar $LogBar.last log_last LogFindLast \
        {find last} $height 5 5
        
    MakeArrowDown LogBar $LogBar.down $height 5
}


# image create photo msg_stop -file [file join $GoblinTclPath msgStop.gif]
# image create photo msg_warn -file [file join $GoblinTclPath msgWarn.gif]
# image create photo open_fold -file [file join $GoblinTclPath openFold.t.gif]
# image create photo close_fold -file [file join $GoblinTclPath closeFold.t.gif]

proc LoadLogFile {} {
    global LogStream LogText LogFile GoblinTclPath StatusInfo
    
    if [catch {open "| cat < \"$LogFile\""} LogStream] {
        set StatusInfo "Could not open logfile"
        return
    }
    
    $LogText configure -state normal
    $LogText delete 1.0 end

    while {[gets $LogStream thisLine]>=0} {
        set ret [scan $thisLine {%d %d %d} thisClass thisObj thisDepth]
        if {$ret==1} {
            set ret [scan $thisLine {%d * %d} thisClass thisDepth]
            set thisObj "*"
        }
        
        if {$ret>0} {
            # if {$thisClass<6} {
            #     $LogText image create end -image msg_stop -pady 3
            # }
            # if {$thisClass==7} {
            #     $LogText image create end -image msg_warn -pady 3
            # }
            $LogText insert end "[string range $thisLine 12 end]\n" \
                tag$thisClass
        } else {
            $LogText insert end "\n"
        }
    }
    close $LogStream
    $LogText see "insert linestart"
    $LogText configure -state disabled
}


proc UploadMessages {} {
    global LogText OldClass

    goblin messenger reset
    $LogText configure -state normal
    $LogText delete 1.0 end
    set OldClass 22
    
    if {[goblin messenger void]} {return}

    $LogText see "end linestart"
    $LogText mark set insert end
    $LogText delete "insert linestart" end

    set scanning 1
    while {$scanning==1} {
        set thisText   [goblin messenger text]
        set thisClass  [goblin messenger class]
        set thisHandle [goblin messenger handle]
        set thisLevel  [goblin messenger level]
        
        if {$thisClass!=6} {
            # if {$thisClass<6} {
            #     $LogText image create end -image msg_stop -pady 3
            # }
            # if {$thisClass==7} {
            #     $LogText image create end -image msg_warn -pady 3
            # }
            $LogText insert end "\n[string repeat "  " $thisLevel]" tag19
            $LogText insert end $thisText tag$thisClass
            set OldClass $thisClass
        } else {
            $LogText insert end $thisText tag$OldClass
        }
        
        if {![goblin messenger eof]} {
            goblin messenger skip
        } else {
            set scanning 0
        }
    }
    
    $LogText see "insert linestart"
    $LogText configure -state disabled
}


proc SearchLogFile {} {
    global LogStream Log LogSelection UploadCommand LogSearchMode LogSearchDir \
        LogSearchString
    
    catch [set LogSelection [selection get]]
    if {![info exists LogSelection]} {set LogSelection ""}

    set UploadCommand {
        switch $LogSearchMode {
            0 {set $LogSearchString "-nocase"}
            1 {set $LogSearchString "-exact"}
            2 {set $LogSearchString "-regexp"}
        }
        
        if {$LogSearchDir==0} {
            LogFindNext
        } else {
            LogFindPrev
        }
    }

    DisplayInputDialog "Find in Messages" "SearchLogFile" "" "Search" {
        global GoblinVersion
    
        label $WDInput.frame.text -text "Search string:"
        entry $WDInput.frame.entry -textvariable LogSelection -bg white -width 32
        pack $WDInput.frame.text $WDInput.frame.entry -side left -padx 1m -pady 2m
        bind $WDInput.frame.entry <Return> {
            eval $UploadCommand
            if {$InternalWindowing} {
                DestroyActiveDialog
            } else {
                destroy $WDInput
            }
        }
    
        frame $WDInput.options1
        radiobutton $WDInput.options1.literal -text "Literal" \
            -variable LogSearchMode -value 0 -anchor c
        radiobutton $WDInput.options1.caseSensitive -text "Case Sensitive" \
            -variable LogSearchMode -value 1 -anchor c
        radiobutton $WDInput.options1.regularExpr -text "Regular Expression" \
            -variable LogSearchMode -value 2 -anchor c
        pack $WDInput.options1.literal $WDInput.options1.caseSensitive \
            $WDInput.options1.regularExpr -side left -expand yes -fill x

        frame $WDInput.options2
        radiobutton $WDInput.options2.forward -text "Search forward" \
            -variable LogSearchDir -value 0 -anchor w
        radiobutton $WDInput.options2.backward -text "Search backward" \
            -variable LogSearchDir -value 1 -anchor w
        pack $WDInput.options2.forward -side left
        pack $WDInput.options2.backward -side right

        pack $WDInput.options1 -side top -padx $DefPadX \
            -pady 3m -expand yes -fill x
        pack $WDInput.options2 -side top -padx $DefPadX \
            -expand yes -fill x

        focus $WDInput.frame.entry
    }
}

proc LogFindNext {} {
    global LogText LogSelection LogSearchString

    set nextOccurence \
        [$LogText search -forward $LogSearchString $LogSelection "insert +1 chars" end]
    if {$nextOccurence!=""} {
        $LogText tag remove sel 1.0 end
        $LogText mark set insert $nextOccurence
        $LogText tag add sel insert \
            "insert +[string length $LogSelection] chars"
        $LogText see insert
    }
}

proc LogFindPrev {} {
    global LogText LogSelection LogSearchString

    set prevOccurence \
        [$LogText search -backward $LogSearchString $LogSelection "insert -1 chars" 1.0]
    if {$prevOccurence!=""} {
        $LogText tag remove sel 1.0 end
        $LogText mark set insert $prevOccurence
        $LogText tag add sel insert \
            "insert +[string length $LogSelection] chars"
        $LogText see insert
    }
}

proc LogFindLast {} {
    global LogText LogSelection LogSearchString

    set lastOccurence \
        [$LogText search -backward $LogSearchString $LogSelection end 1.0]
    if {$lastOccurence!=""} {
        $LogText tag remove sel 1.0 end
        $LogText mark set insert $lastOccurence
        $LogText tag add sel insert \
            "insert +[string length $LogSelection] chars"
        $LogText see insert
    }
}

proc LogFindFirst {} {
    global LogText LogSelection LogSearchString

    set firstOccurence \
        [$LogText search -forward $LogSearchString $LogSelection 1.0 end]
    if {$firstOccurence!=""} {
        $LogText tag remove sel 1.0 end
        $LogText mark set insert $firstOccurence
        $LogText tag add sel insert \
            "insert +[string length $LogSelection] chars"
        $LogText see insert
    }
}


proc DestroyLogFile {} {
    global Log
    destroy $Log
    InitDisplay
}
