#!/usr/bin/env python3
# -*- coding: us-ascii -*-

# --------------------------------------------------------------------------------
# Copyright (C) 2015-2016 BigDFT group
# This file is distributed under the terms of the
# GNU General Public License, see
# or http://www.gnu.org/copyleft/gpl.txt .
# --------------------------------------------------------------------------------
from __future__ import print_function

from copy import deepcopy
BIGDFT_CFG = 'BIGDFT_CONFIGURE_FLAGS'
CLEAN = ' clean '
CLEANONE = ' cleanone '
UNINSTALL = ' uninstall '
LIST = ' list '
BUILD = ' build '
BUILDONE = ' buildone '
TINDERBOX = ' tinderbox -o buildlogs '
DOT = ' dot '
DOTCMD = ' | dot -Edir=back -Tpng > buildprocedure.png '
DIST = '  dist --dist-only '  # bigdft-suite '
RCFILE = 'buildrc'
MKFILE = 'Makefile'
SETUP = ' setup '


def get_macros(fr, *expressions):
    """
    Given a file, find the macros in it.

    Args:
      fr (str): path of the file to search in.
      *expressions: list of expressions to match.
    Returns:
      (list): a list of macros (strings).
    """
    from re import compile, search

    regex = [compile(x.strip()) for x in expressions]
    result = []
    with open(fr) as ifile:
        for line in ifile:
            if all(search(r, line) for r in regex) \
                    and "dnl" not in line and '#' not in line:
                result.append(line.rstrip('\n'))
    return result


def get_files(fd, *expressions):
    """
    Given a directory, find the files which match the given macros.

    Args:
      fd (str): path to the directory to look in.
      *expressions: a list of expressions to match.

    Returns:
      (list): a list of files which have lines that match the expressions.
    """
    from os.path import join
    from re import compile, search
    from glob import glob

    regex = [compile(x.strip()) for x in expressions]
    result = []
    for f in glob(join(fd, "*")):
        with open(f) as ifile:
            for line in ifile:
                if all(search(r, line) for r in regex) \
                        and "dnl" not in line and '#' not in line:
                    result.append(f)
                    break
    return result


CHECKMODULES = ['futile', 'atlab', 'chess', 'liborbs',
                'psolver', 'bigdft', 'PyBigDFT', 'spred',
                'bigdft-client']
MAKEMODULES = deepcopy(CHECKMODULES)
MAKEMODULES.insert(CHECKMODULES.index('bigdft'), 'libABINIT')

MANUALMAKEMODULES = deepcopy(MAKEMODULES)
MANUALMAKEMODULES.remove('PyBigDFT')
# allowed actions and corresponding description
ACTIONS = {'build':
           'Compile and install the code with the given configuration.',
           'make':
           'Recompile the bigdft internal branches, skip configuring step.',
           'clean':
           'Clean the branches for a fresh reinstall.',
           'startover':
           'Wipe out all the build directories and recompile the important parts',
           'autogen':
           'Perform the autogen in the modules which need that. For developers only.',
           'update':
           'Useful to update a pre-compiled branch after a merge',
           'dist':
           'Creates a tarfile for the suite tailored to reproduce the compilation options specified.',
           'check':
           'Perform check in the bigdft branches, skip external libraries.',
           'cleanone':
           'Clean a single module of the suite',
           'buildone':
           'Build a single module of the suite',
           'dry_run':
           "Visualize the list of modules that will be compiled with the provided configuration in the 'buildprocedure.png' file.",
           'link':
           'Show the linking line that have to be used to connect an external executable to the package (when applicable)'}

# actions which need rcfile to be executed
NEEDRC = ['build', 'dist', 'dry_run', 'startover', 'buildone']

# actions which do not need Makefile creation
NOMAKEFILE = ['autogen', 'dry_run']

TARGETS = {
    'bigdft': ['bin', 'bigdft'],
    'spred': ['bin', 'mhgps'],
    'chess': ['lib', 'libCheSS-1.a'],
    'futile': ['lib', 'libfutile-1.a'],
    'PyBigDFT': ['bin', 'bigdft'],  # not really a target
    'bigdft-client': ['lib'],  # not really a target
    'psolver': ['lib', 'libPSolver-1.a'],
    'atlab': ['lib', 'libatlab-1.a'],
    'liborbs': ['lib', 'liborbs.a'],
}


