#!/usr/bin/env python
'''
Copyright (C) 2010-2013, 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
import logging

from twisted.application import service, internet
from twisted.internet import reactor, defer
from starpy import manager
from starpy import fastagi

sys.path.append("lib/python")
from asterisk.asterisk import Asterisk
from asterisk.test_case import TestCase

LOGGER = logging.getLogger(__name__)

class ChanSpyMixMonitorTest(TestCase):

    def __init__(self):
        """Constructor"""
        super(ChanSpyMixMonitorTest, self).__init__()

        self.received_spy_events = 0
        self.expected_spy_events = 3
        self.talk_detected = 0
        self.chanspy_channel = ""

        self.create_asterisk()

        self.talkingaudio = os.path.join(os.getcwd(), "%s/sounds/talking" % self.test_name)
        self.audiofile1 = self.ast[0].get_path("astspooldir", "tmp", "testaudio1")

    def fastagi_connect(self, agi):
        LOGGER.info("Got pass results!")

        sequence = fastagi.InSequence()
        sequence.append(agi.execute, "HangUp")
        sequence.append(agi.finish)

        self.set_passed(True)
        reactor.callLater(1, self.read_result)

        return sequence()

    def read_result(self):
        if self.passed == True:
            self.stop_reactor()
            LOGGER.info("SIP ChanSpy test PASSED!")
        else:
            LOGGER.warn("SIP ChanSpy test FAILED!")

    def handle_chanspy_start(self, ami, event):
        """Handler for the ChanSpyStart AMI event"""

        self.received_spy_events += 1
        LOGGER.info("Received ChanSpyStart event for %s" % event["spyeechannel"])
        if event["spyeechannel"].count("end_a") > 0:
            reactor.callLater(1, self.hangup_pjsua, self.pja, "A")
            reactor.callLater(3, self.call_pjsua, self.pjb, "B")
        if event["spyeechannel"].count("end_b") > 0:
            reactor.callLater(1, self.hangup_pjsua, self.pjb, "B")
            reactor.callLater(3, self.call_pjsua, self.pjc, "C")
        if event["spyeechannel"].count("end_c") > 0:
            reactor.callLater(2, self.hangup_pjsua, self.pjc, "C")
            reactor.callLater(3, self.hangup_chanspy)

    def handle_newexten(self, ami, event):
        """Handler for the Newexten AMI event"""

        if event["context"] != "test" or event["extension"] != "chanspytest" or event["priority"] != "1":
            return
        self.chanspy_channel = event["channel"]
        LOGGER.debug("ChanSpy channel set to %s." % self.chanspy_channel)

    def ami_connect(self, ami):
        """AMI Connect handler"""

        self.ami_instance = ami
        self.ami_instance.registerEvent('ChanSpyStart', self.handle_chanspy_start)
        self.ami_instance.registerEvent('Newexten', self.handle_newexten)
        self.ami_instance.setVar(channel="", variable="TESTAUDIO1", value=self.audiofile1)
        self.ami_instance.setVar(channel="", variable="TALK_AUDIO", value=self.talkingaudio)
        self.start_processes()
        reactor.callLater(1, self.call_chanspy)
        reactor.callLater(2, self.call_pjsua, self.pja, "A")

    def call_pjsua(self, pjsua, name):
        """Have some PJSUA instance call into Asterisk

        Keyword Arguments:
        pjsua The instance of pjsua to use
        name The name to call the instance
        """
        LOGGER.info("%s Calling into Playback" % name)
        pjsua.stdin.write("m\n")
        pjsua.stdin.write("sip:play_exten@127.0.0.1:5060\n")

    def hangup_pjsua(self, pjsua, name):
        """Hangup some PJSUA instance

        Keyword Arguments:
        pjsua The instance of pjsua to use
        name The name to call the instance
        """
        LOGGER.info("Hanging up %s" % name)
        pjsua.stdin.write("h\n")

    def start_processes(self):
        """Start up the PJSUA processes"""
        LOGGER.info("Starting Processes")
        self.pja = subprocess.Popen(['pjsua', '--local-port=5065', '--auto-answer=200', '--null-audio'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
        self.pjb = subprocess.Popen(['pjsua', '--local-port=5066', '--auto-answer=200', '--null-audio'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
        self.pjc = subprocess.Popen(['pjsua', '--local-port=5067', '--auto-answer=200', '--null-audio'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)

    def stop_processes(self):
        """Stop said processes with prejudice"""
        LOGGER.info("Stopping processes")
        os.kill(self.pja.pid, signal.SIGKILL)
        os.kill(self.pjb.pid, signal.SIGKILL)
        os.kill(self.pjc.pid, signal.SIGKILL)

    def stop_reactor(self):
        """Override of TestCase.stop_reactor"""
        super(ChanSpyMixMonitorTest, self).stop_reactor()
        self.stop_processes()

    def call_chanspy(self):
        """Start spying!"""

        LOGGER.info("Placing call to ChanSpy extension.")
        self.ami_instance.originate(channel="Local/chanspytest@test",
                           exten="generate",
                           context="test",
                           priority="1").addErrback(self.handle_originate_failure)

    def hangup_chanspy(self):
        """Hangup the current ChanSpy channel"""

        LOGGER.info("Hangup ChanSpy channel %s." % self.chanspy_channel)
        self.ami_instance.hangup(channel=self.chanspy_channel)
        reactor.callLater(2, self.verify_audio)

    def verify_audio(self):
        """Verifies that audio was left appropriately from the last iteration"""

        self.ami_instance.originate(channel="Local/play_recording@test",
                           exten="detect_audio",
                           context="test",
                           priority="1").addErrback(self.handle_originate_failure)

    def stop_asterisk(self):
        """Override of TestCase.stop_asterisk"""
        self.read_result()

    def run(self):
        """Override of TestCase.run"""
        super(ChanSpyMixMonitorTest, self).run()
        self.create_fastagi_factory()
        self.create_ami_factory()

def main():
    test = ChanSpyMixMonitorTest()
    reactor.run()
    if test.passed != True:
        return 1
    return 0

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

# vim:sw=4:ts=4:expandtab:textwidth=79
