#!/usr/bin/env python
'''
Copyright (C) 2012, Digium, Inc.
Mark Michelson <mmichelson@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

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

from asterisk.asterisk import Asterisk
from asterisk.test_case import TestCase
from asterisk.sipp import SIPpScenario
from twisted.internet import reactor

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

SIPP_SCENARIO_INITIAL = {
    'scenario' : 'initial.xml',
    '-p' : '5061',
    '-s' : 'bob',
}

SIPP_SCENARIO_RESUBSCRIBE = {
    'scenario' : 'resubscribe.xml',
    '-p' : '5061',
    '-s' : 'bob',
}

class Resubscribe(TestCase):
    def __init__(self):
        TestCase.__init__(self)
        self.create_asterisk()
        self.sipTestInitial = SIPpScenario(TEST_DIR, SIPP_SCENARIO_INITIAL)
        self.sipTestResubscribe = SIPpScenario(TEST_DIR, SIPP_SCENARIO_RESUBSCRIBE)
        self.sippPassed = False
        self.notifyPassed = False
        self.num_notifies = 0

    def sippComplete(self, result):
        # Okay, we now know that the subscription is terminated. Now let's
        # originate that second call to change the state to 'available'
        self.ami[0].registerEvent("UserEvent", self.originateComplete)
        df = self.ami[0].originate(channel = "Local/available@default",
                application = "Echo")
        df.addErrback(self.handle_originate_failure)

    def sippResubscribeComplete(self, result):
        self.sippPassed = True
        self.stop_reactor()

    def originateComplete(self, ami, event):
        if not event.get("userevent") == "Presence":
            return
        # The state has changed to "available". Now start the other
        # SIPP scenario and make sure it gets notified as we expect
        df = self.sipTestResubscribe.run(self)
        df.addCallback(self.sippResubscribeComplete)

    def runSippTest(self):
        df = self.sipTestInitial.run(self)
        df.addCallback(self.sippComplete)

        df = self.ami[0].originate(channel = "Local/away@default", application = "Echo")
        df.addErrback(self.handle_originate_failure)

    def inspectPresence(self, ami, event):
        # For this test, we expect four of these events.
        # First one is when the presence is changed to "away"
        # Second one is when the first subscription is terminated
        # Third one is when the subscription is re-established.
        # Fourth one is when the subscription is re-terminated.
        # The first two and last two should have the same values present.
        if event.get("state") != "DIGIUM_PRESENCE_SENT":
            return

        self.num_notifies = self.num_notifies + 1

        if self.num_notifies > 4:
            logger.error("Too many NOTIFYs!")
            self.notifyPassed = False

        if self.num_notifies < 3:
            if event.get("presencestate") != "away":
                logger.error("Incorrect presencestate value!")
                self.notifyPassed = False
                ami.unregisterEvent("TestEvent")
            if event.get("subtype") != "down the hall":
                logger.error("Incorrect presence subtype!")
                self.notifyPassed = False
                ami.unregisterEvent("TestEvent")
            if event.get("message") != "Quarterly financial meeting":
                logger.error("Incorrect presence message!")
                self.notifyPassed = False
                ami.unregisterEvent("TestEvent")
        else:
            if event.get("presencestate") != "available":
                logger.error("Incorrect presencestate value!")
                self.notifyPassed = False
                ami.unregisterEvent("TestEvent")
            if event.get("subtype") != "":
                logger.error("Incorrect presence subtype!")
                self.notifyPassed = False
                ami.unregisterEvent("TestEvent")
            if event.get("message") != "":
                logger.error("Incorrect presence message!")
                self.notifyPassed = False
                ami.unregisterEvent("TestEvent")

        if self.num_notifies == 4:
            self.notifyPassed = True

    def ami_connect(self, ami):
        self.ast[ami.id].cli_exec("sip set debug on")
        ami.registerEvent("TestEvent", self.inspectPresence)
        self.runSippTest()

    def stop_asterisk(self):
        ''' Kill the SIPp test if it didn't exit '''
        if not self.sipTestInitial.exited:
            self.sipTestInitial.kill()
        if not self.sipTestResubscribe.exited:
            self.sipTestResubscribe.kill()

    def run(self):
        TestCase.run(self)
        self.create_ami_factory()

def main():
    test = Resubscribe()
    reactor.run()
    if not test.sippPassed or not test.notifyPassed:
        return 1
    return 0

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