class BigDFTInstaller():
    """Class for the installation of the ``bigdft-suite``.

    Attributes:
        action (str): Action to be performed.
        package (str): Package to install.
        rcfile (str): Configuration file.
        conditions (list(str)): List of conditions.
        verbose (bool): If ``True``, more verbose.
        quiet (bool): If ``True``, no messages.
        yes (bool): If ``True``, ask a question.
    """
    m4_re = ['^AX_', 'CHECK_PYTHON[^_]',
             'PKG_CHECK_MODULES']  # regular expressions to identify proprietary macros

    def __init__(self, action, package, rcfile, conditions, verbose, quiet, yes):
        import os
        from sys import executable as pythonpath
        self.action = action  # Action to be performed
        self.conditions = [] if conditions is None else conditions
        self.package = package  # Package
        self.yes = yes  # Ask a question
        # the position of the script
        self.scriptpath = __file__
        # look where we are
        self.srcdir = os.path.abspath(os.path.dirname(self.scriptpath))
        if self.srcdir == '':
            self.srcdir = '.'
        # look the builddir
        self.builddir = os.getcwd()
        # look if we are building from a branch
        bigdftdir = os.path.join(self.srcdir, 'bigdft')
        self.branch = os.path.isfile(os.path.join(bigdftdir, 'branchfile'))
        self.verbose = (verbose or action == 'check')  # verbose option
        if not self.verbose and not quiet:
            self.verbose = self.branch
        # To be done BEFORE any exit instruction in __init__ (get_rcfile)
        self.time0 = None

        if os.path.abspath(self.srcdir) == os.path.abspath(self.builddir) and self.action not in NOMAKEFILE:
            print(50 * '-')
            print("ERROR: BigDFT Installer works better with a build directory different from the source directory, install from another directory")
            print("SOLUTION: Create a separate directory and invoke this script from it")
            exit(1)
        # hostname
        self.hostname = os.uname()[1]

        # rcfile
        self.get_rcfile(rcfile)

        # jhbuild script
        self.jhb = pythonpath + ' ' + \
            os.path.join(self.srcdir, 'bundler/jhbuild.py ')
        if self.rcfile != '':
            self.jhb += '-f ' + self.rcfile

        # conditions to be added
        if len(self.conditions) > 0:
            self.jhb += ' --conditions=+' + self.conditions[0]
        for cond in self.conditions[1:]:
            self.jhb += ',+' + cond

        # date of bigdft executable if present
        self.time0 = self.target_time()

        self.print_present_configuration()

        # now get the list of modules that has to be treated with the given command
        self.modulelist = self.get_output(
            self.jhb + LIST + self.package).split('\n')
        print(" List of modules to be treated:", self.modulelist)

        # then choose the actions to be taken
        getattr(self, action)()

    def target_time(self):
        import os
        dt = TARGETS['bigdft']
        dt = TARGETS.get(self.package)
        # print(TARGETS)
        tgt = os.path.join(*dt)
        return self.filename_time(os.path.join(self.builddir, 'install', tgt))

    def filename_time(self, filename):
        import os
        if os.path.isfile(filename):
            return os.path.getmtime(filename)
        else:
            return 0

    def hook_environment_modifications(self):
        """
        Intercepts the `py:func:addpath` method of jhbuild
        in order to understand which environment variables have been
        identified to compile the suite.
        """
        pass

    def get_rcfile(self, rcfile):
        """Determine the rcfile"""
        import os
        # see if the environment variables BIGDFT_CFG is present
        self.rcfile = ''
        if rcfile is not None:
            self.rcfile = rcfile
        else:
            if not (BIGDFT_CFG in list(os.environ.keys())) or self.action in NEEDRC:
                self.rcfile = RCFILE
        # see if it exists where specified
        if os.path.exists(self.rcfile):
            return
        # otherwise search again in the rcfiles
        rcdir = os.path.join(self.srcdir, 'rcfiles')
        if self.rcfile != '':
            self.rcfile = os.path.join(rcdir, self.rcfile)
        if os.path.exists(self.rcfile):
            return
        self.rcfile = ''
        if BIGDFT_CFG in list(os.environ.keys()):
            return
        # otherwise search for rcfiles similar to hostname and propose a choice
        rcs = []
        for file in os.listdir(rcdir):
            testname = os.path.basename(file)
            base = os.path.splitext(testname)[0]
            if base in self.hostname or self.hostname in base or base.split('-')[0] in self.hostname:
                rcs.append(file)
        print("Search in the configuration directory '%s'" % rcdir)
        if len(rcs) == 1:
            self.rcfile = os.path.join(rcdir, rcs[0])
        elif len(rcs) > 0 and (self.action in NEEDRC or not self.yes):
            print("No valid configuration file specified, found various that matches the hostname '%s'" % self.hostname)
            print('In the directory "' + rcdir + '"')
            print('Choose among the following options')
            for i, rc in enumerate(rcs):
                print(str(i + 1) + '. ' + rc)
            while True:
                choice = input('Pick your choice (q to quit) ')
                if choice == 'q':
                    exit(0)
                try:
                    ival = int(choice)
                    if (ival <= 0):
                        raise
                    ch = rcs[ival - 1]
                    break
                except:
                    print('The choice must be a valid integer among the above')
            self.rcfile = os.path.join(rcdir, ch)
        elif self.action in NEEDRC:
            print('No valid configuration file provided and ' +
                  BIGDFT_CFG + ' variable not present, exiting...')
            exit(1)

    def __dump(self, *msg, **kwargs):
        if self.verbose and kwargs.get('verbose', True):
            for m in msg:
                print(m)

    def print_present_configuration(self):
        import os
        indent = ' ' * 2
        print('Configuration chosen for the Installer:')
        print(indent + 'Hostname:', self.hostname)
        print(indent + 'Source directory:', os.path.abspath(self.srcdir))
        print(indent + 'Compiling from a branch:', self.branch)
        print(indent + 'Build directory:', os.path.abspath(self.builddir))
        print(indent + 'Action chosen:', self.action)
        print(indent + 'Verbose:', self.verbose)
        print(indent + 'Jhbuild baseline:', self.jhb)
        if self.rcfile == '' and self.action in NEEDRC:
            print(indent + 'Configuration options:')
            print(indent * 2 + "Source: Environment variable '%s'" % BIGDFT_CFG)
            print(indent * 2 + "Value: '%s'" % os.environ[BIGDFT_CFG])
        elif self.rcfile != '':
            print(indent + 'Configuration options:')
            print(indent * 2 + "Source: Configuration file '%s'" %
                  os.path.abspath(self.rcfile))
        while not self.yes:
            if not self.branch:
                print(
                    indent + '#WARNING: You are compiling from a User Branch. Developments are discouraged in this case')
                print(
                    indent + '# as compilation errors might lead to source deletion. For extensive developments the usage')
                print(
                    indent + '# of a versioned branch is advised. Please ignore this warning if you are not a developer.')
            ok = input('Do you want to continue (Y/n)? ')
            if ok == 'n' or ok == 'N':
                exit(0)
            elif ok != 'y' and ok != 'Y' and repr(ok) != repr(''):
                print('Please answer y or n')
            else:
                break

    def selected(self, l):
        return [val for val in l if val in self.modulelist]

    def jhbuildaction(self, action, target, options=''):
        "Call jhbuild to do action on target."
        import os
        command = " ".join((action, options, target))
        ret = os.system(self.jhb + command)
        if (ret != 0):
            raise RuntimeError('JHBuild failed to complete :' + command)

    def shellaction(self, path, modules, action, hidden=False):
        "Perform a shell action, dump also the result if verbose is True."
        import os
        import sys
        for mod in self.selected(modules):
            directory = os.path.join(path, mod)
            here = os.getcwd()
            if os.path.isdir(directory):
                #self.__dump('Treating directory '+directory)
                sys.stdout.write('Module ' + mod +
                                 ' [' + directory + ']: ' + action)
                sys.stdout.flush()
                os.chdir(directory)
                if hidden:
                    self.get_output(action)
                else:
                    ierr = os.system(action)
                    if ierr != 0:
                        raise Exception('Error in action: "' +
                                        action + '" for package: "' + mod + '"')
                    # print 'Error in action: "'+action+'" for package: "'+mod+'"'
                    # sys.exit(1)
                os.chdir(here)
                # self.__dump('done.')
                sys.stdout.write(' (done)\n')
            else:
                sys.stdout.write('Cannot perform action "' + action +
                                 '" on module "' + mod + '" directory not present in the build.\n')
            sys.stdout.flush()

    def get_output(self, cmd, verbose=True):
        import subprocess
        self.__dump('executing:', cmd, verbose=verbose)
        # note the use of universal_newlines
        # in python3, this forces the output to plain text instead of binary.
        # this poorly named parameter was aliased as "text" in version 3.7
        proc = subprocess.Popen(
            cmd, stdout=subprocess.PIPE, shell=True, universal_newlines=True)
        (out, err) = proc.communicate()
        self.__dump("program output:", out, verbose=verbose or len(out) > 0)
        return out

    def removefile(self, pattern, dirname, names):
        "Delete the files matching the pattern"
        import os
        import fnmatch
        for name in names:
            if fnmatch.fnmatch(name, pattern):
                self.__dump('removing', os.path.join(dirname, name))
                os.remove(os.path.join(dirname, name))

    def get_ac_argument(self, tgt, acmacro):
        "Retrieve the list of ac arguments for the macro acmacro from file tgt"
        import os
        m4args = set()
        if os.path.isfile(tgt):
            for dd in get_macros(tgt, acmacro):
                if len(dd) == 0:
                    continue
                m4 = dd.split('[')[1]
                m4args.add(m4.split(']')[0])
        return list(m4args)

    def get_m4_macros(self, tgt, previous_macros=[]):
        "Identify the name of the proprietary m4 macros used in configure.ac"
        import os
        macros = set()
        if os.path.isfile(tgt):
            for regexp in self.m4_re:
                for m4 in get_macros(tgt, regexp):
                    if len(m4) > 0 and not m4.strip().startswith('AC_DEFUN'):
                        m4t = m4.split('(')[0].strip()
                        if m4t not in previous_macros:
                            macros.add(m4t)
            required = self.get_ac_argument(tgt, 'AC_REQUIRE')
            for m in required:
                found = m in previous_macros
                if found:
                    continue
                for regexp in self.m4_re:
                    found = regexp.lstrip('^') in m
                    if found:
                        break
                if found:
                    macros.add(m)
        return list(macros)

    def get_m4_files(self, macros):
        "Find the files needed for the definition of the proprietary macros"
        import os
        files = set()
        # localize then the associated file in the m4 repository
        tgt = os.path.join(self.srcdir, 'm4') + os.sep
        # print 'XXXXX',macros
        for m in macros:
            ffs = get_files(tgt, m, 'AC_DEFUN')[0]
            if ffs != '':
                files.add(ffs)
        # now for each of the files get all the macros which are required but not explicitly called
        files = list(files)
        newm4 = set()
        for f in files:
            tgt = os.path.join(self.srcdir, f)
            newm = self.get_m4_macros(tgt, previous_macros=macros)
            # print 'new macros',newm,f
            for m4 in newm:
                newm4.add(m4)
        newm4 = list(newm4)
        # print "new macros which have to be added",newm4,files
        if len(newm4) > 0:
            files = self.get_m4_files(macros + newm4)
        return list(files)

    def get_m4_dir(self, mod):
        "Return the configure macro dir(s)"
        import os
        tgt = os.path.join(self.srcdir, mod, 'configure.ac')
        return self.get_ac_argument(tgt, 'AC_CONFIG_MACRO_DIR')

    def copyfiles(self, filelist, dest):
        import os
        import shutil
        if not os.path.isdir(dest):
            return
        for f in filelist:
            test = os.path.join(dest, os.path.basename(f))
            if os.path.isfile(test):
                if len(self.get_output('diff -q ' + f + ' ' + test, verbose=False)) == 0:
                    continue
            try:
                shutil.copy(f, dest)
            except:
                os.chmod(dest, 777)  # ?? still can raise exception
                shutil.copy(f, dest)
            print('Copied file ' + f + ' in directory ' + dest)

    def autogen(self):
        "Perform the autogen action"
        import os
        # first copy the macros in the config.m4 directories of proprietary packages
        for mod in self.selected(MAKEMODULES):
            macros = self.get_m4_macros(
                os.path.join(self.srcdir, mod, 'configure.ac'))
            # print 'initial macros',mod,macros
            files = self.get_m4_files(macros)
            # print 'related files',files
            # print 'directory to copy files',self.get_m4_dir(mod)
            # now copy the files, overwriting the previously existing ones
            for d in self.get_m4_dir(mod):
                self.copyfiles(files, os.path.join(self.srcdir, mod, d))
            self._setupone(mod)
        #self.jhbuildaction(SETUP, self.package)
        #self.shellaction(self.srcdir,self.modulelist,'autoreconf -fi')

    def check(self):
        "Perform the check action"
        self.shellaction('.', CHECKMODULES, 'make check',
                         hidden=not self.verbose)

    def make(self):
        "Perform the simple make action"
        self.shellaction('.', MANUALMAKEMODULES,
                         'make -j6 && make install', hidden=not self.verbose)

    def dist(self):
        "Perform make dist action"
        import os
        tarfile = os.path.join(self.builddir, self.package + '-suite.tar.gz')
        disttime0 = self.filename_time(tarfile)
        self.jhbuildaction(DIST, self.package + "-suite")
        disttime1 = self.filename_time(tarfile)
        if not (disttime1 == disttime0):
            print('SUCCESS: distribution file "' + self.package +
                  '-suite.tar.gz" generated correctly')
        else:
            print(
                'WARNING: the dist file seems not have been updated or generated correctly')

    def build(self):
        "Build the bigdft module with the options provided by the rcfile"
        import os
        # in the case of a nonbranch case, like a dist build, force checkout
        # should the make would not work
        co = '' if self.branch else ' -C'
        if (self.verbose):
            self.jhbuildaction(BUILD, self.package, options=co)
        else:
            self.jhbuildaction(TINDERBOX, self.package, options=co)

    def _wipeout(self, mod):
        import shutil
        print('Wipe directory: ', mod)
        shutil.rmtree(mod, ignore_errors=True)

    def _cleanone(self, mod):
        import os
        self.jhbuildaction(UNINSTALL, mod)
        self.jhbuildaction(CLEANONE, mod)
        # here we should eliminate residual .mod files
        os.walk(mod, self.removefile, "*.mod")
        os.walk(mod, self.removefile, "*.MOD")
        if not self.branch:  # this is necessary as we come from a tarfile
            self._wipeout(mod)

    def cleanone(self):
        self._cleanone(self.package)

    def buildone(self):
        self._buildone(self.package)

    def clean(self):
        "Clean files in the build directory"
        # invert cleaning order for elegance
        for mod in self.selected(MAKEMODULES[::-1]):
            self._cleanone(mod)

    def _buildone(self, mod):
        print('Resetting: ', mod)
        self._setupone(mod)
        print('Building: ', mod)
        self.jhbuildaction(BUILDONE, mod)

    def _setupone(self, mod):
        self.jhbuildaction(SETUP, mod, options=' -t ' + mod)

    def startover(self):
        "Wipe files in the makemodules directory"
        if not self.branch:
            print('ERROR: The action "startover" is allowed only from a developer branch')
            exit(1)
        import os
        for mod in self.selected(MAKEMODULES):
            self.get_output(self.jhb + UNINSTALL + mod)
            self._wipeout(mod)
        print('Building again...')
        for mod in self.selected(MAKEMODULES):
            self._buildone(mod)
        self.build()

    def dry_run(self):
        "Do dry build"
        self.get_output(self.jhb + DOT + self.package + DOTCMD)

    def link(self):
        "Show the linking line, when applicable"
        import os
        PPATH = "PKG_CONFIG_PATH"
        addpath = os.path.join(self.builddir, 'install', 'lib', 'pkgconfig')
        if PPATH in os.environ:
            if addpath not in os.environ[PPATH].split(':'):
                os.environ[PPATH] += ':' + addpath
        else:
            os.environ[PPATH] = addpath
        includes = self.get_output('pkg-config --cflags ' + self.package)
        libs = self.get_output('pkg-config --libs ' + self.package)
        # add the external linalg at the end to avod linking problems
        linalg = self.get_output(
            'pkg-config --variable linalglibs ' + self.package)
        plugin = self.get_output(
            'pkg-config --variable plugin ' + self.package)
        print('--------- Linking line to build with package "' + self.package + '":')
        print("  " + includes + " " + libs)

    def makefile_dump(self):
        "Build the Makefile that the installation of BigDFT creates for performing the same actions on this build"
        import os
        sflist = []
        sflist.append("""
        #This Makefile is automatically generated from the BigDFT installer to avoid the calling to
        #the installer again for future action on this build
        #Clearly such actions only _assume_ that the build is fully functional and almost nothing
        #can be done with this file if a problem might arise.
        #Otherwise stated: this is an automatic message, please do not reply.
all: build
        """)
        # this should be done only if buildrc is there
        for a in ACTIONS:
            sflist.append(a + ':  ')
            sflist.append('\t' +
                          os.path.abspath(self.scriptpath) + ' ' + a + ' ' + self.package + ' -y')
        mkfile = open(MKFILE, 'w')
        for item in sflist:
            mkfile.write("%s\n" % item)
            # rcfile.write("\n")
        mkfile.close()

    def rcfile_from_env(self):
        "Build the rcfile information from the chosen " + \
            BIGDFT_CFG + " environment variable"
        import os
        if os.path.isfile(self.rcfile) and not os.path.isfile(RCFILE):
            from shutil import copyfile
            copyfile(self.rcfile, RCFILE)
            print(
                'The configuration file used has been copied in the build tree, file "' + RCFILE + '"')
            return
        if BIGDFT_CFG not in list(os.environ.keys()) or os.path.isfile(RCFILE):
            return
        print('The suite has been built from a single configure line.')
        rclist = []
        rclist.append(
            """#This is the configuration file for the BigDFT installer""")
        rclist.append(
            """#This is a python script which is executed by the build suite """)
        rclist.append(" ")
        rclist.append(
            """#Add the condition testing to run tests and includes PyYaml""")
        for cond in self.conditions:
            rclist.append('conditions.add("' + cond + '")')
        rclist.append("""#List the module the this rcfile will build""")
        rclist.append("modules = ['" + self.package + "',]")
        sep = ' """ '
        confline = sep + os.environ[BIGDFT_CFG] + sep
        rclist.append(
            "#example of the potentialities of the python syntax in this file")
        rclist.append("def env_configuration():")
        rclist.append("    return " + confline)
        rclist.append(
            "#the following command sets the environment variable to give these settings")
        rclist.append("#to all the modules")
        rclist.append("import os")
        rclist.append("os.environ['" + BIGDFT_CFG + "']=env_configuration()")
        rclist.append(
            "#here follow the configuration instructions for the modules built")
        rclist.append(
            "#we specify the configurations for the modules to customize the options if needed")
        rclist.append("module_autogenargs.update({")
        rclist.append("   ")
        for mod in self.modulelist:
            rclist.append("'" + mod + "': env_configuration(),")
            rclist.append("   ")
        rclist.append("})")
        # then write the file
        rcfile = open(RCFILE, 'w')
        for item in rclist:
            rcfile.write("%s\n" % item)
            # rcfile.write("\n")
        rcfile.close()
        print("Your used configuration options have been saved in the file '%s'." % RCFILE)
        print("Such file will be used for next builds, you might also save it in the 'rcfiles/'.")
        print(
            "Directory of the source for future use. The name might contain the hostname.")

    def __del__(self):
        import os
        print(50 * '-')
        print('Thank you for using the Installer of BigDFT suite.')
        print('The action considered was:', self.action)
        try:
            if self.time0 is not None:
                if not (self.time0 == self.target_time()) and self.target_time() != 0:
                    print(
                        'SUCCESS: The Installer seems to have built correctly', self.package, ' bundle')
                    print(
                        'All the available executables and scripts can be found in the directory')
                    print(
                        '"' + os.path.join(os.path.abspath(self.builddir), 'install', 'bin') + '"')
                    print(
                        'Before using the code consider sourcing the script:')
                    print(
                        '   "' + os.path.join(os.path.abspath(self.builddir), 'install', 'bin', 'bigdftvars.sh') + '"')


                    if self.action in NEEDRC:
                        self.rcfile_from_env()
                elif (self.action == 'build' or self.action == 'make'):
                    print('WARNING: The Installer seems NOT have created or updated',
                          self.package, ' binaries')
                    print('        (maybe everything was already compiled?)')
                    print('ACTION: check the compiling procedure.')
                    if self.branch:
                        print(
                            'HINT: It appears you are compiling from a branch source tree. Did you perform the action "autogen"?')
                    if not self.verbose and self.action == 'build':
                        print(
                            '  HINT: Have a look at the file index.html of the buildlogs/ directory to find the reason')
                    if self.yes:
                        exit(1)
        except:
            print('Goodbye...')
        if self.action not in NOMAKEFILE:
            self.makefile_dump()  # temporary


