#################################################################
# Class DirectoryListing
# Author: A.T.
# Added 02.03.2015
#################################################################

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

__RCSID__ = "$Id$"

import stat

from DIRAC import gConfig
from DIRAC.ConfigurationSystem.Client.Helpers import Registry


class DirectoryListing(object):
    def __init__(self):

        self.entries = []

    def addFile(self, name, fileDict, repDict, numericid):
        """Pretty print of the file ls output"""
        perm = fileDict["Mode"]
        date = fileDict["ModificationDate"]
        # nlinks = fileDict.get('NumberOfLinks',0)
        nreplicas = len(repDict)
        size = fileDict["Size"]
        if "Owner" in fileDict:
            uname = fileDict["Owner"]
        elif "OwnerDN" in fileDict:
            result = Registry.getUsernameForDN(fileDict["OwnerDN"])
            if result["OK"]:
                uname = result["Value"]
            else:
                uname = "unknown"
        else:
            uname = "unknown"
        if numericid:
            uname = str(fileDict["UID"])
        if "OwnerGroup" in fileDict:
            gname = fileDict["OwnerGroup"]
        elif "OwnerRole" in fileDict:
            groups = Registry.getGroupsWithVOMSAttribute("/" + fileDict["OwnerRole"])
            if groups:
                if len(groups) > 1:
                    gname = groups[0]
                    default_group = gConfig.getValue("/Registry/DefaultGroup", "unknown")
                    if default_group in groups:
                        gname = default_group
                else:
                    gname = groups[0]
            else:
                gname = "unknown"
        else:
            gname = "unknown"
        if numericid:
            gname = str(fileDict["GID"])

        self.entries.append(("-" + self.__getModeString(perm), nreplicas, uname, gname, size, date, name))

    def addDirectory(self, name, dirDict, numericid):
        """Pretty print of the file ls output"""
        perm = dirDict["Mode"]
        date = dirDict["ModificationDate"]
        nlinks = 0
        size = 0
        if "Owner" in dirDict:
            uname = dirDict["Owner"]
        elif "OwnerDN" in dirDict:
            result = Registry.getUsernameForDN(dirDict["OwnerDN"])
            if result["OK"]:
                uname = result["Value"]
            else:
                uname = "unknown"
        else:
            uname = "unknown"
        if numericid:
            uname = str(dirDict["UID"])
        if "OwnerGroup" in dirDict:
            gname = dirDict["OwnerGroup"]
        elif "OwnerRole" in dirDict:
            groups = Registry.getGroupsWithVOMSAttribute("/" + dirDict["OwnerRole"])
            if groups:
                if len(groups) > 1:
                    gname = groups[0]
                    default_group = gConfig.getValue("/Registry/DefaultGroup", "unknown")
                    if default_group in groups:
                        gname = default_group
                else:
                    gname = groups[0]
            else:
                gname = "unknown"
        if numericid:
            gname = str(dirDict["GID"])

        self.entries.append(("d" + self.__getModeString(perm), nlinks, uname, gname, size, date, name))

    def addDataset(self, name, datasetDict, numericid):
        """Pretty print of the dataset ls output"""
        perm = datasetDict["Mode"]
        date = datasetDict["ModificationDate"]
        size = datasetDict["TotalSize"]
        if "Owner" in datasetDict:
            uname = datasetDict["Owner"]
        elif "OwnerDN" in datasetDict:
            result = Registry.getUsernameForDN(datasetDict["OwnerDN"])
            if result["OK"]:
                uname = result["Value"]
            else:
                uname = "unknown"
        else:
            uname = "unknown"
        if numericid:
            uname = str(datasetDict["UID"])

        gname = "unknown"
        if "OwnerGroup" in datasetDict:
            gname = datasetDict["OwnerGroup"]
        if numericid:
            gname = str(datasetDict["GID"])

        numberOfFiles = datasetDict["NumberOfFiles"]

        self.entries.append(("s" + self.__getModeString(perm), numberOfFiles, uname, gname, size, date, name))

    def __getModeString(self, perm):
        """Get string representation of the file/directory mode"""

        pstring = ""
        if perm & stat.S_IRUSR:
            pstring += "r"
        else:
            pstring += "-"
        if perm & stat.S_IWUSR:
            pstring += "w"
        else:
            pstring += "-"
        if perm & stat.S_IXUSR:
            pstring += "x"
        else:
            pstring += "-"
        if perm & stat.S_IRGRP:
            pstring += "r"
        else:
            pstring += "-"
        if perm & stat.S_IWGRP:
            pstring += "w"
        else:
            pstring += "-"
        if perm & stat.S_IXGRP:
            pstring += "x"
        else:
            pstring += "-"
        if perm & stat.S_IROTH:
            pstring += "r"
        else:
            pstring += "-"
        if perm & stat.S_IWOTH:
            pstring += "w"
        else:
            pstring += "-"
        if perm & stat.S_IXOTH:
            pstring += "x"
        else:
            pstring += "-"

        return pstring

    def humanReadableSize(self, num, suffix="B"):
        """Translate file size in bytes to human readable

        Powers of 2 are used (1Mi = 2^20 = 1048576 bytes).
        """
        num = int(num)
        for unit in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]:
            if abs(num) < 1024.0:
                return "%3.1f%s%s" % (num, unit, suffix)
            num /= 1024.0
        return "%.1f%s%s" % (num, "Yi", suffix)

    def printListing(self, reverse, timeorder, sizeorder, humanread):
        """ """
        if timeorder:
            if reverse:
                self.entries.sort(key=lambda x: x[5])
            else:
                self.entries.sort(key=lambda x: x[5], reverse=True)
        elif sizeorder:
            if reverse:
                self.entries.sort(key=lambda x: x[4])
            else:
                self.entries.sort(key=lambda x: x[4], reverse=True)
        else:
            if reverse:
                self.entries.sort(key=lambda x: x[6], reverse=True)
            else:
                self.entries.sort(key=lambda x: x[6])

        # Determine the field widths
        wList = [0] * 7
        for d in self.entries:
            for i in range(7):
                if humanread and i == 4:
                    humanreadlen = len(str(self.humanReadableSize(d[4])))
                    if humanreadlen > wList[4]:
                        wList[4] = humanreadlen
                else:
                    if len(str(d[i])) > wList[i]:
                        wList[i] = len(str(d[i]))

        for e in self.entries:
            size = e[4]
            if humanread:
                size = self.humanReadableSize(e[4])
            print(str(e[0]), end=" ")
            print(str(e[1]).rjust(wList[1]), end=" ")
            print(str(e[2]).ljust(wList[2]), end=" ")
            print(str(e[3]).ljust(wList[3]), end=" ")
            print(str(size).rjust(wList[4]), end=" ")
            print(str(e[5]).rjust(wList[5]), end=" ")
            print(str(e[6]))

    def addSimpleFile(self, name):
        """Add single files to be sorted later"""
        self.entries.append(name)

    def printOrdered(self):
        """print the ordered list"""
        self.entries.sort()
        for entry in self.entries:
            print(entry)
