# -*- coding: UTF-8 -*-
import re
import time
from frame.cli import cliResource
from cbb.frame.util.common import wrapAllExceptionLogged

MAX_RETRYS = 5
CLI_EXECUTE_CMD_SUCCESS = "Command executed successfully"
DEVELOPER_MODEL_FLAG = "developer:/>"
CLI_RET_END_FLAG = ":/>"
DEBUG_MODEL_FLAG = ":/diagnose>"
MINISYSTEM_MODEL_FLAG = "minisystem>"
RESULT_NOCHECK = "NOCHECK"
SERIES_T = "T_SERIES"
SERIES_V3 = "V3_SERIES"
SERIES_18000 = "18000_SERIES"

CLI_CAN_NOT_CONNECT_CODE = "1073949185" #与设备通信异常，请检查网络连接或设备状态是否正常

STOR_DEV_INFO_DICT = {
"S2600T":SERIES_T,
"S5500T":SERIES_T,
"S5600T":SERIES_T,
"S5800T":SERIES_T,
"S6800T":SERIES_T,
"5300 V3":SERIES_V3,
"5500 V3":SERIES_V3,
"5600 V3":SERIES_V3,
"5800 V3":SERIES_V3,
"6800 V3":SERIES_V3,
"6900 V3":SERIES_V3,
"HVS85T":SERIES_18000,
"HVS88T":SERIES_18000,
"18500":SERIES_18000,
"18800":SERIES_18000,
"18800F":SERIES_18000,
}

class CheckStatus():
    ERROR = 'ERROR'

def getMsg(lang, msg, args="", resource=cliResource.MESSAGES_DICT):
    '''
    @summary: 消息国际化
    @param lang: 语言lang
    @param msg: 消息
    @param args: 消息参数
    @param resource: 消息字典
    @return: 经过国际化处理后的消息
    '''
    errMsg = "\n--"

    try:
        if not resource.has_key(msg):
            return errMsg

        localeDict = resource.get(msg)
        if not localeDict.has_key(lang):
            return errMsg

        localeMsg = localeDict.get(lang)
        if "%s" in localeMsg or "%i" in localeMsg:
            return localeMsg % args
        else:
            return localeMsg

    except:
        return errMsg

def isChinese(lang):
    '''
    @summary: 判断lang是否为中文
    @param lang: 语言lang
    @return: 
        True: 中文
        False: 非中文
    '''
    if lang == "zh":
        return True
    return False

def isNoneLicense(cliRet):
    '''
    @summary: 判断回显结果里面是否包含需要license
    @param cliRet: cli回显
    @return: 
        True: cli回显包含需要license
        False: cli回显不包含需要license
    '''
    cliRetList = cliRet.splitlines()
    for line in cliRetList:
        lowerLine = line.lower()
        if "license" in lowerLine and ("error" in lowerLine or "suggestion" in lowerLine):
            return True

    return False

def queryResultWithNoRecord(cliRet):
    '''
    @summary: 判断回显是否为Command executed successfully
    @param cliRet: cli回显
    @return: 
        True: cli回显中包含Command executed successfully
        False: cli回显中不包含Command executed successfully
    '''
    if re.search(CLI_EXECUTE_CMD_SUCCESS, cliRet, re.IGNORECASE):
        return True
    return False

def isInternalError(cliRet):
    '''
    @summary: 判断回显结果是否包含内部错误信息
    @param cliRet: cli回显
    @return: 
        True: cli回显包含内部错误信息
        False: cli回显不包含内部错误信息
    '''
    lowerCliRet = cliRet.lower()
    if "internal error" in lowerCliRet:
        return True
    else:
        return False

def getUserName(cli, lang):
    '''
    @summary: 获取设备上登录的用户名
    @param cli: cli对象
    @param cli: 语言lang
    @return: (falg, ret, errMsg)
        flag: 
            True: 获取成功
            False: 获取失败
        ret: 
            flag为True时，返回设备上登录的用户名
            flag为False时，返回cli回显结果
        errMsg: 错误消息
    '''
    cliRet = ""
    errMsg = ""
    userName = ""

    try:
        cmd = "show system general"
        checkRet = execCmdInCliMode(cli, cmd, True, lang)
        if not checkRet[0]:
            return checkRet

        cliRet = checkRet[1]
        lineList = cliRet.splitlines()

        if len(lineList) == 0:
            errMsg = getMsg(lang, "cannot.get.sys.info")
            return (False, cliRet, errMsg)

        lastLine = lineList[-1]
        if CLI_RET_END_FLAG in lastLine:
            userName = lastLine.replace(" ", "").replace(CLI_RET_END_FLAG, "")
            return (True, userName, errMsg)

    except:
        errMsg = getMsg(lang, "cannot.get.sys.info")
        return (False, cliRet, errMsg)

    return (False, cliRet, errMsg)

