# jidlink.tcl --
#
#       This file is a part of the Jidlink plugin for the Tkabber XMPP client.

package require msgcat

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

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

    variable transport
    set transport(list) {}
}

proc ::jidlink::load {dir} {
    ::xmpp::negotiate::register jabber:iq:jidlink ::jidlink::negotiate_handler
    ::xmpp::iq::register set query jabber:iq:jidlink ::jidlink::set_handler

    # Loading jidlink plugins
    foreach file [lsort [glob -nocomplain [file join $dir plugins]/*.tcl]] {
        debugmsg jidlink "Loading plugin from $file"
        source $file
    }

    ::trans::load [file join $dir trans]

    foreach ns [namespace children] {
        ${ns}::load
    }

    setup_customize
}

proc ::jidlink::unload {} {
    foreach ns [namespace children] {
        ${ns}::unload
    }

    ::xmpp::negotiate::unregister jabber:iq:jidlink
    ::xmpp::iq::unregister set query jabber:iq:jidlink
}

package require xmpp::negotiate

proc ::jidlink::connect {xlib jid {key {}}} {
    variable connection

    if {$key == ""} {
        set key [rand 1000000000]
    }

    #set connection(sf,$key) $send_func
    #set connection(rf,$key) $recv_func
    set connection(xlib,$key) $xlib
    set connection(jid,$key) $jid

    set_status [::msgcat::mc "Opening Jidlink connection"]

    ::xmpp::sendIQ $xlib set \
        -query [::xmpp::xml::create query \
                        -xmlns jabber:iq:jidlink \
                        -subelement [::xmpp::xml::create key -cdata $key]] \
        -to $jid \
        -command [list [namespace current]::connect_response $xlib $jid $key]

    vwait [namespace current]::connection(status,$key)
    return connection(status,$key)
}

proc ::jidlink::connect_response {xlib jid key status xml} {
    variable connection
    variable transport

    if {$status != "ok"} {
        # TODO
        set connection(status,$key) 0
        return
    }

    set trans [lsort -unique -index 1 $transport(list)]
    set options {}
    foreach t $trans {
        set name [lindex $t 0]
        if {![info exists transport(allowed,$name)] || \
                $transport(allowed,$name)} {
            lappend options $name
        }
    }

    if {[llength $options] == 0} {
        # TODO
        set connection(status,$key) 0
        return
    }

    ::xmpp::negotiate::sendOptions $xlib $jid jabber:iq:jidlink $options \
            -command [namespace code [list negotiate_recv_response \
                                           $xlib $jid $key $options]]
}

proc ::jidlink::negotiate_recv_response {xlib jid key options status opts} {
    variable connection
    variable transport

    if {$status != "ok"} {
        set connection(status,$key) 0
        return
    }

    foreach {tag field} $opts {
        if {$tag != "field"} continue

        lassign $field var type label values

        if {$var != "jabber:iq:jidlink"} continue

        set name [lindex $values 0]
        if {[lsearch -exact $options $name] >= 0} {
            set connection(transport,$key) $name
            {*}$transport(connect,$name) $xlib $jid $key
            set connection(status,$key) 1
            return
        }
    }

    set connection(status,$key) 0
}


proc ::jidlink::set_readable_handler {key handler} {
    variable connection
    set connection(readable_handler,$key) $handler
}

proc ::jidlink::set_closed_handler {key handler} {
    variable connection
    set connection(closed_handler,$key) $handler
}

proc ::jidlink::send_data {key data} {
    variable connection
    variable transport
    {*}$transport(send,$connection(transport,$key)) $key $data
}

proc ::jidlink::recv_data {key data} {
    variable connection
    debugmsg jidlink "RECV_DATA [list $key $data]"

    append connection(data,$key) $data
    if {[info exists connection(readable_handler,$key)]} {
        {*}$connection(readable_handler,$key) $key
    }
}

proc ::jidlink::read_data {key} {
    variable connection

    set data $connection(data,$key)
    set connection(data,$key) {}
    return $data
}

proc ::jidlink::close {key} {
    variable connection
    variable transport
    {*}$transport(close,$connection(transport,$key)) $key
    set_status [::msgcat::mc "Jidlink connection closed"]
}

proc ::jidlink::closed {key} {
    variable connection
    if {[info exists connection(closed_handler,$key)]} {
        {*}$connection(closed_handler,$key) $key
    }
}

proc ::jidlink::negotiate_handler {xlib from options args} {
    variable transport

    set trans [lsort -unique -index 1 $transport(list)]
    set myoptions {}
    foreach t $trans {
        set name [lindex $t 0]
        if {![info exists transport(allowed,$name)] || \
                $transport(allowed,$name)} {
            lappend myoptions $transport(oppos,$name)
        }
    }

    if {$options == {}} {
        # Options request

        return $myoptions
    } else {
        foreach opt $options {
            if {[lsearch -exact $myoptions $opt] >= 0} {
                return [list $opt]
            }
        }
    }

    return {}
}

proc ::jidlink::set_handler {xlib from xml args} {
    debugmsg jidlink "set: [list $from $xml]"

    ::xmpp::xml::split $xml tag xmlns attrs cdata subels

    if {$tag == "query"} {
        foreach item $subels {
            ::xmpp::xml::split $item stag sxmlns sattrs scdata ssubels
            if {$stag == "key"} {
                set key $scdata
                debugmsg jidlink "KEY: $key"
            }
        }

        if {[info exists key]} {
            return [list result $xml]

        } else {
            # TODO
        }
    } else {
        # TODO
    }
}

proc ::jidlink::register_transport \
            {name oppos prio default connect send close} {
    variable transport

    lappend transport(list) [list $name $prio]
    set transport(oppos,$name) $oppos
    set transport(connect,$name) $connect
    set transport(send,$name) $send
    set transport(close,$name) $close
    if {$default == "enabled"} {
        set transport(default,$name) 1
    } else {
        set transport(default,$name) 0
    }
}

proc ::jidlink::setup_customize {} {
    variable transport

    foreach t [lsort -unique -index 1 $transport(list)] {
        lassign $t name prio

        custom::defvar transport(allowed,$name) $transport(default,$name) \
            [::msgcat::mc "Enable Jidlink transport %s." $name] \
            -type boolean -group Jidlink
    }
}

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