#
#   Cython - Command Line Parsing
#

from __future__ import absolute_import

import os
import sys
from . import Options

usage = """\
Cython (http://cython.org) is a compiler for code written in the
Cython language.  Cython is based on Pyrex by Greg Ewing.

Usage: cython [options] sourcefile.{pyx,py} ...

Options:
  -V, --version                  Display version number of cython compiler
  -l, --create-listing           Write error messages to a listing file
  -I, --include-dir <directory>  Search for include files in named directory
                                 (multiple include directories are allowed).
  -o, --output-file <filename>   Specify name of generated C file
  -t, --timestamps               Only compile newer source files
  -f, --force                    Compile all source files (overrides implied -t)
  -v, --verbose                  Be verbose, print file names on multiple compilation
  -p, --embed-positions          If specified, the positions in Cython files of each
                                 function definition is embedded in its docstring.
  --cleanup <level>              Release interned objects on python exit, for memory debugging.
                                 Level indicates aggressiveness, default 0 releases nothing.
  -w, --working <directory>      Sets the working directory for Cython (the directory modules
                                 are searched from)
  --gdb                          Output debug information for cygdb
  --gdb-outdir <directory>       Specify gdb debug information output directory. Implies --gdb.

  -D, --no-docstrings            Strip docstrings from the compiled module.
  -a, --annotate                 Produce a colorized HTML version of the source.
  --annotate-coverage <cov.xml>  Annotate and include coverage information from cov.xml.
  --line-directives              Produce #line directives pointing to the .pyx source
  --cplus                        Output a C++ rather than C file.
  --embed[=<method_name>]        Generate a main() function that embeds the Python interpreter.
  -2                             Compile based on Python-2 syntax and code semantics.
  -3                             Compile based on Python-3 syntax and code semantics.
  --3str                         Compile based on Python-3 syntax and code semantics without
                                 assuming unicode by default for string literals under Python 2.
  --lenient                      Change some compile time errors to runtime errors to
                                 improve Python compatibility
  --capi-reexport-cincludes      Add cincluded headers to any auto-generated header files.
  --fast-fail                    Abort the compilation on the first error
  --warning-errors, -Werror      Make all warnings into errors
  --warning-extra, -Wextra       Enable extra warnings
  -X, --directive <name>=<value>[,<name=value,...] Overrides a compiler directive
  -E, --compile-time-env name=value[,<name=value,...] Provides compile time env like DEF would do.
  --module-name                  Fully qualified module name. If not given, it is deduced from the
                                 import path if source file is in a package, or equals the
                                 filename otherwise.
  -M, --depfile                  Produce depfiles for the sources
"""


# The following experimental options are supported only on MacOSX:
#  -C, --compile    Compile generated .c file to .o file
#  --link           Link .o file to produce extension module (implies -C)
#  -+, --cplus      Use C++ compiler for compiling and linking
#  Additional .o files to link may be supplied when using -X."""

def bad_usage():
    sys.stderr.write(usage)
    sys.exit(1)

