# $Id$

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
    }

    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
	    eval $transport(connect,$name) [list $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
    eval $transport(send,$connection(transport,$key)) [list $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)]} {
	eval $connection(readable_handler,$key) [list $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
    eval $transport(close,$connection(transport,$key)) [list $key]
    set_status [::msgcat::mc "Jidlink connection closed"]
}

proc ::jidlink::closed {key} {
    variable connection
    if {[info exists connection(closed_handler,$key)]} {
	eval $connection(closed_handler,$key) [list $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
    }
}

