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

import base64
import os

from oslo_log import log as logging
import six
from six.moves import configparser

from cinder import exception
from cinder.i18n import _
from cinder import utils
from cinder.volume.drivers.fusionstorage import constants


LOG = logging.getLogger(__name__)


class FusionStorageConf(object):
    def __init__(self, configuration, host):
        self.configuration = configuration
        self._check_host(host)

    def _check_host(self, host):
        if host and len(host.split('@')) > 1:
            self.host = host.split('@')[1]
        else:
            msg = _("The host %s is not reliable. Please check cinder-volume "
                    "backend.") % host
            LOG.error(msg)
            raise exception.InvalidInput(reason=msg)

    def update_config_value(self):
        self._encode_authentication()
        self._pools_name()
        self._san_address()
        self._san_user()
        self._san_password()

    def _encode_authentication(self):
        name_node = self.configuration.safe_get(constants.CONF_USER)
        pwd_node = self.configuration.safe_get(constants.CONF_PWD)

        need_encode = False
        if name_node is not None and not name_node.startswith('!&&&'):
            encoded = base64.b64encode(six.b(name_node)).decode()
            name_node = '!&&&' + encoded
            need_encode = True

        if pwd_node is not None and not pwd_node.startswith('!&&&'):
            encoded = base64.b64encode(six.b(pwd_node)).decode()
            pwd_node = '!&&&' + encoded
            need_encode = True

        if need_encode:
            self._rewrite_conf(name_node, pwd_node)

    def _rewrite_conf(self, name_node, pwd_node):
        if os.path.exists(constants.CONF_PATH):
            utils.execute("chmod", "666", constants.CONF_PATH,
                          run_as_root=True)
            conf = configparser.ConfigParser()
            conf.read(constants.CONF_PATH)
            if name_node:
                conf.set(self.host, constants.CONF_USER, name_node)
            if pwd_node:
                conf.set(self.host, constants.CONF_PWD, pwd_node)
            fh = open(constants.CONF_PATH, 'w')
            conf.write(fh)
            fh.close()
            utils.execute("chmod", "644", constants.CONF_PATH,
                          run_as_root=True)

    def _assert_text_result(self, text, mess):
        if not text:
            msg = _("%s is not configured.") % mess
            LOG.error(msg)
            raise exception.InvalidInput(reason=msg)

    def _san_address(self):
        address = self.configuration.safe_get(constants.CONF_ADDRESS)
        self._assert_text_result(address, mess=constants.CONF_ADDRESS)
        setattr(self.configuration, 'san_address', address)

    def _decode_text(self, text):
        return (base64.b64decode(six.b(text[4:])).decode() if
                text.startswith('!&&&') else text)

    def _san_user(self):
        user_text = self.configuration.safe_get(constants.CONF_USER)
        self._assert_text_result(user_text, mess=constants.CONF_USER)
        user = self._decode_text(user_text)
        setattr(self.configuration, 'san_user', user)

    def _san_password(self):
        pwd_text = self.configuration.safe_get(constants.CONF_PWD)
        self._assert_text_result(pwd_text, mess=constants.CONF_PWD)
        pwd = self._decode_text(pwd_text)
        setattr(self.configuration, 'san_password', pwd)

    def _pools_name(self):
        pools_name = self.configuration.safe_get(constants.CONF_POOLS)
        self._assert_text_result(pools_name, mess=constants.CONF_POOLS)
        pools = set(x.strip() for x in pools_name.split(';') if x.strip())
        if not pools:
            msg = _('No valid storage pool configured.')
            LOG.error(msg)
            raise exception.InvalidInput(msg)
        setattr(self.configuration, 'pools_name', list(pools))

    def _manager_ip(self):
        manager_ips = self.configuration.safe_get(constants.CONF_MANAGER_IP)
        self._assert_text_result(manager_ips, mess=constants.CONF_MANAGER_IP)
        setattr(self.configuration, 'manager_ips', manager_ips)
