"""
Test use-case when client requests going online and immediately
attempts to call a contact. Gabble should delay the RequestStreams
call until caps have arrived.
"""

from functools import partial
from gabbletest import exec_test
from servicetest import make_channel_proxy, call_async, sync_dbus
import jingletest2

import dbus

import constants as cs

from config import VOIP_ENABLED

if not VOIP_ENABLED:
    print "NOTE: built with --disable-voip"
    raise SystemExit(77)

def test(q, bus, conn, stream, channel_type):
    jp = jingletest2.JingleProtocol031()
    jt = jingletest2.JingleTest2(jp, conn, q, stream, 'test@localhost',
        'foo@bar.com/Foo')
    jt2 = jingletest2.JingleTest2(jp, conn, q, stream, 'test@localhost',
        'foo2@bar.com/Foo')
    # Make gabble think this is a different client
    jt2.remote_caps['node'] = 'http://example.com/fake-client1'

    run_test(q, bus, conn, stream, jt, True, channel_type)
    run_test(q, bus, conn, stream, jt2, False, channel_type)

def run_test(q, bus, conn, stream, jt, request_before_presence, channel_type):
    """
    Requests streams on a media channel to jt.peer, either before their
    presence is received (if request_before_presence is True) or after their
    presence is received but before we've got a disco response for their
    capabilities (otherwise).
    """

    # We intentionally DON'T set remote presence yet. Since Gabble is still
    # unsure whether to treat contact as offline for this purpose, it
    # will tentatively allow channel creation and contact handle addition
    request = dbus.Dictionary({ cs.CHANNEL_TYPE: channel_type,
                                cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
                                cs.TARGET_ID: jt.peer,
                              }, signature='sv')

    if channel_type == cs.CHANNEL_TYPE_CALL:
        request[cs.CALL_INITIAL_AUDIO] = True

    if channel_type == cs.CHANNEL_TYPE_STREAMED_MEDIA:
        path, props = conn.CreateChannel(request,
            dbus_interface=cs.CONN_IFACE_REQUESTS)
        media_iface = make_channel_proxy(conn, path,
            'Channel.Type.StreamedMedia')

        handle = props[cs.TARGET_HANDLE]

    sync_dbus(bus, q, conn)

    def call_request_streams():
        if channel_type == cs.CHANNEL_TYPE_STREAMED_MEDIA:
            call_async(q, media_iface, 'RequestStreams', handle,
                [cs.MEDIA_STREAM_TYPE_AUDIO])
        else:
            call_async(q, conn.Requests, 'CreateChannel', request)

    if request_before_presence:
        # Request streams before either <presence> or caps have arrived. Gabble
        # should wait for both to arrive before returning from RequestStreams.
        call_request_streams()

        # Ensure Gabble's received the method call.
        sync_dbus(bus, q, conn)

        # Now send the presence.
        info_event = jt.send_presence()
    else:
        info_event = jt.send_presence()

        # Now call RequestStreams; it should wait for the disco reply.
        call_request_streams()

    jt.send_remote_disco_reply(info_event.stanza)

    # RequestStreams should now happily complete
    if channel_type == cs.CHANNEL_TYPE_STREAMED_MEDIA:
        q.expect('dbus-return', method='RequestStreams')
    else:
        q.expect('dbus-return', method='CreateChannel')

if __name__ == '__main__':
    exec_test(partial(test, channel_type=cs.CHANNEL_TYPE_STREAMED_MEDIA),
        timeout=10)
    exec_test(partial(test, channel_type=cs.CHANNEL_TYPE_CALL),
        timeout=10)

