# -*- coding:utf-8 -*-
import time
from BaseLog import CBaseLog
from ExtraData import CExtraData
from OptionExcel import COptionExcel
from OptionConfig import COptionConfig
from OptionAction import COptionAction
from ssat_sdk.source_input import SourceGenInput
# 测试使用到
import random


class CTMenu(CBaseLog):
    sourceInput = SourceGenInput()

    def __init__(self, ocrDict=None):
        CBaseLog.__init__(self)
        self.__exData = CExtraData()
        self.__optionExcel = COptionExcel(self.__exData)
        self.__optionConfig = COptionConfig(self.__exData, self.__optionExcel)

    @property
    def optionExcel(self):
        return self.__optionExcel

    @property
    def optionConfig(self):
        return self.__optionConfig

    '''
    函数:判断两值(for_ocr与ocr识别结果)是否相等;
    参数:
        srcValue        源值,excel表格中读取的value值。
        tagValue        目标值,ocr识别的结果值。
    返回:相同返回True。
    '''
    def __isValueEqual(self, srcValue, tagValue):
        self.info(u"源值=%s, 目标值=%s" % (str(srcValue), str(tagValue)))

    '''
    函数:移动到目标节点上(路径节点和value节点)
    参数:
        opa                 COptionAction对象;
        moveDirection       移动方向,True表示调用move_key[1](向下或向右), False表示调用move_key[0]。
        maxTry              最大移动次数,防止死循环。
    返回:Boolean是否在目标节点上, 文本或数值。
    '''
    def __move2TargetNode(self, opa, moveDirection, maxTry=15):
        tryCount = 0
        # 是否到目标结点了;
        isOnTargetNode = False
        # 目标节点聚焦状态;
        targetFocus = False
        # 目标文本或数值;
        targetText = None
        # 移动到目标节点;
        while True:
            # 判断是否移动成功;
            targetFocus, targetText = opa.isOnTargetNode()
            if targetFocus is True:
                # 如果已在目标结点,退出循环;
                if opa.isOnTargetOption() or opa.isOnValueSheet():
                    self.info(u"<到达目标路径节点或value节点>")
                    isOnTargetNode = True
                    break

                # 先处理密码框;
                hasBox, dealStatus = opa.dealPasswordBox()
                if hasBox is True and dealStatus is False:
                    break

                # 未到目标,进入下一节点;
                self.info(u"<进入下一节点>")
                opa.enterNode()
                continue
            # endif

            # 移动到下/上一节点;
            if moveDirection:
                opa.move2NextSiblingNode()
            else:
                opa.move2PrevSiblingNode()

            tryCount += 1
            if tryCount > maxTry:
                self.warn(u"已%s遍历超过%d次,仍未找到焦点" % ("正向" if moveDirection else "逆向", maxTry))
                break
        # end-while

        return isOnTargetNode, targetText

    '''
    函数:聚焦到指定option中。
    参数:
        opa         COptionAction对象。
    返回:Boolean,成功返回True.
    '''

    def __focusOption(self, opa):
        # 检测路径是否有效;
        if opa.checkRunOptionPath() is False:
            self.__back2Home(opa)
            return False

        # 首先,调用根菜单;
        opa.callFirstOptionShortCutKey()
        time.sleep(1)
        if opa.isOnFirstOption() is False:
            self.error(u"未聚焦到根节点上,退出")
            self.__back2Home(opa)
            return False

        # 遍历到目标option中;
        if self.__move2TargetNode(opa, True)[0] is False:
            if self.__move2TargetNode(opa, False)[0] is False:
                self.__back2Home(opa)
                return False

        return True

    '''
    函数:进入到指定的option中。
    参数:
        opa         COptionAction对象。
    返回:Boolean,成功返回True.
    '''
    def __openOption(self, opa):
        if self.__focusOption(opa) is False:
            return False

        # 先处理密码框;
        hasBox, dealStatus = opa.dealPasswordBox()
        if hasBox is True and dealStatus is False:
            self.error(u"密码框处理失败")
            return False

        # 到达目标option后;
        self.info(u"进入option")
        opa.enterNode()

        return True

    '''
    函数:返回到主页(不一定就是Home页,一般指返回运行前的那个画面)
    参数:
        opa         COptionAction对象;
    返回:
    
    '''
    def __back2Home(self, opa):
        self.info(u"返回主页")
        while opa.pos > 0:
            opa.back2ParentNode()
        self.info(u"【如果设置value时,会自动回退到上一层父节点,此处操作正常。否则要多返回一层。】")

    '''
    函数:设置指定的option的值为optionValue。
    参数:
        optionName      要设置的option;
        optionValue     option要设置的值;
    返回: Boolean。
    '''
    def setOptionValue(self, optionName, optionValue):
        self.info(u"【%s】【%s】" % (optionName, optionValue))
        CTMenu.sourceInput.setPattern(11)
        opa = COptionAction(optionName, optionValue, self.__optionConfig, self.__optionExcel)

        # 检测路径是否有效;
        if self.__openOption(opa) is False:
            return False

        # 遍历到value节点中;
        if self.__move2TargetNode(opa, True)[0] is False:
            if self.__move2TargetNode(opa, False)[0] is False:
                self.__back2Home(opa)
                return False

        # 找到value节点,设置值;
        self.info(u"设置value值:一般只适用于Number类型或Input类型,不适合选择类型。但都必须调用,因为里面有enterkey操作")
        opa.setOptionValue()

        # 返回主页;
        self.__back2Home(opa)

    '''
    函数:移动到目标option后,读取该option的value值,与optionValue进行比较,相等表示检测值与目标值一致;
    参数:
        optionName      要设置的option;
        optionValue     option要设置的值;
    返回: Boolean。
    '''

    def checkOptionValue(self, optionName, optionValue):
        self.info(u"【%s】【%s】" % (optionName, optionValue))
        CTMenu.sourceInput.setPattern(11)
        opa = COptionAction(optionName, optionValue, self.__optionConfig, self.__optionExcel)

        # 进入节点;
        if self.__openOption(opa) is False:
            return False

        isValueEqual = False
        # 获取value节点值;
        valueFocus, valueText = opa.isOnTargetNode()
        self.info(u"===当前捕获的文本内容=%s,目标文本=%s,状态:%d===" % (str(valueText), str(optionValue), valueFocus))

        # 如果是数值,则判断获取的值是否相等;否则,只判断是否聚焦.
        if type(optionValue) == int or type(optionValue) == float:
            isValueEqual = True if float(optionValue) == float(valueText) else False
        else:
            isValueEqual = valueFocus

        # 因为只是查看值,没有设置值,所以需要再手动返回一层。
        opa.back2ParentNode(False)

        # 返回主页;
        self.__back2Home(opa)

        # 聚焦状态就是结果;
        self.info(u"checkOptionValue结果:optionValue=%s, ocrValue=%s, 结果=%d" % (str(optionValue), str(valueText), isValueEqual))
        return isValueEqual

    '''
    函数:进入指定的option,并且不返回主页。
    参数:
        optionName          指定要进入的option节点。
    返回:Boolean。成功进入返回True.
    '''
    def openOption(self, optionName):
        self.info(u"【%s】" % optionName)
        CTMenu.sourceInput.setPattern(11)
        opa = COptionAction(optionName, None, self.__optionConfig, self.__optionExcel)

        if self.__openOption(opa) is False:
            return False

        # 聚焦状态就是结果;
        self.info(u"成功open指定option=%s" % optionName)
        return True

    '''
    函数:聚焦到指定option的value上,不设置不打开不返回。
    参数:
        optionName
        optionValue
    返回:
    '''
    def focusOptionValue(self, optionName, optionValue):
        self.info(u"【%s】【%s】" % (optionName, optionValue))
        CTMenu.sourceInput.setPattern(11)
        opa = COptionAction(optionName, optionValue, self.__optionConfig, self.__optionExcel)

        # 进入节点;
        if self.__openOption(opa) is False:
            return False

        # 遍历到value节点中;
        if self.__move2TargetNode(opa, True)[0] is False:
            if self.__move2TargetNode(opa, False)[0] is False:
                self.__back2Home(opa)
                return False

        return True

    '''
    函数:获取当前option节点的value值。
    参数:
        optionName      要获取值的option;
    返回:Boolean, str/int/float
    '''
    def getOptionValue(self, optionName):
        self.info(u"【%s】" % optionName)
        CTMenu.sourceInput.setPattern(11)
        opa = COptionAction(optionName, None, self.__optionConfig, self.__optionExcel)

        # 检测路径是否有效;
        if self.__openOption(opa) is False:
            return False

        # 获取value节点值;
        valueFocus, valueText = opa.isOnTargetNode()
        self.info(u"===当前捕获的文本内容=%s,聚焦状态:%d===" % (str(valueText), valueFocus))

        # 因为只是查看值,没有设置值,所以需要再手动返回一层。
        opa.back2ParentNode(False)

        # 返回主页;
        self.__back2Home(opa)

        return valueFocus, valueText

    '''
    函数:
    参数:
    返回:
    '''

    def focusOption(self, optionName):
        self.info(u"【%s】" % optionName)
        CTMenu.sourceInput.setPattern(11)
        opa = COptionAction(optionName, None, self.__optionConfig, self.__optionExcel)

        return self.__focusOption(opa)

    '''
    函数:
    参数:
    返回:
    '''
    def inputUnlock(self, stdText, password=''):
        opa = COptionAction(None, None, self.__optionConfig, self.__optionExcel)
        return opa.inputUnlock(stdText, password)

    '''
    函数:当焦点已经在option层级上时,移动到指定的option上。
    参数:
        optionName      目标option.
    返回:Boolean,成功移动到目标节点返回True。
    
    注意:该函数不是从根节点开始移动到目标节点,而是假定焦点已经在目标节点层级菜单上。
    '''
    def moveToOption(self, optionName):
        opa = COptionAction(optionName, None, self.__optionConfig, self.__optionExcel)
        # 已经在该层级上.
        opa.setCurPos(opa.getPathLength()-1)

        # 检测路径是否有效;
        if opa.checkRunOptionPath() is False:
            self.__back2Home(opa)
            return False

        # 遍历到目标option中;
        if self.__move2TargetNode(opa, True)[0] is False:
            if self.__move2TargetNode(opa, False)[0] is False:
                self.__back2Home(opa)
                return False

        self.info(u"已移动到目标节点[%s]" % optionName)
        return True

    '''
    函数:
    参数:
    返回:
    '''
    def watchOption(self):
        pass


