#!/usr/bin/env python2
# coding=utf-8

"""
Entry-point script for gitver
"""

import sys
import argparse
from os.path import dirname, abspath, realpath, exists, join


def setup_env():
    """Provides access to the gitver modules"""
    prefix = dirname(dirname(realpath(abspath(__file__))))
    gitver_mod = join(prefix, 'gitver', '__init__.py')
    if exists(gitver_mod):
        # source tree
        sys.path.insert(1, prefix)

setup_env()


def main():
    from gitver.termcolors import term

    # check for the git command
    from gitver.git import git_version
    v = git_version()
    if not 'git version' in v:
        term.err("This program requires \"git\" to be installed and "
                 "configured.")
        sys.exit(1)

    # requires the git command
    from gitver.sanity import check_config_dir, check_gitignore, \
        check_project_root

    from gitver.commands import cmd_clean, cmd_cleanall, cmd_next

    cfg = None
    inject_default_action()
    parser = create_parser()
    args = parser.parse_args()

    # always permit simple, innocuous commands to be run
    innocuous = ['version', '--help']
    if len(sys.argv) == 2 and sys.argv[1] in innocuous:
        pass
    else:
        check_project_root()

        # apply quiet flags
        term.set_quiet_flags(args.quiet_stdout, args.quiet_stderr)

        # avoid check if 'init' command
        if not 'init' in sys.argv:
            check_config_dir()

            # apply colors configuration
            from gitver.config import load_user_config
            cfg = load_user_config()

            term.enable_colors(cfg['use_terminal_colors'])

            # apply colors from command line
            if args.use_colors == 'yes':
                term.enable_colors(True)
            elif args.use_colors == 'no':
                term.enable_colors(False)

            if cfg['safe_mode'] and not args.ignore_gitignore:
                if args.func in [cmd_next, cmd_clean, cmd_cleanall]:
                    if not check_gitignore():
                        term.warn("A potentially unsafe operation has been "
                                  "prevented to\ncontinue because your "
                                  ".gitignore file doesn't exclude gitver's\n"
                                  "configuration directory from the "
                                  "repository.\nIf you know what you are doing"
                                  ", use the \"--ignore-gitignore\"\nflag to "
                                  "ignore this warning or just disable "
                                  "\"safe_mode\" in\nyour configuration file.")
                        sys.exit(1)

    return args.func(cfg, args)


def inject_default_action():
    """
    Inspects the actual command line arguments and inject the default action
    'info' if none has been found.
    """
    is_short = len(sys.argv) < 2
    only_flags = True
    for arg in sys.argv[1:]:
        only_flags = only_flags and arg.startswith('--')
    if is_short or only_flags:
        sys.argv.append('info')


def create_parser():
    """
    Construct and returns the main command line argument parser.
    """
    parser = argparse.ArgumentParser()

    # ignore gitver-generated warnings (not recommended!)
    parser.add_argument('--ignore-gitignore',
                        help='Ignore the .gitignore warning and continue '
                             'running as normal (specify this flag before '
                             'any other command, at YOUR own risk)',
                        dest='ignore_gitignore',
                        default=False,
                        action='store_true')

    parser.add_argument('--colors',
                        help='Enable or disable colorized terminal output: '
                             '\'config\' (default) reads the setting from '
                             'your configuration file, \'yes\' will '
                             'force-enable it, \'no\' will force-disable it.',
                        dest='use_colors',
                        type=str,
                        choices=['config', 'yes', 'no'],
                        default='config')

    parser.add_argument('--quiet',
                        help='Disable any stdout message.',
                        dest='quiet_stdout',
                        default=False,
                        action='store_true')

    parser.add_argument('--quiet-errors',
                        help='Disable any stderr message.',
                        dest='quiet_stderr',
                        default=False,
                        action='store_true')

    sp = parser.add_subparsers(title='Valid commands')
    create_commands(sp)
    return parser


def create_commands(sp):
    """
    Create available commands to be selected from the command line.
    """
    from gitver.commands import cmd_build_template, cmd_clean, cmd_cleanall, \
        cmd_info, cmd_init, cmd_list_next, cmd_list_templates, cmd_next, \
        cmd_version, cmd_current, cmd_check_gitignore, cmd_preview_template

    add_command(sp, 'version', "Shows gitver version", cmd_version)
    add_command(sp, 'init', "Creates gitver's configuration directory and "
                            "creates the default configuration file, if it "
                            "doesn't exist.", cmd_init)
    add_command(sp, 'check', "Checks your .gitignore file for gitver's "
                             "configuration directory inclusion.",
                cmd_check_gitignore)

    add_command(sp, 'info', "Prints full version information and tag-based "
                            "metadata for this repository. [default]",
                cmd_info)
    add_command(sp, 'current', "Prints the current version information only, "
                               "without any formatting applied.", cmd_current)

    add_command(sp, 'list-templates', "Enumerates available templates.",
                cmd_list_templates)

    add_command(sp, 'list-next', "Enumerates user-defined next stable "
                                 "versions.", cmd_list_next)

    p = add_command(sp, 'update', "Performs simple keyword substitution on the "
                                  "specified template file(s) and place it to "
                                  "the path described by the first line in the "
                                  "template. This is usually performed "
                                  "*AFTER* a release has been tagged already.",
                    cmd_build_template)
    p.add_argument('templates', default='', type=str)

    p = add_command(sp, 'preview', "Same as \"update\", but the output is "
                                   "written to the stdout instead (same rules "
                                   "apply).",
                    cmd_preview_template)
    p.add_argument('templates', default='', type=str)

    p = add_command(sp, 'next', "Defines the next stable version for the "
                                "most recent and reachable tag.", cmd_next)
    p.add_argument('next_version_numbers', default='', type=str)

    p = add_command(sp, 'clean', "Removes the user-defined next stable version"
                                 " for the most recent and reachable tag or "
                                 "the specified tag.", cmd_clean)
    p.add_argument('tag', nargs='?', type=str, default='')

    add_command(sp, 'clean-all', "Removes ALL user-defined next stable "
                                 "versions.", cmd_cleanall)


def add_command(parent, name, desc, func):
    """
    Add a single command to the specified parser.
    """
    p = parent.add_parser(name, help=desc)
    p.set_defaults(func=func)
    return p


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