def getUserPrivilege(cli, lang):
    '''
    @summary: 获取用户权限级别
    @param cli: cli对象
    @param cli: 语言lang
    @return: (falg, ret, errMsg)
        flag: 
            True: 获取成功
            False: 获取失败
        ret: 
            flag为True时，返回用户权限级别
            flag为False时，返回cli回显结果
        errMsg: 错误消息
    '''
    cliRet = ""
    errMsg = ""

    try:
        checkRet = getUserName(cli, lang)
        if not checkRet:
            return checkRet

        userName = checkRet[1]
        cmd = "show user user_name=%s" % userName
        checkRet = execCmdInCliMode(cli, cmd, True, lang)
        if not checkRet[0]:
            return checkRet

        cliRet = checkRet[1]
        cliRetLinesList = getHorizontalCliRet(cliRet)

        if len(cliRetLinesList) == 0:
            errMsg = getMsg(lang, "cannot.get.user.info")
            return (False, cliRet, errMsg)

        for line in cliRetLinesList:
            name = line["Name"]
            if name == userName:
                userPrivilege = line["Level"]
                return (True, userPrivilege, errMsg)

    except:
        errMsg = getMsg(lang, "cannot.get.user.info")
        return (False, cliRet, errMsg)

    return (False, cliRet, errMsg)

def hasAdminOrSuperAdminPrivilege(cli, lang):
    '''
    @summary: 判断用户是否具有管理员或超级管理员权限
    @param cli: cli对象
    @param cli: 语言lang
    @return: (falg, ret, errMsg)
        flag: 
            True: 获取成功
            False: 获取失败
        ret: 
            flag为True时
                True: 具有管理员或超级管理员权限
                False： 不具有管理员或超级管理员权限
            flag为False时，返回cli回显结果
        errMsg: 错误消息
    '''
    checkRet = getUserPrivilege(cli, lang)
    if not checkRet[0]:
        return checkRet

    userLevel = checkRet[1]
    if userLevel is None or len(userLevel) == 0 or userLevel.lower() not in ["super_admin", "admin"]:
        return (True, False, "")
    else:
        return (True, True, "")

def hasSuperAdminPrivilege(cli, lang):
    '''
    @summary: 判断用户是否具有超级管理员权限
    @param cli: cli对象
    @param cli: 语言lang
    @return: (falg, ret, errMsg)
        flag: 
            True: 获取成功
            False: 获取失败
        ret: 
            flag为True时
                True: 具有超级管理员权限
                False： 不具有超级管理员权限
            flag为False时，返回cli回显结果
        errMsg: 错误消息
    '''
    checkRet = getUserPrivilege(cli, lang)
    if not checkRet[0]:
        return checkRet

    userLevel = checkRet[1]
    if userLevel is None or len(userLevel) == 0 or userLevel.lower() not in ["super_admin"]:
        return (True, False, "")
    else:
        return (True, True, "")

def enterDeveloperMode(cli, lang):
    '''
    @summary: 进入developer模式
    @param cli: cli对象
    @param lang: 语言lang
    @return: (falg, cliRet, errMsg)
        flag:
            True: 进入developer模式成功
            False: 进入developer模式失败
        cliRet: cli回显
        errMsg: 进入developer模式失败时的错误消息
    '''
    errMsg = ""
    cliRet = ""

    try:
        cmd = "change user_mode current_mode user_mode=developer"
        checkRet = execCmdInCliMode(cli, cmd, True, lang)
        if not checkRet[0]:
            return checkRet

        cliRet = checkRet[1]

        # 需要确认直接输入y
        cnt = 1
        while "y/n" in cliRet and cnt <= 3:
            cliRet = cli.execCmd("y")
            cnt += 1

        if isInDeveloperMode(cliRet):
            return (True, cliRet, errMsg)
        else:
            errMsg = getMsg(lang, "cannot.access.developer.mode")
            return (False, cliRet, errMsg)

    except:
        errMsg = getMsg(lang, "cannot.access.developer.mode")
        return (False, cliRet, errMsg)

def developerMode2CliMode(cli):
    '''
    @summary: developer模式下退回到cli模式
    @param cli: cli对象
    '''
    index = 0
    try:
        cliRet = cli.execCmd("show system general")
        while ("Password is wrong" in cliRet or "Password:" in cliRet or isInDeveloperMode(cliRet)):
            index += 1
            cliRet = cli.execCmd("exit")
            if "Are you sure to exit?(y/n):" in cliRet:
                cliRet = cli.execCmd("n")
            if index > MAX_RETRYS:
                break
    except:
        return None

    return None

