# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
# 
#   http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

 

'''
Created on Aug 2, 2010

'''


import sys
import os
import inspect
from optparse import OptionParser, OptParseError, BadOptionError, OptionError, OptionConflictError, OptionValueError
import cloudapis as apis


def describe(name,desc):
    def inner(decoratee):
        if not hasattr(decoratee,"descriptions"): decoratee.descriptions = {}
        decoratee.descriptions[name] = desc
        return decoratee
    return inner


def error(msg):
    sys.stderr.write(msg)
    sys.stderr.write("\n")


class MyOptionParser(OptionParser):
    def error(self, msg):
        error("%s: %s\n" % (self.get_prog_name(),msg))
        self.print_usage(sys.stderr)
        self.exit(os.EX_USAGE)
        
    def parse_args(self,*args,**kwargs):
        options,arguments = OptionParser.parse_args(self,*args,**kwargs)
        
        def prune_options(options,alist):
            """Given 'options' -- a list of arguments to OptionParser.add_option,
            and a set of optparse Values, return a dictionary of only those values
            that apply exclusively to 'options'"""
            return dict( [ (k,getattr(options,k)) for k in dir(options) if k in alist ] )
        
        api_options = prune_options(options,self.api_dests)
        cmd_options = prune_options(options,self.cmd_dests)
        
        return options,arguments,api_options,cmd_options


def get_parser(api_callable=None,cmd_callable=None): # this should probably be the __init__ method of myoptionparser
    
    def getdefaulttag(default):
        if default is not None: return " [Default: %default]"
        return ''
    
    def get_arguments_and_options(callable):
        """Infers and returns arguments and options based on a callable's signature.
        Cooperates with decorator @describe"""
	try:
        	funcargs = inspect.getargspec(callable).args
        	defaults = inspect.getargspec(callable).defaults
	except:
		funcargs = inspect.getargspec(callable)[0]
        	defaults = inspect.getargspec(callable)[3]
        if not defaults: defaults = []
        args = funcargs[1:len(funcargs)-len(defaults)] # this assumes self, so assumes methods
        opts = funcargs[len(funcargs)-len(defaults):]
        try: descriptions = callable.descriptions
        except AttributeError: descriptions = {}
        arguments = [ (argname, descriptions.get(argname,'') ) for argname in args ]
        options = [ [
                          ("--%s"%argname.replace("_","-"),),
                          {
                           "dest":argname,
                           "help":descriptions.get(argname,'') + getdefaulttag(default),
                           "default":default,
                          }
                        ] for argname,default in zip(opts,defaults) ]
        return arguments,options

    basic_usage = "usage: %prog [options...] "
    
    api_name = "<api>"
    cmd_name = "<command>"
    description = "%prog is a command-line tool to access several cloud APIs."
    arguments = ''
    argexp = ""
    
    if api_callable:
        api_name = api_callable.__module__.split(".")[-1].replace("_","-")
        api_arguments,api_options = get_arguments_and_options(api_callable)
        assert len(api_arguments) is 0 # no mandatory arguments for class initializers
        
    if cmd_callable:
        cmd_name = cmd_callable.func_name.replace("_","-")
        cmd_arguments,cmd_options = get_arguments_and_options(cmd_callable)
        if cmd_arguments:
            arguments   = " " + " ".join( [ s[0].upper() for s in cmd_arguments ] )
            argexp = "\n\nArguments:\n" + "\n".join ( "  %s\n                        %s"%(s.upper(),u) for s,u in cmd_arguments )
        description = cmd_callable.__doc__
       
    api_command = "%s %s"%(api_name,cmd_name)

    if description: description = "\n\n" + description
    else: description = ''
        
    usage = basic_usage + api_command + arguments + description + argexp

    parser = MyOptionParser(usage=usage, add_help_option=False)
    
    parser.add_option('--help', action="help")
 
    group = parser.add_option_group("General options")
    group.add_option('-v', '--verbose', dest="verbose", help="Print extra output")

    parser.api_dests = []
    if api_callable and api_options:
        group = parser.add_option_group("Options for the %s API"%api_name)
        for a in api_options:
            group.add_option(a[0][0],**a[1])
            parser.api_dests.append(a[1]["dest"])
 
    parser.cmd_dests = []
    if cmd_callable and cmd_options:
        group = parser.add_option_group("Options for the %s command"%cmd_name)
        for a in cmd_options:
            group.add_option(a[0][0],**a[1])
            parser.cmd_dests.append(a[1]["dest"])
 
    return parser

def lookup_command_in_api(api,command_name):
    command = getattr(api,command_name.replace("-","_"),None)
    return command

def get_api_list(api):
	apilist = []
	for cmd_name in dir(api):
		cmd = getattr(api,cmd_name)
            	if callable(cmd) and not cmd_name.startswith("_"):
			apilist.append(cmd_name)	
	return apilist

def get_command_list(api):
        cmds = []
        for cmd_name in dir(api):
            cmd = getattr(api,cmd_name)
            if callable(cmd) and not cmd_name.startswith("_"):
		if cmd.__doc__:docstring = cmd.__doc__
		else:docstring = ''
		cmds.append( "    %s" % (cmd_name.replace('_','-')) )
        return cmds
