# Copyright (c) 2014 Mirantis 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.


from itertools import ifilter

from cinderclient.v1 import client as cinder_client
from cinderclient import exceptions as cinder_exc

from cloudferrylib.base import storage
from cloudferrylib.os.identity import keystone
from cloudferrylib.os.storage import filters as cinder_filters
from cloudferrylib.utils import filters
from cloudferrylib.utils import log
from cloudferrylib.utils import proxy_client
from cloudferrylib.utils import retrying
from cloudferrylib.utils import utils

import re

RE_EXTRACT_HOST = re.compile(r'//([^:^/]*)')

AVAILABLE = 'available'
IN_USE = "in-use"
CINDER_VOLUME = "cinder-volume"
LOG = log.getLogger(__name__)
ID = 'id'
DISPLAY_NAME = 'display_name'
PROJECT_ID = 'project_id'
STATUS = 'status'
TENANT_ID = 'tenant_id'
USER_ID = 'user_id'
DELETED = 'deleted'
HOST = 'host'
IGNORED_TBL_LIST = ('quotas', 'quota_usages')
QUOTA_TABLES = (
    'quotas',
    'quota_classes',
    'quota_usages',
)
SRC = 'src'
TABLE_UNIQ_KEYS = {
    'volumes': ['id'],
    'quotas': ['project_id', 'resource'],
    'quota_classes': ['class_name', 'resource'],
    'quota_usages': ['project_id', 'resource'],
    'reservations': ['project_id', 'resource', 'usage_id'],
    'volume_metadata': ['volume_id', 'key'],
    'volume_glance_metadata': ['volume_id', 'snapshot_id', 'key'],
}

VALID_STATUSES = ['available', 'in-use', 'attaching', 'detaching']
MIGRATED_VOLUMES_METADATA_KEY = 'src_volume_id'


class CinderStorage(storage.Storage):

    """Implements basic functionality around cinder client"""

    def __init__(self, config, cloud):
        super(CinderStorage, self).__init__(config)
        self.ssh_host = config.cloud.ssh_host
        self.mysql_host = config.mysql.db_host \
            if config.mysql.db_host else self.ssh_host
        self.cloud = cloud
        self.identity_client = cloud.resources[utils.IDENTITY_RESOURCE]
        self.mysql_connector = cloud.mysql_connector('cinder')
        self.volume_filter = None
        self.filter_tenant_id = None

    @property
    def cinder_client(self):
        return self.proxy(self.get_client(self.config), self.config)

    def get_client(self, params=None, tenant=None):
        params = params or self.config

        return cinder_client.Client(
            params.cloud.user,
            params.cloud.password,
            tenant or params.cloud.tenant,
            params.cloud.auth_url,
            cacert=params.cloud.cacert,
            insecure=params.cloud.insecure,
            region_name=params.cloud.region
        )

    def get_filter(self):
        if self.volume_filter is None:
            with open(self.config.migrate.filter_path, 'r') as f:
                filter_yaml = filters.FilterYaml(f)
                filter_yaml.read()

            self.volume_filter = cinder_filters.CinderFilters(
                self.cinder_client, filter_yaml)

        return self.volume_filter

    def read_info(self, target='volumes', **kwargs):
        if target == 'volumes':
            return self._read_info_volumes(**kwargs)
        if target == 'resources':
            return self._read_info_resources(**kwargs)

    def _read_info_resources(self, **kwargs):
        res = dict()
        self.filter_tenant_id = kwargs.get('tenant_id', None)
        res['quotas'] = self._read_info_quota()
        return res

    def _read_info_volumes(self, **kwargs):
        info = {utils.VOLUMES_TYPE: {}}
        for vol in self.get_volumes_list(search_opts=kwargs):
            if vol.status not in ['available', 'in-use']:
                continue

            volume = self.convert_volume(vol, self.config, self.cloud)
            snapshots = {}
            if self.config.migrate.keep_volume_snapshots:
                search_opts = {'volume_id': volume['id']}
                for snap in self.get_snapshots_list(search_opts=search_opts):
                    snapshot = self.convert_snapshot(snap,
                                                     volume,
                                                     self.config,
                                                     self.cloud)
                    snapshots[snapshot['id']] = snapshot
            info[utils.VOLUMES_TYPE][vol.id] = {utils.VOLUME_BODY: volume,
                                                'snapshots': snapshots,
                                                utils.META_INFO: {
                                                }}