# @GPL_HEADER_START
# Use of the RAVE and related source code is subject to the terms
# of the following licenses:
# 
# GNU Public License (GPL) Rights pursuant to Version 2, June 1991
# Government Purpose License Rights (GPLR) pursuant to DFARS 252.225-7013
# 
# NO WARRANTY
# 
# ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER
# PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY
# PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN
# "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
# KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT
# LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE,
# MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE
# OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT,
# SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY
# TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF
# WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES.
# LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF
# CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON
# CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE
# DELIVERABLES UNDER THIS LICENSE.
# 
# Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie
# Mellon University, its trustees, officers, employees, and agents from
# all claims or demands made against them (and any related losses,
# expenses, or attorney's fees) arising out of, or relating to Licensee's
# and/or its sub licensees' negligent use or willful misuse of or
# negligent conduct or willful misconduct regarding the Software,
# facilities, or other rights or assistance granted by Carnegie Mellon
# University under this License, including, but not limited to, any
# claims of product liability, personal injury, death, damage to
# property, or violation of any laws or regulations.
# 
# Carnegie Mellon University Software Engineering Institute authored
# documents are sponsored by the U.S. Department of Defense under
# Contract F19628-00-C-0003. Carnegie Mellon University retains
# copyrights in all material produced under this contract. The U.S.
# Government retains a non-exclusive, royalty-free license to publish or
# reproduce these documents, or allow others to do so, for U.S.
# Government purposes only pursuant to the copyright license under the
# contract clause at 252.227.7013.
# 
# @GPL_HEADER_END
"""
A simple wrapper over python's getopt to make argument parsing slightly
clearer, more informative and more convenient.
"""
import getopt
import sys

from ConfigParser import ConfigParser

class OptionError(Exception):
    pass

class Option(object):
#   Number of characters before the end of a tabstop (in help string,
#   between long/short option and opt documentation)
    tabstop = 33

    def __init__(self, shortopt, longopt, opt_valdesc, type, doc):
        assert(longopt != None)
        self.shortopt = shortopt
        self.longopt = longopt
        self.opt_valdesc = opt_valdesc
        self.type = type
        self.doc = doc

    def as_shortopt(self):
        if not self.shortopt:
            return ''
        else:
            if self.opt_valdesc:
                return "%s:" % self.shortopt
            else:
                return self.shortopt

    def as_longopt(self):
        if self.opt_valdesc:
            return "%s=" % self.longopt
        else:
            return self.longopt

    def __str__(self):
        if self.shortopt and self.longopt:
            opts = "-%s, --%s" % (self.shortopt, self.longopt)
        elif self.shortopt:
            opts = "-%s" % self.shortopt
        elif self.longopt:
            opts = "--%s" % self.longopt

        if self.opt_valdesc:
            if self.longopt:
                val = "=%s" % self.opt_valdesc
            else:
                val = " %s" % self.opt_valdesc
        else:
            val = ''

        doc = self.doc or ''
        kvpair = "%s%s" % (opts, val)
        if len(kvpair) < self.tabstop:
            kvpair = kvpair + ''.join(
                ' ' for x in range(self.tabstop - len(kvpair))
            )
        return "%s%s%s" % (kvpair, ' ', doc)

class OptionList(object):
    @staticmethod
    def from_options(opts):
        olist = OptionList()
        for o in opts:
            olist.add(o)
     #  Add help option
        olist.add(Option('?', 'help', None, None, "Print help and exit"))
        return olist

    def __init__(self):
        self._options = {}
        self.short2long = {}

    def add(self, opt):
        self._options[opt.longopt] = opt
        if opt.shortopt:
            self.short2long[opt.shortopt] = opt.longopt

    def options(self):
        return self._options.values()


    def convert_option_name(self, rawname):
        if rawname.startswith('--'):
            if rawname.endswith('='):
                return rawname[2:-1]
            else:
                return rawname[2:]
        else:
            try:
                return self.short2long[rawname[1]]
            except KeyError:
                raise OptionError("Unknown option '%s'" % rawname)


    def convert_value(self, name, v):
        try:
            opt = self._options[name]
        except:
            raise OptionError("Unknown option '%s'" % name)

        if v:
            if opt.type:
                return opt.type(v)
            else:
                return v
        else:
            return True
        

    def parse(self, args):
        "Parse a sys.argv-like command line."
        shortopts = []
        longopts  = []
        for opt in self.options():
            shortopts.append(opt.as_shortopt())
            longopts.append(opt.as_longopt())
        shortopts = ''.join(shortopts)
        (parsed, unparsed) = getopt.getopt(args, shortopts, longopts)
        params = {}
        for k,v in parsed:
            if k.startswith('--'):
                if k.endswith('='):
                    name = k[2:-1]
                else:
                    name = k[2:]
            else:
                try:
                    name = self.short2long[k[1]]
                except KeyError:
                    raise OptionError("Unknown option '%s'" % k)
            try:
                opt = self._options[name]
            except:
                raise OptionError("Unknown option '%s'" % name)

            if v:
                if opt.type:
                    params[name] = opt.type(v)
                else:
                    params[name] = v 
            else:
                params[name] = True

        return params


    def parse_cp(self, cp, section):
        params = {}
        for name in cp.options(section):
            val = cp.get(section, name)
            param[name] = self.convert_value(name, val)
        return params
            

    def help_str(self):
        return "Options:\n%s" % ''.join(
            "%s\n" % opt for opt in sorted(self.options()))

