# -*- coding: UTF-8 -*-
from frame.cli.cliFactory import CliConnection
from frame.rest.restFactory import RestConnection
from frame.rest import restData
from frame.base import jsonUtil,config
from cbb.frame.util.common import wrapAllExceptionLogged
import os

SCRIPT_DEF_CONTEXT = "SCRIPT_DEF_CONTEXT"
RESOURCE_DEF_CONTEXT = "RESOURCE_DEF_CONTEXT"

CLI_CONNECTION = "CLI_CONNECTION"
TLV_CONNECTION = "TLV_CONNECTION"
REST_CONNECTION = "REST_CONNECTION"
SFTP_CONNECTION = "SFTP_CONNECTION"

COMMUNICATION_FAIL_ERROR_CODE = [
     "16797697", #与设备断开连接
     "1073949185", #与设备通信异常，请检查网络连接或设备状态是否正常
]
CLI_CAN_NOT_EXECUTE = ["1077936891"] #命令执行失败

ERRCODE_MESSAGES_DICT = {
"16797697":
    {
        "errMsg_zh":u"与设备通信异常。",
        "errMsg_en":"Communicating with the device failed.",
        "suggestion_zh":u"请检查网络连接或设备状态是否正常。如果有任何疑问，请联系技术支持工程师协助处理。",
        "suggestion_en":"Please check that the network connection or the system is normal. If you have any problems, please contact technical support engineers for help.",
    },
"1073949185":
    {
        "errMsg_zh":u"与设备通信异常。",
        "errMsg_en":"Communicating with the device failed.",
        "suggestion_zh":u"请检查网络连接或设备状态是否正常。如果有任何疑问，请联系技术支持工程师协助处理。",
        "suggestion_en":"Please check that the network connection or the system is normal. If you have any problems, please contact technical support engineers for help.",
    },
"1077936891":
    {
        "errMsg_zh":u"命令执行失败。",
        "errMsg_en":"Command execute failed.",
        "suggestion_zh":u"",
        "suggestion_en":"",
    },
"1073949187":
    {
        "errMsg_zh":u"sftp传输失败。",
        "errMsg_en":"Failed to download file by sftp.",
        "suggestion_zh":u"请在网络和设备状态正常时重试。",
        "suggestion_en":"Retry when the network and device is normal.",
    },
"DO_NOT_HAS_SUPER_ADMIN_RIGHTS":
    {
        "errMsg_zh":u"连接到设备失败，请检查网络及设备状态是否正常，登录用户是否拥有超级管理员权限，登录信息是否正确，以及帐号是否被锁定。",
        "errMsg_en":"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_zh":u"",
        "suggestion_en":"",
    },

}

def getLang(context):
    '''
    @summary: 获取语言
    @param context: 上下文对象
    '''
    return context.get("lan")

def getMsg(lang, msg, msgDict=ERRCODE_MESSAGES_DICT):
    '''
    @summary: 获取错误信息及建议
    @param context: 上下文对象
    '''
    errMsgDict = msgDict.get(msg, {})
    errMsg = errMsgDict.get("errMsg_%s" % lang, "--")
    suggestion = errMsgDict.get("suggestion_%s" % lang , "")

    return (errMsg, suggestion)

def getScriptDefDict(context):
    '''
    @summary: 获取上下文自定义字典
    @param context: 上下文对象
    '''
    if isinstance(context, dict):
        if not context.has_key(SCRIPT_DEF_CONTEXT):
            context.setdefault(SCRIPT_DEF_CONTEXT, {})
    else:
        if not context.containsKey(SCRIPT_DEF_CONTEXT):
            context.put(SCRIPT_DEF_CONTEXT, {})
    return context.get(SCRIPT_DEF_CONTEXT)

def removeItem(context, key):
    '''
    @summary: 删除自定义字典中的项
    @param context: 上下文对象
    @param key: 删除项的键
    '''
    scriptDefDict = getScriptDefDict(context)
    if scriptDefDict.has_key(key):
        scriptDefDict.pop(key)
    return

def getConnectorFactoryObj(context):
    '''
    @summary: 获取上下文对象中创建连接的对象
    @param context: 上下文对象
    '''
    return context.get("protocalContext").get("connectorFactory")

def getDevObj(context):
    '''
    @summary: 获取上下文对象中dev对象
    @param context: 上下文对象
    '''
    return context.get("newDev")

def getUiObserver(context):
    '''
    @summary: 获取上下文对象中uiObserver对象
    @param context: 上下文对象
    '''
    return context.get("uiObserver")

def getResObj(context):
    '''
    @summary: 获取上下文对象中resource对象
    @param context: 上下文对象
    '''
    return context.get("resource")