def isInDeveloperMode(cliRet):
    '''
    @summary: 判断当前是否在developer模式下
    @param cliRet: cli回显
    @return: 
        True: 当前在developer模式下
        False: 当前不在developer模式下
    '''
    if re.search(DEVELOPER_MODEL_FLAG, cliRet, re.IGNORECASE):
        return True
    return False

def checkLineInBlackList(cliLine, lang):
    '''
    @summary: 判断cli语句行是否在黑名单中
    @param cliLine: cli语句行
    @param lang: 语言lang
    @return: 
        True: cli语句行在黑名单中
        False: cli语句行不在黑名单中
    '''
    errMsg = ""

    for dictItems in cliResource.BLACKLIST_DICT:
        if dictItems.get("key_word") in cliLine:
            if isChinese(lang):
                errMsg = dictItems.get("msg_zh")
            else:
                errMsg = dictItems.get("msg_en")
            return (True, errMsg)
    return (False, errMsg)

def execCmdInCliMode(cli, cmd, logResult, lang):
    '''
    @summary: 获取cli模式下执行命令后的回显
    @param cli: cli对象
    @param cmd: 待执行命令
    @param logResult: 是否需要以有log的方式执行cli命令下发
    @param lang: 语言lang
    @return: (falg, cliRet, errMsg)
        flag:
            True: 执行命令正常
            False: 执行命令不正常
        cliRet: cli回显
        errMsg: 错误消息
    '''
    errMsg = ""
    cliRet = ""

    if cli is None:
        errMsg = getMsg(lang, "device.connect.abnormal")
        raise Exception(CLI_CAN_NOT_CONNECT_CODE, "")
        return (False, cliRet, errMsg)

    try:
        cliRet = execCliCmd(cli, cmd, logResult)
    except:
        errMsg = getMsg(lang, "device.connect.abnormal")
        raise Exception(CLI_CAN_NOT_CONNECT_CODE, "")
        return (False, cliRet, errMsg)

    if len(cliRet) == 0:
        errMsg = getMsg(lang, "cli.result.is.empty")
        return (False, cliRet, errMsg)

    if queryResultWithNoRecord(cliRet):
        return (True, cliRet, errMsg)

    if isNoneLicense(cliRet):
        return (True, cliRet, errMsg)

    if isInternalError(cliRet):
        return (True, cliRet, errMsg)

    lineList = cliRet.splitlines()
    for line in lineList:
        checkRet = checkLineInBlackList(line, lang)
        if checkRet[0]:
            errMsg = getMsg(lang, "system.status.abnormal")
            return (False, cliRet, errMsg)

    return (True, cliRet, errMsg)

def execCmdInDeveloperMode(cli, cmd, isHasLog, lang):
    '''
    @summary: 获取developer模式下执行命令后的回显
    @param cli: cli对象
    @param cmd: 待执行命令
    @param isHasLog: 是否需要以有log的方式执行cli命令下发
    @param lang: 语言lang
    @return: (falg, ret, errMsg)
        flag:
            True: 执行命令正常
            False: 执行命令不正常
        ret: cli回显
        errMsg: 错误消息
    '''
    isOpened = False
    try:
        isOpened, checkRet = needOpenDeveloperSwitch(cli, lang)

        if isOpened == True:
            checkRet = openDeveloperSwitch(cli, lang)
            if checkRet[0] != True:
                return checkRet

        enterDeveloperCheckRet = enterDeveloperMode(cli, lang)
        if not enterDeveloperCheckRet[0]:
            developerMode2CliMode(cli)
            return enterDeveloperCheckRet

        checkRet = execCmdInCliMode(cli, cmd, isHasLog, lang)
        cliRet = checkRet[1]

        if isInDeveloperMode(cliRet):
            developerMode2CliMode(cli)

        return checkRet
    finally:
        #关闭开关
        if isOpened == True :
            closeDeveloperSwitch(cli, lang)

def excuteCmdInDebugModel(cli, cmd, lang):
    """
    @summary: 在debug模式下执行命令
    """
    cliRet = ''
    try:
        _, cliRet, _ = execCmdInCliMode(cli, cmd, True, lang)

        if isInDebugMode(cliRet):
            return (True, cliRet, "")

        if isInMinisystemMode(cliRet):
            cliRet = cli.execCmd("exit")
            if "(y/n)" in cliRet:
                cliRet = cli.execCmd("y")

        if isInDeveloperMode(cliRet):
            cliRet = cli.execCmd("debug")
            if isInDebugMode(cliRet):
                cliRet = execCmdInCliMode(cli, cmd, True, lang)
                return (True, cliRet, "")

            return (False, cliRet, getMsg(lang, "has.not.cli.privilege"))

        flag, cliRet, errMsg = enterDebugModeFromCliMode(cli, lang)
        if flag != True:
            return flag, cliRet, errMsg

        flag, cliRet, errMsg = execCmdInCliMode(cli, cmd, True, lang)
        return (flag, cliRet, errMsg)
    except:
        return (False, cliRet, "")


