import os
import sys
import subprocess

from bento.commands.hooks \
    import \
        pre_configure, command
from bento.core.package \
    import \
        file_list
from bento.commands.errors \
    import \
        CommandExecutionFailure
from bento.commands.core \
    import \
        Command, Option
from bento.core.utils \
    import \
        pprint, test_program_run

import yaku.context
import yaku.scheduler

@pre_configure()
def pconfigure(ctx):
    try:
        ctx.yaku_configure_ctx.load_tool("python_2to3")
    except ImportError:
        pass

PY3K_BUILD = os.path.join("build", "py3k")

@command()
def _run_2to3(ctx):
    bld = yaku.context.get_bld()
    if not "python_2to3" in bld.builders:
        raise ValueError("2to3 is not available")
    builder = bld.builders["python_2to3"]

    builder.env["2TO3_EXCLUDE_LIST"] = [
        os.path.join("bento", "private", "_ply", "ply", f) for f in \
        os.listdir(os.path.join("bento", "private", "_ply", "ply"))
        if f.endswith(".py")]

    files = file_list(ctx.pkg, bld.src_root)
    builder.convert("bento_2to3", files)

    try:
        yaku.scheduler.run_tasks(bld)
    finally:
        bld.store()

@command()
def run_2to3(ctx):
    """\
Purpose: run 2to3 on bento.
Usage: bentomaker run_2to3 [OPTIONS]"""
    msg = """\
===============================================================================
python 3 version of bento is now available in build/py3k. You can install bento
for python 3 as follows:

    cd %s
    python3 -m bentomakerlib.bentomaker configure # add custom options here
    python3 -m bentomakerlib.bentomaker install
===============================================================================\
""" % PY3K_BUILD
    pprint('BLUE', msg)

class TestPy3kCommand(Command):
    long_descr = """\
Purpose: test py3k output generated by 2to3
Usage:   bentomaker test_py3k [OPTIONS]."""
    short_descr = "check whether generated py3k code works."
    common_options = Command.common_options \
                        + [Option("-p", "--python-interpreter",
                                  help="python interpreter to use", dest="python_interpreter")]
    def run(self, ctx):
        argv = ctx.get_command_arguments()
        p = ctx.options_context.parser
        o, a = p.parse_args(argv)
        if o.help:
            p.print_help()
            return
        if o.python_interpreter:
            python_interpreter = o.python_interpreter
        else:
            python_interpreter = "python3"

        pprint("BLUE", "running distcheck on python 3 code...")
        p = subprocess.Popen([python_interpreter, "-m", "bentomakerlib.bentomaker", "distcheck"],
                             stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=PY3K_BUILD)
        stdout, stderr = p.communicate()
        print(stdout.decode())
        if p.returncode != 0:
            pprint('RED', "error while distchecking python 3 code: exception was")
            pprint('RED', "=" * 79)
            pprint('RED', stderr.decode())
            pprint('RED', "=" * 79)
            return p.returncode

class TestCommand(Command):
    def run(self, opts):
        pprint('BLUE', "Running test command....")

        if sys.platform == "win32":
            suffix = ".exe"
        else:
            suffix = ""

        cmd = ["nosetests-%s%s" % (".".join([str(i) for i in sys.version_info[:2]]), suffix)]
        if not test_program_run(cmd + ["-h"]):
            raise CommandExecutionFailure(
                    "program %r not found - needed to test bento !" % cmd[0])
        cmd.extend(["-s", "-v", "bento"])
        p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        stdout, stderr = p.communicate()
        if p.returncode != 0:
            print(stderr.decode())
            return p.returncode
        else:
            for stream in [stdout, stderr]:
                print(stream.decode())

def startup(context):
    context.register_command("test", TestCommand)
    context.register_command("test_py3k", TestPy3kCommand)

    context.set_before("_run_2to3", "configure")
    context.set_before("run_2to3", "_run_2to3")
    context.set_before("test_py3k", "_run_2to3")
