
from __future__ import absolute_import

import os

from vdsm.storage import clusterlock
from vdsm.storage import constants as sc
from vdsm.storage import exception as se
from vdsm.storage import fileSD
from vdsm.storage import fileUtils
from vdsm.storage import misc
from vdsm.storage import mount
from vdsm.storage import outOfProcess as oop
from vdsm.storage import sd


class NfsStorageDomain(fileSD.FileStorageDomain):

    supported_block_size = (sc.BLOCK_SIZE_512,)

    @classmethod
    def _preCreateValidation(cls, sdUUID, domPath, typeSpecificArg,
                             storageType, version):
        if storageType == sd.NFS_DOMAIN and ":" not in typeSpecificArg:
            raise se.StorageDomainIllegalRemotePath(typeSpecificArg)

        sd.validateDomainVersion(version)

        if not mount.isMounted(domPath):
            raise se.StorageDomainFSNotMounted(domPath)

        fileSD.validateDirAccess(domPath)

        mdpat = os.path.join(domPath, "*", sd.DOMAIN_META_DATA)
        if len(oop.getProcessPool(sdUUID).glob.glob(mdpat)) > 0:
            raise se.StorageDomainNotEmpty(typeSpecificArg)

    @classmethod
    def create(cls, sdUUID, domainName, domClass, remotePath, storageType,
               version, block_size=sc.BLOCK_SIZE_512,
               max_hosts=sc.HOSTS_4K_1M):
        cls._validate_block_size(block_size, version)

        remotePath = fileUtils.normalize_path(remotePath)

        if not misc.isAscii(domainName) and not sd.supportsUnicode(version):
            raise se.UnicodeArgumentException()

        mntPath = fileUtils.transformPath(remotePath)

        mntPoint = cls.getMountPoint(mntPath)

        cls._preCreateValidation(sdUUID, mntPoint, remotePath, storageType,
                                 version)

        storage_block_size = cls._detect_block_size(sdUUID, mntPoint)
        block_size = cls._validate_storage_block_size(
            block_size, storage_block_size)

        alignment = clusterlock.alignment(block_size, max_hosts)

        domainDir = os.path.join(mntPoint, sdUUID)
        cls._prepareMetadata(domainDir, sdUUID, domainName, domClass,
                             remotePath, storageType, version, alignment,
                             block_size)

        imagesDir = os.path.join(domainDir, sd.DOMAIN_IMAGES)
        cls.log.info("Creating domain images directory %r", imagesDir)
        oop.getProcessPool(sdUUID).fileUtils.createdir(imagesDir)

        if domClass is sd.ISO_DOMAIN:
            isoDir = os.path.join(imagesDir, sd.ISO_IMAGE_UUID)
            cls.log.info("Creating ISO domain images directory %r", isoDir)
            oop.getProcessPool(sdUUID).fileUtils.createdir(isoDir)

        fsd = cls(os.path.join(mntPoint, sdUUID))
        fsd.initSPMlease()

        return fsd

    @classmethod
    def getMountPoint(cls, mountPath):
        return os.path.join(sc.REPO_MOUNT_DIR, mountPath)

    @staticmethod
    def findDomainPath(sdUUID):
        for tmpSdUUID, domainPath in fileSD.scanDomains("*"):
            if tmpSdUUID == sdUUID:
                mountpoint = os.path.dirname(domainPath)
                if mount.isMounted(mountpoint):
                    return domainPath

        raise se.StorageDomainDoesNotExist(sdUUID)

    def getRealPath(self):
        try:
            return mount.getMountFromTarget(self.mountpoint).fs_spec
        except mount.MountError:
            return ""


def findDomain(sdUUID):
    return NfsStorageDomain(NfsStorageDomain.findDomainPath(sdUUID))
