# -*- coding: UTF-8 -*-
from com.huawei.ism.tlv.lang import UnsignedInt32
from com.huawei.ism.tlv.bean import Param
from com.huawei.ism.tlv.docoder import ParamType
from java.lang import Exception
from com.huawei.ism.tlv import TLVUtils
from com.huawei.ism.tool.protocol.tlv.exception import TLVException
from common import resourceParse, upload
from common.constant import *
from common.baseFactory import log, threadUp, finishProcess
from service.patch_multi_service import PatchMultiPackagesManager
from hotpatch import PatchCheck
import time
import traceback
totalRemainTime = 317


def execute(dataDict):
    """
    功能说明：
    """
    package_path = dataDict.get('packagePath')
    manager = PatchMultiPackagesManager(dataDict, package_path)
    try:
        lang = dataDict['lang']
        """解析resource文件并保存"""
        resource = resourceParse.execute(lang)
        dataDict["resource"] = resource
        log.info(dataDict,"execute upgrade")
        # 升级前检查状态是否允许升级
        checkList = checkUpgradeState(dataDict)
        if not checkList[0]:
            return False, checkList[1]
        if manager.is_multi_patch_package():
            processRet = manager.install_multi_packages(
                upload.execute, upgrade, PatchCheck.execute, totalRemainTime)
        else:
            # 执行升级
            threadUp(dataDict, "upgrade", totalRemainTime)
            processRet = upgrade(dataDict)
    finally:
        finishProcess(dataDict, "upgrade")
        manager.del_child_directory()
    return processRet

def checkUpgradeStatusIsNomarl(status):
    """
    功能说明：检查升级中的状态是不是正常的
    输入：升级状态
    输出：bool检查结果False/True
    """
    
    ###检查升级状态是不是处于回退阶段
    if OM_MSG_OP_UPD_LST_SYS_PROGRESS.UPD_ROLLBACKING == status or OM_MSG_OP_UPD_LST_SYS_PROGRESS.UPD_ROLLBACK_SUCCESS == status or OM_MSG_OP_UPD_LST_SYS_PROGRESS.UPD_ROLLBACK_FAIL == status or OM_MSG_OP_UPD_LST_SYS_PROGRESS.UPD_UPD_FAIL == status:
        return False
    
    return True

def checkUpgradeStatusIsUpgrade(status):
    """
    功能说明：检查升级中的状态是不是升级中和升级成功
    输入：升级状态
    输出：bool检查结果False/True
    """
    ###检查升级状态是否处于升级中和升级成功
    if OM_MSG_OP_UPD_LST_SYS_PROGRESS.UPD_UPDING == status or OM_MSG_OP_UPD_LST_SYS_PROGRESS.UPD_UPD_SUCCESS == status:
        return True
    return False

