#    Copyright 2012 OpenStack Foundation
#
#    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 cinder.i18n import _
from cinder.openstack.common import log as logging
from cinder.tests.brick.fake_lvm import FakeBrickLVM
from cinder.volume import driver
from cinder.volume.drivers import lvm
from cinder.zonemanager import utils as fczm_utils


LOG = logging.getLogger(__name__)


class FakeISCSIDriver(lvm.LVMISCSIDriver):
    """Logs calls instead of executing."""
    def __init__(self, *args, **kwargs):
        super(FakeISCSIDriver, self).__init__(execute=self.fake_execute,
                                              *args, **kwargs)
        self.vg = FakeBrickLVM('cinder-volumes', False,
                               None, 'default',
                               self.fake_execute)

    def check_for_setup_error(self):
        """No setup necessary in fake mode."""
        pass

    def initialize_connection(self, volume, connector):
        volume_metadata = {}
        for metadata in volume['volume_admin_metadata']:
            volume_metadata[metadata['key']] = metadata['value']
        access_mode = volume_metadata.get('attached_mode')
        if access_mode is None:
            access_mode = ('ro'
                           if volume_metadata.get('readonly') == 'True'
                           else 'rw')
        return {
            'driver_volume_type': 'iscsi',
            'data': {'access_mode': access_mode}
        }

    def terminate_connection(self, volume, connector, **kwargs):
        pass

    @staticmethod
    def fake_execute(cmd, *_args, **_kwargs):
        """Execute that simply logs the command."""
        LOG.debug("FAKE ISCSI: %s", cmd)
        return (None, None)


class FakeISERDriver(FakeISCSIDriver):
    """Logs calls instead of executing."""
    def __init__(self, *args, **kwargs):
        super(FakeISERDriver, self).__init__(execute=self.fake_execute,
                                             *args, **kwargs)

    def initialize_connection(self, volume, connector):
        return {
            'driver_volume_type': 'iser',
            'data': {}
        }

    @staticmethod
    def fake_execute(cmd, *_args, **_kwargs):
        """Execute that simply logs the command."""
        LOG.debug("FAKE ISER: %s", cmd)
        return (None, None)


class FakeFibreChannelDriver(driver.FibreChannelDriver):

    @fczm_utils.AddFCZone
    def initialize_connection(self, volume, connector):
        return {
            'driver_volume_type': 'fibre_channel',
            'data': {
                'initiator_target_map': {'fake_wwn': ['fake_wwn2']},
            }}

    @fczm_utils.AddFCZone
    def no_zone_initialize_connection(self, volume, connector):
        """This shouldn't call the ZM."""
        return {
            'driver_volume_type': 'bogus',
            'data': {
                'initiator_target_map': {'fake_wwn': ['fake_wwn2']},
            }}

    @fczm_utils.RemoveFCZone
    def terminate_connection(self, volume, connector, **kwargs):
        return {
            'driver_volume_type': 'fibre_channel',
            'data': {
                'initiator_target_map': {'fake_wwn': ['fake_wwn2']},
            }}

    @fczm_utils.RemoveFCZone
    def no_zone_terminate_connection(self, volume, connector, **kwargs):
        return {
            'driver_volume_type': 'bogus',
            'data': {
                'initiator_target_map': {'fake_wwn': ['fake_wwn2']},
            }}


class LoggingVolumeDriver(driver.VolumeDriver):
    """Logs and records calls, for unit tests."""

    def check_for_setup_error(self):
        pass

    def create_volume(self, volume):
        self.log_action('create_volume', volume)

    def delete_volume(self, volume):
        self.clear_volume(volume)
        self.log_action('delete_volume', volume)

    def clear_volume(self, volume):
        self.log_action('clear_volume', volume)

    def local_path(self, volume):
        LOG.error(_("local_path not implemented"))
        raise NotImplementedError()

    def ensure_export(self, context, volume):
        self.log_action('ensure_export', volume)

    def create_export(self, context, volume):
        self.log_action('create_export', volume)

    def remove_export(self, context, volume):
        self.log_action('remove_export', volume)

    def initialize_connection(self, volume, connector):
        self.log_action('initialize_connection', volume)

    def terminate_connection(self, volume, connector):
        self.log_action('terminate_connection', volume)

    _LOGS = []

    @staticmethod
    def clear_logs():
        LoggingVolumeDriver._LOGS = []

    @staticmethod
    def log_action(action, parameters):
        """Logs the command."""
        LOG.debug("LoggingVolumeDriver: %s" % (action))
        log_dictionary = {}
        if parameters:
            log_dictionary = dict(parameters)
        log_dictionary['action'] = action
        LOG.debug("LoggingVolumeDriver: %s" % (log_dictionary))
        LoggingVolumeDriver._LOGS.append(log_dictionary)

    @staticmethod
    def all_logs():
        return LoggingVolumeDriver._LOGS

    @staticmethod
    def logs_like(action, **kwargs):
        matches = []
        for entry in LoggingVolumeDriver._LOGS:
            if entry['action'] != action:
                continue
            match = True
            for k, v in kwargs.iteritems():
                if entry.get(k) != v:
                    match = False
                    break
            if match:
                matches.append(entry)
        return matches