if __name__ == "__main__":
    ml = CTMenu()
    if 0:
        st = 2
        ml.setOptionValue('picture_preset', 'personal')
        time.sleep(st)
        ml.setOptionValue('picture_preset', 'dynamic')
        time.sleep(st)
        ml.setOptionValue('picture_preset', 'stadium')
        time.sleep(st)
        ml.setOptionValue('picture_preset', 'standard')
        time.sleep(st)
        ml.setOptionValue('picture_preset', 'natural')
        time.sleep(st)
        ml.setOptionValue('picture_preset', 'movie')

    if 0:
        st = 5
        value = random.randint(0, 100)
        time.sleep(st)
        ml.setOptionValue('brightness', value)
        time.sleep(st)
        ml.setOptionValue('contrast', value)
        time.sleep(st)
        ml.setOptionValue('saturation', value)
        time.sleep(st)
        ml.setOptionValue('tint', value)
        time.sleep(st)
        ml.setOptionValue('sharpness', value)
        time.sleep(st)
        ml.setOptionValue('backlight', value)

    if 0:
        st = 2
        ml.checkOptionValue('picture_preset', 'personal')
        time.sleep(st)
        ml.checkOptionValue('picture_preset', 'dynamic')
        time.sleep(st)
        ml.checkOptionValue('picture_preset', 'stadium')
        time.sleep(st)
        ml.checkOptionValue('picture_preset', 'standard')
        time.sleep(st)
        ml.checkOptionValue('picture_preset', 'natural')
        time.sleep(st)
        ml.checkOptionValue('picture_preset', 'movie')

    if 0:
        st = 1
        value = random.randint(0, 100)
        ml.setOptionValue('backlight', value)
        time.sleep(st)
        ml.checkOptionValue('backlight', value + 10)
        time.sleep(st)
        ml.checkOptionValue('backlight', value)
        time.sleep(st)

        ml.setOptionValue('brightness', value)
        time.sleep(st)
        ml.checkOptionValue('brightness', value + 10)
        time.sleep(st)
        ml.checkOptionValue('brightness', value)
        time.sleep(st)

        ml.setOptionValue('contrast', value)
        time.sleep(st)
        ml.checkOptionValue('contrast', value + 10)
        time.sleep(st)
        ml.checkOptionValue('contrast', value)
        time.sleep(st)

        ml.setOptionValue('saturation', value)
        time.sleep(st)
        ml.checkOptionValue('saturation', value + 10)
        time.sleep(st)
        ml.checkOptionValue('saturation', value)
        time.sleep(st)

        ml.setOptionValue('tint', value)
        time.sleep(st)
        ml.checkOptionValue('tint', value + 10)
        time.sleep(st)
        ml.checkOptionValue('tint', value)
        time.sleep(st)

        ml.setOptionValue('sharpness', value)
        time.sleep(st)
        ml.checkOptionValue('sharpness', value + 10)
        time.sleep(st)
        ml.checkOptionValue('sharpness', value)
        time.sleep(st)

    if 0:
        st = 30
        ml.openOption('picture_preset')
        time.sleep(st)

        ml.openOption('brightness')
        time.sleep(st)

        ml.openOption('contrast')
        time.sleep(st)

        ml.openOption('tint')
        time.sleep(st)

        ml.openOption('sharpness')
        time.sleep(st)

        ml.openOption('backlight')
        time.sleep(st)

    if 0:
        st = 30
        value = random.randint(0, 100)
        ml.focusOptionValue('brightness', value)
        time.sleep(st)
        ml.focusOptionValue('contrast', value)
        time.sleep(st)
        ml.focusOptionValue('saturation', value)
        time.sleep(st)
        ml.focusOptionValue('tint', value)
        time.sleep(st)
        ml.focusOptionValue('sharpness', value)
        time.sleep(st)
        ml.focusOptionValue('backlight', value)
        time.sleep(st)

        ml.focusOptionValue('picture_preset', 'personal')
        time.sleep(st)
        ml.focusOptionValue('picture_preset', 'dynamic')
        time.sleep(st)
        ml.focusOptionValue('picture_preset', 'stadium')
        time.sleep(st)
        ml.focusOptionValue('picture_preset', 'standard')
        time.sleep(st)
        ml.focusOptionValue('picture_preset', 'natural')
        time.sleep(st)
        ml.focusOptionValue('picture_preset', 'movie')

    if 0:
        st = 2
        ml.getOptionValue('brightness')
        time.sleep(st)
        ml.getOptionValue('contrast')
        time.sleep(st)
        ml.getOptionValue('saturation')
        time.sleep(st)
        ml.getOptionValue('tint')
        time.sleep(st)
        ml.getOptionValue('sharpness')
        time.sleep(st)
        ml.getOptionValue('backlight')
        time.sleep(st)
        ml.getOptionValue('picture_preset')

    if 1:
        ml.openOption('picture')
        ml.moveToOption('brightness')
        ml.moveToOption('picture_reset')
        ml.moveToOption('picture_preset')