#!/usr/bin/env python
 
'''
Asterisk/CLI.py: Command-line wrapper around the Asterisk Manager API.
'''
 
__author__ = 'David M. Wilson <dw@autosols.com>'
__id__ = '$Id$'
 
import sys, os, inspect
from Asterisk import Manager, BaseException, Config
import Asterisk.Util
 
 
 
 
class ArgumentsError(BaseException):
    _prefix = 'bad arguments'
 
 
 
 
def usage(argv0, out_file):
    '''
    Print command-line program usage.
    '''
 
    argv0 = os.path.basename(argv0)
 
    usage = '''
        %(argv0)s actions
            Show available actions and their arguments.
 
        %(argv0)s action <API action> [<arg1> [<argn> ..]]
            Execute the specified action.
            For named arguments "--name=<val>" syntax may also be used.
 
        %(argv0)s command "<console command>"
            Execute the specified Asterisk console command.
 
        %(argv0)s usage
            Display this message.
 
        %(argv0)s help <action>
            Display usage message for the given <action>.
 
    ''' % locals()
 
    out_file.writelines([ line[6:] + '\n' for line in usage.splitlines() ])
 
 
 
 
def show_actions(action = None):
    if action is None:
        print
        print 'Supported actions and their arguments.'
        print '======================================'
        print
 
    class AllActions(Manager.CoreActions, Manager.ZapataActions):
        pass
 
    methods = [
        (name, obj) for (name, obj) in inspect.getmembers(AllActions) \
        if inspect.ismethod(obj) and name[0] != '_'
    ]
 
    if action is not None:
        methods = [ x for x in methods if x[0].lower() == action.lower() ]
 
    for name, method in methods:
        arg_spec = inspect.getargspec(method)
        arg_spec[0].pop(0)
        print '   Action:', name
 
        fmt = inspect.formatargspec(*arg_spec)[1:-1]
        if fmt:
            print 'Arguments:', fmt
 
        foo = [ x.strip() for x in method.__doc__.strip().splitlines() ]
        print '           ' + '\n           '.join(foo)
        print
 
 
 
 
def execute_action(manager, argv):
    method_name = argv.pop(0).lower()
    method_dict = dict(\
        [ (k.lower(), v) for (k, v) in inspect.getmembers(manager) \
        if inspect.ismethod(v) ])
 
    try:
        method = method_dict[method_name]
    except KeyError, e:
        raise ArgumentsError('%r is not a valid action.' % (method_name,))
 
    pos_args = []
    kw_args = {}
    process_kw = True
 
    for arg in argv:
        if process_kw and arg == '--':
            process_kw = False # stop -- processing.
        elif process_kw and arg[:2] == '--' and '=' in arg:
            key, val = arg[2:].split('=', 2)
            kw_args[key] = val
        else:
            pos_args.append(arg)
 
    Asterisk.Util.dump_human(method(*pos_args, **kw_args))
 
 
def command_line(argv):
    '''
    Act as a command-line tool.
    '''
 
    commands = [ 'actions', 'action', 'command', 'usage', 'help' ]
 
    if len(argv) < 2:
        raise ArgumentsError('please specify at least one argument.')
 
    command = argv[1]
 
    if command not in commands:
        raise ArgumentsError('invalid arguments.')
 
 
 
    if command == 'usage':
        return usage(argv[0], sys.stdout)
 
    manager = Manager.Manager(*Config.Config().get_connection())
 
    if command == 'actions':
        show_actions()
 
    if command == 'help':
        if len(argv) < 3:
            raise ArgumentsError('please specify an action.')
 
        show_actions(argv[2])
 
    elif command == 'action':
        if len(argv) < 3:
            raise ArgumentsError('please specify an action.')
 
        try:
            execute_action(manager, argv[2:])
        except TypeError, e:
            print "Bad arguments specified. Help for %s:" % (argv[2],)
            show_actions(argv[2])
 
    elif command == 'command':
        execute_action('command', argv[2])