# quotelastmsg.tcl --
#
#       "Quote last message" chat plugin for Tkabber.
#       Allows to copy message located at the bottom of the
#       conversation log in the chat window to the input box
#       of that chat window.
#
# Author: Konstantin Khomoutov <flatworm@users.sourceforge.net>
#
# See license.terms for the terms of distribution.
# See README for usage details.

package require msgcat

namespace eval quotelastmsg {
    variable state
    variable options

    ::msgcat::mcload [file join [file dirname [info script]] msgs]

    variable desc [::msgcat::mc \
            "This plugin provides a way to copy a message located\
            at the bottom of a chat window conversation log\
            to the input box of that chat window."]

    if {![::plugins::is_registered quotelastmsg]} {
        ::plugins::register quotelastmsg \
            -namespace [namespace current] \
            -source [info script] \
            -description [::msgcat::mc \
                "Whether the last message quoting plugin is loaded."]\n$desc \
            -loadcommand [namespace code load] \
            -unloadcommand [namespace code unload]
        return
    }

    custom::defgroup Plugins [::msgcat::mc "Plugins options."] -group Tkabber

    custom::defgroup {Quote Last Message} \
        [::msgcat::mc "Quote Last Message plugin options."]\ $desc \
        -group Plugins \
        -group Chat

    custom::defvar options(format) {>> %m} \
        [::msgcat::mc "Format string used to quote the message.\
            Format specifer \"%m\" is replaced by the whole message\
            being quoted. Format specifier \"%%\" is replaced by\
            a single character \"%\"."] \
        -group {Quote Last Message} \
        -type string

}

proc quotelastmsg::load {} {
    hook::add open_chat_post_hook [namespace current]::prepare_chat_window
    hook::add close_chat_post_hook [namespace current]::cleanup_state
    hook::add draw_message_post_hook [namespace current]::on_message_drawn

    event add <<QuoteLastMessage>> <Alt-q>
    event add <<QuoteLastMessage>> <Meta-q>

    foreach chatid [chat::opened] {
        prepare_chat_window $chatid ?
    }
}

proc quotelastmsg::unload {} {
    foreach chatid [chat::opened] {
        unprepare_chat_window $chatid
    }

    event delete <<QuoteLastMessage>> <Alt-q>
    event delete <<QuoteLastMessage>> <Meta-q>

    hook::remove open_chat_post_hook [namespace current]::prepare_chat_window
    hook::remove close_chat_post_hook [namespace current]::cleanup_state
    hook::remove draw_message_post_hook [namespace current]::on_message_drawn
}

proc quotelastmsg::prepare_chat_window {chatid type} {
    set iw [::chat::input_win $chatid]
    set cw [::chat::chat_win $chatid]
    bind $iw <<QuoteLastMessage>> \
         [list [namespace current]::quote [double% $chatid]]

    variable state
    set state($chatid,last) [$cw index {end - 1 char}]
}

proc quotelastmsg::unprepare_chat_window {chatid} {
    set iw [::chat::input_win $chatid]
    bind $iw <<QuoteLastMessage>> {}

    set cw [::chat::chat_win $chatid]
    $cw tag delete lastmsg

    cleanup_state $chatid
}

proc quotelastmsg::cleanup_state {chatid} {
    variable state
    unset state($chatid,last)
}

proc quotelastmsg::on_message_drawn {chatid from type body x} {
    if {![chat::is_opened $chatid]} return


    variable state
    upvar 0 state($chatid,last) last

    set cw [::chat::chat_win $chatid]
    set now [$cw index {end - 1 char}]
    if {[$cw compare $last < $now]} {
        $cw tag delete lastmsg
        $cw tag add lastmsg $last $now
    }

    set last $now
}

proc quotelastmsg::quote {chatid} {
    variable options

    set cw [::chat::chat_win $chatid]
    set iw [::chat::input_win $chatid]

    set range [$cw tag prevrange lastmsg end]
    if {$range == ""} return
    lassign $range x y
    $iw insert end [string map \
        [list %% % %m [$cw get $x $y]] $options(format)]
    $iw see end
}

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