#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# michael a.g. aïvázis
# orthologue
# (c) 1998-2023 all rights reserved
#

# externals
import datetime, os, sys

# the location of project configuration files
pdir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".mm"))
# if it doesn't exist, make it
os.makedirs(pdir, exist_ok=True)

# attempt to
try:
    # access the framework
    import pyre
# if this fails
except ImportError:
    # the target version
    release = "v1.12.3"
    # the bootstrapping  package
    boot = "pyre-boot.zip"
    # the local file
    local = os.path.join(pdir, boot)
    # if it not already here
    if not os.path.exists(local):
        # support for URL access
        import urllib.request

        # form the url to the bootstrapper
        url = f"http://github.com/pyre/pyre/releases/download/{release}/{boot}"
        # show me
        print(f"downloading '{url}'")  # form the url to the bootstrapper
        # pull the bootstrapper from the web
        with urllib.request.urlopen(url=url) as ins:
            # open the local file
            with open(local, "wb") as outs:
                # pull the data and write it
                outs.write(ins.read())
    # grab the sys module
    import sys

    # so we can add the bootstrapper to it
    sys.path.insert(1, local)
    # try importing pyre again
    import pyre


# the app
class configure(pyre.application, family="pyre.applications.configure"):
    """
    The pyre configuration utility
    """

    # user configurable state
    # packages
    gsl = pyre.externals.gsl()
    gsl.doc = "the GSL installation"

    mpi = pyre.externals.mpi()
    mpi.doc = "the MPI installation"

    postgres = pyre.externals.postgres()
    postgres.doc = "the client side of postgres"

    python = pyre.externals.python()
    python.doc = "the python installation"

    # geography
    config = pyre.properties.path(default=os.path.join(pdir, "config.def"))
    config.doc = "the path to the configuration file"

    # behavior
    @pyre.export
    def main(self, *args, **kwds):
        """
        The main entry point
        """
        # render the configuration in {mm} format
        table = self.render()
        # save the configuration
        self.save(table=table)
        # all done
        return 0

    # implementation
    def render(self, table=None):
        """
        Create a table with the {mm} settings for the given choices of packages
        """
        # initialize
        table = table or {}

        # gsl
        gsl = self.gsl
        # update the table
        if gsl:
            table["GSL_DIR"] = gsl.prefix
            table["GSL_VERSION"] = gsl.sigver
            table["GSL_INCDIR"] = gsl.join(gsl.incdir)
            table["GSL_LIBDIR"] = gsl.join(gsl.libdir)

        # mpi
        mpi = self.mpi
        # update the table
        if mpi:
            table["MPI_DIR"] = mpi.prefix
            table["MPI_INCDIR"] = mpi.join(mpi.incdir)
            table["MPI_LIBDIR"] = mpi.join(mpi.libdir)
            table["MPI_EXECUTIVE"] = mpi.launcher
            table["MPI_VERSION"] = mpi.flavor

        # postgres
        postgres = self.postgres
        # update the table
        if postgres:
            table["LIBPQ_DIR"] = postgres.prefix
            table["LIBPQ_VERSION"] = postgres.sigver
            table["LIBPQ_INCDIR"] = postgres.join(postgres.incdir)
            table["LIBPQ_LIBDIR"] = postgres.join(postgres.libdir)

        # python
        python = self.python
        # update the table
        if python:
            table["PYTHON"] = python.interpreter
            table["PYTHON_DIR"] = python.prefix
            table["PYTHON_INCDIR"] = python.join(python.incdir)
            table["PYTHON_LIBDIR"] = python.join(python.libdir)
            table["PYTHON_PYCFLAGS"] = "-b"
            table["PYTHON_LIB"] = python.interpreter

        # all done
        return table

    def save(self, table):
        """
        Generate the file with the configuration options
        """
        # open the output stream
        stream = self.config.open("w")
        # assemble the document
        doc = "\n".join(self.assemble(table))
        # print
        print(doc, file=stream)
        # all done
        return table

    def assemble(self, table):
        """
        Generate the file with the configuration settings
        """
        # build a time stamp
        stamp = datetime.datetime.now().ctime()
        # render a preamble
        yield "# -*- Makefile -*-"
        yield "#"
        yield "# generated by configure on {}".format(stamp)
        yield "#"
        yield ""

        # go through all the variable names
        for key in sorted(table):
            # and print their values
            yield "{} = {}".format(key, table[key])

        # epilogue
        yield ""
        yield "# end of file"

        # all done
        return

    # pyre framework hooks
    # support for the help system
    def pyre_banner(self):
        """
        Place the application banner in the {info} channel
        """
        # show the license header
        return "configuration utility"

    # interactive session management
    def pyre_interactiveSessionContext(self, context):
        """
        Go interactive
        """
        # protect against bad contexts
        if context is None:
            # by initializing as an empty dict
            context = {}

        # set up some context
        context["config"] = self

        # and chain up
        return super().pyre_interactiveSessionContext(context=context)


# main
if __name__ == "__main__":
    # make an instance
    app = configure(name="configure")
    # ride
    status = app.run()
    # all done
    raise SystemExit(status)


# end of file
