# Copyright (c) 2013 - 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.
"""
Volume api for FusionStorage systems.
"""

import os
import re
import six

from oslo_log import log as logging

from cinder.i18n import _LE
from cinder import utils

LOG = logging.getLogger(__name__)
fsc_conf_file = "/etc/cinder/volumes/fsc_conf"
fsc_cli = "fsc_cli"
fsc_ip = []
fsc_port = '10519'
manage_ip = "127.0.0.1"
CMD_BIN = fsc_cli

volume_info = {
    'result': '',
    'vol_name': '',
    'father_name': '',
    'status': '',
    'vol_size': '',
    'real_size': '',
    'pool_id': '',
    'create_time': ''}


snap_info = {
    'result': '',
    'snap_name': '',
    'father_name': '',
    'status': '',
    'snap_size': '',
    'real_size': '',
    'pool_id': '',
    'delete_priority': '',
    'create_time': ''}


pool_info = {
    'result': '',
    'pool_id': '',
    'total_capacity': '',
    'used_capacity': '',
    'alloc_capacity': ''}


class FSPythonApi(object):

    def __init__(self):
        LOG.debug("FSPythonApi init.")
        self.get_ip_port()
        self.res_idx = len('result=')

    def get_ip_port(self):
        LOG.debug("File fsc_conf_file is %s.", fsc_conf_file)
        if os.path.exists(fsc_conf_file):
            try:
                fsc_file = open(fsc_conf_file, 'r')
                full_txt = fsc_file.readlines()
                LOG.debug("Full_txt is %s.", full_txt)
                for line in full_txt:
                    if re.search('^vbs_url=', line):
                        tmp_vbs_url = line[8:]
                        return re.split(',', tmp_vbs_url)
            except Exception as e:
                LOG.debug("Get fsc ip failed, error=%s.", e)
            finally:
                fsc_file.close()
        else:
            LOG.debug("Fsc conf file not exist, file_name=%s.", fsc_conf_file)

    def get_manage_ip(self):
        LOG.debug("File fsc_conf_file is %s.", fsc_conf_file)
        if os.path.exists(fsc_conf_file):
            try:
                fsc_file = open(fsc_conf_file, 'r')
                full_txt = fsc_file.readlines()
                for line in full_txt:
                    if re.search('^manage_ip=', line):
                        manage_ip = line[len('manage_ip='):]
                        manage_ip = manage_ip.strip('\n')
                        return manage_ip
            except Exception as e:
                LOG.debug("Get manage ip failed, error=%s.", e)
            finally:
                fsc_file.close()
        else:
            LOG.debug("Fsc conf file not exist, file_name=%s.", fsc_conf_file)

    def get_dsw_manage_ip(self):
        return manage_ip

    def start_execute_cmd(self, cmd, full_result_flag):
        fsc_ip = self.get_ip_port()
        manage_ip = self.get_manage_ip()
        ip_num = len(fsc_ip)

        LOG.debug("fsc_ip is %s", fsc_ip)

        if ip_num <= 0:
            return None

        if ip_num > 3:
            ip_num = 3

        exec_result = ''
        result = ''
        if full_result_flag:
            for ip in fsc_ip:
                cmd_args = [CMD_BIN, '--manage_ip', manage_ip.replace(
                    '\n', ''), '--ip', ip.replace('\n', '')] + cmd.split()
                LOG.debug("Dsware cmd_args is %s.", cmd_args)

                exec_result, err = utils.execute(*cmd_args, run_as_root=True)
                exec_result = exec_result.split('\n')
                LOG.debug("Result is %s.", exec_result)
                if exec_result:
                    for line in exec_result:
                        if re.search('^result=0', line):
                            return exec_result
                        elif re.search('^result=50150007', line):
                            return 'result=0'
                        elif re.search('^result=50150008', line):
                            return 'result=0'
                        elif re.search('^result=50', line):
                            return exec_result
            return exec_result
        else:
            for ip in fsc_ip:
                cmd_args = [CMD_BIN, '--manage_ip', manage_ip.replace(
                    '\n', ''), '--ip', ip.replace('\n', '')] + cmd.split()
                LOG.debug("Dsware cmd_args is %s.", cmd_args)

                exec_result, err = utils.execute(*cmd_args, run_as_root=True)
                LOG.debug("Result is %s.", exec_result)
                exec_result = exec_result.split('\n')
                if exec_result:
                    for line in exec_result:
                        if re.search('^result=', line):
                            result = line
                            if re.search('^result=0', line):
                                return line
                            elif re.search('^result=50150007', line):
                                return 'result=0'
                            elif re.search('^result=50150008', line):
                                return 'result=0'
                            elif re.search('^result=50', line):
                                return line
            return result

    def create_volume(self, vol_name, pool_id, vol_size, thin_flag):
        cmd = '--op createVolume' + ' ' + '--volName' + ' ' + six.text_type(
            vol_name) + ' ' + '--poolId' + ' ' + six.text_type(
            pool_id) + ' ' + '--volSize' + ' ' + six.text_type(
            vol_size) + ' ' + '--thinFlag' + ' ' + six.text_type(thin_flag)

        exec_result = self.start_execute_cmd(cmd, 0)
        if exec_result:
            if re.search('^result=0', exec_result):
                return 0
            else:
                return exec_result[self.res_idx:]
        else:
            return 1

    def extend_volume(self, vol_name, new_vol_size):
        cmd = ''
        cmd = '--op expandVolume' + ' ' + '--volName' + ' ' + six.text_type(
            vol_name) + ' ' + '--volSize' + ' ' + six.text_type(new_vol_size)

        exec_result = self.start_execute_cmd(cmd, 0)
        if exec_result:
            if re.search('^result=0', exec_result):
                return 0
            else:
                return exec_result[self.res_idx:]
        else:
            return 1

    def create_volume_from_snap(self, vol_name, vol_size, snap_name):
        cmd = ('--op createVolumeFromSnap' + ' ') + (
            '--volName' + ' ') + six.text_type(
            vol_name) + ' ' + '--snapNameSrc' + ' ' + six.text_type(
            snap_name) + ' ' + '--volSize' + ' ' + six.text_type(vol_size)

        exec_result = self.start_execute_cmd(cmd, 0)
        if exec_result:
            if re.search('^result=0', exec_result):
                return 0
            else:
                return exec_result[self.res_idx:]
        else:
            return 1

    def create_fullvol_from_snap(self, vol_name, snap_name):
        cmd = ('--op createFullVolumeFromSnap' + ' ') + (
            '--volName' + ' ') + six.text_type(
            vol_name) + ' ' + '--snapName' + ' ' + six.text_type(snap_name)

        exec_result = self.start_execute_cmd(cmd, 0)
        if exec_result:
            if re.search('^result=0', exec_result):
                return 0
            else:
                return exec_result[self.res_idx:]
        else:
            return 1

    def create_volume_from_volume(self, vol_name, vol_size, src_vol_name):
        retcode = 1
        tmp_snap_name = six.text_type(vol_name) + '_tmp_snap'

        retcode = self.create_snapshot(tmp_snap_name, src_vol_name, 0)
        if 0 != retcode:
            return retcode

        retcode = self.create_volume(vol_name, 0, vol_size, 0)
        if 0 != retcode:
            self.delete_snapshot(tmp_snap_name)
            return retcode

        retcode = self.create_fullvol_from_snap(vol_name, tmp_snap_name)
        if 0 != retcode:
            self.delete_snapshot(tmp_snap_name)
            self.delete_volume(vol_name)
            return retcode

        return 0

    def create_clone_volume_from_volume(self, vol_name,
                                        vol_size, src_vol_name):
        retcode = 1
        tmp_snap_name = six.text_type(src_vol_name) + '_DT_clnoe_snap'

        retcode = self.create_snapshot(tmp_snap_name, src_vol_name, 0)
        if 0 != retcode:
            return retcode

        retcode = self.create_volume_from_snap(
            vol_name, vol_size, tmp_snap_name)
        if 0 != retcode:
            return retcode

        return 0

    def volume_info_analyze(self, vol_info):
        local_volume_info = volume_info

        if not vol_info:
            local_volume_info['result'] = 1
            return local_volume_info

        local_volume_info['result'] = 0

        vol_info_list = []
        vol_info_list = re.split(',', vol_info)
        for line in vol_info_list:
            line = line.replace('\n', '')
            if re.search('^vol_name=', line):
                local_volume_info['vol_name'] = line[len('vol_name='):]
            elif re.search('^father_name=', line):
                local_volume_info['father_name'] = line[len('father_name='):]
            elif re.search('^status=', line):
                local_volume_info['status'] = line[len('status='):]
            elif re.search('^vol_size=', line):
                local_volume_info['vol_size'] = line[len('vol_size='):]
            elif re.search('^real_size=', line):
                local_volume_info['real_size'] = line[len('real_size='):]
            elif re.search('^pool_id=', line):
                local_volume_info['pool_id'] = line[len('pool_id='):]
            elif re.search('^create_time=', line):
                local_volume_info['create_time'] = line[len('create_time='):]
            else:
                LOG.error(_LE("Analyze key not exist, key=%s."),
                          six.text_type(line))
        return local_volume_info

    def query_volume(self, vol_name):
        tmp_volume_info = volume_info
        cmd = '--op queryVolume' + ' ' + '--volName' + ' ' + vol_name

        exec_result = self.start_execute_cmd(cmd, 1)
        if exec_result:
            for line in exec_result:
                if re.search('^result=', line):
                    if not re.search('^result=0', line):
                        tmp_volume_info['result'] = line[self.res_idx:]
                        return tmp_volume_info
                    for line in exec_result:
                        if re.search('^vol_name=' + vol_name, line):
                            tmp_volume_info = self.volume_info_analyze(line)
                            if six.text_type(0) == tmp_volume_info['status']:
                                tmp_snap_name = six.text_type(
                                    vol_name) + '_tmp_snap'
                                self.delete_snapshot(tmp_snap_name)
                            return tmp_volume_info

        tmp_volume_info['result'] = 1
        return tmp_volume_info

    def delete_volume(self, vol_name):
        cmd = '--op deleteVolume' + ' ' + '--volName' + ' ' + vol_name

        exec_result = self.start_execute_cmd(cmd, 0)
        if exec_result:
            if re.search('^result=0', exec_result):
                return 0
            else:
                return exec_result[self.res_idx:]
        else:
            return 1

    def create_snapshot(self, snap_name, vol_name, smart_flag):
        cmd = '--op createSnapshot' + ' ' + '--volName' + ' ' + six.text_type(
            vol_name) + ' ' + '--snapName' + ' ' + six.text_type(
            snap_name) + ' ' + '--smartFlag' + ' ' + six.text_type(smart_flag)

        exec_result = self.start_execute_cmd(cmd, 0)
        if exec_result:
            if re.search('^result=0', exec_result):
                return 0
            else:
                return exec_result[self.res_idx:]
        else:
            return 1

    def snap_info_analyze(self, info):
        local_snap_info = snap_info.copy()

        if not info:
            local_snap_info['result'] = 1
            return local_snap_info

        local_snap_info['result'] = 0

        snap_info_list = []
        snap_info_list = re.split(',', info)
        for line in snap_info_list:
            line = line.replace('\n', '')
            if re.search('^snap_name=', line):
                local_snap_info['snap_name'] = line[len('snap_name='):]
            elif re.search('^father_name=', line):
                local_snap_info['father_name'] = line[len('father_name='):]
            elif re.search('^status=', line):
                local_snap_info['status'] = line[len('status='):]
            elif re.search('^snap_size=', line):
                local_snap_info['snap_size'] = line[len('snap_size='):]
            elif re.search('^real_size=', line):
                local_snap_info['real_size'] = line[len('real_size='):]
            elif re.search('^pool_id=', line):
                local_snap_info['pool_id'] = line[len('pool_id='):]
            elif re.search('^delete_priority=', line):
                local_snap_info['delete_priority'] = line[
                    len('delete_priority='):]
            elif re.search('^create_time=', line):
                local_snap_info['create_time'] = line[len('create_time='):]
            else:
                LOG.error(_LE("Analyze key not exist, key=%s."),
                          line)

        return local_snap_info

    def query_snap(self, snap_name):
        tmp_snap_info = snap_info.copy()
        cmd = '--op querySnapshot' + ' ' + '--snapName' + ' ' + snap_name

        exec_result = self.start_execute_cmd(cmd, 1)
        if exec_result:
            for line in exec_result:
                if re.search('^result=', line):
                    if not re.search('^result=0', line):
                        tmp_snap_info['result'] = line[self.res_idx:]
                        return tmp_snap_info
                    for line in exec_result:
                        if re.search('^snap_name=' + snap_name, line):
                            tmp_snap_info = self.snap_info_analyze(line)
                            return tmp_snap_info

        tmp_snap_info['result'] = 1
        return tmp_snap_info

    def delete_snapshot(self, snap_name):
        cmd = '--op deleteSnapshot' + ' ' + '--snapName' + ' ' + snap_name

        exec_result = self.start_execute_cmd(cmd, 0)
        if exec_result:
            if re.search('^result=0', exec_result):
                return 0
            else:
                return exec_result[self.res_idx:]
        else:
            return 1

    def pool_info_analyze(self, info):
        local_pool_info = pool_info.copy()

        if not info:
            local_pool_info['result'] = 1
            return local_pool_info

        local_pool_info['result'] = 0

        pool_info_list = []
        pool_info_list = re.split(',', info)
        for line in pool_info_list:
            line = line.replace('\n', '')
            if re.search('^pool_id=', line):
                local_pool_info['pool_id'] = line[len('pool_id='):]
            elif re.search('^total_capacity=', line):
                local_pool_info['total_capacity'] = line[
                    len('total_capacity='):]
            elif re.search('^used_capacity=', line):
                local_pool_info['used_capacity'] = line[len('used_capacity='):]
            elif re.search('^alloc_capacity=', line):
                local_pool_info['alloc_capacity'] = line[
                    len('alloc_capacity='):]
            else:
                LOG.error(_LE("Analyze key not exist, key=%s."),
                          six.text_type(line))
        return local_pool_info

    def query_pool_info(self, pool_id):
        tmp_pool_info = pool_info.copy()
        cmd = '--op queryPoolInfo' + ' ' + '--poolId' + ' ' + six.text_type(
            pool_id)
        LOG.debug("Pool id is %s.", pool_id)
        exec_result = self.start_execute_cmd(cmd, 1)
        if exec_result:
            for line in exec_result:
                if re.search('^result=', line):
                    if not re.search('^result=0', line):
                        tmp_pool_info['result'] = line[self.res_idx:]
                        return tmp_pool_info
                    for line in exec_result:
                        if re.search('^pool_id=' + six.text_type(pool_id),
                                     line):
                            tmp_pool_info = self.pool_info_analyze(line)
                            return tmp_pool_info

        tmp_pool_info['result'] = 1
        return tmp_pool_info

    def query_pool_type(self, pool_type):
        pool_list = []
        tmp_pool_info = {}
        result = 0
        cmd = ''
        cmd = '--op queryPoolType --poolType' + ' ' + pool_type
        LOG.debug("Query poolType: %s.", pool_type)
        exec_result = self.start_execute_cmd(cmd, 1)
        if exec_result:
            for line in exec_result:
                line = line.replace('\n', '')
                if re.search('^result=', line):
                    if not re.search('^result=0', line):
                        result = int(line[self.res_idx:])
                        break
                    for one_line in exec_result:
                        if re.search('^pool_id=', one_line):
                            tmp_pool_info = self.pool_info_analyze(one_line)
                            pool_list.append(tmp_pool_info)
                    break
        return (result, pool_list)

    def query_dsware_version(self):
        retcode = 2
        cmd = '--op getDSwareIdentifier'
        exec_result = self.start_execute_cmd(cmd, 0)
        if exec_result:
            # New version.
            if re.search('^result=0', exec_result):
                retcode = 0
            # Old version.
            elif re.search('^result=50500001', exec_result):
                retcode = 1
            # Failed!
            else:
                retcode = exec_result[self.res_idx:]
        return retcode
