#!/usr/bin/env python

from __future__ import print_function

import argparse
import logging
import os
import sys
import yaml

from rosinstall_generator.generator import ARG_ALL_PACKAGES, ARG_CURRENT_ENVIRONMENT, generate_rosinstall, sort_rosinstall


def main(argv=sys.argv[1:]):
    distro_name = os.environ['ROS_DISTRO'] if 'ROS_DISTRO' in os.environ else None
    parser = argparse.ArgumentParser(
        description='Generate a .rosinstall file for a set of packages.')
    parser.add_argument('--debug', action='store_true', default=False,
        help='Print debug information about fetching the ROS distribution files to stderr')
    parser.add_argument('--verbose', action='store_true', default=False,
        help='Print verbose information to stderr')
    parser.add_argument('--rosdistro', required=distro_name is None, default=distro_name,
        help='The ROS distro (default: environment variable ROS_DISTRO if defined)')
    parser.add_argument('package_names', nargs='+', metavar='pkgname',
        help="Wet package names, dry stack names or variant names. Use '%s' to specify all packages available in the current environment. Use '%s' to specify all release packages (only usable as a single argument)." % (ARG_CURRENT_ENVIRONMENT, ARG_ALL_PACKAGES))

    group = parser.add_mutually_exclusive_group()
    group.add_argument('--deps', action='store_true', default=False,
        help='Include recursive dependencies')
    group.add_argument('--deps-up-to', nargs='*',
        help="A set of packages which will limit the recursive dependencies to packages which (in-)directly depend on a package in this set. Use '%s' to specify all packages available in the current environment." % ARG_CURRENT_ENVIRONMENT)

    # implies either --deps or --deps-up-to
    parser.add_argument('--deps-depth', type=int, metavar='N',
        help='Limit recursive dependencies to a specific level (not supported on Groovy).')
    parser.add_argument('--deps-only', action='store_true', default=False,
        help='Include only the recursive dependencies but not the specified packages')

    group = parser.add_mutually_exclusive_group()
    group.add_argument('--wet-only', action='store_true', default=False,
        help='Only include wet packages')
    group.add_argument('--dry-only', action='store_true', default=False,
        help='Only include dry stacks')
    group.add_argument('--catkin-only', action='store_true', default=False,
        help="Only wet packages with build type 'catkin'")
    group.add_argument('--non-catkin-only', action='store_true', default=False,
        help="Only wet packages with build type other than 'catkin'")

    parser.add_argument('--exclude', nargs='*',
        help="Exclude a set of packages (also skips further recursive dependencies). Use '%s' to specify all packages available in the current environment." % ARG_CURRENT_ENVIRONMENT)

    parser.add_argument('--tar', action='store_true', default=False,
        help='Use tarballs instead of repositories for wet packages (dry packages are always tarballs)')

    args = parser.parse_args(argv)

    # check for invalid combinations
    if args.rosdistro == 'groovy' and args.deps_depth:
        parser.error("Option '--deps-depth N' is not available for the ROS distro 'groovy'")
    if args.rosdistro != 'groovy':
        if args.dry_only:
            parser.error("For the ROS distro '%s' there are no dry released packages so '--dry-only' is not a valid option" % args.rosdistro)
        args.wet_only = True

    if ARG_ALL_PACKAGES in args.package_names and len(args.package_names) > 1:
        parser.error("When using '%s' as a package name no other names can be specified" % ARG_ALL_PACKAGES)

    if not args.deps and not args.deps_up_to:
        if args.deps_depth:
            parser.error("Option '--deps-depth N' can only be used together with either '--deps' or '--deps-up-to'")
        if args.deps_only:
            parser.error("Option '--deps-only' can only be used together with either '--deps' or '--deps-up-to'")

    if args.deps_depth is not None and args.deps_depth < 1:
        parser.error("The argument 'N' to the option '--deps-depth ' must be a positive integer")

    if args.catkin_only or args.non_catkin_only:
        args.wet_only = True

    # pass all logging output to stderr
    logger = logging.getLogger('rosinstall_generator')
    logger.addHandler(logging.StreamHandler(sys.stderr))

    verbose_level = logging.DEBUG if args.verbose else logging.INFO
    logger.setLevel(verbose_level)

    debug_level = logging.DEBUG if args.debug else logging.INFO
    logger = logging.getLogger('rosinstall_generator.dry')
    logger.setLevel(debug_level)
    logger = logging.getLogger('rosinstall_generator.wet')
    logger.setLevel(debug_level)

    if '--rosdistro' not in argv:
        print('Using ROS_DISTRO: %s' % args.rosdistro, file=sys.stderr)

    try:
        rosinstall_data = generate_rosinstall(args.rosdistro, args.package_names,
            deps=args.deps, deps_up_to=args.deps_up_to, deps_depth=args.deps_depth, deps_only=args.deps_only,
            wet_only=args.wet_only, dry_only=args.dry_only, catkin_only=args.catkin_only, non_catkin_only=args.non_catkin_only,
            excludes=args.exclude,
            tar=args.tar)
    except RuntimeError as e:
        if args.debug:
            raise
        print(str(e), file=sys.stderr)
        return 1
    rosinstall_data = sort_rosinstall(rosinstall_data)
    print(yaml.safe_dump(rosinstall_data, default_flow_style=False))
    return 0


if __name__ == '__main__':
    rc = main()
    sys.exit(rc)