def enterCliModeFromDebugModel(cli, lang):
    '''
    @summary: 从debug模式进入cli模式
    '''
    cmd = "exit"
    #切换到developer
    checkRet = execCmdInCliMode(cli, cmd, True, lang)
    if checkRet[0] != True:
        return checkRet

    #切换到CLI
    checkRet = execCmdInCliMode(cli, cmd, True, lang)
    return checkRet



def isInMinisystemMode(cliRet):
    '''
    @summary: 判断当前是否在minisystem模式下
    '''
    if re.search(MINISYSTEM_MODEL_FLAG, cliRet, re.IGNORECASE):
        return True
    return False


def enterDebugModeFromCliMode(cli, lang):
    '''
    @summary: 从cli模式进入debug模式
    '''
    allCliRet = ""

    #进入devoper模式
    checkRet = enterDeveloperMode(cli, lang)
    allCliRet += checkRet[1]
    if checkRet[0] != True:
        return checkRet

    cmd = "debug"
    checkRet = execCmdInCliMode(cli, cmd, True, lang)
    allCliRet += "\n" + checkRet[1]
    if checkRet[0] != True:
        return (checkRet[0], allCliRet, checkRet[2])

    if isInDebugMode(checkRet[1]):
        return (True, allCliRet, "")
    else:
        errMsg = getMsg(lang, "has.not.cli.privilege")
        return (RESULT_NOCHECK, allCliRet, errMsg)


def isInDebugMode(cliRet):
    '''
    @summary: 判断当前是否在debug模式下
    '''
    if re.search(DEBUG_MODEL_FLAG, cliRet, re.IGNORECASE):
        return True
    return False


def getProductModelVersion(cli, lang):
    '''
    @summary: 获取产品类型和产品版本
    @param cli: cli对象
    @param lang: 语言lang
    @return: (falg, ret, errMsg)
        flag:
            True: 获取成功
            False: 获取失败
        ret: 
            flag为True时，产品类型 产品版本 
            flag为False时，cli回显
        errMsg: 错误消息
    '''
    cmd = "show system general"
    checkRet = execCmdInCliMode(cli, cmd, True, lang)
    if not checkRet[0]:
        return checkRet

    cliRet = checkRet[1]
    cliRetList = cliRet.splitlines()
    product_model = ""
    product_version = ""
    for line in cliRetList:
        fields = line.split(":")
        if len(fields) < 2:
            continue

        fieldName = fields[0].strip()
        fieldValue = fields[1].strip()

        if fieldName == "Product Model":
            product_model = fieldValue
        elif fieldName == "Product Version":
            product_version = fieldValue

        if len(product_model) != 0 and len(product_version) != 0 and product_model != "--" and product_version != "--":
            return (True, " ".join((product_model, product_version)), "")

    return (False, cliRet, getMsg(lang, "cannot.get.product.version.info"))

def getProductModel(cli, lang):
    '''
    @summary: 获取产品类型
    @param cli: cli对象
    @param lang: 语言lang
    @return: (falg, ret, errMsg)
        flag:
            True: 获取成功
            False: 获取失败
        ret: 
            flag为True时，产品类型
            flag为False时，cli回显
        errMsg: 错误消息
    '''
    cmd = "show system general"
    checkRet = execCmdInCliMode(cli, cmd, True, lang)
    if not checkRet[0]:
        return checkRet

    cliRet = checkRet[1]
    cliRetList = cliRet.splitlines()
    product_model = ""
    for line in cliRetList:
        fields = line.split(":")
        if len(fields) < 2:
            continue

        fieldName = fields[0].strip()
        fieldValue = fields[1].strip()

        if fieldName == "Product Model":
            product_model = fieldValue

        if len(product_model) != 0 and product_model != "--":
            return (True, product_model, "")

    return (False, cliRet, getMsg(lang, "cannot.get.product.model.info"))

