#!/usr/bin/env python
'''
Copyright (C) 2011-2013, Digium, Inc.
Jonathan Rose <jrose@digium.com>

This program is free software, distributed under the terms of
the GNU General Public License Version 2.
'''
import sys
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.version import AsteriskVersion
from twisted.internet import reactor, defer
from starpy import manager

logger = logging.getLogger(__name__)

"""
Creates an Asterisk instance with some premade queues containing some premade sip peers as members
and changes penalties by using CLI commands and manager actions.

Tests against regression such as the one discussed in https://reviewboard.asterisk.org/r/1609/
"""
class QueuePenaltyTest(TestCase):
    def __init__(self):
        TestCase.__init__(self)
        self.create_asterisk()
        self.state = 0 # State of the test... determines next action and next event expectations.
        self.passed = False
        self.state_passed_flags = 0 # Meant to be used like a bit array for storing condition successes on specific states.
        self.ast_version = AsteriskVersion()

        if self.ast_version < AsteriskVersion("12"):
            self.interface = 'location'
        else:
            self.interface = 'interface'

    #Setup loopback for QueueMemberPenalty events and set first test state
    def ami_connect(self, ami):
        TestCase.ami_connect(self, ami)
        ami.registerEvent("QueueMemberPenalty", self.check_queue_penalty_result)
        self.state_advance(ami)

    #when an event is received, pass it to the state dependent evaluation function 'state_receive()'
    def check_queue_penalty_result(self, ami, event):
        self.state_receive(event, ami)
        pass

    #Evaluates events according to the expectations of a given state and advances the state when finished.
    def state_receive(self, event, ami):
        if (self.state == 1):
            if (event['queue'] == "queue1" and event[self.interface] == "sip/mem1" and event['penalty'] == "1"):
                logger.info("state 1: Successfully Completed")
                self.state_advance(ami)

            else:
                logger.error("state 1: received unexpected QueuePenalty event: %s" % event)
                self.stop_reactor()

        elif (self.state == 2):
            if (event['queue'] == "queue1" and event[self.interface] == "sip/mem2" and event['penalty'] == "2"):
                logger.info("state 2: verified condition 1")
                self.state_passed_flags = self.state_passed_flags | 1

            elif (event['queue'] == "queue2" and event[self.interface] == "sip/mem2" and event['penalty'] == '2'):
                logger.info("state 2: verified condition 2")
                self.state_passed_flags = self.state_passed_flags | 2

            else:
                logger.error("state 2: received unexpected QueuePenalty event: %s" % event)
                self.stop_reactor()

            if (self.state_passed_flags == 3):
                logger.info("state 2: Successfully Completed")
                self.state_advance(ami)

        elif (self.state == 3):
            if (event['queue'] == "queue1" and event[self.interface] == "sip/mem3" and event['penalty'] == '3'):
                logger.info("state 3: verified condition 1")
                self.state_passed_flags = self.state_passed_flags | 1

            elif (event['queue'] == "queue2" and event[self.interface] == "sip/mem3" and event['penalty'] == '3'):
                logger.info("state 3: verified condition 2")
                self.state_passed_flags = self.state_passed_flags | 2

            elif (event['queue'] == "queue3" and event[self.interface] == "sip/mem3" and event['penalty'] == '3'):
                logger.info("state 3: verified condition 3")
                self.state_passed_flags = self.state_passed_flags | 4

            else:
                logger.error("state 3: received unexpected QueuePenalty event: %s" % event)
                self.stop_reactor()

            if (self.state_passed_flags == 7):
                logger.info("state 3: Successfully Completed")
                self.state_advance(ami)

        elif (self.state == 4):
            if (event['queue'] == "queue3" and event[self.interface] == "sip/mem1" and event['penalty'] == '4'):
                logger.info("state 4: Successfully Completed")
                self.state_advance(ami)

            else:
                logger.error("state 4: received unexpected QueuePenalty event: %s" % event)
                self.stop_reactor()

    #Advances test to the next state, resets state_passed_flags, and executes any actions/commands
    def state_advance(self, ami):
        #common:
        self.state += 1
        self.state_passed_flags = 0

        #state specific:
        if (self.state == 1): #state 1 - cli command with specific queue on mem1
            ami.command('queue set penalty 1 on sip/mem1 in queue1')

        elif (self.state == 2): #state 2 - cli command with unspecified queue on mem2
            ami.command('queue set penalty 2 on sip/mem2')

        elif (self.state == 3): #state 3 - manager action queuePenalty with unspecified queue on mem3
            message = {'action': 'queuepenalty', 'penalty': '3', 'interface': 'sip/mem3'}
            ami.sendMessage(message)

        elif (self.state == 4): #state 4 - mamager action queuePenalty with specific queue on mem1
            message = {'action': 'queuepenalty', 'penalty': '4', 'interface': 'sip/mem1', 'queue': 'queue3'}
            ami.sendMessage(message)

        #states exhausted:
        else:
            logger.info("Test Successful")
            self.passed = True
            self.stop_reactor()

    #Create and commect ami.
    def run(self):
        TestCase.run(self)
        self.create_ami_factory()

def main():
    test = QueuePenaltyTest()
    test.start_asterisk()
    reactor.run()
    test.stop_asterisk()
    if test.passed:
        return 0
    return 1


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


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