def getCheckType(context):
    '''
    @summary: 获取上下文对象中checkType对象
    @param context: 上下文对象
    '''
    return context.get("checkType")

def initCliConnection(context):
    '''
    @summary: 初始化cli连接
    @param context: 上下文对象
    '''
    connectorFactoryObj = getConnectorFactoryObj(context)
    devObj = getDevObj(context)

    ip = devObj.get("ip")
    sshPort = int(devObj.get("sshPort"))

    conn = CliConnection(connectorFactoryObj, ip, sshPort)
    conn.create(devObj.get("user"), devObj.get("pawd"))

    setItem(context, CLI_CONNECTION, conn)
    return

def getCli(context):
    '''
    @summary: 获取cli连接
    @param context: 上下文对象
    '''
    conn = getItem(context, CLI_CONNECTION)
    if conn is None:
        initCliConnection(context)
        conn = getItem(context, CLI_CONNECTION)

    devObj = getDevObj(context)
    cli = conn.getCli(devObj.get("user"), devObj.get("pawd"))
    return cli


@wrapAllExceptionLogged(logger=None)
def destroyCliConnection(context):
    '''
    @summary: 销毁cli连接
    @param context: 上下文对象
    '''

    conn = getItem(context, CLI_CONNECTION)
    if conn is not None:
        conn.close()
        removeItem(context, CLI_CONNECTION)


def setResult(context, flag, errMsg="", suggestion=""):
    '''
    @summary: 往上下文对象中传递处理结果
    @param context: 上下文对象
    @param flag: 标识
    @param errMsg: 错误消息
    @param suggestion: 修复建议
    '''
    context["succ"] = flag
    context["errMsg"] = errMsg
    context["suggestion"] = suggestion
    return

def handleSuccess(context):
    '''
    @summary: 处理成功时，返回成功的结果给上下文对象
    @param context: 上下文对象
    '''
    setResult(context, True)
    return

def handleFailure(context, resultDict={"flag":False, "errMsg":"", "suggestion":""}):
    '''
    @summary: 处理失败时，返回失败的结果给上下文对象
    @param context: 上下文对象
    @param resultDict: 结果字典
    '''
    errMsg = resultDict["errMsg"]
    suggestion = resultDict["suggestion"]

    lang = getLang(context)
    if len(errMsg) == 0:
        if lang == "zh":
            errMsg = u"系统处理消息失败。"
        else:
            errMsg = "Failed to process the message."
    if len(suggestion) == 0:
        if lang == "zh":
            suggestion = u"请检查系统状态或稍后重试。如果有任何疑问，请联系技术支持工程师协助处理。"
        else:
            suggestion = "Please check the system status or try again later. If you have any problems, please contact technical support engineers for help."

    setResult(context, False, errMsg, suggestion)
    return

def handleException(context, exception):
    '''
    @summary: 处理异常时，返回失败的结果给上下文对象
    @param context: 上下文对象
    @param exception: 异常信息
    '''
    lang = getLang(context)
    initConnection(context)
    expArgs = exception.args
    if expArgs is not None and len(expArgs) >= 2:
        errCode = str(expArgs[0]).strip()
        #设备未连接
        if errCode in ERRCODE_MESSAGES_DICT.keys():
            errMsg,suggestion = getMsg(lang, errCode)
            setResult(context, False, errMsg, suggestion)
            return

    handleFailure(context)
    return

def getImportRootDir(context):
    '''
    @summary: 获取脚本的根目录
    @param context: 上下文对象
    '''
    return os.path.dirname(context.get("importRootDir"))

def getResourceDict(context):
    '''
    @summary: 将property资源文件转换为键值对字典
    @param context: 上下文对象
    '''
    scriptDefDict = getScriptDefDict(context)
    if not scriptDefDict.has_key(RESOURCE_DEF_CONTEXT):
        resourceFilePath = getResourecePath(context)
        with open(resourceFilePath, "r", encoding="UTF-8") as resourceFile:
            contents = resourceFile.read().splitlines()
        resourceDict = {}
        for line in contents:
            fields = line.split("=")
            if len(fields) < 2:
                continue
            key = fields[0].strip()
            value = "=".join(fields[1:]).strip()
            resourceDict.setdefault(key, value)
        scriptDefDict.setdefault(RESOURCE_DEF_CONTEXT, resourceDict)

    return scriptDefDict.get(RESOURCE_DEF_CONTEXT)

def getResource(context, key):
    '''
    @summary: 根据property资源文件中的键，获取对应的值
    @param context: 上下文对象
    @param key: property资源文件中的键
    '''
    resourceDict = getResourceDict(context)
    return resourceDict.get(key, "--")

def getResourecePath(context):
    '''
    @summary: 返回property文件所在的路径
    @param context:
    '''
    lang = getLang(context)
    return os.path.join(getImportRootDir(context), "res", "language", "common_%s.properties" % lang)


