# -*- mode: python; -*-

import os
import shutil
import stat


def _copy(src, dst):
    shutil.copy2(src, dst)
    st = os.stat(src)
    os.chmod(dst, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)


def _symlink(src, dst):
    if os.path.islink(src):
        _copy(src, dst)
    else:
        os.symlink(os.path.relpath(src, os.path.dirname(dst)), dst)


def _hardlink(src, dst):
    if os.path.islink(src):
        _copy(src, dst)
    else:
        try:
            os.link(src, dst)
        except:
            _copy(src, dst)


available_actions = {
    "copy": _copy,
    "hardlink": _hardlink,
    "symlink": _symlink,
}


class _CopytreeError(EnvironmentError):
    pass


def _generate_install_actions(base_action):
    # This is a patched version of shutil.copytree from python 2.5.  It
    # doesn't fail if the dir exists, which regular copytree does
    # (annoyingly).  Note the XXX comment in the docstring.
    def _mongo_copytree(src, dst, symlinks=False):
        """Recursively copy a directory tree using copy2().

        The destination directory must not already exist.
        If exception(s) occur, an _CopytreeError is raised with a list of reasons.

        If the optional symlinks flag is true, symbolic links in the
        source tree result in symbolic links in the destination tree; if
        it is false, the contents of the files pointed to by symbolic
        links are copied.

        XXX Consider this example code rather than the ultimate tool.

        """
        names = os.listdir(src)
        # garyo@genarts.com fix: check for dir before making dirs.
        if not os.path.exists(dst):
            os.makedirs(dst)
        errors = []
        for name in names:
            srcname = os.path.join(src, name)
            dstname = os.path.join(dst, name)
            try:
                if symlinks and os.path.islink(srcname):
                    linkto = os.readlink(srcname)
                    os.symlink(linkto, dstname)
                elif os.path.isdir(srcname):
                    _mongo_copytree(srcname, dstname, symlinks)
                else:
                    base_action(srcname, dstname)
                # XXX What about devices, sockets etc.?
            except (IOError, os.error) as why:
                errors.append((srcname, dstname, str(why)))
            # catch the _CopytreeError from the recursive copytree so that we can
            # continue with other files
            except _CopytreeError as err:
                errors.extend(err.args[0])
        try:
            shutil.copystat(src, dst)
        except SCons.Util.WinError:
            # can't copy file access times on Windows
            pass
        except OSError as why:
            errors.extend((src, dst, str(why)))
        if errors:
            raise _CopytreeError(errors)

    #
    # Functions doing the actual work of the Install Builder.
    #
    def _mongo_copyFunc(dest, source, env):
        """Install a source file or directory into a destination by copying,
        (including copying permission/mode bits)."""

        if os.path.isdir(source):
            if os.path.exists(dest):
                if not os.path.isdir(dest):
                    raise SCons.Errors.UserError(
                        "cannot overwrite non-directory `%s' with a directory `%s'"
                        % (str(dest), str(source))
                    )
            else:
                parent = os.path.split(dest)[0]
                if not os.path.exists(parent):
                    os.makedirs(parent)
            _mongo_copytree(source, dest)
        else:
            base_action(source, dest)

        return 0

    #
    # Functions doing the actual work of the InstallVersionedLib Builder.
    #
    def _mongo_copyFuncVersionedLib(dest, source, env):
        """Install a versioned library into a destination by copying,
        (including copying permission/mode bits) and then creating
        required symlinks."""

        if os.path.isdir(source):
            raise SCons.Errors.UserError(
                "cannot install directory `%s' as a version library" % str(source)
            )
        else:
            # remove the link if it is already there
            try:
                os.remove(dest)
            except:
                pass
            base_action(source, dest)
            SCons.tool.install.installShlibLinks(dest, source, env)

        return 0

    return (_mongo_copyFunc, _mongo_copyFuncVersionedLib)


def setup(env, action):
    if action == "default":
        return
    base_action = available_actions.get(action, None)
    handlers = _generate_install_actions(base_action)
    env["INSTALL"] = handlers[0]
    env["INSTALLVERSIONEDLIB"] = handlers[1]
