import sys
import os
import subprocess

from numpy.distutils.misc_util \
    import \
        get_numpy_include_dirs, get_pkg_info
from numpy.distutils.conv_template \
    import \
        process_str as process_c_str
from numpy.distutils.from_template \
    import \
        process_str as process_f_str, resolve_includes

from bento.backends.waf_backend \
    import \
        WAF_TOOLDIR
from bento.backends.waf_tools \
    import \
        blas_lapack
from bento.commands import hooks

import waflib
from waflib import Options

# Importing setup.py needed to get version info
import setup


# FIXME: add this to numpy so that we can reuse it
class CTemplateTask(waflib.Task.Task):
    color = 'BLUE'
    #ext_out = ['.c', '.pyf']
    def run(self):
        s = self.inputs[0]
        cnt = s.read()
        writestr = process_c_str(cnt)
        o = self.outputs[0]
        o.write(writestr)

class FTemplateTask(waflib.Task.Task):
    color = 'BLUE'
    ext_out = ['.pyf']
    def run(self):
        s = self.inputs[0]
        lines = resolve_includes(s.abspath())
        writestr = process_f_str("".join(lines))
        o = self.outputs[0]
        o.write(writestr)
        return 0

@waflib.TaskGen.extension(".src")
def c_template(self, node):
    output_name = node.name.rsplit(".", 1)[0]
    output = node.parent.find_or_declare(output_name)
    assert output.is_bld()

    ext = output.name.rsplit(".")[1]
    if ext in ["f", "pyf", "ipyf"]:
        tsk = self.create_task('FTemplateTask', node, output)
        if "fc" in self.features:
            self.source.append(output)
        else:
            raise ValueError("FTemplateTask without feature 'fc' (node: %r)?" %
                    (node,))
    elif ext in ["c"]:
        tsk = self.create_task('CTemplateTask', node, output)
        if "c" in self.features:
            self.source.append(output)
        else:
            raise ValueError("CTemplateTask without feature 'c': %r" % node)
    else:
        raise ValueError("Unknown extension in templating: %r" % ext)

# FIXME: abstract those module gen tasks...
class write_module(waflib.Task.Task):
    color = "CYAN"
    vars = ["CONTENT"]
    def run(self):
        # FIXME: put actual data here
        self.outputs[0].write(self.env.CONTENT)

@waflib.TaskGen.feature("gen_pymodule")
def process_write_config(self):
    if not hasattr(self, "content"):
        raise ValueError("task gen %r expects a 'content' argument" % self.name)
    else:
        self.env.CONTENT = self.content
    output = self.path.find_or_declare(self.target)
    name = getattr(self, "name", None) or self.target

    bento_context = self.bld.bento_context
    b_output = bento_context.build_node.make_node(output.bldpath())
    bento_context.outputs_registry.register_outputs(
        "gen_pymodule", name, [b_output], bento_context.build_node, "$sitedir")

    tsk = self.create_task("write_module")
    tsk.set_outputs(output)
    return tsk

def _set_mangling_var(conf, u, du, case, f2pycompat=True):
    env = conf.env
    macros = []

    if du == '_':
        env['F77_UNDERSCORE_G77'] = 1
        macros.append('F77_UNDERSCORE_G77')
        if f2pycompat:
            macros.append('UNDERSCORE_G77')
    else:
        env['F77_UNDERSCORE_G77'] = 0

    if u == '_':
        env['F77_NO_APPEND_FORTRAN'] = 0
    else:
        env['F77_NO_APPEND_FORTRAN'] = 1
        macros.append('F77_NO_APPEND_FORTRAN')
        if f2pycompat:
            macros.append('NO_APPEND_FORTRAN')

    if case == 'upper':
        env['F77_UPPERCASE_FORTRAN'] = 1
        macros.append('F77_UPPERCASE_FORTRAN')
        if f2pycompat:
            macros.append('UPPERCASE_FORTRAN')
    else:
        env['F77_UPPERCASE_FORTRAN'] = 0

    env.DEFINES.extend(macros)

def _generate_cython():
    print("Cythonizing sources")
    cwd = os.path.abspath(os.path.dirname(__file__))
    p = subprocess.call([sys.executable,
                          os.path.join(cwd, 'tools', 'cythonize.py'),
                          'scipy'],
                         cwd=cwd)
    if p != 0:
        raise RuntimeError("Running cythonize failed!")

@hooks.post_configure
def post_configure(context):
    opts = context.waf_options_context
    conf = context.waf_context

    opts.load("compiler_cxx")
    opts.load("compiler_fc")
    opts.load("f2py", tooldir=[WAF_TOOLDIR])
    Options.options.check_fc = "gfortran"
    Options.options.check_cxx_compiler = "g++"
    if sys.platform == "win32" and conf.env.CC_NAME == "msvc":
        Options.options.check_fc = "ifort"
        Options.options.check_cxx_compiler = "msvc"

    conf.load("compiler_cxx")
    conf.load("compiler_fc")
    conf.load("f2py", tooldir=[WAF_TOOLDIR])
    conf.load("ordered_c", tooldir=[WAF_TOOLDIR])
    conf.load("arch", tooldir=[WAF_TOOLDIR])

    if conf.env.CC_NAME == 'gcc':
        conf.env.append_value('CFLAGS_PYEXT', "-Wfatal-errors")
        conf.env.append_value('CXXFLAGS_PYEXT', "-Wfatal-errors")

    if sys.platform == "darwin":
        conf.env["MACOSX_DEPLOYMENT_TARGET"] = "10.4"

        conf.check_cc_default_arch()
        archs = [conf.env.DEFAULT_CC_ARCH]
        conf.env.ARCH = archs

    conf.check_fortran_verbose_flag()
    conf.check_fortran_clib()
    conf.check_fortran_dummy_main()
    u, du, c = conf.check_fortran_mangling()
    _set_mangling_var(conf, u, du, c)

    conf.env.INCLUDES = get_numpy_include_dirs()

    blas_lapack.check_blas_lapack(context)
    if not (conf.env.HAS_BLAS and conf.env.HAS_LAPACK):
        raise waflib.Errors.ConfigurationError("You need blas and lapack")

    blas_lapack.check_blas_lapack(context)

    npymath_info = get_pkg_info("npymath")
    conf.parse_flags(npymath_info.cflags() + " " + npymath_info.libs(), "NPYMATH")

    _generate_cython()


FULLVERSION, GIT_REVISION = setup.get_version_info()

version_file_content = """\
# THIS FILE IS GENERATED FROM SCIPY BSCRIPT
short_version = '%(version)s'
version = '%(version)s'
full_version = '%(full_version)s'
git_revision = '%(git_revision)s'
release = %(isrelease)s

if not release:
    version = full_version
""" % {'version': setup.VERSION,
       'full_version' : FULLVERSION,
       'git_revision' : GIT_REVISION,
       'isrelease': str(setup.ISRELEASED)}

@hooks.pre_build
def pre_build(context):
    bld = context.waf_context

    context.register_category("gen_pymodule")
    bld(features="gen_pymodule",
        target="scipy/__config__.py",
        content="""\
def show():
    pass
""",
        always=True)

    bld(features="gen_pymodule",
        target="scipy/version.py",
        content=version_file_content,
        always=True)

@hooks.options
def options(global_context):
    blas_lapack.add_options(global_context)