#------------------NEW Frame---------------
def getItem(context, key):
    '''
    @summary: 获取自定义字典中的项
    @param context: 上下文对象
    @param key: 项的键
    '''
    scriptDefDict = getScriptDefDict(context)
    return scriptDefDict.get(key, None)

def setItem(context, key, value):
    '''
    @summary: 往自定义字典中添加项
    @param context: 上下文对象
    @param key: 添加项的键
    @param value: 添加项的值
    '''
    scriptDefDict = getScriptDefDict(context)
    scriptDefDict[key] = value

    if isinstance(context, dict):
        context[SCRIPT_DEF_CONTEXT] = scriptDefDict.copy()
    else:
        context.put(SCRIPT_DEF_CONTEXT, scriptDefDict.copy())
    return

def initRestConnection(context):
    '''
    @summary: 初始化rest连接
    @param context: 上下文对象
    '''
    connectorFactoryObj = getConnectorFactoryObj(context)
    devObj = getDevObj(context)

    ip = devObj.get("ip")
    devSN = devObj.get("sn")
    conn = RestConnection(connectorFactoryObj, ip, devSN)
    conn.create(devObj.get("user"), devObj.get("pawd"), restData.REST_SCOPE_DEFAULT)
    setItem(context, REST_CONNECTION, conn)
    return

def createRest(context, newIp):
    '''
    @summary: 使用ip创建rest连接
    @param context: 上下文对象
    @param newIp: 创建连接的ip
    '''
    try:
        connectorFactoryObj = getConnectorFactoryObj(context)
        devObj = getDevObj(context)

        devSN = devObj.get("sn")
        restConn = RestConnection(connectorFactoryObj, newIp, devSN)
        result = restConn.create(devObj.get("user"), devObj.get("pawd"), restData.REST_SCOPE_DEFAULT)
        return (result, restConn)
    except:
        return (False, None)


def initSftpConnection(dataDict,ip):
    '''
    @summary: 初始化rest连接
    @param context: 上下文对象
    '''
    connectorFactoryObj = getConnectorFactoryObj(dataDict)
    devObj = dataDict["dev"]

    user = devObj.getLoginUser().getUserName()
    pwd = devObj.getLoginUser().getPassword()
    port = config.STP_DEFAULT_PORT
    return connectorFactoryObj.createSftpConnector(ip, port, user, pwd)


def getRest(context):
    '''
    @summary: 获取rest连接
    @param context: 上下文对象
    '''
    restConn = getItem(context,REST_CONNECTION)
    if restConn is None:
        initRestConnection(context)
        restConn = getItem(context,REST_CONNECTION)

    devObj = getDevObj(context)
    restConn.getRestConnection(devObj.get("user"), devObj.get("pawd"),restData.REST_SCOPE_DEFAULT)
    return restConn

def getBaseUri(context):
    '''
    @summary: 获取rest的基础链接
    @param context: 上下文对象
    '''
    return getItem(context,"REST_BASE_URI")

def getProductModel(context):
    '''
    @summary: 获取自定义字典中的产品型号
    @param context: 上下文对象
    '''
    dev = getDevObj(context)
    productModel = dev.get("type")
    return productModel

def getInnerIpList(context):
    '''
    @summary: 设置高端的内部IP
    @param context: 上下文对象
    '''
    dev = getDevObj(context)
    return dev.get("devInnerIpList")

def setInnerIpList(context):
    '''
    @summary: 设置高端的内部IP
    @param context: 上下文对象
    '''
    setItem(context,"DEV_INNER_IP_LIST",getInnerIpList(context))
    return

def getContextItem(context, key):
    '''
    @summary: 获取框架字典中的项
    @param context: 上下文对象
    @param key: 项的键
    '''
    return context.get(key)

def getSelectedItem(context, key):
    '''
    @summary: 获取框架字典中的被选中的数据，用于FRU工具
    @param context: 上下文对象
    @param key: 项的键
    '''
    selectedInfo = getContextItem(context, key)
    return jsonUtil.jsonStr2Dict(selectedInfo)

def getIp(context):
    '''
    @summary: 获取当前工具连接的ip
    @param context: 上下文对象
    '''
    devObj = getContextItem(context, "dev")
    return devObj.get("ip")

def initConnection(context):
    '''
    @summary: 初始化连接（cli, tlv, rest, sftp）
    @param context: 上下文对象
    '''
    rest_conn = getItem(context, REST_CONNECTION)
    if rest_conn:
        rest_conn.close()
    removeItem(context, TLV_CONNECTION)
    removeItem(context, CLI_CONNECTION)
    setItem(context, REST_CONNECTION, None)
    setItem(context, SFTP_CONNECTION, None)
    return