#!/usr/bin/env python
'''
Copyright (C) 2010, Digium, Inc.
David Vossel <dvossel@digium.com>

This program is free software, distributed under the terms of
the GNU General Public License Version 2.
'''

import sys
import os
import signal
import subprocess
from twisted.internet import reactor

sys.path.append("lib/python")
from asterisk.test_case import TestCase
from asterisk.sipp import SIPpScenario
import logging

LOGGER = logging.getLogger(__name__)
TEST_DIR = os.path.dirname(os.path.realpath(__file__))

class AttTransferTestTcp(TestCase):
    '''This class handles the testing of attended transfers when using
       TCP transport for SIP.'''
    def __init__(self):
        '''Handle initialization of members.'''
        TestCase.__init__(self)
        self.reactor_timeout = 20
        self.create_asterisk()
        self.chans = []
        self.final_bridge = 0

        # start pjsua client
        self.pja = subprocess.Popen(['pjsua', '--local-port=5065',
                            '--auto-answer=200', '--null-audio', '--no-udp'],
                            stdin=subprocess.PIPE,
                            stdout=subprocess.PIPE)

    def run(self):
        '''Handle completion of Asterisk startup.'''
        # start up sipp scenarios
        self.sippb = SIPpScenario(TEST_DIR, {'scenario': 'uas-no-hangup.xml', '-t': 't1', '-p': '5066'})
        self.sippc = SIPpScenario(TEST_DIR, {'scenario': 'uas-no-hangup.xml', '-t': 't1', '-p': '5067'})
        self.sippb.run(self)
        self.sippc.run(self)
        TestCase.run(self)
        self.create_ami_factory()

    def ami_connect(self, ami):
        '''Handle successful AMI connection.'''

        # register callbacks required to handle call completion events
        self.ami[0].registerEvent('Bridge', self.bridge_callback)
        self.ami[0].registerEvent('VarSet', self.bridgepeer_callback)

        LOGGER.info("Kicking off A-to-B call")
        self.pja.stdin.write("m\n")
        self.pja.stdin.write("sip:call_b@127.0.0.1:5060;transport=TCP\n")

    def bridge_callback(self, ami, event):
        '''Handle Bridge events to catch.'''
        self.chans.append(event['channel2'])
        numchans = len(self.chans)
        if numchans == 1:
            LOGGER.info("Kicking off A-to-C call")
            self.pja.stdin.write("m\n")
            self.pja.stdin.write("sip:call_c@127.0.0.1:5060;transport=TCP\n")
        elif numchans == 2:
            LOGGER.info("Kicking off transfer")
            self.pja.stdin.write("X\n")
            self.pja.stdin.write("1\n")

    def bridgepeer_callback(self, ami, event):
        '''Handle BRIDGEPEER VarSet events to check for successful transfers.'''
        if event['variable'] != "BRIDGEPEER" or len(self.chans) < 2:
            return

        LOGGER.info("Inspecting BRIDGEPEER VarSet")

        # we should get 2 bridgepeers with swapped channel and value headers indicating the bridged channels
        if self.chans[:2] == [event['channel'], event['value']] or\
            self.chans[:2] == [event['value'], event['channel']]:
            LOGGER.info("Got expected VarSet")
            self.final_bridge += 1
            if self.final_bridge == 2:
                LOGGER.info("Transfer successful!")
                # success!
                self.passed = True
                self.doCleanup()

    def doCleanup(self):
        '''Do final cleanup, output debugging, kill off pjsua processes.'''
        self.ami[0].hangup(self.chans[1])
        self.ast[0].cli_exec("core show locks")   # get lock output in case of deadlock before tearing down.
        self.ast[0].cli_exec("core show channels")# if channels are still up for some reason, we want to know that as well
        os.kill(self.pja.pid, signal.SIGKILL)
        self.stop_reactor()

def main():
    '''Run SIP TCP attended transfer test.'''
    # Run Attended Transfer Test
    test = AttTransferTestTcp()
    reactor.run()
    if test.passed != True:
        return 1
    return 0

if __name__ == "__main__":
    sys.exit(main() or 0)

