# -*- coding: UTF-8 -*-
from com.huawei.ism.exception import IsmException
from java.lang import Exception as JException
from com.huawei.ism.tlv.lang import UnsignedInt32, UnsignedInt64
from com.huawei.ism.tool.protocol.rest.iterf.IRestConn import RestParamEntity 

from java.util import ArrayList
from frame.base import config, jsonUtil
from frame.rest import restData, restDataType
from frame.context import contextUtil
import os
import time

REST_CAN_NOT_EXECUTE = "1077936891" #命令执行失败

class Tlv2Rest:
    '''
     @summary:  将tlv命令封装为rest参数下发
    '''
    @staticmethod
    def convertRecord2Dict(jsonRecord):
        """
        @summary: 将Json格式的回显转换成字典
        @param jsonRecord: REST返回的数据. 
        """
        if ":true" in jsonRecord:
            jsonRecord = jsonRecord.replace(":true", ":True")
        if ":false" in jsonRecord:
            jsonRecord = jsonRecord.replace(":false", ":False")
        return jsonUtil.jsonStr2Dict(jsonRecord)
    @staticmethod
    def getParamsJsonStr(paramDict):
        """
        @summary: 将参数字典转化为json字符串
        @param paramDict: 参数字典. 
        """ 
        if paramDict is None or len(paramDict) == 0:
            return ""
        return jsonUtil.dict2JsonStr(paramDict)
    
    @staticmethod
    def getRecordValue(record, field):
        """
        @summary: 获取指定属性Key值转化后成指定类型并返回
        @param data: REST返回的单个DATA数据（类型为字典）. 
        @param field: 包含 key, type。其中key是DATA中的属性。TYPE是该属性的值。 
        """
        if type(record) == ArrayList:
            record = record[0]
        fieldIndex = field.get("index")
        fieldType = field.get("type")
        paramInfo = record.get(str(fieldIndex), None)
        if paramInfo == None:
            return None
        paramValue = paramInfo.get("value")
        if fieldType == restDataType.DATA_TYPE_UNSIGN_INT or \
           fieldType == restDataType.DATA_TYPE_SIGN_INT or \
           fieldType == restDataType.DATA_TYPE_BOOL or \
           fieldType == restDataType.DATA_TYPE_ENUM or \
           fieldType == restDataType.DATA_TYPE_TIME:
            return int(paramValue)
        
        elif fieldType == restDataType.DATA_TYPE_U64LONG_TYPE:
            return UnsignedInt64(paramValue)
        else:
            return unicode(paramValue)
    @staticmethod
    def getErrorTetail(record, field):
        fieldkey = field.get("key")
        fieldType = field.get("type")
        paramValue = record.get(fieldkey)
        
        if fieldType == restDataType.DATA_TYPE_UNSIGN_INT or \
           fieldType == restDataType.DATA_TYPE_SIGN_INT or \
           fieldType == restDataType.DATA_TYPE_BOOL or \
           fieldType == restDataType.DATA_TYPE_ENUM or \
           fieldType == restDataType.DATA_TYPE_TIME:
            return int(paramValue)
        
        elif fieldType == restDataType.DATA_TYPE_U64LONG_TYPE:
            return UnsignedInt64(paramValue)
        else:
            return unicode(paramValue)
    @staticmethod
    def getData(record):
        """
        @summary: 获取回显中的data数据
        @param record: rest回显
        @return : 返回data数据
        """  
        if record is None or len(record) == 0:
            return None
        
        return record.get("data", None)
    @staticmethod
    def getErrInfo(record):
        """
        @summary: 获取回显中的error数据
        @param record: rest回显
        @return : 返回error数据
        """   
        if record is None or len(record) == 0:
            return None
        
        return record.get("error", None)
    @staticmethod
    def tlvInfo2Json(cmd, params):
        '''
         @summary:  将tlv命令参数转换为rest下发的json字符串
         @param cmd:tlv命令字，restData的TlvCmd类
                params:参数列表
        @return: restJsonStr:为下发rest命令使用的json字符串
        '''
        restParams = []
        paramDict = {}
        
        for param in params:
            if len(param) < 2:
                continue
            pIndex = param[0].get("index")
            paramDict["index"] = pIndex
            
            #type要和DM约定
            pType = param[0].get("type")
            paramDict["type"] = pType
            
            pValue = param[1]
            paramDict["value"] = pValue
            restParams.append(paramDict)
            paramDict = {}
            
        restJsonDict = {"cmd":cmd.get('cmd'),
                        "timeout":cmd.get('timeout'),
                        "params":restParams
                        }
        paramJson = jsonUtil.dict2JsonStr(restJsonDict)
        paramJson = paramJson.replace("\'", "\"").replace("\"[{", "\'[{").replace("}]\"", "}]\'")
        return paramJson
    
    @staticmethod
    def pList2JList(dataList):
        ret = ArrayList()
        for i in range(len(dataList)):
            ret.add(dataList[i])
        return ret
    
    @staticmethod
    def getRestUri(baseUri, objUri):
        """
        @summary: 获取REST接口使用的uri连接
        @param objUri: objUri为各对象差异的URI
        """ 
        return os.path.join(baseUri, objUri)         

    @staticmethod
    def execCmdWithRetry(data_dict, cmd, params):
        """
        异常重试执行rest命令
        :param rest: 连接对象
        :param cmd: 命令
        :param params: 参数
        :return: 执行结果
        """
        rest = contextUtil.getRest(data_dict)
        for i in range(config.RETRY_TIMES):
            try:
                return Tlv2Rest.execCmd(
                    rest, cmd, params,
                    restMethod=restData.Enum.RestMethod.POST,
                    timeOut=restData.REST_CMD_TIMEOUT)
            except (Exception, JException) as e:
                if i >= config.RETRY_TIMES-1:
                    raise e
                time.sleep(config.RETRY_INTEVAL)
                rest = contextUtil.getRest(data_dict)
                continue



    @staticmethod
    def execCmd(rest, cmd, params, restMethod=restData.Enum.RestMethod.POST, timeOut=restData.REST_CMD_TIMEOUT):
        '''
         @summary:  将tlv命令参数转换为rest下发的json字符串
         @param rest:restFactory类
                cmd:tlv命令字，restData的TlvCmd类
                params:参数列表
        @return: records:返回回显
        '''
        
        isLog = RestParamEntity(True)
        
        records = None
        restConn = rest.getRest()
        baseUri = rest.getBaseUri()  
        uri = Tlv2Rest.getRestUri(baseUri, restData.Uri.TLV_COMMUNICATION)
        restJsonStr = Tlv2Rest.tlvInfo2Json(cmd, params)
        for i in range(config.RETRY_TIMES + 1):
            try:
                records = Tlv2Rest.convertRecord2Dict(restConn.execPost(uri, restJsonStr, isLog).getContent())
            except (Exception, JException), e:
                raise IsmException(int(REST_CAN_NOT_EXECUTE), e)
                
            data = Tlv2Rest.pList2JList(Tlv2Rest.getData(records))
            errInfo = Tlv2Rest.getErrInfo(records)
            if errInfo is not None:
                errCode = Tlv2Rest.getErrorTetail(errInfo, restData.ErrorInfo.CODE)

                #为默认错误码则为正常情况
                if errCode == config.REST_DEFAULT_ERR_CODE:
                    return data
                
                #往从节点下发消息失败，可以忽略。
                if errCode == config.ERR_CODE_SLAVE_NODE_HANDLE_MSG_IGNORE:
                    return None
                
                #通信异常进行重试
                if i < config.RETRY_TIMES and errCode == config.COMMUNICATION_FAIL_ERROR_CODE:
                    time.sleep(30)  #间隔30s重新下发
                    continue
                
                #无法处理的错误码，以异常形式抛出。
                description = Tlv2Rest.getErrorTetail(errInfo, restData.ErrorInfo.DESCRIPTION)
                raise IsmException(int(errCode), description)
            
            return data
        
        return data 
        
    @staticmethod
    def getRestValue(record, objAttr):
        '''
         @summary:  获取单条回显中的指定属性
         @param record:单条回显信息，类型为字典
                objAttr:tlv命令字，restData的对象属性
        @return: restJsonStr:为下发rest命令使用的json字符串
        '''
        value = ''
        return value
    
    @staticmethod
    def executeUpgProcess(self, rest, msgType, pkgType, upgradeModel=restData.Enum.UpdActiveType.ONLINE, diagCmd={}, flowChoice=0):
        
        params = []
        cmd = restData.TlvCmd.OM_MSG_OP_UPD_EXECUTE
        param0 = (restData.Upgrade.NotifyExcUpgrade.CMO_EXE_UPD_MSGTYPE, int(msgType))
        params.append(param0)
        
        param2 = (restData.Upgrade.NotifyExcUpgrade.CMO_EXE_UPD_ACTIVETYPE, int(upgradeModel))
        params.append(param2)
        
        param9 = (restData.Upgrade.NotifyExcUpgrade.CMO_EXE_UPD_PKG_TYPE, int(pkgType))
        params.append(param9)
        
        param12 = (restData.Upgrade.NotifyExcUpgrade.CMO_EXC_DIAG_CMD, diagCmd.get('cmd', ''))
        params.append(param12)
        
        if diagCmd.get('checkModel', None) is not None:
            param13 = (restData.Upgrade.NotifyExcUpgrade.CMO_EXC_CHECK_MODEL, diagCmd.get('checkModel'))
            params.append(param13)
        
        return self.execCmd(rest, cmd, params)
    
    def changeBMC(self, rest):
        '''
         @summary:  修改BMC信息
        '''
        cmd = restData.TlvCmd.CHANGE_BMC_INFO
        params = []
        param1 = (restData.Upgrade.BmcInfoDefine.FLAG, restData.Enum.BmcChangeModeEnum.CHANGE)
        param2 = ''
        params.append(param1)
        params.append(param2)
        return self.execCmd(rest, cmd, params)
    
    @staticmethod
    def getEncRecords(rest):
        '''
         @summary:  修改BMC信息
        '''
        cmd = restData.TlvCmd.GET_BATCH
        params = []
        param1 = (restData.Hardware.Enclosure.TYPE, 206)
        params.append(param1)
        param2 = (restData.Hardware.Enclosure.ID, "CTE0")
        params.append(param2)
        return Tlv2Rest.execCmd(rest, cmd=cmd, params=params)