def parse_command_line(args):
    from .Main import CompilationOptions, default_options

    pending_arg = []

    def pop_arg():
        if not args or pending_arg:
            bad_usage()
        if '=' in args[0] and args[0].startswith('--'):  # allow "--long-option=xyz"
            name, value = args.pop(0).split('=', 1)
            pending_arg.append(value)
            return name
        return args.pop(0)

    def pop_value(default=None):
        if pending_arg:
            return pending_arg.pop()
        elif default is not None:
            return default
        elif not args:
            bad_usage()
        return args.pop(0)

    def get_param(option):
        tail = option[2:]
        if tail:
            return tail
        else:
            return pop_arg()

    options = CompilationOptions(default_options)
    sources = []
    while args:
        if args[0].startswith("-"):
            option = pop_arg()
            if option in ("-V", "--version"):
                options.show_version = 1
            elif option in ("-l", "--create-listing"):
                options.use_listing_file = 1
            elif option in ("-+", "--cplus"):
                options.cplus = 1
            elif option == "--embed":
                Options.embed = pop_value("main")
            elif option.startswith("-I"):
                options.include_path.append(get_param(option))
            elif option == "--include-dir":
                options.include_path.append(pop_value())
            elif option in ("-w", "--working"):
                options.working_path = pop_value()
            elif option in ("-o", "--output-file"):
                options.output_file = pop_value()
            elif option in ("-t", "--timestamps"):
                options.timestamps = 1
            elif option in ("-f", "--force"):
                options.timestamps = 0
            elif option in ("-v", "--verbose"):
                options.verbose += 1
            elif option in ("-p", "--embed-positions"):
                Options.embed_pos_in_docstring = 1
            elif option in ("-z", "--pre-import"):
                Options.pre_import = pop_value()
            elif option == "--cleanup":
                Options.generate_cleanup_code = int(pop_value())
            elif option in ("-D", "--no-docstrings"):
                Options.docstrings = False
            elif option in ("-a", "--annotate"):
                Options.annotate = True
            elif option == "--annotate-coverage":
                Options.annotate = True
                Options.annotate_coverage_xml = pop_value()
            elif option == "--convert-range":
                Options.convert_range = True
            elif option == "--line-directives":
                options.emit_linenums = True
            elif option == "--no-c-in-traceback":
                options.c_line_in_traceback = False
            elif option == "--gdb":
                options.gdb_debug = True
                options.output_dir = os.curdir
            elif option == "--gdb-outdir":
                options.gdb_debug = True
                options.output_dir = pop_value()
            elif option == "--lenient":
                Options.error_on_unknown_names = False
                Options.error_on_uninitialized = False
            elif option == '-2':
                options.language_level = 2
            elif option == '-3':
                options.language_level = 3
            elif option == '--3str':
                options.language_level = '3str'
            elif option == "--capi-reexport-cincludes":
                options.capi_reexport_cincludes = True
            elif option == "--fast-fail":
                Options.fast_fail = True
            elif option == "--cimport-from-pyx":
                Options.cimport_from_pyx = True
            elif option in ('-Werror', '--warning-errors'):
                Options.warning_errors = True
            elif option in ('-Wextra', '--warning-extra'):
                options.compiler_directives.update(Options.extra_warnings)
            elif option == "--old-style-globals":
                Options.old_style_globals = True
            elif option == "--directive" or option.startswith('-X'):
                if option.startswith('-X') and option[2:].strip():
                    x_args = option[2:]
                else:
                    x_args = pop_value()
                try:
                    options.compiler_directives = Options.parse_directive_list(
                        x_args, relaxed_bool=True,
                        current_settings=options.compiler_directives)
                except ValueError as e:
                    sys.stderr.write("Error in compiler directive: %s\n" % e.args[0])
                    sys.exit(1)
            elif option == "--compile-time-env" or option.startswith('-E'):
                if option.startswith('-E') and option[2:].strip():
                    x_args = option[2:]
                else:
                    x_args = pop_value()
                try:
                    options.compile_time_env = Options.parse_compile_time_env(
                        x_args, current_settings=options.compile_time_env)
                except ValueError as e:
                    sys.stderr.write("Error in compile-time-env: %s\n" % e.args[0])
                    sys.exit(1)
            elif option == "--module-name":
                options.module_name = pop_value()
            elif option in ('-M', '--depfile'):
                options.depfile = True
            elif option.startswith('--debug'):
                option = option[2:].replace('-', '_')
                from . import DebugFlags
                if option in dir(DebugFlags):
                    setattr(DebugFlags, option, True)
                else:
                    sys.stderr.write("Unknown debug flag: %s\n" % option)
                    bad_usage()
            elif option in ('-h', '--help'):
                sys.stdout.write(usage)
                sys.exit(0)
            else:
                sys.stderr.write(usage)
                sys.stderr.write("Unknown compiler flag: %s\n" % option)
                sys.exit(1)
        else:
            sources.append(pop_arg())

    if pending_arg:
        bad_usage()

    if options.use_listing_file and len(sources) > 1:
        sys.stderr.write(
            "cython: Only one source file allowed when using -o\n")
        sys.exit(1)
    if len(sources) == 0 and not options.show_version:
        bad_usage()
    if Options.embed and len(sources) > 1:
        sys.stderr.write(
            "cython: Only one source file allowed when using --embed\n")
        sys.exit(1)
    if options.module_name:
        if options.timestamps:
            sys.stderr.write(
                "cython: Cannot use --module-name with --timestamps\n")
            sys.exit(1)
        if len(sources) > 1:
            sys.stderr.write(
                "cython: Only one source file allowed when using --module-name\n")
            sys.exit(1)
    return options, sources
