# Copyright (c) 2016 Huawei Technologies Co., Ltd.
# All Rights Reserved.
#
#    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 oslo_log import log as logging
from oslo_utils import excutils

from cinder import context
from cinder import exception
from cinder.i18n import _
from cinder import utils
from cinder.volume.drivers.huawei import constants
from cinder.volume import qos_specs

LOG = logging.getLogger(__name__)


class SmartQos(object):
    def __init__(self, client):
        self.client = client

    @staticmethod
    def get_qos_by_volume_type(volume_type):
        # We prefer the qos_specs association
        # and override any existing extra-specs settings
        # if present.
        if not volume_type:
            return {}

        qos_specs_id = volume_type.get('qos_specs_id')
        if not qos_specs_id:
            return {}

        qos = {}
        io_type_flag = None
        ctxt = context.get_admin_context()
        consumer = qos_specs.get_qos_specs(ctxt, qos_specs_id)['consumer']
        if consumer == 'front-end':
            return {}

        kvs = qos_specs.get_qos_specs(ctxt, qos_specs_id)['specs']
        LOG.info('The QoS sepcs is: %s.', kvs)
        for k, v in kvs.items():
            if k not in constants.HUAWEI_VALID_KEYS:
                continue
            if k != 'IOType' and int(v) <= 0:
                msg = _('QoS config is wrong. %s must > 0.') % k
                LOG.error(msg)
                raise exception.InvalidInput(reason=msg)
            if k == 'IOType':
                if v not in ['0', '1', '2']:
                    msg = _('Illegal value specified for IOTYPE: 0, 1, or 2.')
                    LOG.error(msg)
                    raise exception.InvalidInput(reason=msg)
                io_type_flag = 1
                qos[k.upper()] = v
            else:
                qos[k.upper()] = v

        if not io_type_flag:
            msg = (_('QoS policy must specify for IOTYPE: 0, 1, or 2, '
                     'QoS policy: %(qos_policy)s ') % {'qos_policy': qos})
            LOG.error(msg)
            raise exception.InvalidInput(reason=msg)

        # QoS policy must specify for IOTYPE and another qos_specs.
        if len(qos) < 2:
            msg = (_('QoS policy must specify for IOTYPE and another '
                     'qos_specs, QoS policy: %(qos_policy)s.')
                   % {'qos_policy': qos})
            LOG.error(msg)
            raise exception.InvalidInput(reason=msg)

        for upper_limit in constants.UPPER_LIMIT_KEYS:
            for lower_limit in constants.LOWER_LIMIT_KEYS:
                if upper_limit in qos and lower_limit in qos:
                    msg = (_('QoS policy upper_limit and lower_limit '
                             'conflict, QoS policy: %(qos_policy)s.')
                           % {'qos_policy': qos})
                    LOG.error(msg)
                    raise exception.InvalidInput(reason=msg)

        return qos

    def _is_high_priority(self, qos):
        """Check QoS priority."""
        for key, value in qos.items():
            if (key.find('MIN') == 0) or (key.find('LATENCY') == 0):
                return True

        return False

    @utils.synchronized('huawei_qos', external=True)
    def add(self, qos, lun_id):