# osd.tcl --
#
#       Tkabber OSD Module.
#
# Requirements:
#       osd_cat:    Utility to put messages on-screen. (apt-get install
#                   xosd-bin in Debian)
#
# Author: Jan Hudec
# Modifications: Sergei Golovan <sgolovan@nes.ru>

package require msgcat

namespace eval ::osd {
    ::msgcat::mcload [file join [file dirname [info script]] msgs]

    if {![::plugins::is_registered osd]} {
        ::plugins::register osd \
                            -namespace [namespace current] \
                            -source [info script] \
                            -description [::msgcat::mc "Whether the OSD plugin\
                                                        is loaded."] \
                            -loadcommand [namespace code load] \
                            -unloadcommand [namespace code unload]
        return
    }

    variable options ""
    variable delay 5
    variable osdfont ""
    variable pipe ""
    variable statuses
    array set statuses {}
}

proc ::osd::load {} {
    if {![info exists ::osd] || $::osd == ""} return

    ::osd::open_osd_cat

    foreach event $::osd {
        switch -- $event {
            presence {
                hook::add client_presence_hook ::osd::presence_notify 100
            }
            chat_message {
                hook::add draw_message_hook ::osd::chat_message_notify 20
            }
            default {
                debugmsg osd "Unsupported notify type $event"
            }
        }
    }
}

proc ::osd::unload {} {
    if {![info exists ::osd] || $::osd == ""} return

    foreach event $::osd {
        switch -- $event {
            presence {
                hook::remove client_presence_hook ::osd::presence_notify 100
            }
            chat_message {
                hook::remove draw_message_hook ::osd::chat_message_notify 20
            }
            default {
                debugmsg osd "Unsupported notify type $event"
            }
        }
    }

    variable pipe
    close $pipe
    set pipe ""
}

proc ::osd::open_osd_cat {} {
    variable pipe
    variable options
    variable delay
    variable osdfont
    if {$pipe != ""} {
        close $pipe
        set pipe ""
    }
    set command "|osd_cat $options -d $delay -a$delay"
    if {$osdfont != ""} {
        append command " -f $osdfont"
    }
    debugmsg osd $command
    set pipe [open $command w]
    fconfigure $pipe -buffering line
}

proc ::osd::try_write {text} {
    variable pipe
    if {[catch {puts $pipe $text}]} {
        osd::open_osd_cat
        if {[catch {puts $pipe $text}]} {
            debugmsg osd "Can't write to OSD"
        }
    }
}

proc ::osd::presence_notify {xlib from type x args} {
    variable statuses

    if {[catch  { set nick [get_nick $xlib $from chat] }]} {
        set nick "$from"
    }

    if {"$nick" != "$from"} {
        set thefrom "$nick ($from)"
    } else {
        set thefrom "$from"
    }
    if {"$type" == ""} {
        set type "available"
    }

    set status ""
    set show ""
    foreach {attr val} $args {
        switch -- $attr {
            -status {
                set status $val
            }
            -show {
                set show $val
            }
        }
    }

    if {"$status" != ""} {
        set status " ($status)"
    }
    if {"$show" != ""} {
        set type "$type/$show"
    }

    set newstatus "$thefrom: $type$status"

    if {[catch { set oldstatus $statuses($from) } ]} {
        set oldstatus "$newstatus"
    }

    if {"$newstatus" != "$oldstatus"} {
        osd::try_write "$newstatus"
    }

    set statuses($from) "$newstatus"
}

proc ::osd::chat_message_notify {chatid from type body extras} {
    if {[chat::is_our_jid $chatid $from] || $type ne "chat"} {
        return
    }

    foreach xelem $extras {
        ::xmpp::xml::split $xelem tag xmlns attrs cdata subels

        # Don't notify if this 'empty' tag is present. It indicates
        # messages history in chat window.
        if {[string equal $tag ""] && [string equal $xmlns tkabber:x:nolog]} {
            return
        }
    }

    set nick [get_nick [chat::get_xlib $chatid] $from $type]
    osd::try_write "New message from $nick"
}

proc ::osd::get_nick {xlib jid type} {
    if {[catch {chat::get_nick $xlib $jid $type} nick]} {
        return [chat::get_nick $jid $type]
    } else {
        return $nick
    }
}

# vim:ts=8:sw=4:sts=4:et
