#!/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


"""Answers an incoming AsyncAGI call and says "hello, world!"

For this to work, you need a dialplan hook on an incoming extension
that passes the call to AsyncAGI, like so:

    [context]
    exten => 400,1,AGI(agi:async)
    same => n,Hangup

When this context/exten/priority is reached, Asterisk will emit an
AsyncAGI event on the channel, which our AnswererChannel will intercept
and check and, if it's the one we want, will use AGI actions to play
the hello-world sound and hang up.

An important detail to note here is that the channel is *not* answered
when control is transferred.  In this specific case, the playback will
go ahead and answer the channel, but you'll probably want to AGI ANSWER
it yourself normally when you're ready, or do it in dialplan.

"""


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


class AnswererChannel(AsyncAGIChannel):
    def asyncAGIStarted(self, context, extension, priority, env):
        print 'Call received: ', context, extension, priority

        # In the example extensions.conf provided in the Vagrant setup,
        # the AGI(agi:async) invocation is in the default context at
        # extension 403.  I don't bother checking priority here because
        # there's no way to reach it otherwise, but you may wish to.

        if context == 'default' and extension == '403':
            print 'It is ours, executing hello-world'
            d = self.sendAGI('EXEC Playback hello-world')
            d.addCallback(self.playbackDone)


    def playbackDone(self, result):

        # This callback is invoked when the previous AGI is done.  You
        # can also do several sendAGI actions and have Asterisk queue
        # them if you wish instead.

        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 Answerer(AsyncAGIProtocol):
    channelClass = AnswererChannel

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


    def bannerReceived(self, banner):
        AsyncAGIProtocol.bannerReceived(self, banner)
        self.loginMD5(self.username, self.secret)


    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 AnswererFactory(ClientFactory):
        def buildProtocol(self, addr):
            return Answerer('manager', 'secret')

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


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