#    Copyright 2016 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 oslo_log import log

from bareon_allocator.objects import Disk
from bareon_allocator.objects import Space
from bareon_allocator.parsers import ExpressionsParser


LOG = log.getLogger(__name__)


class DynamicSchemaParser(object):

    def __init__(self, hw_info, schema):
        self.hw_info = hw_info
        self.schema = schema
        self.raw_disks = self.hw_info['disks']
        self.rendered_spaces = []
        self.disks = []
        self.spaces = []
        # TODO(eli): In the future should be moved into config.
        self.strategies = {
            'vg': {'strategy': 'container'},
            'lv': {'strategy': 'elastic'},
            'partitions': {'strategy': 'elastic'}
        }

        self.parse()
        self.post_parse()

    def parse(self):
        self.render_expressions()

        self.disks = [
            Disk(**disk)
            for disk in self.raw_disks]

        for s in self.rendered_spaces:
            strategy = self.strategies.get(s['type'], {}).get('strategy')
            if strategy == 'elastic':
                self.spaces.append(Space(**s))
            elif strategy is None:
                LOG.warn('There is not strategy for space %s', s)

    def post_parse(self):
        # Add fake volume Unallocated, in order to be able
        # to have only volumes with minimal size, without
        # additional space allocation
        self.spaces.append(Space(
            id='unallocated',
            type='unallocated',
            none_order=True,
            weight=0))

    def render_expressions(self):
        self.rendered_spaces = self._convert_disks_to_indexes(
            ExpressionsParser(self.schema, self.hw_info).parse(),
            self.hw_info)

    def _convert_disks_to_indexes(self, spaces, hw_info):
        """Convert disks to indexes.

        Convert disks which are specified in `best_with_disks`
        to a list of indexes in `disks` list.
        """
        for i, space in enumerate(spaces):

            if space.get('best_with_disks'):
                disks_ids = set()
                for disk in space['best_with_disks']:
                    try:
                        disks_ids.add(disk['id'])
                    except ValueError as exc:
                        LOG.warn('Warning: %s', exc)

                spaces[i]['best_with_disks'] = disks_ids

        return spaces