#!/usr/bin/env python
# vim: sw=3 et:
'''
Copyright (C) 2011, 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.asterisk import Asterisk
from asterisk.test_case import TestCase
from asterisk.voicemail import VoiceMailMailboxManagement
from asterisk.voicemail import VoiceMailState
from asterisk.voicemail import VoiceMailTest

logger = logging.getLogger(__name__)

class StartVoiceMailState(VoiceMailState):
    """
    TestState that is the entry point for the VoiceMail application.

    Note that since this test is exercising leaving the VoiceMail
    application due to DTMF transfers, it doesn't do much other then
    wait for the intro prompt, then ask to be transferred out
    """

    def __init__(self, controller, voiceMailTest):
        VoiceMailState.__init__(self, controller, voiceMailTest)

    def handle_state_change(self, ami, event):
        state = event['state']
        if state == 'PLAYBACK':
            message = event.get('message')

            if message == 'vm-intro':
                dtmf = self.voice_mail_test.get_dtmf_to_send()
                if dtmf:
                    self.voice_mail_test.send_dtmf(dtmf)
            else:
                self.handle_default_state(event)
        else:
            self.handle_default_state(event)

    def get_state_name(self):
        return "START"

class LeaveVoicemailContexts(VoiceMailTest):

    """
    The parent directory that this test resides in
    """
    testParentDir = "tests/apps/voicemail"

    def __init__(self):
        super(LeaveVoicemailContexts, self).__init__()

        self.testCounter = 0
        self.create_asterisk(2)
        self.expectedValues = {'operator@voicemail': False,
                               'attendant@voicemail': False,
                               '1@voicemail': False,
                               '3@voicemail': False,
                               '5678@voicemail': False,
                               'operator@othercontext': False,
                               'attendant@othercontext': False,
                               '1@othercontext': False,
                               '3@othercontext': False,
                               '5678@othercontext': False,
                               '9@othercontext': False,}

        self.senderAmi = None

    def ami_connect(self, ami):
        super(LeaveVoicemailContexts, self).ami_connect(ami)

        self.audioFile = os.path.join(os.getcwd(), "%s/sounds/talking" % (self.testParentDir))

        # Record which AMI instance we've received and attempt to set up the test controller
        if (ami.id == 0):
            self.ami_receiver = ami
            ami.registerEvent('UserEvent', self.user_event)
        elif (ami.id == 1):
            self.ami_sender = ami
            self.ami_sender.registerEvent('Newchannel', self.new_channel_handler)
            self.ast_sender = self.ast[self.ami_sender.id]
        self.create_test_controller()
        if (self.test_state_controller != None):
            self.test_state_controller.change_state(StartVoiceMailState(self.test_state_controller, self))
            self.execute_test()

    def new_channel_handler(self, ami, event):
        if 'channel' not in event:
            return
        channel = event['channel']
        logger.debug("Setting sender channel as %s" % channel)
        self.sender_channel = channel

    def get_dtmf_to_send(self):
        """
        Retrieve the DTMF to send based on what test we happen to be executing
        """
        if self.testCounter == len(self.expectedValues) - 1:
            logger.debug("Test exiting out before leaving voicemail and going to 9 extension in othercontext")
            return "9"
        elif self.testCounter % 5 == 0:
            logger.debug("Test exiting out before leaving voicemail and going to operator extension")
            return "0"
        elif self.testCounter % 5 == 1:
            logger.debug("Test exiting out before leaving voicemail and going to asterisk (a) extension")
            return "*"
        elif self.testCounter % 5 == 2:
            logger.debug("Test exiting out before leaving voicemail and going to numeric 1 extension")
            return "1"
        elif self.testCounter % 5 == 3:
            logger.debug("Test exiting out before leaving voicemail and going to numeric 3 extension")
            return "3"
        elif self.testCounter % 5 == 4:
            logger.debug("Testing exiting out before leaving voicemail and going to numeric 5678 extension")
            return "5678"

    def execute_test(self):
        logger.info("Executing test [" + str(self.testCounter) + "]")
        self.reset_timeout()
        if self.testCounter < 5:
            # The first 5 tests start out in extension 9000
            self.ami_sender.originate(channel = "sip/ast1/9000",
                context = "voicemailCaller",
                exten = "wait",
                priority= 1).addErrback(self.handle_originate_failure)
        elif self.testCounter < len(self.expectedValues):
            self.ami_sender.originate(channel = "sip/ast1/1234",
                context = "voicemailCaller",
                exten = "wait",
                priority = 1).addErrback(self.handle_originate_failure)
        else:
            logger.warn("Test iterated [" + str(self.testCounter) + "] - expected less than %d"
                % len(self.expectedValues))

    def user_event(self, ami, event):

        if event['userevent'] != 'TestResult':
            return

        if event['result'] != 'fail':
            logger.info("Received non-failure result " + event['result'])
            if event['result'] in self.expectedValues:
                self.expectedValues[event['result']] = True
            else:
                logger.warn("Unsupported or unexpected result: " + event['result'])
        else:
            logger.warn("VoiceMail did not successfully exit:")
            logger.warn("result: %s" % (event['result'],))
            logger.warn("error: %s" % (event['status'],))
            self.passed = False

        self.testCounter += 1
        if self.testCounter == len(self.expectedValues):
            self.stop_reactor()
        else:
            self.execute_test()
        return

    def run(self):
        super(LeaveVoicemailContexts, self).run()

        """ Create the AMI factories
        """
        self.create_ami_factory(2)


def main():

    test = LeaveVoicemailContexts()
    voicemailManager = VoiceMailMailboxManagement(test.ast[0])

    reactor.run()

    # Verify that we received all expected results
    test.passed = True
    for k, v in test.expectedValues.items():
        if not v:
            logger.warning("%s: %s" % (k, str(v)))
            test.passed = False
        else:
            logger.info("%s: %s" % (k, str(v)))

    if not test.passed:
        return 1

    return 0

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