#!/usr/bin/env python
# vim: sw=3 et:
'''
Copyright (C) 2012, Digium, Inc.
Matt Jordan <mjordan@digium.com>

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

import sys
import os
import logging


from twisted.internet import reactor

sys.path.append("lib/python")

from asterisk.version import AsteriskVersion
from asterisk.sipp import SIPpScenario, SIPpScenarioSequence
from asterisk.test_case import TestCase

"""
The TestCase class will initialize the python LOGGER - creating a
LOGGER here will log under the '__main__' namespace
"""
LOGGER = logging.getLogger(__name__)

TEST_DIR = os.path.dirname(os.path.realpath(__file__))

class InfoDTMF(TestCase):
    """
    Test handling of SIP INFO requests with DTMF payloads
    """

    def __init__(self):
        super(InfoDTMF, self).__init__()
        """ Expected events for both scenarios.  Order matters. """
        self.expected_events = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "#", "*", "A", "A", "A", "B", "B", "B", "C", "C", "C", "D", "D", "D",
                                "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "#", "*", "A", "A", "A", "B", "B", "B", "C", "C", "C", "D", "D", "D"]
        self.received_events = []
        self.create_asterisk()
        self.passed = True

    def run(self):
        super(InfoDTMF, self).run()
        self.create_ami_factory()

    def ami_connect(self, ami):
        """
        This method is called by the StarPY manager class when AMI connects to Asterisk

        Keyword Arguments:
        ami    -    The StarPY manager object that connected
        """
        if (AsteriskVersion() >= AsteriskVersion('12')):
            ami.registerEvent('DTMFEnd', self.handle_dtmf_end_event)
        else:
            ami.registerEvent('DTMF', self.handle_dtmf_event)
        sipp_scenario_params = [{'scenario':'dtmf-relay.xml','-p':'5061'}, {'scenario':'dtmf.xml','-p':'5061'}]
        sequence = SIPpScenarioSequence(test_case = self)
        for scenario_param in sipp_scenario_params:
            sequence.register_scenario(SIPpScenario(TEST_DIR, scenario_param))

        sequence.execute()

    def handle_dtmf_end_event(self, ami, event):
        """
        Callback handler for a DTMF End Event received over AMI.
        This event is returned back in Asterisk 12+

        Keyword Arguments:
        ami    -    The instance of AMI that received this event
        event    -    The AMI event object
        """
        digit = event['digit']
        LOGGER.debug('Received end of DTMF digit %s' % digit)
        self.received_events.append(digit)
        if (len(self.received_events) == len(self.expected_events)):
            LOGGER.info("Received all expected events, stopping test")
            self.stop_reactor()

    def handle_dtmf_event(self, ami, event):
        """
        Callback handler for a DTMF Event received over AMI.

        Keyword Arguments:
        ami    -    The instance of AMI that received this event
        event    -    The AMI event object
        """
        digit = event["digit"]
        end = event["end"]
        if (end == "Yes"):
            LOGGER.debug("Received end of DTMF digit %s" % digit)
            self.received_events.append(digit)
        if (len(self.received_events) == len(self.expected_events)):
            LOGGER.info("Received all expected events, stopping test")
            self.stop_reactor()

def main():
    """
    Main entry point for the test.
    """

    test = InfoDTMF()
    reactor.run()

    if (len(test.expected_events) != len(test.received_events)):
        LOGGER.warn("Failed to receive %d expected events - received %d instead" % (len(test.expected_events), len(test.received_events)))
        test.passed = False

    for i in range(min(len(test.expected_events), len(test.received_events))):
        if (test.expected_events[i] != test.received_events[i]):
            LOGGER.warn("Failed to received expected DTMF event [%s], received [%s] instead" % (test.expected_events[i], test.received_events[i]))
            test.passed = False

    if not test.passed:
        return 1

    return 0

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