def upgrade(dataDict):
    """
    功能说明：执行升级并轮询升级结果
    输入：工具框架上下文
    输出：bool执行结果False/True，str错误信息
    """
    try:
        resource = dataDict["resource"]
        tlvCon = dataDict["tlv"]
        context = dataDict['context']
        deviceSN = str(dataDict.get('dev').getDeviceSerialNumber())
        patchType = context["patchType_%s"%deviceSN]
        msgType = ''
        errMsg = ''
        #用来判断异构包和热补丁包
        if patchType == PATCH_TYPE.ASL_PATCH:
            msgType = CMO_EXE_UPD_MSGTYPE.ASL_PATCH_MSGTYPE
        elif patchType == PATCH_TYPE.HOT_PATCH:
            msgType = CMO_EXE_UPD_MSGTYPE.HOT_PATCH_MSGTYPE
        #在线升级类型都为在线升级
        modelNum = 0
        
        msgParam0 = Param(0, ParamType.UNSIGN_INT, UnsignedInt32(msgType))
        msgParam1 = Param(1, ParamType.STRING, "")
        msgParam2 = Param(2, ParamType.UNSIGN_INT, UnsignedInt32(modelNum))
        params = TLVUtils.paramList(msgParam0, msgParam1, msgParam2)
        
        ##执行升级命令 
        tlvCon.invoke(TLV_CMD.EXC_UPD, params, CMD_DEFAULT_TIMEOUT)
        time.sleep(5)
      
        ##查询检查进度命令      
        DEVEICE_UP_FALLD_BASE_VALUE = 0 #轮询计数器
        status = None;
        while (OM_MSG_OP_UPD_LST_SYS_PROGRESS.UPD_UPD_SUCCESS != status):
            try:
                DEVEICE_UP_FALLD_BASE_VALUE = DEVEICE_UP_FALLD_BASE_VALUE + 1
                if DEVEICE_UP_FALLD_BASE_VALUE > UPGRADE_PACKAGE_POLL_TIMES:
                    return (False, resource.get("upgrade.faild"))
                #查询升级进度
                rec = tlvCon.invoke(TLV_CMD.OM_MSG_OP_UPD_LST_SYS_PROGRESS, TLVUtils.paramList(), CMD_DEFAULT_TIMEOUT)
                log.info(dataDict,'TLV cmd [%d] send[%s] receive[%s]'%(TLV_CMD.OM_MSG_OP_UPD_LST_SYS_PROGRESS,str(TLVUtils.paramList()),str(rec)))
                if (None != rec):
                    log.info(dataDict,"upgrade process:" + rec.toString())
                    status = rec.getParamIntValue(3).intValue()
                ###升级状态检查
                if not checkUpgradeStatusIsUpgrade(status):
                    ##查询升级详情
                    log.info(dataDict,"system status is not in upgrading, status is:"+str(status))
                    if not checkUpgradeStatusIsNomarl(status):
                        log.info(dataDict,"system status is not normal.")
                    ##查询升级详细信息
                    recs = tlvCon.getBatch(TLV_CMD.OM_MSG_OP_UPD_LIST_DETAILINFO, TLVUtils.paramList(), CMD_DEFAULT_TIMEOUT)
                    log.info(dataDict,'TLV cmd [%d] send[%s] receive[%s]'%(TLV_CMD.OM_MSG_OP_UPD_LIST_DETAILINFO,str(TLVUtils.paramList()),str(recs)))
                    itemNum = recs.size()
                    for index in range(0,itemNum):
                        rec = recs.get(index)
                        nameKey = rec.getParamStrValue(0)
                        errorKey = rec.getParamStrValue(2)
                        nodeId = rec.getParamStrValue(3)
                        errMsg += (nodeId + '--' + resource.get(nameKey) + '--' + resource.get(errorKey) + '\n')
                    return (False, errMsg)
                try:   
                    time.sleep(UPGRADE_PACKAGE_POLL_INTERVAL)
                except KeyboardInterrupt:
                    log.error(dataDict,"Interrupted" )
            except Exception,e:
                log.error(dataDict,"device upgrade query progress error"+ str(e)) 
                #第一个原子执行时间较长，会抛出该错误码，继续执行查询
                if isinstance(e, TLVException):
                    if OM_OPERATE_FAIL_CODE == e.getErrorId():
                        continue
                tlvCon.close()
                if not checkDevReboot(dataDict):
                    errMsg = resource.get("upgrade.rebooterr")
                    return (False, errMsg)
                else:
                    continue
    except:
        log.error(dataDict,"upgrade error!" +  str(traceback.format_exc()))
        return(False, resource.get("upgrade.faild"))
    return (True, '')

def checkUpgradeState(dataDict):
    """
        功能说明：升级前检查状态是否允许升级
        输入：工具框架上下文
        输出：bool检查结果False/True，str错误信息
    """
    tlvCon = dataDict.get("tlv")
    lang = dataDict.get('lang')
    """解析resource文件并保存"""
    resource = resourceParse.execute(lang)
    dataDict["resource"] = resource
    #查询状态
    rec = tlvCon.invoke(TLV_CMD.OM_MSG_OP_UPD_LST_SYS_PROGRESS, TLVUtils.paramList(), CMD_DEFAULT_TIMEOUT)
    log.info(dataDict,'TLV cmd [%d] send[%s] receive[%s]'%(TLV_CMD.OM_MSG_OP_UPD_LST_SYS_PROGRESS,str(TLVUtils.paramList()),str(rec)))
    status = rec.getParamIntValue(3).intValue()
    #得到状态值
    
    log.info(dataDict,"current device status is:" + str(status))
    
    #不能执行升级的状态有（升级中，回滚中，同步中）
    if status == OM_MSG_OP_UPD_LST_SYS_PROGRESS.UPD_UPDING : #升级中判断
        return (False, resource.get("upgrade.upding"))
    elif status == OM_MSG_OP_UPD_LST_SYS_PROGRESS.UPD_ROLLBACKING : #回滚中判断
        return (False, resource.get("upgrade.rollbacking"))
    
    return (True, "")


def checkDevReboot(dataDict):
    """
    功能说明：等待设备重启完成后，服务正常启动，重新建立连接
    输入：工具上下文
    输出：bool连接结果False/True
    """
    tlvCon = dataDict['tlv']
    
    ##进行UPGRADE_REBOOT_AFTER_CONNECT_TIMES次重试连接，如果连接成功则返回，如果全部没有连接成功在返回失败
    rebootAfterConnectSuc = False
    for times in range(0, UPGRADE_REBOOT_AFTER_CONNECT_TIMES):
        try:
            tlvCon.reConnect()
            rebootAfterConnectSuc = True
            break;
        except Exception, e:
            time.sleep(UPGRADE_REBOOT_AFTER_CONNECT_INTERVAL)
            log.error(dataDict,"dev reboot after connect error " + str(times + 1) + " times"+str(e))

    log.info(dataDict,"device reboot moniter finished . isOK:" + str(rebootAfterConnectSuc))
    return rebootAfterConnectSuc
