# -*- coding: utf-8 -*-

import sys

from behave import __version__
from behave.configuration import Configuration, ConfigError
from behave.formatter.ansi_escapes import escapes
from behave.i18n import languages
from behave.formatter import formatters
from behave.runner import Runner
from behave.parser import ParserError

TAG_HELP = """
Scenarios inherit tags declared on the Feature level. The simplest
TAG_EXPRESSION is simply a tag::

    --tags @dev

You may even leave off the "@" - behave doesn't mind.

When a tag in a tag expression starts with a ~, this represents boolean NOT::

    --tags ~@dev

A tag expression can have several tags separated by a comma, which represents
logical OR::

    --tags @dev,@wip

The --tags option can be specified several times, and this represents logical
AND, for instance this represents the boolean expression
"(@foo or not @bar) and @zap"::

    --tags @foo,~@bar --tags @zap.

Beware that if you want to use several negative tags to exclude several tags
you have to use logical AND::

    --tags ~@fixme --tags ~@buggy.
""".strip()

# TODO: Enable positive Tags w/ threshold
# Positive tags can be given a threshold to limit the number of occurrences.
# Which can be practical if you are practicing Kanban or CONWIP. This will fail
# if there are more than 3 occurrences of the @qa tag:
#
# --tags @qa:3
# """.strip()


def main():
    # pylint: disable=R0912,R0915
    #   R0912   Too many branches (17/12)
    #   R0915   Too many statements (57/50)
    config = Configuration()

    if config.version:
        print "behave " + __version__
        sys.exit(0)

    if config.tags_help:
        print TAG_HELP
        sys.exit(0)

    if config.lang_list:
        iso_codes = languages.keys()
        iso_codes.sort()
        print "Languages available:"
        for iso_code in iso_codes:
            native = languages[iso_code]['native'][0]
            name = languages[iso_code]['name'][0]
            print u'%s: %s / %s' % (iso_code, native, name)
        sys.exit(0)

    if config.lang_help:
        if config.lang_help not in languages:
            sys.exit('%s is not a recognised language: try --lang-list' %
                     config.lang_help)
        trans = languages[config.lang_help]
        print u"Translations for %s / %s" % (trans['name'][0],
              trans['native'][0])
        for kw in trans:
            if kw in 'name native'.split():
                continue
            print u'%16s: %s' % (kw.title().replace('_', ' '),
                  u', '.join(w for w in trans[kw] if w != '*'))
        sys.exit(0)

    if not config.format:
        config.format = ['pretty']
    elif 'help' in config.format:
        print "Available formatters:"
        formatters.list_formatters(sys.stdout)
        sys.exit(0)
    # -- SANITY: Use at most one formatter, more cause various problems.
    # PROBLEM DESCRIPTION:
    #   1. APPEND MODE: configfile.format + --format
    #   2. Daisy chaining of formatters does not work
    #     => behave.formatter.formatters.get_formatter()
    #     => Stream methods, stream.write(), stream.flush are missing
    #        in Formatter interface
    config.format = config.format[-1:]

    stream = config.output
    runner = Runner(config)
    try:
        failed = runner.run()
    except ParserError, e:
        sys.stderr.write("PARSE-ERROR: {0}".format(e))
        sys.exit(2)
    except ConfigError, e:
        sys.stderr.write("CONFIG-ERROR: {0}".format(e))
        sys.exit(3)

    if config.show_snippets and runner.undefined:
        msg = u"\nYou can implement step definitions for undefined steps with "
        msg += u"these snippets:\n\n"
        printed = set()

        if sys.version_info[0] == 3:
            string_prefix = "('"
        else:
            string_prefix = u"(u'"

        for step in set(runner.undefined):
            if step in printed:
                continue
            printed.add(step)

            msg += u"@" + step.step_type + string_prefix + step.name + u"')\n"
            msg += u"def impl(context):\n"
            msg += u"    assert False\n\n"

        # XXX-JE-OOPS: Unclear is stream supports ANSI coloring.
        sys.stderr.write(escapes['undefined'] + msg + escapes['reset'])
        sys.stderr.flush()

    if failed:
        sys.exit(1)

if __name__ == '__main__':
    main()

@@ -4306,16 +4306,68 @@
 .exit(1)
+%0A    # -- OTHERWISE: Successful run.%0A    sys.exit(0)
 %0A%0Aif __n

FIX issue #83: Use sys.exit(0) in main() for succesful test run.