if __name__ == '__main__':
    # import the uniparse module
    import UniParse

    # Redefine ArgumentParser to have the help message if no arguments
    class Installer_Parser(UniParse.UniParser):
        def error(self, message):
            import sys
            sys.stderr.write('error: %s\n' % message)
            self.print_help()
            self.exit()

    parser = Installer_Parser(description='BigDFT suite Installer',
                              epilog='''
    If you want more help type "%(prog)s help"
    ------------------------------------------------
    For more information, visit www.bigdft.org''')

    parser.option('action', nargs='?', default='help',
                  help='Action to be performed by the Installer.'
                  ' (default: %(default)s)', choices=['help'] + [a for a in ACTIONS])
    parser.option('package', nargs='?', default='bigdft',
                  help='Package to be built by the installer. (default: %(default)s)',
                  choices=CHECKMODULES)
    parser.option('-f', '--file',
                  help='Use an alternative configuration file instead of the default configuration '
                  + 'given by the environment variable %s' % BIGDFT_CFG)

    parser.add_group(mutually_exclusive=True)
    parser.group_option("-v", "--verbose", action="store_true",
                        help='Verbose output, default from a development branch')
    parser.group_option("-q", "--quiet", action="store_true",
                        help='Verbosity disabled output, default from a development branch')

    parser.option('-d', '--debug', action='store_true',
                  help='Verbose output, default from a development branch')
    parser.option('-a', '--add-condition',
                  help='Add a condition for the compilation of the suite.')
    parser.option('-y', '--yes', action='store_true',
                  help='Answer yes to dialog questions')
    parser.option('-c', '--configure-line', remainder=True,
                  help='Specify the configure line to be passed (set BIGDFT_CONFIGURE_FLAGS variable)')

    args = parser.args()

    conds = None if args.add_condition is None else args.add_condition.split(
        ',')

    if args.configure_line is not None:
        cfg = ''
        for i in args.configure_line:
            if i is not None:
                cfg += i + ' '
        # scratch the BIGDFT_CFG environment variable
        import os
        os.environ[BIGDFT_CFG] = cfg

    if args.action == 'help':
        print("Quick overview of the BigDFT suite Installer program")
        print(50 * '-')
        print("USAGE: Installer.py <action> <package>")
        print(50 * '-')
        print('Available actions:')
        actions = list(ACTIONS.keys())
        actions.sort()
        for a in actions:
            print(a, ':')
            print('\t', ACTIONS[a])
        print(50 * '-')
        print('Available packages:', CHECKMODULES)
        print(50 * '-')
        print(10 * "QIFI-" + ' (Quick Instructions For the Impatient)')
        print('Ideally, there are two different policies:')
        print('Developer: From a development branch, start by "autogen", then "build"')
        print('     User: From a tarball, start by "build"')
        print('Perform the "dry_run" command to have a graphical overview of the building procedure')
    elif args.action == 'update':
        yes = args.yes
        for action in ['clean', 'autogen', 'build']:
            BigDFTInstaller(action, args.package, args.file,
                            conds, args.verbose, args.quiet, yes)
            yes = True
    else:
        BigDFTInstaller(args.action, args.package, args.file,
                        conds, args.verbose, args.quiet, args.yes)