def getStorageType(cli, lang):
    '''
    @summary: 获取存储设备类型
    @param cli: cli对象
    @param lang: 语言lang
    @return: (falg, ret, errMsg)
        flag:
            True: 获取成功
            False: 获取失败
        ret: 
            flag为True时，存储设备类型
            flag为False时，cli回显
        errMsg: 错误消息
    '''
    getProductModelRet = getProductModel(cli, lang)
    if not getProductModelRet[0]:
        return getProductModelRet

    pdtModel = getProductModelRet[1]

    if not STOR_DEV_INFO_DICT.has_key(pdtModel):
        errMsg = getMsg(lang, "cannot.get.storage.type.info")
        return (False, "", errMsg)

    storageType = STOR_DEV_INFO_DICT.get(pdtModel)
    return (True, storageType, "")

def getHorizontalCliRet(cliRet):
    '''
    @summary: 按逐行字典的方式获取水平表格形式的cli回显集合
    @param cliRet: cli回显
    @return: 将表格形式cli回显处理为以表头为key，以项值为键的字典集合,处理不正常时，返回空集合
    '''
    try:
        headline = ""
        i = 0
        cliRetList = cliRet.encode("utf8").splitlines()
        for line in cliRetList:
            reg_headline = re.compile("^\s*-+(\s+-+)*\s*$")
            match_headline = reg_headline.search(line)
            if match_headline:
                headline = match_headline.group()
                break
            i += 1
        if headline == "" or i == 0 or i >= len(cliRetList) - 1:
            return []

        title = cliRetList[i - 1]
        field_words = cliRetList[(i + 1):]
        reg_split = re.compile("\s*-+\s*")
        tuple_idxs = []
        start_pos = 0
        end_pos = 0

        while (start_pos <= len(headline)):
            match = reg_split.search(headline, start_pos)
            if match:
                end_pos = match.end()
                tuple_idxs.append((start_pos, end_pos))
                start_pos = end_pos
            else:
                break

        keys = []
        for item in tuple_idxs:
            key = title[item[0]:item[1]].strip()
            if keys.count(key):
                key += "_" + str(str(keys).count(key + "_") + 1)
            keys.append(key.decode("utf8"))

        requiredLineLen = tuple_idxs[-1][0]
        dictList = []
        for line in field_words:
            if CLI_RET_END_FLAG in line:
                break

            if line.strip().endswith(":"):
                break

            if len(line) <= requiredLineLen:
                break

            vals = []
            for item in tuple_idxs:
                vals.append(line[item[0]:item[1]].strip().decode("utf8"))
            dictList.append(dict(zip(keys, vals)))

        return dictList
    except:
        return []

def getVerticalCliRet(cliRet):
    '''
    @summary: 按逐行字典的方式获取垂直表格形式的cli回显集合
    @param cliRet: cli回显
    @return: 将表格形式cli回显处理为以表头为key，以项值为键的字典集合,处理不正常时，返回空集合
    '''
    cliRetList = cliRet.encode("utf8").splitlines()
    dictList = []
    lineDict = {}
    for line in cliRetList:
        if CLI_RET_END_FLAG in line:
            break

        if re.search("^-+\r*\n*$", line):
            dictList.append(lineDict.copy())
            lineDict.clear()

        fields = line.split(" : ")
        if len(fields) < 2:
            continue

        key = fields[0].strip().decode("utf8")
        value = ":".join(fields[1:len(fields)]).strip().decode("utf8")

        if lineDict.has_key(key):
            key += "_" + str(str(lineDict.keys()).count(key + "_") + 1)
        lineDict.setdefault(key, value)

    if len(lineDict) > 0:
        dictList.append(lineDict.copy())

    return dictList

def getSplitedCliRet(cliRet, splitMark):
    '''
    @summary: 按分割标记从回显中获取仅包含该分割标记对应的的回显
    @param cliRet: cli回显
    @param splitMark: 分割标记 
    '''
    cliRetlist = cliRet.split(splitMark)
    if len(cliRetlist) < 2:
        return ""

    splitedCliRet = cliRetlist[1]
    match = re.search("^.*:(/>)*\r*\n*$", splitedCliRet, re.MULTILINE)
    if match:
        splitedCliRet = splitedCliRet[0:match.start()]

    if len(splitedCliRet.strip()) == 0:
        return ""
    else:
        return splitedCliRet

def isEngineId(value):
    '''
    @summary: 根据id判断是否为引擎ID
    @param value: 回显中的ID
    @return: 
        True: 是引擎ID
        False: 不是引擎ID
    '''
    if "ENG" in value or "CTE" in value:
        return True
    else:
        return False

def isDiskId(value):
    '''
    @summary: 根据id判断是否为硬盘ID
    @param value: 回显中的ID
    @return: 
        True: 是硬盘ID
        False: 不是硬盘ID
    '''
    if "DAE" in value:
        return True
    else:
        return False

