#!/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")
sys.path.append("tests/apps/voicemail")

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__)

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

    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':
                self.change_state(IntroVoiceMailState(self.controller, self.voice_mail_test))
            else:
                self.handle_default_state(event)
        else:
            self.handle_default_state(event)

    def get_state_name(self):
        return "START"

"""
TestState that occurs when the Intro message is read, and will start the audio playback at the beep.
After this the test states transition to a pending until switched back to Start by the reception
of a UserEvent.
"""
class IntroVoiceMailState(VoiceMailState):

    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 == 'beep':
                """ A beep indicates we need to stream some sound file over - use the same sound file for everything """
                audioFile = os.path.join(os.getcwd(), "%s/sounds/talking" % (self.voice_mail_test.testParentDir))
                self.voice_mail_test.send_sound_file_with_dtmf(audioFile, "#")
                self.change_state(PendingVoiceMailState(self.controller, self.voice_mail_test))
            else:
                self.handle_default_state(event)
        else:
            self.handle_default_state(event)
    def get_state_name(self):
        return "INTRO"

"""
TestState that occurs between leaving voicemails
"""
class PendingVoiceMailState(VoiceMailState):

    def __init__(self, controller, voiceMailTest):
        VoiceMailState.__init__(self, controller, voiceMailTest)
        """ Reset the reactor timeout """
        self.voice_mail_test.reset_timeout()

    def handle_state_change(self, ami, event):
        pass

    def get_state_name(self):
        return "PENDING"


class LeaveVoicemailNominal(VoiceMailTest):

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

    def __init__(self):
        super(LeaveVoicemailNominal, self).__init__()
        self.testResultsReceived = 0
        self.reactor_timeout = 45
        self.create_asterisk(2)
        self.test_counter = 0
        self.extensions = [1234,1234,5678,5678,9000]

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

        ami.registerEvent('UserEvent', self.user_event)

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

        if not (ami.id == 0):
            self.originate_call()

    def originate_call(self):
        extension = self.extensions[self.test_counter]
        logger.info("Originating call to sip/ast1/" + str(extension))
        df = self.ami_sender.originate("sip/ast1/" + str(extension), "voicemailCaller", "wait", 1, None, "CallId-" + str(extension), None, None, None, {}, True )
        df.addErrback(self.handle_originate_failure)

    def user_event(self, ami, event):
        if event['userevent'] != 'TestResult':
            return

        self.testResultsReceived += 1
        if event['result'] == "pass":
            self.passed = True
            logger.info("VoiceMail successfully exited")
        else:
            logger.warn("VoiceMail did not successfully exit:")
            logger.warn("result: %s" % (event['result'],))
            logger.warn("error: %s" % (event['error'],))

        if self.testResultsReceived == 5:
            logger.info("All results received; stopping reactor")
            self.stop_reactor()
        else:
            """ Originate the next call and reset the state machine """
            self.test_counter += 1
            self.sender_channel = "SIP/ast1-0000000" + str(self.test_counter)
            self.test_state_controller.change_state(StartVoiceMailState(self.test_state_controller, self))
            self.originate_call()

    def run(self):
        super(LeaveVoicemailNominal, self).run()
        self.create_ami_factory(2)


def main():
    test = LeaveVoicemailNominal()
    voicemailManager = VoiceMailMailboxManagement(test.ast[0])

    test.start_asterisk()

    reactor.run()

    test.stop_asterisk()

    """
    Verify that all of the voicemails we expect to be created were created.  That would be:
    Two voicemails in default/1234
    Two voicemails in default/5678
    One voicemail in notdefault/1234
    All voicemails should have formats ulaw|wav49|wav
    """
    if test.passed:
        formats = ["ulaw","wav","WAV"]
        if not voicemailManager.check_voicemail_exists("default","1234",0,formats):
            logger.warn("Failed to find voicemail 0 for default/1234")
            test.passed = 0

        if not voicemailManager.check_voicemail_exists("default","1234",1,formats):
            logger.warn("Failed to find voicemail 1 for default/1234")
            test.passed = 0

        if not voicemailManager.check_voicemail_exists("default","5678",0,formats):
            logger.warn("Failed to find voicemail 0 for default/5678")
            test.passed = 0

        if not voicemailManager.check_voicemail_exists("default","5678",1,formats):
            logger.warn("Failed to find voicemail 1 for default/5678")
            test.passed = 0

        if not voicemailManager.check_voicemail_exists("notdefault","1234",0,formats):
            logger.warn("Failed to find voicemail 0 for notdefault/1234")
            test.passed = 0

    if not test.passed:
        return 1

    return 0

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