# Copyright (c) 2014 VMware, Inc.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

"""
Datastore utility functions
"""

from nova.openstack.common.gettextutils import _
from nova.openstack.common import log as logging
from nova.virt.vmwareapi import error_util
from nova.virt.vmwareapi import vm_util

LOG = logging.getLogger(__name__)


def build_datastore_path(datastore_name, path):
    """Build the datastore compliant path."""
    return "[%s] %s" % (datastore_name, path)


def split_datastore_path(datastore_path):
    """Return the datastore and path from a datastore_path.

    Split the VMware style datastore path to get the Datastore
    name and the entity path.
    """
    spl = datastore_path.split('[', 1)[1].split(']', 1)
    path = ""
    if len(spl) == 1:
        datastore_name = spl[0]
    else:
        datastore_name, path = spl
    return datastore_name, path.strip()


def file_delete(session, datastore_path, dc_ref):
    LOG.debug(_("Deleting the datastore file %s"), datastore_path)
    vim = session._get_vim()
    file_delete_task = session._call_method(
            session._get_vim(),
            "DeleteDatastoreFile_Task",
            vim.get_service_content().fileManager,
            name=datastore_path,
            datacenter=dc_ref)
    session._wait_for_task(file_delete_task)
    LOG.debug(_("Deleted the datastore file"))


def file_move(session, dc_ref, src_file, dst_file):
    """Moves the source file or folder to the destination.

    The list of possible faults that the server can return on error
    include:
    - CannotAccessFile: Thrown if the source file or folder cannot be
                        moved because of insufficient permissions.
    - FileAlreadyExists: Thrown if a file with the given name already
                         exists at the destination.
    - FileFault: Thrown if there is a generic file error
    - FileLocked: Thrown if the source file or folder is currently
                  locked or in use.
    - FileNotFound: Thrown if the file or folder specified by sourceName
                    is not found.
    - InvalidDatastore: Thrown if the operation cannot be performed on
                        the source or destination datastores.
    - NoDiskSpace: Thrown if there is not enough space available on the
                   destination datastore.
    - RuntimeFault: Thrown if any type of runtime fault is thrown that
                    is not covered by the other faults; for example,
                    a communication error.
    """
    LOG.debug(_("Moving file from %(src)s to %(dst)s."),
              {'src': src_file, 'dst': dst_file})
    vim = session._get_vim()
    move_task = session._call_method(
            session._get_vim(),
            "MoveDatastoreFile_Task",
            vim.get_service_content().fileManager,
            sourceName=src_file,
            sourceDatacenter=dc_ref,
            destinationName=dst_file,
            destinationDatacenter=dc_ref)
    session._wait_for_task(move_task)
    LOG.debug(_("File moved"))


def file_exists(session, ds_browser, ds_path, file_name):
    """Check if the file exists on the datastore."""
    client_factory = session._get_vim().client.factory
    search_spec = vm_util.search_datastore_spec(client_factory, file_name)
    search_task = session._call_method(session._get_vim(),
                                             "SearchDatastore_Task",
                                             ds_browser,
                                             datastorePath=ds_path,
                                             searchSpec=search_spec)
    try:
        task_info = session._wait_for_task(search_task)
    except error_util.FileNotFoundException:
        return False

    file_exists = (getattr(task_info.result, 'file', False) and
                   task_info.result.file[0].path == file_name)
    return file_exists


def mkdir(session, ds_path, dc_ref):
    """Creates a directory at the path specified. If it is just "NAME",
    then a directory with this name is created at the topmost level of the
    DataStore.
    """
    LOG.debug(_("Creating directory with path %s"), ds_path)
    session._call_method(session._get_vim(), "MakeDirectory",
            session._get_vim().get_service_content().fileManager,
            name=ds_path, datacenter=dc_ref,
            createParentDirectories=True)
    LOG.debug(_("Created directory with path %s"), ds_path)


def get_sub_folders(session, ds_browser, ds_path):
    """Return a set of subfolders for a path on a datastore.

    If the path does not exist then an empty set is returned.
    """
    client_factory = session._get_vim().client.factory
    search_task = session._call_method(
            session._get_vim(),
            "SearchDatastore_Task",
            ds_browser,
            datastorePath=ds_path)
    try:
        task_info = session._wait_for_task(search_task)
    except error_util.FileNotFoundException:
        return set()
    # populate the folder entries
    if hasattr(task_info.result, 'file'):
        return set([file.path for file in task_info.result.file])
    return set()