def isDataSwitchId(value):
    '''
    @summary: 根据id判断是否为交换机ID
    @param value: 回显中的ID
    @return: 
        True: 是交换机ID
        False: 不是交换机ID
    '''
    if "DSW" in value:
        return True
    else:
        return False

def isHighDensityDisk(enclosureId, cli, lang):
    '''
    @summary: 判断硬盘框是否为高密框
    @param enclosureId: 框ID
    @param cli: cli对象
    @param lang: 语言lang
    @return: (flag, ret, errMsg)
        flag: 
            True： 判断时正常
            False： 判断时异常
        ret: 
            flag为True时，是高密框
            flag为False时，不是高密框
        errMsg: 错误时的消息
    '''
    if not isDiskId(enclosureId):
        return (True, False, "")

    checkRet = getHighDensityDiskEnclosureIdList(cli, lang)
    if not checkRet[0]:
        return checkRet

    highDensityDiskEnclosureIdList = checkRet[1]
    if enclosureId in highDensityDiskEnclosureIdList:
        return (True, True, "")
    else:
        return (True, False, "")

def getEnclosureHeight(cli, enclosureId, lang):
    '''
    @summary: 根据框ID获取框高度(U)
    @param cli: cli对象
    @param enclosureId: 框ID
    @param lang: 语言lang
    @return: (falg, ret, errMsg)
        flag:
            True: 获取成功
            False: 获取失败
        ret: 
            flag为True时，框ID对应的高度(U)
            flag为False时，cli回显
        errMsg: 错误消息
    '''

    cmd = "show enclosure enclosure_id=%s|filterColumn include columnList=Height(U)" % enclosureId
    checkRet = execCmdInCliMode(cli, cmd, True, lang)
    if not checkRet[0]:
        return checkRet

    cliRet = checkRet[1]
    cliRetList = cliRet.splitlines()
    for line in cliRetList:
        fields = line.split(":")
        if len(fields) < 2:
            continue

        fieldName = fields[0].strip()
        fieldValue = fields[1].strip()

        if fieldName == "Height(U)":
            enclosureHeight = fieldValue
            return (True, enclosureHeight, "")

    errMsg = getMsg(lang, "cannot.get.enclosure.info")
    return (False, cliRet, errMsg)

def getEnclosureType(cli, enclosureId, lang):
    '''
    @summary: 根据框ID获取框类型
    @param cli: cli对象
    @param enclosureId: 框ID
    @param lang: 语言lang
    @return: (falg, ret, errMsg)
        flag:
            True: 获取成功
            False: 获取失败
        ret: 
            flag为True时，框ID对应的类型
            flag为False时，cli回显
        errMsg: 错误消息
    '''

    cmd = "show enclosure enclosure_id=%s|filterColumn include columnList=Type" % enclosureId
    checkRet = execCmdInCliMode(cli, cmd, True, lang)
    if not checkRet[0]:
        return checkRet

    cliRet = checkRet[1]
    cliRetList = cliRet.splitlines()
    for line in cliRetList:
        fields = line.split(":")
        if len(fields) < 2:
            continue

        fieldName = fields[0].strip()
        fieldValue = fields[1].strip()

        if fieldName == "Type":
            enclosureType = fieldValue
            return (True, enclosureType, "")

    errMsg = getMsg(lang, "cannot.get.enclosure.info")
    return (False, cliRet, errMsg)

def getControllerIdList(cli, lang):
    '''
    @summary: 获取设备所有控制器ID
    @param cli: cli对象
    @param lang: 语言lang
    @return: (falg, ret, errMsg)
        flag:
            True: 获取成功
            False: 获取失败
        ret: 
            flag为True时，设备所有控制器ID列表
            flag为False时，cli回显
        errMsg: 错误消息
    '''
    cmd = "show controller general|filterColumn include columnList=Controller"
    checkRet = execCmdInCliMode(cli, cmd, True, lang)
    if not checkRet[0]:
        return checkRet

    cliRet = checkRet[1]
    cliRetLinesList = cliRet.splitlines()
    controlList = []

    for line in cliRetLinesList:
        fields = line.split(":")
        if len(fields) < 2:
            continue

        fieldName = fields[0].strip()
        fieldValue = fields[1].strip()

        if fieldName == "Controller":
            ctrlId = fieldValue
            controlList.append(ctrlId)

    if len(controlList) == 0:
        errMsg = getMsg(lang, "cannot.get.controller.info")
        return (False, cliRet, errMsg)

    return (True, controlList, "")

