#!/usr/bin/env python
#
# Copyright (c) 2013 Matt Behrens <matt@zigg.com>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.


from twisted.python import log

from octothorpe.asyncagi import AsyncAGIChannel, AsyncAGIProtocol


"""Originates an outgoing AsyncAGI call and says "hello, world!".

This is very similar to what we did for agihello, but the way we get
into AsyncAGI mode is a little different.

On the protocol, we call originateAsyncAGI with a channel parameter.
(While this is actually called "channel" on AMI, it's actually what you
would use as the parameter to the Dial application.  In this example
case, we'll use SIP/201 to dial to our SIP phone.)

originateAsyncAGI returns a Deferred that we'll now attach a callback
to.  This callback calls back when the AsyncAGI session is started, and
passes a new AsyncAGIChannel object, ready-to-use.  In our callback,
we then call start() on our new AsyncAGIChannel, which in turn starts
executing AGI on it.

For details of how this works, check the docstring for
originateAsyncAGI.

"""


def _printDict(d):
    for key in sorted(d.keys()):
        print '\t%r: %r' % (key, d[key])


class OriginatorChannel(AsyncAGIChannel):
    def start(self):
        print 'Executing hello-world'
        d = self.sendAGI('EXEC Playback hello-world')
        d.addCallback(self.playbackDone)


    def playbackDone(self, result):
        if result[0] == 0:
            print 'Playback successful, hanging up'
            d = self.sendAGI('HANGUP')
            d.addCallback(self.hangupDone)
        else:
            raise Exception(result)


    def hangupDone(self, result):
        if result[0] == 1:
            print 'Hangup successful'
        else:
            raise Exception(result)


class Originator(AsyncAGIProtocol):
    channelClass = OriginatorChannel

    def __init__(self, username, secret):
        self.username = username
        self.secret = secret
        AsyncAGIProtocol.__init__(self)


    def bannerReceived(self, banner):
        AsyncAGIProtocol.bannerReceived(self, banner)
        d = self.loginMD5(self.username, self.secret)
        d.addCallback(self.loggedIn)


    def loggedIn(self, result):
        d = self.originateAsyncAGI('SIP/201', callerId='Caller <301>')
        d.addCallback(self.asyncAGIStarted)


    def asyncAGIStarted(self, (channel, env)):
        channel.start()


    def eventReceived(self, event, message):
        print 'Event received:', event
        _printDict(message)
        AsyncAGIProtocol.eventReceived(self, event, message)


    def responseReceived(self, response, message, body):
        print 'Response received:', response
        _printDict(message)
        if body:
            print '\tbody: %r' % (body,)
        AsyncAGIProtocol.responseReceived(self, response, message, body)


    def sendAction(self, action, fields):
        print 'Sending action:', action
        _printDict(fields)
        return AsyncAGIProtocol.sendAction(self, action, fields)


if __name__ == '__main__':
    from twisted.internet import reactor
    from twisted.internet.protocol import ClientFactory
    from twisted.python import log
    from sys import stderr

    class OriginatorFactory(ClientFactory):
        def buildProtocol(self, addr):
            return Originator('manager', 'secret')

    log.startLogging(stderr)
    reactor.connectTCP('172.20.64.100', 5038, OriginatorFactory())
    reactor.run()


# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
