"""
   Collection of DIRAC useful operating system related modules
   by default on Error they return None
"""

from __future__ import print_function
from __future__ import absolute_import
from __future__ import division

import six
import os
import distutils.spawn  # pylint: disable=no-name-in-module,import-error

import DIRAC
from DIRAC.Core.Utilities.Subprocess import shellCall, systemCall
from DIRAC.Core.Utilities import List

__RCSID__ = "$Id$"


DEBUG = 0


def uniquePath(path=None):
    """
    Utility to squeeze the string containing a PATH-like value to
    leave only unique elements preserving the original order
    """
    if not isinstance(path, six.string_types):
        return None

    try:
        elements = List.uniqueElements(List.fromChar(path, ":"))
        return ":".join(elements)
    except Exception:
        return None


def getDiskSpace(path=".", exclude=None):
    """Get the free disk space in the partition containing the path.
    The disk space is reported in MBytes. Returned 0 in case of any
    error, e.g. path does not exist
    """

    if not os.path.exists(path):
        return -1
    comm = "df -P -m %s " % path
    if exclude:
        comm += "-x %s " % exclude
    comm += "| tail -1"
    resultDF = shellCall(10, comm)
    if resultDF["OK"] and not resultDF["Value"][0]:
        output = resultDF["Value"][1]
        if output.find(" /afs") >= 0:  # AFS disk space
            comm = "fs lq | tail -1"
            resultAFS = shellCall(10, comm)
            if resultAFS["OK"] and not resultAFS["Value"][0]:
                output = resultAFS["Value"][1]
                fields = output.split()
                quota = int(fields[1])
                used = int(fields[2])
                space = (quota - used) / 1024
                return int(space)
            else:
                return -1
        else:
            fields = output.split()
            try:
                value = int(fields[3])
            except Exception as error:
                print("Exception during disk space evaluation:", str(error))
                value = -1
            return value
    else:
        return -1


def getDirectorySize(path):
    """Get the total size of the given directory in MB"""

    comm = "du -s -m %s" % path
    result = shellCall(10, comm)
    if not result["OK"] or result["Value"][0] != 0:
        return 0
    else:
        output = result["Value"][1]
        print(output)
        size = int(output.split()[0])
        return size


def sourceEnv(timeout, cmdTuple, inputEnv=None):
    """Function to source configuration files in a platform dependent way and get
    back the environment
    """

    # add appropriate extension to first element of the tuple (the command)
    envAsDict = '&& python -c "import os,sys ; print >> sys.stderr, os.environ"'

    # 1.- Choose the right version of the configuration file
    if DIRAC.getPlatformTuple()[0] == "Windows":
        cmdTuple[0] += ".bat"
    else:
        cmdTuple[0] += ".sh"

    # 2.- Check that it exists
    if not os.path.exists(cmdTuple[0]):
        result = DIRAC.S_ERROR("Missing script: %s" % cmdTuple[0])
        result["stdout"] = ""
        result["stderr"] = "Missing script: %s" % cmdTuple[0]
        return result

    # Source it in a platform dependent way:
    # On windows the execution makes the environment to be inherit
    # On Linux or Darwin use bash and source the file.
    if DIRAC.getPlatformTuple()[0] == "Windows":
        # this needs to be tested
        cmd = " ".join(cmdTuple) + envAsDict
        ret = shellCall(timeout, [cmd], env=inputEnv)
    else:
        cmdTuple.insert(0, "source")
        cmd = " ".join(cmdTuple) + envAsDict
        ret = systemCall(timeout, ["/bin/bash", "-c", cmd], env=inputEnv)

    # 3.- Now get back the result
    stdout = ""
    stderr = ""
    result = DIRAC.S_OK()
    if ret["OK"]:
        # The Command has not timeout, retrieve stdout and stderr
        stdout = ret["Value"][1]
        stderr = ret["Value"][2]
        if ret["Value"][0] == 0:
            # execution was OK
            try:
                result["outputEnv"] = eval(stderr.split("\n")[-2] + "\n")
                stderr = "\n".join(stderr.split("\n")[:-2])
            except Exception:
                stdout = cmd + "\n" + stdout
                result = DIRAC.S_ERROR("Could not parse Environment dictionary from stderr")
        else:
            # execution error
            stdout = cmd + "\n" + stdout
            result = DIRAC.S_ERROR("Execution returns %s" % ret["Value"][0])
    else:
        # Timeout
        stdout = cmd
        stderr = ret["Message"]
        result = DIRAC.S_ERROR(stderr)

    # 4.- Put stdout and stderr in result structure
    result["stdout"] = stdout
    result["stderr"] = stderr

    return result


def which(executable):

    return distutils.spawn.find_executable(executable)  # pylint: disable=no-member