def getHighDensityDiskEnclosureIdList(cli, lang):
    '''
    @summary: 获取高密硬盘框ID集合
    @param cli: cli对象
    @param lang: 语言lang
    @return: (falg, ret, errMsg)
        flag: 
            True： 判断时正常
            False： 判断时异常
        ret: 
            flag为True时，高密硬盘框ID集合
            flag为False时，返回cli回显
        errMsg: 错误时的消息
    '''
    cmd = "show enclosure"
    checkRet = execCmdInCliMode(cli, cmd, True, lang)
    if not checkRet[0]:
        return checkRet

    cliRet = checkRet[1]
    highDensityDiskEnclosureIdList = []
    cliRetLinesList = getHorizontalCliRet(cliRet)

    if len(cliRetLinesList) == 0:
        errMsg = getMsg(lang, "cannot.get.enclosure.info")
        return (False, cliRet, errMsg)

    for line in cliRetLinesList:
        enclosureType = line["Type"]
        enclosureId = line["ID"]
        if "4U 75" in enclosureType:
            highDensityDiskEnclosureIdList.append(enclosureId)

    return (True, highDensityDiskEnclosureIdList, "")

def expandCtrlCapacityFor2800(cli, lang):
    '''
    @summary: 执行扩容
    @param cli: cli对象
    @param lang: 语言lang
    '''
    #进入developer模式
    cmd = "change user_mode current_mode user_mode=developer"
    checkRet = execCmdInCliMode(cli, cmd, True, lang)
    if not checkRet[0]:
        return checkRet

    # 需要确认直接输入y
    cnt = 1
    cliRet = checkRet[1]
    while "y/n" in cliRet and cnt <= 3:
        cliRet = cli.execCmd("y")
        cnt += 1

    #下发扩容命令
    cliRet = cli.execCmd("change system config_model")

    tempRet = cliRet
    cnt = 0
    while ("y/n" in tempRet and cnt < 3):
        cmd = "y"
        checkRet = execCmdInCliMode(cli, cmd, True, lang)
        tempRet = checkRet[1]
        cliRet += tempRet
        if checkRet[0] != True:
            break
        cnt += 1

    developerMode2CliMode(cli)

    if CLI_EXECUTE_CMD_SUCCESS in cliRet:
        return (True, cliRet, "")
    elif "in multi-controller model" in cliRet.lower():
        return (True, cliRet, "")
    else:
        return (False, cliRet, "")

def execCliCmd(cli, cmd, logResult):
    '''
    @summary: 获取cli回显，回显异常（回显中包含Error）时，进行重试
    @param cli: cli对象
    @param cmd: cli命令
    @param logResult: cli命令日志打印标志
    '''
    cliRet = ""
    retryNum = 3    #回显异常（回显中包含Error）时，重试次数
    retryIntervalTime = 30  #每次重试间隔时间（秒）

    for index in range(retryNum):
        if logResult:
            cliRet = cli.execCmd(cmd)
        else:
            cliRet = cli.execCmdNoLog(cmd)

        # 正常情况无需重试
        if "Error:" not in cliRet:
            break

        time.sleep(retryIntervalTime)

    return cliRet


def hasCliExecPrivilege(cliRet):
    '''
    @summary: 判断是否具有执行cli命令的权限
    @param cliRet: cli回显
    @return: 
        True: 具有执行cli命令的权限
        False: 不具有执行cli命令的权限
    '''
    for line in cliRet.splitlines():
        if line.strip() == "^":
            return False
        if "does not have the permission" in line:
            return False
    return True

def execCmdInDeveloperModePrompt(cli, cmd, isHasLog, lang, prompt="y"):
    '''
    @summary: 获取developer模式下执行命令后的回显
    @param cli: cli对象
    @param cmd: 待执行命令
    @param isHasLog: 是否需要以有log的方式执行cli命令下发
    @param lang: 语言lang
    @param prompt: 确认命令(y/n)
    @return: (falg, ret, errMsg)
        flag:
            True: 执行命令正常
            False: 执行命令不正常
        ret: cli回显
        errMsg: 错误消息
    '''
    isOpened = False
    try:
        isOpened, checkRet = needOpenDeveloperSwitch(cli, lang)

        if isOpened == True:
            checkRet = openDeveloperSwitch(cli, lang)
            if checkRet[0] != True:
                return checkRet

        cliRetAll = ""
        enterDeveloperCheckRet = enterDeveloperMode(cli, lang)
        if not enterDeveloperCheckRet[0]:
            developerMode2CliMode(cli)
            return enterDeveloperCheckRet

        checkRet = execCmdInCliMode(cli, cmd, isHasLog, lang)
        cliRet = checkRet[1]
        cliRetAll += cliRet

        cnt = 0
        while ("y/n" in cliRet and cnt < 5):
            ret = execCmdInCliMode(cli, prompt, isHasLog, lang)
            cliRet = ret[1]
            cliRetAll += cliRet
            cnt += 1

        if isInDeveloperMode(cliRet):
            developerMode2CliMode(cli)

        return (checkRet[0], cliRetAll, checkRet[2])
    finally:
        if isOpened == True :
            closeDeveloperSwitch(cli, lang)


