#!/usr/bin/env python3
# -*- coding: utf-8 -*- vim60:fdm=marker
#
# Copyright: 2016, Maximiliano Curia <maxy@debian.org>
#
# License: ISC
#  Permission to use, copy, modify, and/or distribute this software for any
#  purpose with or without fee is hereby granted, provided that the above
#  copyright notice and this permission notice appear in all copies.
#  .
#  THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
#  REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
#  AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
#  INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
#  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
#  OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
#  PERFORMANCE OF THIS SOFTWARE.

''' Command line option handling. '''

import argparse
import logging
import os

try:
    import regex as re
except ImportError:
    import re


class Defaults(object):

    exclude_file_regex = r'''
    # Ignore general backup files
    ~$|
    # Ignore emacs recovery files
    \.\#.*$|
    # Ignore vi swap files
    \..*\.swp$|
    # Ignore baz-style junk files or directories
    ^,,|
    # File-names that should be ignored (never directories)
    ^(?:DEADJOE|\.cvsignore|\.arch-inventory|\.bzrignore|\.gitignore)$|
    # File or directory names that should be ignored
    ^(?:CVS|RCS|\.deps|\{arch\}|\.arch-ids|\.svn|\.hg|_darcs|\.git|
    \.shelf|_MTN|\.bzr(?:\.backup|tags)?)$
    '''

    exclude_directory_regex = r'''
    # Ignore baz-style junk files or directories
    ^,,|
    # File or directory names that should be ignored
    ^(?:CVS|RCS|\.deps|\{arch\}|\.arch-ids|\.svn|\.hg|_darcs|\.git|
    \.pc|\.shelf|_MTN|\.bzr(?:\.backup|tags)?)$|
    # Python compiled files
    ^__pycache__$
    '''

    # Exclude debian/copyright and debian/changelog by default
    exclude_special_regex = r'''
    ^debian/(copyright|changelog)$
    '''

    # Empty exclude regexp, to be overridden by users
    exclude_fullname_regex = r'''
    ^$
    '''

    # Top directory for processing files
    root = '.'

    # Files/dirs to parse
    files = []

    # Mode to work on:
    # partial: only process the files/dirs specified and generate the output
    #          for this subset
    # full: (default) parse the files/dirs specified, and generate the
    #       copyright information for the whole source tree
    mode = 'full'

    # copyright 1.0 file, relative to the package dir
    copyright_file = 'debian/copyright'

    # group by license or by copyright
    group_by = 'license'

    # Split groups on sub dirs containing licenses
    split_on_license = True

    # Split the debian/* file paragraph
    split_debian = True

    # Treat all files as text
    text = False

    # Try to use glob patterns in the File: output
    glob = True

    # Progress bar
    progress = True

    # Number of parallel jobs (0 for auto)
    jobs = 0

    # output filename, empty for stdout
    output = ''


def _add_boolean_argument(parser, name, default, dest=None):
    '''Helper to add options --name --no-name and set the default'''
    if dest is None:
        dest = name.replace('-', '_')
    parser.add_argument('--{}'.format(name), action='store_true',
                        dest=dest)
    parser.add_argument('--no-{}'.format(name),
                        action='store_false', dest=dest)
    parser.set_defaults(**{dest: default})


def process_options(args=None):

    def _filename(arg):
        if not os.path.exists(arg):
            raise argparse.ArgumentTypeError("{} does not exist".format(arg))
        return arg

    kwargs = {
        'format': '[%(levelname)s] %(message)s',
    }

    parser = argparse.ArgumentParser(
        description='License checker and copyright dep5 helper',
        fromfile_prefix_chars='@'
    )
    parser.add_argument('-X', '--exclude', default=Defaults.exclude_fullname_regex)

    parser.add_argument('--mode', choices=['full', 'partial'],
                        default=Defaults.mode)

    parser.add_argument('--copyright-file',
                        default=Defaults.copyright_file)

    parser.add_argument('--debug', action='store_true')
    parser.add_argument('-v', '--verbose', action='store_true')
    parser.add_argument('-q', '--quiet', action='store_true')

    parser.add_argument('-a', '--text', action='store_true')

    parser.add_argument('--group-by', choices=['license', 'copyright'],
                        default=Defaults.group_by)
    _add_boolean_argument(parser, 'split-on-license',
                          Defaults.split_on_license)
    _add_boolean_argument(parser, 'split-debian',
                          Defaults.split_debian)

    _add_boolean_argument(parser, 'glob',
                          Defaults.glob)

    _add_boolean_argument(parser, 'progress',
                          Defaults.progress)
    parser.add_argument('--jobs', '-j', type=int, default=Defaults.jobs,
                        help='Number of jobs to run in parallel (0 for auto)')

    parser.add_argument('-o', '--output', default=Defaults.output)

    parser.add_argument('--root', default=Defaults.root,
                        type=_filename)

    parser.add_argument('files', nargs='*', default=Defaults.files,
                        type=_filename)

    options = parser.parse_args(args)

    if options.debug:
        kwargs['level'] = logging.DEBUG
    elif options.verbose:
        kwargs['level'] = logging.INFO
    elif options.quiet:
        kwargs['level'] = logging.ERROR
    else:
        kwargs['level'] = logging.WARN

    logging.basicConfig(**kwargs)

    options.exclude_fullname_re = re.compile(options.exclude, re.IGNORECASE | re.VERBOSE)
    options.exclude_special_re = re.compile(Defaults.exclude_special_regex,
                                            re.IGNORECASE | re.VERBOSE)
    options.exclude_file_re = re.compile(Defaults.exclude_file_regex, re.VERBOSE)
    options.exclude_directory_re = re.compile(Defaults.exclude_directory_regex, re.VERBOSE)

    # - can also be used to specify the stdout
    if options.output == '-':
        options.output = ''

    # Force an absolute path for options.root, and sanitize the user option
    # (see #855778, for problem caused by a trailing /)
    options.root = os.path.abspath(options.root)
    # Transform positional arguments into paths that are relative to the root
    # path
    options.files = [os.path.relpath(i, options.root) for i in options.files]

    return options