def changeTlvChannel(cli, lang, switch):
    '''
    @summary: 打开或关闭tlv端口
    @param cli: cli对象
    @param switch: 开关状态
    @return: (falg, ret)
        flag:
            True:  执行成功
            False: 执行失败
        ret: cli回显
    '''

    cliRet = ""
    try:

        cmd = "change system external_TLV_channel enabled=%s" % switch
        checkRet = execCmdInDeveloperModePrompt(cli, cmd, True, lang)
        cliRet = checkRet[1]
        if not hasCliExecPrivilege(cliRet):
            return (True, cliRet)

        if checkRet[0] != True:
            return (False, cliRet)

        if CLI_EXECUTE_CMD_SUCCESS in cliRet:
            return (True, cliRet)
        else:
            return (False, cliRet)
    except:
        return (False, cliRet)

def openTlvChannel(cli, lang):
    '''
    @summary: 打开或关闭tlv端口
    @param cli: cli对象
    @param switch: 开关状态
    @return: (falg, ret, errMsg, suggestion)
        flag:
            True:  执行成功
            False: 执行失败
        ret: cli回显
        errMsg: 错误消息
        suggestion: 修复建议
    '''

    ret = hasSuperAdminPrivilege(cli, lang)
    if not ret[1]:
        #当用户没有超级管理员权限时，打开tlv端口肯定失败
        raise Exception("DO_NOT_HAS_SUPER_ADMIN_RIGHTS", "")
    flag, cliRet = changeTlvChannel(cli, lang, "yes")

    if flag:
        return (True, cliRet, "", "")
    else:
        errMsg = ""
        suggestion = ""
        if lang == "zh":
            errMsg = u"连接到设备失败，请检查网络及设备状态是否正常，登录用户是否拥有超级管理员权限，登录信息是否正确，以及帐号是否被锁定。"
            suggestion = u""
        else:
            errMsg = "Failed to connect the device. Please check whether the status of the network and device is normal, whether the login user has the super administer permission, whether login information is correct, and whether the login account is locked."
            suggestion = ""
        return (False, cliRet, errMsg, suggestion)

def closeTlvChannel(cli, lang):
    '''
    @summary: 打开或关闭tlv端口
    @param cli: cli对象
    @param switch: 开关状态
    @return: (falg, ret, errMsg)
        flag:
            True:  执行成功
            False: 执行失败
        ret: cli回显
        errMsg: 错误消息
        suggestion: 修复建议
    '''

    flag, cliRet = changeTlvChannel(cli, lang, "no")
    return (True, cliRet, "", "")

def openDeveloperSwitch(cli, lang='en'):
    '''
            打开切换developer模式开关
    '''
    opencmd = "change user_mode enabled user_mode=developer enabled=yes"
    return execCmdInCliMode(cli, opencmd, True, lang)

def needOpenDeveloperSwitch(cli, lang='en'):
    '''
    @summary: #兼容V3R6版本，查看切developer模式开关是否打开
    '''
    developercmd = "show user_mode enabled"
    checkRet = execCmdInCliMode(cli, developercmd, True, lang)
    if checkRet[0] != True:
        return (CheckStatus.ERROR, checkRet)

    cliRetLinesList = getVerticalCliRet(checkRet[1])
    for line in cliRetLinesList:
        if "Disabled" == line.get("Developer View", ""):
            return (True, checkRet)

    return (False, checkRet)


@wrapAllExceptionLogged(logger=None)
def closeDeveloperSwitch(cli, lang='en'):
    '''
    @summary: 关闭developer视图开关
    '''

    closecmd = "change user_mode enabled user_mode=developer enabled=no"
    execCmdInCliMode(cli, closecmd, True, lang)


def get_file_system_info(cli, lang):
    """ 获取文件系统信息
    :param cli: ssh连接
    :param lang: 语言
    :return: (flag, ret, errMsg)
        flag:
            True: 获取成功
            False: 获取失败
        ret:
            flag为True时，文件系统信息
            flag为False时，cli回显
        errMsg: 错误消息
    """
    cmd = "show file_system general"
    excute_ret = execCmdInCliMode(cli, cmd, True, lang)

    cli_ret = excute_ret[1]
    if excute_ret[0] is not True:
        return False, excute_ret[1], excute_ret[2]
    file_sys_list = getHorizontalCliRet(cli_ret)
    return True, file_sys_list, ""
