# -*- coding=utf-8 -*-
"""
Created by lichen on 2019-06-10.
宝藏系统
"""

import json
import time
import math
import random

import freetime.util.log as ftlog
from freetime.entity.msg import MsgPack
from freetime.core.timer import FTLoopTimer
import poker.util.timestamp as pktimestamp
from poker.protocol import router
from poker.util import strutil
from poker.entity.dao import daobase, userchip
from poker.entity.configure import gdata
from hall.entity import hallitem, datachangenotify
from newfish.entity.config import FISH_GAMEID
from newfish.entity import config, item, util, module_tip, mail_system
from newfish.entity.msg import GameMsg
from newfish.entity.redis_keys import UserData
from newfish.entity.event import TreasureLevelUp

INDEX_LEVEL = 0         # 第0位:宝藏等级
INDEX_FINISH_COUNT = 1  # 第1位:宝藏奖励今日触发次数
INDEX_FINISH_TIME = 2   # 第2位:宝藏奖励上一次触发时间

class EffectType:
    """
    宝藏效果类型
    """
    MatchRewardAdd = 1      # 参加回馈赛可额外得金币
    CoinComplement = 2      # 每日首次登录时，金币补足
    ItemComplement = 3      # 每日首次登陆时，锁定、冰冻补足
    ResComplement = 4       # 每日首次登陆时，珍珠、紫水晶、黄水晶补足
    AlmsCoinAdd = 5         # 救济金额度提高
    MatchItemReward = 6     # 完成大奖赛可得红宝石
    SaleItemCoinAdd = 7     # 出售道具获得金币提高
    FreeUseItemAdd = 8      # 使用锁定、冰冻时，有概率不消耗道具卡
    MatchRankRewardAdd = 9  # 回馈赛、大奖赛排名奖励提高
    BossRankRewardAdd = 10  # 任意Boss榜单、招财榜单排名奖励提高

def _getUserTreasureKey(userId):
    """
    宝藏数据存取key
    """
    return UserData.treasure % (FISH_GAMEID, userId)

def initTreasure(userId):
    """
    初始化宝藏数据
    """
    for kindId in config.getTreasureConf().keys():
        updateTreasure(userId, kindId)

def updateTreasure(userId, kindId):
    """
    更新新增宝藏数据
    """
    assert str(kindId) in config.getTreasureConf()
    daobase.executeUserCmd(userId, "HSETNX", _getUserTreasureKey(userId), str(kindId), json.dumps([0, 0, 0]))

def setTreasure(userId, kindId, treasureData):
    """
    存储单个宝藏数据
    """
    assert str(kindId) in config.getTreasureConf()
    assert isinstance(treasureData, list)
    daobase.executeUserCmd(userId, "HSET", _getUserTreasureKey(userId), str(kindId), json.dumps(treasureData))

def getTreasure(userId, kindId):
    """
    获得单个宝藏数据
    """
    assert str(kindId) in config.getTreasureConf()
    value = daobase.executeUserCmd(userId, "HGET", _getUserTreasureKey(userId), str(kindId))
    if value:
        return strutil.loads(value, False, True)
    return [0, 0, 0]

def getTreasureList(userId):
    """
    宝藏列表
    """
    treasures = []
    lang = util.getLanguage(userId)
    for kindId, treasureConf in config.getTreasureConf().iteritems():
        kindId = int(kindId)
        treasure = {}
        level, _ = getTreasureInfo(userId, kindId)
        treasure["kindId"] = kindId
        treasure["sortId"] = treasureConf["sortId"]
        treasure["name"] = config.getMultiLangTextConf(treasureConf["name"], lang=lang)
        treasure["desc"] = config.getMultiLangTextConf(treasureConf.get("desc"), lang=lang)
        treasure["level"] = level
        treasure["convert"] = treasureConf["convert"]
        treasures.append(treasure)

    def cmpSort(x, y):
        if x["level"] > y["level"]:
            return 1
        elif x["level"] < y["level"]:
            return -1
        else:
            if x["sortId"] < y["sortId"]:
                return 1
            else:
                return -1

    treasures.sort(cmp=cmpSort, reverse=True)
    return treasures

def getTreasureInfo(userId, kindId):
    """
    获取宝藏详情
    :param kindId: 宝藏道具ID
    :return: 当前等级, 等级配置
    """
    treasureData = getTreasure(userId, kindId)
    level = treasureData[INDEX_LEVEL]
    levelConf = config.getTreasureConf(kindId, level=level) if level else {}
    return level, levelConf

def upgradeTreasure(userId, kindId):
    """
    升级宝藏
    """
    code = 0
    treasureData = getTreasure(userId, kindId)
    levelConf = config.getTreasureConf(kindId, level=treasureData[INDEX_LEVEL] + 1)
    if treasureData[INDEX_LEVEL] >= len(config.getTreasureConf(kindId).get("levels", {})):
        code = 3
    elif not levelConf or not levelConf.get("cost", 0):
        code = 2
    else:
        consumeItems = [{"name": int(kindId), "count": int(levelConf["cost"])}]
        isOK = consumeUpgradeTreasureItem(userId, consumeItems, treasureData[INDEX_LEVEL] + 1)
        if isOK:
            treasureData[INDEX_LEVEL] += 1
            setTreasure(userId, kindId, treasureData)
            from newfish.game import TGFish
            event = TreasureLevelUp(userId, config.FISH_GAMEID, kindId, treasureData[INDEX_LEVEL])
            TGFish.getEventBus().publishEvent(event)
            checkTreasureUpgrade(userId)
        else:
            code = 1
    return code, treasureData[INDEX_LEVEL]

def convertTreasure(userId, kindId, count):
    """
    兑换宝藏碎片
    """
    code, rewards = 1, None
    treasureConf = config.getTreasureConf(kindId)
    convert = treasureConf.get("convert")
    if convert:
        surplusCount = util.balanceItem(userId, convert["kindId"])
        consumeCount = convert["rate"] * count
        if surplusCount >= consumeCount:
            consume = [{"name": convert["kindId"], "count": -abs(consumeCount)}]
            rewards = [{"name": kindId, "count": count}]
            consume.extend(rewards)
            code = util.addRewards(userId, consume, "BI_NFISH_TREASURE_CONVERT", kindId)
            return code, rewards
    return code, rewards

def checkUpgradeTreasureItemCount(userId, items):
    """
    检查升级所需道具是否足够
    """
    isOK = True
    for item in items:
        kindId = item["name"]
        needCount = item["count"]
        userAssets = hallitem.itemSystem.loadUserAssets(userId)
        surplusCount = userAssets.balance(FISH_GAMEID, util.getAssetKindId(kindId),
                                          pktimestamp.getCurrentTimestamp())
        if surplusCount < needCount:
            isOK = False
            break
    return isOK

def consumeUpgradeTreasureItem(userId, items, intEventParam=0, param01=0, param02=0):
    """
    升级所需道具
    """
    if checkUpgradeTreasureItemCount(userId, items):
        ret = util.consumeItems(userId, items, "BI_NFISH_TREASURE_UPGRADE", intEventParam, param01, param02)
        if len(ret) == len(items):
            return True
    return False

def refreshTreasureState(userId, kindId):
    """
    刷新宝藏状态等数据
    """
    treasureData = getTreasure(userId, kindId)
    lastTimestamp = treasureData[INDEX_FINISH_TIME]
    if util.getDayStartTimestamp(int(time.time())) != util.getDayStartTimestamp(lastTimestamp):
        treasureData[INDEX_FINISH_COUNT] = 0
        setTreasure(userId, kindId, treasureData)

def checkTreasureUpgrade(userId):
    """
    检查宝藏能否升级
    """
    upTreasures = []
    for kindId, _ in config.getTreasureConf().iteritems():
        treasureData = getTreasure(userId, kindId)
        levelConf = config.getTreasureConf(kindId, level=treasureData[INDEX_LEVEL] + 1)
        if treasureData[INDEX_LEVEL] < len(config.getTreasureConf(kindId).get("levels", {})):
            consumeItems = [{"name": int(kindId), "count": int(levelConf["cost"])}]
            if checkUpgradeTreasureItemCount(userId, consumeItems):
                upTreasures.append(int(kindId))
    module_tip.resetModuleTip(userId, "treasure")
    if upTreasures:
        module_tip.addModuleTipEvent(userId, "treasure", upTreasures)
    else:
        module_tip.resetModuleTipEvent(userId, "treasure")

def activeTreasure(userId, kindId, treasureData):
    """
    触发宝藏奖励
    """
    treasureData[INDEX_FINISH_COUNT] += 1
    treasureData[INDEX_FINISH_TIME] = int(time.time())
    setTreasure(userId, kindId, treasureData)

def getAlmsCoin(userId):
    """
    获取救济金额度
    """
    treasureConf = config.getTreasureConf(effectType=EffectType.AlmsCoinAdd)
    if treasureConf:
        kindId = treasureConf["kindId"]
        _, levelConf = getTreasureInfo(userId, kindId)
        return levelConf.get("params", {}).get("value", 0)
    return 0

# def getAlmsCountAdd(userId):
#     """
#     获取救济金加成次数
#     """
#     for treasureConf in config.getTreasureConf(effectType=EffectType.AlmsCountAdd):
#         kindId = treasureConf["kindId"]
#         _, levelConf = getTreasureInfo(userId, kindId)
#         return levelConf.get("params", {}).get("almsCount", 0)
#     return 0

def getCoinComplement(userId, coin=0):
    """
    获得金币补足
    :param userId:
    :param coin: 当处于渔场中时，使用渔场传过来的金币数
    """
    effect = {}
    userCoin = coin if coin > 0 else userchip.getChip(userId)
    treasureConf = config.getTreasureConf(effectType=EffectType.CoinComplement)
    if treasureConf:
        kindId = treasureConf["kindId"]
        level, levelConf = getTreasureInfo(userId, kindId)
        if not levelConf:
            return
        refreshTreasureState(userId, kindId)
        treasureData = getTreasure(userId, kindId)
        if treasureData[INDEX_FINISH_COUNT] >= treasureConf["limitCount"]:
            return
        coinComplement = levelConf.get("params", {}).get("value", 0)
        if coinComplement > userCoin:
            lang = util.getLanguage(userId)
            rewards = [{"name": config.CHIP_KINDID,
                        "count": coinComplement - userCoin,
                        "chgCount": [userCoin, coinComplement]}]
            util.addRewards(userId, rewards, "BI_NFISH_TREASURE_REWARDS", kindId)
            activeTreasure(userId, kindId, treasureData)
            treasureName = config.getMultiLangTextConf(treasureConf["name"], lang=lang)
            coinStr = util.formatScore(coinComplement, lang=lang)
            message = config.getMultiLangTextConf("ID_CONFIG_TREASURE_SUPPLY_101", lang=lang)
            message = message.format(coinStr, treasureName, coinStr)
            GameMsg.sendPrivate(FISH_GAMEID, userId, 0, message)
            effect = {
                "kindId": kindId,
                "level": level,
                "rewards": rewards
            }
    return effect

def getItemComplement(userId, count=0):
    """
    获得锁定、冰冻道具卡补足
    """
    effect = {}
    treasureConf = config.getTreasureConf(effectType=EffectType.ItemComplement)
    if treasureConf:
        kindId = treasureConf["kindId"]
        level, levelConf = getTreasureInfo(userId, kindId)
        if not levelConf:
            return
        refreshTreasureState(userId, kindId)
        treasureData = getTreasure(userId, kindId)
        if treasureData[INDEX_FINISH_COUNT] >= treasureConf["limitCount"]:
            return
        rewards = []
        lang = util.getLanguage(userId)
        for _kindId, _complementCount in levelConf.get("params", {}).iteritems():
            _kindId = int(_kindId)
            _surplusCount = util.balanceItem(userId, _kindId)
            if _complementCount > _surplusCount:
                _rewards = [
                    {"name": _kindId,
                     "count": _complementCount - _surplusCount,
                     "chgCount": [_surplusCount, _complementCount]}
                ]
                rewards.extend(_rewards)
                treasureName = config.getMultiLangTextConf(treasureConf["name"], lang=lang)
                countStr = util.formatScore(_complementCount, lang=lang)
                message = config.getMultiLangTextConf("ID_CONFIG_TREASURE_SUPPLY_%s" % _kindId, lang=lang)
                message = message.format(countStr, treasureName, countStr)
                GameMsg.sendPrivate(FISH_GAMEID, userId, 0, message)
        if rewards:
            util.addRewards(userId, rewards, "BI_NFISH_TREASURE_REWARDS", kindId)
            activeTreasure(userId, kindId, treasureData)
            effect = {
                "kindId": kindId,
                "level": level,
                "rewards": rewards
            }
    return effect

def getResComplement(userId, count=0):
    """
    获得珍珠、紫水晶、黄水晶道具补足
    """
    effect = {}
    treasureConf = config.getTreasureConf(effectType=EffectType.ResComplement)
    if treasureConf:
        kindId = treasureConf["kindId"]
        level, levelConf = getTreasureInfo(userId, kindId)
        if not levelConf:
            return
        refreshTreasureState(userId, kindId)
        treasureData = getTreasure(userId, kindId)
        if treasureData[INDEX_FINISH_COUNT] >= treasureConf["limitCount"]:
            return
        rewards = []
        lang = util.getLanguage(userId)
        for _kindId, _complementCount in levelConf.get("params", {}).iteritems():
            _kindId = int(_kindId)
            _surplusCount = util.balanceItem(userId, _kindId)
            if _complementCount > _surplusCount:
                _reward = {
                    "name": _kindId,
                    "count": _complementCount - _surplusCount,
                    "chgCount": [_surplusCount, _complementCount]
                }
                rewards.append(_reward)
                treasureName = config.getMultiLangTextConf(treasureConf["name"], lang=lang)
                countStr = util.formatScore(_complementCount, lang=lang)
                message = config.getMultiLangTextConf("ID_CONFIG_TREASURE_SUPPLY_%s" % _kindId, lang=lang)
                message = message.format(countStr, treasureName, countStr)
                GameMsg.sendPrivate(FISH_GAMEID, userId, 0, message)
        if rewards:
            util.addRewards(userId, rewards, "BI_NFISH_TREASURE_REWARDS", kindId)
            activeTreasure(userId, kindId, treasureData)
            effect = {
                "kindId": kindId,
                "level": level,
                "rewards": rewards
            }
    return effect

def getSaleItemExtraCoin(userId, coin):
    """
    神秘金币加赠额外金币
    """
    extraCoin = 0
    try:
        treasureConf = config.getTreasureConf(effectType=EffectType.SaleItemCoinAdd)
        if treasureConf:
            kindId = treasureConf["kindId"]
            level, levelConf = getTreasureInfo(userId, kindId)
            if levelConf:
                refreshTreasureState(userId, kindId)
                treasureData = getTreasure(userId, kindId)
                if treasureData[INDEX_FINISH_COUNT] < treasureConf["limitCount"]:
                    extraRate = levelConf.get("params", {}).get("value")
                    if extraRate:
                        extraCoin = int(coin * extraRate)
                        activeTreasure(userId, kindId, treasureData)
    except Exception as e:
        ftlog.error("treasure_system.getSaleItemExtraCoin error", e,
                    "userId=", userId,
                    "chip=", coin)
    if ftlog.is_debug():
        ftlog.debug("treasure_system.getSaleItemExtraCoin OUT",
                    "userId=", userId,
                    "chip=", coin,
                    "extraCoin=", extraCoin)
    return extraCoin

def isUseItemFree(userId, value):
    """
    时间沙漏，判断是否不消耗道具卡
    """
    try:
        treasureConf = config.getTreasureConf(effectType=EffectType.FreeUseItemAdd)
        if treasureConf:
            kindId = treasureConf["kindId"]
            level, levelConf = getTreasureInfo(userId, kindId)
            if levelConf:
                refreshTreasureState(userId, kindId)
                treasureData = getTreasure(userId, kindId)
                if treasureData[INDEX_FINISH_COUNT] < treasureConf["limitCount"]:
                    chance = levelConf.get("params", {}).get("value")
                    randomValue = random.randint(1, 10000)
                    if ftlog.is_debug():
                        ftlog.debug("treasure_system.isUseItemFree get",
                                    "userId=", userId,
                                    "level=", level,
                                    "levelConf=", levelConf,
                                    "chance=", chance,
                                    "randomValue=", randomValue)
                    if randomValue <= chance * 10000:
                        activeTreasure(userId, kindId, treasureData)
                        sendTreasureTriggerMsg(userId, kindId, value)
                        return True
    except Exception as e:
        ftlog.error("treasure_system.isUseItemFree error", e,
                    "userId=", userId)
    return False

def getTreasureRewards(userId, count=0):
    """
    发放宝藏奖励
    """
    try:
        effectList = []
        for func in (getCoinComplement,
                     getItemComplement,
                     getResComplement):
            effect = func(userId, count)
            if ftlog.is_debug():
                ftlog.debug("getTreasureRewards", effect)
            if effect:
                effectList.append(effect)
        if effectList:
            FTLoopTimer(2, 0, sendTreasureRewardsMsg, userId, effectList).start()
    except Exception as e:
        ftlog.error("treasure_system.getTreasureRewards error", e,
                    "userId=", userId)

def sendTreasureRewardsMsg(userId, effectList):
    """
    发送宝藏奖励消息
    """
    msg = MsgPack()
    msg.setCmd("treasure_rewards")
    msg.setResult("gameId", FISH_GAMEID)
    msg.setResult("userId", userId)
    msg.setResult("effect", effectList)
    router.sendToUser(msg, userId)

def sendTreasureTriggerMsg(userId, kindId, value=None):
    """
    发送宝藏触发提示消息
    """
    msg = MsgPack()
    msg.setCmd("treasure_trigger")
    msg.setResult("gameId", FISH_GAMEID)
    msg.setResult("userId", userId)
    msg.setResult("kindId", kindId)
    if value:
        msg.setResult("value", value)
    router.sendToUser(msg, userId)

def provideFinishTimeMatchReward(userId, bigRoomId):
    """
    完成回馈赛发放宝藏奖励到邮件
    """
    treasureConf = config.getTreasureConf(effectType=EffectType.MatchRewardAdd)
    if treasureConf:
        kindId = treasureConf["kindId"]
        level, levelConf = getTreasureInfo(userId, kindId)
        if not levelConf:
            return
        refreshTreasureState(userId, kindId)
        treasureData = getTreasure(userId, kindId)
        if treasureData[INDEX_FINISH_COUNT] >= treasureConf["limitCount"]:
            return
        lang = util.getLanguage(userId)
        if str(bigRoomId) in levelConf.get("params", {}):
            matchName = config.getMultiLangTextConf(gdata.getRoomConfigure(bigRoomId).get("name", ""), lang=lang)
            rewards = [{"name": config.CHIP_KINDID, "count": levelConf["params"][str(bigRoomId)]}]
            treasureName = config.getMultiLangTextConf(treasureConf["name"], lang=lang)
            message = config.getMultiLangTextConf("ID_CONFIG_TREASURE_FINISH_TIME_MATCH", lang=lang)
            message = message.format(matchName, level, treasureName)
            title = config.getMultiLangTextConf("ID_MAIL_TITLE_TREASURE_REWARD", lang=lang)
            mail_system.sendSystemMail(userId, mail_system.MailRewardType.TreasureReward, rewards, message, title)
            activeTreasure(userId, kindId, treasureData)

def provideFinishGrandPrixReward(userId):
    """
    完成大奖赛发放宝藏奖励到邮件
    """
    treasureConf = config.getTreasureConf(effectType=EffectType.MatchItemReward)
    if treasureConf:
        kindId = treasureConf["kindId"]
        level, levelConf = getTreasureInfo(userId, kindId)
        if not levelConf:
            return
        refreshTreasureState(userId, kindId)
        treasureData = getTreasure(userId, kindId)
        if treasureData[INDEX_FINISH_COUNT] >= treasureConf["limitCount"]:
            return
        rewards = []
        lang = util.getLanguage(userId)
        for _kindId, _count in levelConf.get("params", {}).iteritems():
            rewards.append({"name": int(_kindId), "count": _count})
        if rewards:
            treasureName = config.getMultiLangTextConf(treasureConf["name"], lang=lang)
            message = config.getMultiLangTextConf("ID_CONFIG_TREASURE_FINISH_GRAND_PRIX", lang=lang).format(level,
                                                                                treasureName)
            title = config.getMultiLangTextConf("ID_MAIL_TITLE_TREASURE_REWARD", lang=lang)
            mail_system.sendSystemMail(userId, mail_system.MailRewardType.TreasureReward, rewards, message, title)
            activeTreasure(userId, kindId, treasureData)

def provideTimeMatchRankReward(userId, roomId, rank, rankRewards):
    """
    回馈赛上榜发放宝藏奖励到邮件
    """
    treasureConf = config.getTreasureConf(effectType=EffectType.MatchRankRewardAdd)
    if treasureConf:
        kindId = treasureConf["kindId"]
        level, levelConf = getTreasureInfo(userId, kindId)
        if not levelConf:
            return
        refreshTreasureState(userId, kindId)
        treasureData = getTreasure(userId, kindId)
        if treasureData[INDEX_FINISH_COUNT] >= treasureConf["limitCount"]:
            return
        rewards = []
        lang = util.getLanguage(userId)
        ratio = levelConf["params"]["time_match"]
        for _reward in rankRewards:
            if _reward["name"] in config.BULLET_VALUE:
                name = config.BRONZE_BULLET_KINDID
                count = int(math.ceil(_reward["count"] * config.BULLET_VALUE[_reward["name"]] * ratio))
            else:
                name = _reward["name"]
                count = int(math.ceil(_reward["count"] * ratio))
            rewards.append({"name": name, "count": count})
        if rewards:
            matchName = config.getMultiLangTextConf(gdata.getRoomConfigure(roomId).get("name", ""), lang=lang)
            treasureName = config.getMultiLangTextConf(treasureConf["name"], lang=lang)
            message = config.getMultiLangTextConf("ID_CONFIG_TREASURE_TIME_MATCH_RANK", lang=lang)
            message = message.format(matchName, rank, level, treasureName)
            title = config.getMultiLangTextConf("ID_MAIL_TITLE_TREASURE_REWARD", lang=lang)
            mail_system.sendSystemMail(userId, mail_system.MailRewardType.TreasureReward, rewards, message, title)
            activeTreasure(userId, kindId, treasureData)

def provideRankReward(userId, rankId, rankType, rank, params):
    """
    特定排行榜上榜发放宝藏奖励到邮件
    """
    from newfish.entity.ranking import ranking_system
    lang = util.getLanguage(userId)
    if rankId == config.RANK_GRAND_PRIX:
        # 大奖赛
        treasureConf = config.getTreasureConf(effectType=EffectType.MatchRankRewardAdd)
        if treasureConf:
            kindId = treasureConf["kindId"]
            level, levelConf = getTreasureInfo(userId, kindId)
            if not levelConf:
                return
            refreshTreasureState(userId, kindId)
            treasureData = getTreasure(userId, kindId)
            if treasureData[INDEX_FINISH_COUNT] >= treasureConf["limitCount"]:
                return
            rewards = []
            ratio = levelConf["params"]["grand_prix"]
            for _reward in params["rewards"]:
                if _reward["name"] in config.BULLET_VALUE:
                    name = config.BRONZE_BULLET_KINDID
                    count = int(math.ceil(_reward["count"] * config.BULLET_VALUE[_reward["name"]] * ratio))
                else:
                    name = _reward["name"]
                    count = int(math.ceil(_reward["count"] * ratio))
                rewards.append({"name": name, "count": count})
            if rewards:
                treasureName = config.getMultiLangTextConf(treasureConf["name"], lang=lang)
                message = config.getMultiLangTextConf("ID_CONFIG_TREASURE_GRAND_PRIX_RANK", lang=lang)
                message = message.format(rank, level, treasureName)
                title = config.getMultiLangTextConf("ID_MAIL_TITLE_TREASURE_REWARD", lang=lang)
                mail_system.sendSystemMail(userId, mail_system.MailRewardType.TreasureReward, rewards, message, title)
                activeTreasure(userId, kindId, treasureData)

    # elif rankType in ranking_system.SbossPointRankTypeDefineIndexDict:
    #     # Boss幸运榜
    #     treasureConf = config.getTreasureConf(effectType=EffectType.BossRankRewardAdd)
    #     if treasureConf:
    #         kindId = treasureConf["kindId"]
    #         level, levelConf = getTreasureInfo(userId, kindId)
    #         if not levelConf:
    #             return
    #         refreshTreasureState(userId, kindId)
    #         treasureData = getTreasure(userId, kindId)
    #         if treasureData[INDEX_FINISH_COUNT] >= treasureConf["limitCount"]:
    #             return
    #         rewards = []
    #         ratio = levelConf["params"]["boss"]
    #         for _reward in params["rewards"]:
    #             if _reward["name"] in config.BULLET_VALUE:
    #                 name = config.BRONZE_BULLET_KINDID
    #                 count = int(math.ceil(_reward["count"] * config.BULLET_VALUE[_reward["name"]] * ratio))
    #             else:
    #                 name = _reward["name"]
    #                 count = int(math.ceil(_reward["count"] * ratio))
    #             rewards.append({"name": name, "count": count})
    #         if rewards:
    #             rankRewardConf = config.getRankRewardConf(rankType)
    #             rankName = config.getMultiLangTextConf(rankRewardConf["rankName"], lang=lang)
    #             treasureName = config.getMultiLangTextConf(treasureConf["name"], lang=lang)
    #             message = config.getMultiLangTextConf("ID_CONFIG_TREASURE_BOSS_RANK", lang=lang).format(rankName, rank, level, treasureName)
    #             title = config.getMultiLangTextConf("ID_MAIL_TITLE_TREASURE_REWARD", lang=lang)
    #             mail_system.sendSystemMail(userId, mail_system.MailRewardType.TreasureReward, rewards, message, title)
    #             activeTreasure(userId, kindId, treasureData)

    elif rankId == config.RANK_ROBBERY_DAY_WIN:
        # 招财赢家榜
        treasureConf = config.getTreasureConf(effectType=EffectType.BossRankRewardAdd)
        if treasureConf:
            kindId = treasureConf["kindId"]
            level, levelConf = getTreasureInfo(userId, kindId)
            if not levelConf:
                return
            refreshTreasureState(userId, kindId)
            treasureData = getTreasure(userId, kindId)
            if treasureData[INDEX_FINISH_COUNT] >= treasureConf["limitCount"]:
                return
            ratio = levelConf["params"]["robbery"]
            count = int(math.ceil(params["originCount"] * ratio))
            rewards = [{"name": config.BRONZE_BULLET_KINDID, "count": count}]
            treasureName = config.getMultiLangTextConf(treasureConf["name"], lang=lang)
            message = config.getMultiLangTextConf("ID_CONFIG_TREASURE_ROBBERY_RANK", lang=lang)
            message = message.format(rank, level, treasureName)
            title = config.getMultiLangTextConf("ID_MAIL_TITLE_TREASURE_REWARD", lang=lang)
            mail_system.sendSystemMail(userId, mail_system.MailRewardType.TreasureReward, rewards, message, title)
            activeTreasure(userId, kindId, treasureData)

def dealTreasureReward(userId, clientId, dayFirst):
    """
    处理宝藏奖励发放
    """
    if ftlog.is_debug():
        ftlog.debug("dealTreasureReward", userId, clientId, dayFirst)
    for kindId, _ in config.getTreasureConf().iteritems():
        refreshTreasureState(userId, kindId)
    if dayFirst:
        isIn, roomId, tableId, seatId = util.isInFishTable(userId)
        if isIn and util.getRoomTypeName(roomId) in config.NORMAL_ROOM_TYPE:
            mo = MsgPack()
            mo.setCmd("table_call")
            mo.setParam("action", "treasure_rewards")
            mo.setParam("gameId", FISH_GAMEID)
            mo.setParam("clientId", clientId)
            mo.setParam("userId", userId)
            mo.setParam("roomId", roomId)
            mo.setParam("tableId", tableId)
            mo.setParam("seatId", seatId)
            router.sendTableServer(mo, roomId)
        else:
            getTreasureRewards(userId)

def _triggerUserLoginEvent(event):
    """
    用户登录事件
    """
    userId = event.userId
    clientId = event.clientId
    dayFirst = event.dayFirst
    dealTreasureReward(userId, clientId, dayFirst)
    checkTreasureUpgrade(userId)

def _triggerMatchOverEvent(event):
    """
    完成回馈赛事件
    """
    provideFinishTimeMatchReward(event.userId, event.bigRoomId)

def _triggerFinishGrandPrixEvent(event):
    """
    完成大奖赛事件
    """
    provideFinishGrandPrixReward(event.userId)

def _triggerMatchRewardEvent(event):
    """
    回馈赛排名结算发奖事件
    """
    provideTimeMatchRankReward(event.userId, event.roomId, event.rank, event.rewards)

def _triggerRankOverEvent(event):
    """
    排行榜结算事件
    """
    provideRankReward(event.userId, event.rankId, event.rankType, event.rank, event.params)

def _triggerTreasureItemCountChangeEvent(event):
    """
    宝藏升级相关物品数量变化事件
    """
    checkTreasureUpgrade(event.userId)

_inited = False

def initialize():
    ftlog.debug("newfish treasure_system initialize begin")
    global _inited
    if not _inited:
        _inited = True
        from poker.entity.events.tyevent import EventUserLogin
        from newfish.game import TGFish
        from newfish.entity.event import MatchOverEvent, RankOverEvent, FinishGrandPrixEvent, \
            MatchRewardEvent, TreasureItemCountChangeEvent
        TGFish.getEventBus().subscribe(EventUserLogin, _triggerUserLoginEvent)
        TGFish.getEventBus().subscribe(MatchOverEvent, _triggerMatchOverEvent)
        TGFish.getEventBus().subscribe(FinishGrandPrixEvent, _triggerFinishGrandPrixEvent)
        TGFish.getEventBus().subscribe(MatchRewardEvent, _triggerMatchRewardEvent)
        TGFish.getEventBus().subscribe(RankOverEvent, _triggerRankOverEvent)
        TGFish.getEventBus().subscribe(TreasureItemCountChangeEvent, _triggerTreasureItemCountChangeEvent)
    ftlog.debug("newfish treasure_system initialize end")


import re
import difflib
import os
from io import StringIO
import shutil

import bs4

from ebooklib import epub
from ebooklib.utils import create_pagebreak

from pdf2ebook import logger
from pdf2ebook.base_page import BasePage

class HTMLPage(BasePage):
    def __init__(self, idx, content):
        self.idx = idx
        self.next_page = None

        soup = bs4.BeautifulSoup(StringIO(content), "html.parser")

        try:
            soup.hr.decompose()
        except:
            pass

        self.content = str(soup)

        super(HTMLPage, self).__init__()

    @property
    def content_hash(self):
        return hash(self.content)

    @property
    def images(self):
        soup = bs4.BeautifulSoup(StringIO(self.content), "html.parser")
        imgs = soup.find_all("img")
        logger.debug(f"Found {len(imgs)} images in page {self.idx}")

        images = []
        for idx, img in enumerate(imgs):
            epub_image = epub.EpubImage()

            real_path = img["src"]

            new_path = os.path.basename(real_path)
            try:
                shutil.copy(real_path, new_path)
            except Exception as ex:
                logger.debug(
                    f'Could not copy image "{real_path}" -> "{new_path}": {ex}'
                )

            try:
                image_content = open(new_path, "rb").read()
            except:
                logger.error(f"Could not get image content from path: {new_path}")
            else:
                epub_image.uid = f"image_{self.idx}_{idx}"
                epub_image.file_name = new_path
                epub_image.media_type = "image/png"  # TODO: detect
                epub_image.set_content(image_content)
                images.append(epub_image)

        return images

    @property
    def text_content(self):
        # Below samples of a newline
        """
        t m0 xb h3 yb ff2 fs0 fc0 sc0 ls0 ws0
        t m0 x1 h3 yc ff3 fs0 fc0 sc0 ls0 ws0
        t m0 x1 h3 yd ff3 fs0 fc0 sc0 ls0 ws0
        t m0 xb h3 ye ff1 fs0 fc0 sc0 ls0 ws0
        t m0 xc h3 yf ff2 fs0 fc2 sc0 ls0 ws0
        t m0 x1 h3 y10 ff2 fs0 fc0 sc0 ls0 ws
        """
        soup = bs4.BeautifulSoup(StringIO(self.content), "html.parser")

        content = []
        for partial in soup.find_all("div", class_="t"):
            text = partial.text
            text = text.replace("", " ").strip()
            text = text.replace("\ue003", " ")
            content.append(text)

        if not content:
            return soup.text.strip()

        return "\n".join(content)

    @property
    def page_no(self):
        raise NotImplementedError()

    @property
    def html_content(self):
        soup = bs4.BeautifulSoup(StringIO(self.content), "html.parser")
        for img in soup.find_all("img"):
            img["src"] = os.path.basename(img["src"])
        self.content = str(soup)
        return self.content

    @property
    def epub_content(self):
        # need a different content that strips headers and footers
        epub_page = epub.EpubHtml(
            title=f"title_{self.idx}",
            file_name=f"page_{self.idx}.xhtml",
            lang=self.lang,
            uid=str(self.idx),
        )
        epub_page.content = self.html_content
        epub_page.content += create_pagebreak(f"p_{self.idx}")
        return epub_page

    def remove_header(self, header):
        if not header:
            return
        # might need to remove tags
        soup = bs4.BeautifulSoup(StringIO(self.content), "html.parser")
        lines = str(soup).split("\n")
        content = []
        collect = False
        for line in lines:
            if collect:
                content.append(line)
            else:
                soup_line = bs4.BeautifulSoup(StringIO(line), "html.parser")
                if (
                    difflib.SequenceMatcher(
                        None, soup_line.text.strip(), header
                    ).ratio()
                    > 0.8
                ):
                    collect = True
        if content:
            self.content = "\n".join(content)

    def remove_footer(self, footer):
        if not footer:
            return
        # might need to remove tags
        soup = bs4.BeautifulSoup(StringIO(self.content), "html.parser")
        lines = str(soup).split("\n")
        content = []
        collect = False
        for line in reversed(lines):
            if collect:
                content.append(line)
            else:
                soup_line = bs4.BeautifulSoup(StringIO(line), "html.parser")
                if (
                    difflib.SequenceMatcher(
                        None, soup_line.text.strip(), footer
                    ).ratio()
                    > 0.8
                ):
                    collect = True
        if content:
            self.content = "\n".join(reversed(content))

    def remove_page_number(self):
        if self.included_page_no is None:
            return

        # find the number from text and remove from html
        soup = bs4.BeautifulSoup(StringIO(self.content), "html.parser")
        lines = str(soup).split("\n")

        if self.page_number_position == "top":
            content = []
            collect = False
            for line in lines:
                if collect:
                    content.append(line)
                else:
                    text_line = bs4.BeautifulSoup(
                        StringIO(line), "html.parser"
                    ).text.strip()
                    if text_line.startswith(self.included_page_no):
                        content.append(
                            re.sub("(^\d+)", "", text_line)
                        )  # FIXME: this removes html elements
                        collect = True
            if content:
                self.content = "\n".join(content)
        elif self.page_number_position == "bottom":
            content = []
            collect = False
            for line in reversed(lines):
                if collect:
                    content.append(line)
                else:
                    text_line = bs4.BeautifulSoup(
                        StringIO(line), "html.parser"
                    ).text.strip()
                    if text_line.startswith(self.included_page_no):
                        content.append(
                            re.sub("(^\d+)", "", text_line)
                        )  # FIXME: this removes html elements
                        collect = True
            if content:
                self.content = "\n".join(reversed(content))

        self.strip_whitespace()

    def strip_whitespace(self):
        soup = bs4.BeautifulSoup(StringIO(self.content), "html.parser")
        lines = str(soup).split("\n")
        content = []
        collect = False
        for line in lines:
            if collect:
                content.append(line)
            else:
                soup_line = bs4.BeautifulSoup(StringIO(line), "html.parser")
                if soup_line.text.strip() == "" and soup.find("img") is None:
                    continue
                else:
                    collect = True
                    content.append(line)
        if content:
            self.content = "\n".join(content)

        soup = bs4.BeautifulSoup(StringIO(self.content), "html.parser")
        lines = str(soup).split("\n")
        content = []
        collect = False
        for line in reversed(lines):
            if collect:
                content.append(line)
            else:
                soup_line = bs4.BeautifulSoup(StringIO(line), "html.parser")
                if soup_line.text.strip() == "" and soup.find("img") is None:
                    continue
                else:
                    collect = True
                    content.append(line)
        if content:
            self.content = "\n".join(reversed(content))


import requests
import os
import json
from enum import Enum

TIME_OUT = 25

class Method(Enum):
    GET = 1
    POST = 2

class HttpClient(object):
    def __init__(self):
        self.session = requests.session()
        self.cookies = None

    def request(self, url, method, cookies=None, postData=None, headers=None, formats="json", encoding=None,jsonData = None,
                timeout=TIME_OUT, allow_redirects=True):
        if headers:
            self.session.headers.update(headers)

        if self.cookies:
            self.session.cookies = self.cookies

        if cookies:
            self.session.cookies = cookies

        try:
            if method == Method.GET:
                response = self.session.get(url, timeout=timeout,allow_redirects=False)
            else:
                response = self.session.post(url, data=postData, timeout=timeout,allow_redirects=allow_redirects,json=jsonData)
            if response.status_code == 200:
                self.session.close()
                if formats == "response":
                    return response
                if formats == "json":
                    return response.json()
                elif formats == "url":
                    return response.url
                elif formats == 'file':
                    return response.content
                else:
                    responseText = ""
                    if encoding:
                        response.encoding = encoding
                        responseText = response.text
                    else:
                        responseText = response.text
                    if formats == "UrlText":
                        return (response.url, responseText)
                    else:
                        return responseText
            elif response.status_code == 302:
                return response
            else:
                self.session.close()
                print("request error status_code:%s", response.status_code)
                return response
        except Exception as e:
            self.session.close()
            print("request error")
            print(e)
            return None

    def download(self, url, dirPath, fileName, headers=None):
        if headers:
            self.session.headers.update(headers)
        try:
            response = self.session.get(url, timeout=TIME_OUT)
            if response.status_code == 200:
                if not os.path.exists(dirPath):
                    os.makedirs(dirPath)
                with open(os.path.join(dirPath, fileName), "wb") as code:
                    code.write(response.content)
                response.close()
                return os.path.join(dirPath, fileName)
            else:
                response.close()
                return None

        except Exception as e:
            self.session.close()
            return None

    def uploadFile(self, url, files, data=None, headers=None):
        print("URL:%s,data%s", url, data)
        if headers:
            self.session.headers.update(headers)
        response = self.session.post(url, files=files, data=data)
        print(response.status_code)
        if response.status_code == 200:
            return 'SUCCESS'
        else:
            return 'FALSE'

    def getCookies(self):
        cookiesDict = {c.name: c.value for c in self.session.cookies}
        return str(cookiesDict)

    def setCookies(self, cookies):
        self.cookies = cookies
        pass

if __name__ == "__main__":
    client = HttpClient()
    result = client.request("http://www.cwl.gov.cn/cwl_admin/kjxx/findKjxx/forIssue?name=ssq&code=2019106", Method.GET, headers={'Accept': 'application/json, text/javascript, */*; q=0.01',
                            'Referer': 'http://www.cwl.gov.cn/kjxx/ssq/',
                            'User-Agent': 'Mozilla/5.0',
                            'X-Requested-With': 'XMLHttpRequest'}, formats="json")
    data = json.dumps(result)
    dict = json.loads(data)
    balls = dict['result'][0]
    print ("red:"+balls['red'])
    print ("blue:"+balls['blue'])


#!/usr/bin/env python

# Modified version of movidius classification-sample.py to test in a snap

from __future__ import print_function
import sys
import os
from argparse import ArgumentParser, SUPPRESS
import cv2
import numpy as np
import logging as log
from time import time
from openvino.inference_engine import IENetwork, IEPlugin

def readLabels(labels_path):
    label_map = None
    with open(labels_path, 'r') as f:
        label_map = [x.strip() for x in f]

    return label_map

def build_argparser():
    parser = ArgumentParser(add_help=False)
    args = parser.add_argument_group('Options')
    args.add_argument("-m", "--model", help="Required. Path to an .xml file with a trained model.", type=str, default='{0}/models/ssd_mobilenet_v2_FP16/ssd_mobilenet_v2.xml')
    args.add_argument("-i", "--input", help="Required. Path to a folder with images or path to an image files", type=str, default='./images/plate-references/cr-truck-plate1.jpg')
    args.add_argument("-pd", "--plugin_dir", help="Optional. Path to a plugin folder", type=str, default=None)
    args.add_argument("-d", "--device", help="Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL, MYRIAD or HETERO: is "
                           "acceptable. The sample will look for a suitable plugin for device specified. Default "
                           "value is CPU", default="MYRIAD", type=str)
    args.add_argument("--labels", help="Optional. Path to a labels mapping file", type=str,  default='{0}/models/ssd_mobilenet_v2_FP16/ssd_mobilenet_v2.labels')
    args.add_argument("-nt", "--number_top", help="Optional. Number of top results", default=10, type=int)
    args.add_argument("-ni", "--number_iter", help="Optional. Number of inference iterations", default=1, type=int)
    args.add_argument("-pc", "--perf_counts", help="Optional. Report performance counters", default=False, action="store_true")
    return parser

def main():
    log.basicConfig(format="[%(levelname)s] %(message)s", level=log.INFO, stream=sys.stdout)
    args = build_argparser().parse_args()
    args.model = args.model.format(os.path.dirname(os.path.realpath(__file__)))
    args.labels = args.labels.format(os.path.dirname(os.path.realpath(__file__)))
    print(args.model)
    model_xml = args.model
    model_bin = os.path.splitext(model_xml)[0] + ".bin"

    #Read labels
    labels = readLabels(args.labels)

    # Plugin initialization for specified device and load extensions library if specified
    plugin = IEPlugin(device=args.device, plugin_dirs=args.plugin_dir)

    # Read IR
    log.info("Loading model files:\n\t{}\n\t{}".format(model_xml, model_bin))
    net = IENetwork(model=model_xml, weights=model_bin)

    assert len(net.inputs.keys()) == 1, "Sample supports only single input topologies"
    assert len(net.outputs) == 1, "Sample supports only single output topologies"

    log.info("Preparing input blobs")
    input_blob = next(iter(net.inputs))
    out_blob = next(iter(net.outputs))
    net.batch_size = 1

    # Read and pre-process input images
    n, c, h, w = net.inputs[input_blob].shape
    image = cv2.imread(args.input)
    original_img = image
    initial_h, initial_w = image.shape[:-1]
    if image.shape[:-1] != (h, w):
        log.warning("Image {} is resized from {} to {}".format(args.input, image.shape[:-1], (h, w)))
        image = cv2.resize(image, (w, h))
    image = image.transpose((2, 0, 1))  # Change data layout from HWC to CHW

    # Loading model to the plugin
    log.info("Loading model to the plugin")
    exec_net = plugin.load(network=net)

    # Start sync inference
    log.info("Starting inference ({} iterations)".format(args.number_iter))
    infer_time = []
    for i in range(args.number_iter):
        t0 = time()
        res = exec_net.infer(inputs={input_blob: image})
        infer_time.append((time() - t0) * 1000)
    log.info("Average running time of one iteration: {} ms".format(np.average(np.asarray(infer_time))))
    if args.perf_counts:
        perf_counts = exec_net.requests[0].get_perf_counts()
        log.info("Performance counters:")
        print("{:<70} {:<15} {:<15} {:<15} {:<10}".format('name', 'layer_type', 'exet_type', 'status', 'real_time, us'))
        for layer, stats in perf_counts.items():
            print("{:<70} {:<15} {:<15} {:<15} {:<10}".format(layer, stats['layer_type'], stats['exec_type'],
                                                              stats['status'], stats['real_time']))

    # Processing output blob
    log.info("Processing output blob")
    res = res[out_blob]
    for obj in res[0][0]:
        # Draw only objects when probability more than specified threshold
        xmin = int(obj[3] * initial_w)
        ymin = int(obj[4] * initial_h)
        xmax = int(obj[5] * initial_w)
        ymax = int(obj[6] * initial_h)
        class_id = int(obj[1])
        label = labels[class_id - 1]
        if obj[2] > 0.6:
            print("Detected: {0} ({1},{2},{3},{4})".format(label, xmin, ymin, xmax, ymax))
            color = (0, 255, 0)
            try:
                cv2.rectangle(original_img, (xmin, ymin), (xmax, ymax), color, 2)
            except:
                pass
        # else:
        #     try:
        #         color = (min(class_id * 12.5, 255), min(class_id * 7, 255), min(class_id * 5, 255))
        #         cv2.rectangle(original_img, (xmin, ymin), (xmax, ymax), color, 2)
        #     except:
        #         pass

        cv2.imwrite('./output.jpg', original_img)

if __name__ == '__main__':
    sys.exit(main() or 0)


import sqlalchemy
import pandas as pd
from datetime import datetime, timedelta
import numpy as np

def get_non_missing(date):
    """Given a date, takes a subset of the historicalReturns df
    corresponding to the year preceeding the date, and returns all
    tickers where zero nan values are found in that time frame."""
    if isinstance(date, str):
        date = datetime.strptime(date, '%Y-%m-%d')
    past = date - timedelta(days=365)
    engine = sqlalchemy.create_engine('sqlite:///backtesting.db')
    with engine.connect() as con:
        hist_df = pd.read_sql('marketCloseData', con=con, index_col='Date')
    date_subset_df = hist_df.loc[past:date]
    tickers = date_subset_df.loc[:, (
        date_subset_df.isna().sum()==0)].columns.to_list()
    return tickers

def get_sp500_date(date):
    """Function to get a list of tickers present in the sp500 at a given date"""
    # Convert string inputs to datetime
    if isinstance(date, str):
        date = datetime.strptime(date, '%Y-%m-%d')
    engine = sqlalchemy.create_engine('sqlite:///backtesting.db')
    with engine.connect() as con:
        tickers = pd.read_sql('ticker_df', con=con).squeeze().to_list()
        changes_df = pd.read_sql('changes_df', con=con, index_col='Date')
    # Get a subset of the changes from today until the input date
    changes_subset = changes_df.loc[:date, :].copy()
    # Add and remove stocks until tickers has sp500 stocks from given date
    for row in changes_subset.itertuples():
        if row.Removed not in tickers:
            tickers.append(row.Removed)
        if row.Added in tickers:
            tickers.remove(row.Added)
    return tickers

def get_eligible(date):
    """Function to get tickers which are in the sp500 at a given
    date and have no nan entries for a year preceeding the given
    date."""
    # Convert string inputs to datetime
    if isinstance(date, str):
        date = datetime.strptime(date, '%Y-%m-%d')
    non_na_set = set(get_non_missing(date))
    sp500_set = set(get_sp500_date(date))
    eligible = list(sp500_set.intersection(non_na_set))
    return eligible

def choose_stocks(date, sel_1_portion = 0.5, sel_2_size=100, sel_3_size=10):
    """Selects stocks for a given date by using the following methodology:
    1)  Of all sp500 stocks, select sel_1_portion percent of them with the
        highest returns over 12 months.  We use sel_1_portion rather than a
        number because the number of eligible stocks for a given date varies
        based on availability of data
    2)  Select sel_2_size stocks with highest returns over last 6 months
        from stocks chosen in step 1
    3)  Finally, select top sel_3_size stocks from subset created by step 2
    4)  At each step, I am only selecting stocks with positive returns over
        the given 12, 6 or 3 month period"""
    # Reading in 12, 6 and 3 month return dataframes into memory
    engine = sqlalchemy.create_engine('sqlite:///backtesting.db')
    with engine.connect() as con:
        ret_12 = pd.read_sql('12MonthReturns', con=con, index_col='Date')
        ret_6 = pd.read_sql('6MonthReturns', con=con, index_col='Date')
        ret_3 = pd.read_sql('3MonthReturns', con=con, index_col='Date')
    # Choosing stocks for 12 month, 6 month and 3 month periods
    eligible = get_eligible(date)
    selection_1_num = int(np.floor(len(eligible)*sel_1_portion))
    selection_1 = (ret_12
        .loc[date, eligible]
        .loc[lambda x: x>=1]
        .nlargest(n=selection_1_num)
        .index
        .to_list())
    selection_2 = (ret_6
        .loc[date, selection_1]
        .loc[lambda x: x>=1]
        .nlargest(n=sel_2_size)
        .index
        .to_list())
    selection_3 = (ret_3
        .loc[date, selection_2]
        .loc[lambda x: x>=1]
        .nlargest(n=sel_3_size)
        .index
        .to_list())
    return selection_3


import torch
import torch.nn as nn
import torch.nn.functional as F

from pcseg.model.segmentor.base_segmentors import BaseSegmentor
from pcseg.model.segmentor.range.utils import ClassWeightSemikitti, CrossEntropyDiceLoss, Lovasz_softmax, BoundaryLoss

class ResContextBlock(nn.Module):
    def __init__(self, in_filters, out_filters):
        super(ResContextBlock, self).__init__()
        self.conv1 = nn.Conv2d(in_filters, out_filters, kernel_size=(1, 1), stride=1)
        self.act1 = nn.LeakyReLU()

        self.conv2 = nn.Conv2d(out_filters, out_filters, (3,3), padding=1)
        self.act2 = nn.LeakyReLU()
        self.bn1 = nn.BatchNorm2d(out_filters)

        self.conv3 = nn.Conv2d(out_filters, out_filters, (3,3),dilation=2, padding=2)
        self.act3 = nn.LeakyReLU()
        self.bn2 = nn.BatchNorm2d(out_filters)

    def forward(self, x):

        shortcut = self.conv1(x)
        shortcut = self.act1(shortcut)

        resA = self.conv2(shortcut)
        resA = self.act2(resA)
        resA1 = self.bn1(resA)

        resA = self.conv3(resA1)
        resA = self.act3(resA)
        resA2 = self.bn2(resA)

        output = shortcut + resA2
        return output

class ResBlock(nn.Module):
    def __init__(
        self,
        in_filters: int,
        out_filters: int,
        dropout_rate: float,
        kernel_size: tuple = (3, 3),
        stride: int = 1,
        pooling: bool = True,
        drop_out: bool = True,
    ):
        super(ResBlock, self).__init__()
        self.pooling = pooling
        self.drop_out = drop_out
        self.conv1 = nn.Conv2d(in_filters, out_filters, kernel_size=(1, 1), stride=stride)
        self.act1 = nn.LeakyReLU()

        self.conv2 = nn.Conv2d(in_filters, out_filters, kernel_size=(3,3), padding=1)
        self.act2 = nn.LeakyReLU()
        self.bn1 = nn.BatchNorm2d(out_filters)

        self.conv3 = nn.Conv2d(out_filters, out_filters, kernel_size=(3,3),dilation=2, padding=2)
        self.act3 = nn.LeakyReLU()
        self.bn2 = nn.BatchNorm2d(out_filters)

        self.conv4 = nn.Conv2d(out_filters, out_filters, kernel_size=(2, 2), dilation=2, padding=1)
        self.act4 = nn.LeakyReLU()
        self.bn3 = nn.BatchNorm2d(out_filters)

        self.conv5 = nn.Conv2d(out_filters*3, out_filters, kernel_size=(1, 1))
        self.act5 = nn.LeakyReLU()
        self.bn4 = nn.BatchNorm2d(out_filters)

        if pooling:
            self.dropout = nn.Dropout2d(p=dropout_rate)
            self.pool = nn.AvgPool2d(kernel_size=kernel_size, stride=2, padding=1)
        else:
            self.dropout = nn.Dropout2d(p=dropout_rate)

    def forward(self, x):
        shortcut = self.conv1(x)
        shortcut = self.act1(shortcut)

        resA = self.conv2(x)
        resA = self.act2(resA)
        resA1 = self.bn1(resA)

        resA = self.conv3(resA1)
        resA = self.act3(resA)
        resA2 = self.bn2(resA)

        resA = self.conv4(resA2)
        resA = self.act4(resA)
        resA3 = self.bn3(resA)

        concat = torch.cat((resA1,resA2,resA3),dim=1)
        resA = self.conv5(concat)
        resA = self.act5(resA)
        resA = self.bn4(resA)
        resA = shortcut + resA

        if self.pooling:
            if self.drop_out:
                resB = self.dropout(resA)
            else:
                resB = resA
            resB = self.pool(resB)

            return resB, resA
        else:
            if self.drop_out:
                resB = self.dropout(resA)
            else:
                resB = resA
            return resB

class UpBlock(nn.Module):
    def __init__(self, in_filters, out_filters, dropout_rate, drop_out=True):
        super(UpBlock, self).__init__()
        self.drop_out = drop_out
        self.in_filters = in_filters
        self.out_filters = out_filters

        self.dropout1 = nn.Dropout2d(p=dropout_rate)

        self.dropout2 = nn.Dropout2d(p=dropout_rate)

        self.conv1 = nn.Conv2d(in_filters//4 + 2*out_filters, out_filters, (3,3), padding=1)
        self.act1 = nn.LeakyReLU()
        self.bn1 = nn.BatchNorm2d(out_filters)

        self.conv2 = nn.Conv2d(out_filters, out_filters, (3,3),dilation=2, padding=2)
        self.act2 = nn.LeakyReLU()
        self.bn2 = nn.BatchNorm2d(out_filters)

        self.conv3 = nn.Conv2d(out_filters, out_filters, (2,2), dilation=2,padding=1)
        self.act3 = nn.LeakyReLU()
        self.bn3 = nn.BatchNorm2d(out_filters)

        self.conv4 = nn.Conv2d(out_filters*3,out_filters,kernel_size=(1,1))
        self.act4 = nn.LeakyReLU()
        self.bn4 = nn.BatchNorm2d(out_filters)

        self.dropout3 = nn.Dropout2d(p=dropout_rate)

    def forward(self, x, skip):
        upA = nn.PixelShuffle(2)(x)
        if self.drop_out:
            upA = self.dropout1(upA)

        upB = torch.cat((upA,skip),dim=1)
        if self.drop_out:
            upB = self.dropout2(upB)

        upE = self.conv1(upB)
        upE = self.act1(upE)
        upE1 = self.bn1(upE)

        upE = self.conv2(upE1)
        upE = self.act2(upE)
        upE2 = self.bn2(upE)

        upE = self.conv3(upE2)
        upE = self.act3(upE)
        upE3 = self.bn3(upE)

        concat = torch.cat((upE1, upE2, upE3), dim=1)
        upE = self.conv4(concat)
        upE = self.act4(upE)
        upE = self.bn4(upE)
        if self.drop_out:
            upE = self.dropout3(upE)

        return upE

class SalsaNext(BaseSegmentor):
    def __init__(
        self,
        model_cfgs,
        num_class: int,
    ):
        super(SalsaNext, self).__init__(model_cfgs, num_class)
        self.num_class = num_class
        self.if_ls_loss = model_cfgs.IF_LS_LOSS
        self.if_bd_loss = model_cfgs.IF_BD_LOSS

        # encoder
        self.downCntx = ResContextBlock(6, 32)
        self.downCntx2 = ResContextBlock(32, 32)
        self.downCntx3 = ResContextBlock(32, 32)

        self.resBlock1 = ResBlock(32, 2 * 32, 0.2, pooling=True, drop_out=False)
        self.resBlock2 = ResBlock(2 * 32, 2 * 2 * 32, 0.2, pooling=True)
        self.resBlock3 = ResBlock(2 * 2 * 32, 2 * 4 * 32, 0.2, pooling=True)
        self.resBlock4 = ResBlock(2 * 4 * 32, 2 * 4 * 32, 0.2, pooling=True)
        self.resBlock5 = ResBlock(2 * 4 * 32, 2 * 4 * 32, 0.2, pooling=False)

        # decoder
        self.upBlock1 = UpBlock(2 * 4 * 32, 4 * 32, 0.2)
        self.upBlock2 = UpBlock(4 * 32, 4 * 32, 0.2)
        self.upBlock3 = UpBlock(4 * 32, 2 * 32, 0.2)
        self.upBlock4 = UpBlock(2 * 32, 32, 0.2, drop_out=False)

        # head
        self.logits = nn.Conv2d(32, num_class, kernel_size=(1, 1))

        # loss
        self.build_loss_funs(model_cfgs)

    def build_loss_funs(self, model_cfgs):
        self.top_k_percent_pixels = model_cfgs.TOP_K_PERCENT_PIXELS

        if model_cfgs.LOSS == 'wce':
            weight = torch.tensor(ClassWeightSemikitti.get_weight()).cuda()
            self.WCE = torch.nn.CrossEntropyLoss(reduction='none', weight=weight).cuda()
        elif model_cfgs.LOSS == 'dice':
            self.WCE = CrossEntropyDiceLoss(reduction='none').cuda()

        if self.if_ls_loss:
            self.LS = Lovasz_softmax(ignore=0).cuda()

        if self.if_bd_loss:
            self.BD = BoundaryLoss().cuda()

    def forward(self, batch):
        scan_rv = batch['scan_rv']  # [bs, 6, H, W]
        label_rv = batch['label_rv']
        if len(label_rv.size()) != 3:
            label_rv = label_rv.squeeze(dim=1)  # [bs, H, W]

        downCntx = self.downCntx(scan_rv)
        downCntx = self.downCntx2(downCntx)
        downCntx = self.downCntx3(downCntx)

        down0c, down0b = self.resBlock1(downCntx)
        down1c, down1b = self.resBlock2(down0c)
        down2c, down2b = self.resBlock3(down1c)
        down3c, down3b = self.resBlock4(down2c)
        down5c = self.resBlock5(down3c)

        up4e = self.upBlock1(down5c,down3b)
        up3e = self.upBlock2(up4e, down2b)
        up2e = self.upBlock3(up3e, down1b)
        up1e = self.upBlock4(up2e, down0b)

        logits = self.logits(up1e)

        if self.training:
            pixel_losses = self.WCE(logits, label_rv)
            pixel_losses = pixel_losses.contiguous().view(-1)

            if self.top_k_percent_pixels == 1.0:
                loss_ce = pixel_losses.mean()
            else:
                top_k_pixels = int(self.top_k_percent_pixels * pixel_losses.numel())
                pixel_losses, _ = torch.topk(pixel_losses, top_k_pixels)
                loss_ce = pixel_losses.mean()

            if self.if_ls_loss:
                loss_ls = self.LS(F.softmax(logits, dim=1), label_rv)
                loss_ls = loss_ls.mean()
            else:
                loss_ls = 0.

            if self.if_bd_loss:
                loss_bd = self.BD(F.softmax(logits, dim=1), label_rv)
            else:
                loss_bd = 0.

            loss = 1.0 * loss_ce + 3.0 * loss_ls + 1.0 * loss_bd

            ret_dict = {'loss': loss}
            disp_dict = {'loss': loss.item()}
            tb_dict = {'loss': loss.item()}

            return ret_dict, tb_dict, disp_dict

        else:
            return {'point_predict': logits, 'point_labels': label_rv}


import sys
import time

from qtpy.QtWidgets import QApplication

from ..lsl import StreamInlet, resolve_streams
from ..utils._checks import check_type
from ..utils.logs import _use_log_level, logger
from .control_gui.control_eeg import ControlGUI_EEG
from .scope.scope_eeg import ScopeEEG

class StreamViewer:
    """Class for visualizing the signals coming from an LSL stream.

    The stream viewer will connect to only one LSL stream. If ``stream_name``
    is set to ``None``, an automatic search is performed followed by a prompt
    if multiple non-markers streams are found.

    Parameters
    ----------
    stream_name : str | None
        Servers' name to connect to. ``None`` will prompt the user.
    """

    def __init__(self, stream_name=None):
        self._sinfo = StreamViewer._check_stream_name(stream_name)

    def start(self, bufsize=0.2):
        """Connect to the selected amplifier and plot the streamed data.

        If ``stream_name`` is not provided, look for available streams on the
        network.

        Parameters
        ----------
        bufsize : int | float
            Buffer/window size of the attached Viewer.
            The default ``0.2`` should work in most cases since data is fetched
            every 20 ms.
        """
        self._inlet = StreamInlet(self._sinfo)
        self._inlet.open_stream()
        time.sleep(bufsize)  # Delay to fill the LSL buffer.
        self._scope = ScopeEEG(self._inlet)
        app = QApplication(sys.argv)
        self._ui = ControlGUI_EEG(self._scope)
        sys.exit(app.exec_())

    # --------------------------------------------------------------------
    @staticmethod
    def _check_stream_name(stream_name):  # noqa
        """
        Check that the stream_name is valid or search for a valid stream on
        the network.
        """
        check_type(stream_name, (None, str), item_name="stream_name")
        streams = resolve_streams(name=stream_name)
        if len(streams) == 0:
            raise RuntimeError("No LSL stream found.")
        elif len(streams) == 1:
            return streams[0]
        else:
            with _use_log_level("INFO"):
                logger.info("-- List of servers --")
                for k, stream in enumerate(streams):
                    logger.info("%i: %s", k, stream.name)
            index = input(
                "Stream index? Hit enter without index to select the first server.\n>> "
            )
            if index.strip() == "":
                index = 0
            else:
                index = int(index.strip())
            return streams[index]


import numpy as np
import math
from typing import Union, Tuple, List, Dict
import pandas as pd
from tqdm import tqdm_notebook
from itertools import combinations
import matplotlib.pyplot as plt

EPS = 0.1

def in_shape(img: np.ndarray, pixel: List) -> bool:
    """Short summary:
        function that verifies if a pixel belongs to the image

    Parameters
    ----------
    img : np.ndarray
        Description of parameter `img`.
    pixel : List
        Description of parameter `pixel`.

    Returns
    -------
    bool
        Description of returned object.

    """
    return (
        pixel[0] > -1
        and pixel[0] < img.shape[0]
        and pixel[1] > -1
        and pixel[1] < img.shape[1]
    )

sign = lambda x: math.copysign(1, x)
"""Short summary:

    Fonction that return sign of a real number.

Parameters
----------
x : float
    Description of parameter `x`.

Returns
-------
int
    Description of returned object.

"""

def dl(pixel1: np.ndarray, pixel2: np.ndarray, frontier: List[List]) -> int:

    """Short summary:

        Fonction that compute piece of frontier perimeter.

    Parameters
    ----------
    pixel1 : np.ndarray
        Description of parameter `pixel1`.
    pixel2 : np.ndarray
        Description of parameter `pixel2`.
    frontier : List[List]
        Description of parameter `frontier`.

    Returns
    -------
    int
        Description of returned object.

    """

    if (
        (pixel1 in frontier)
        and (pixel2 in frontier)
        and (pixel1[0] != pixel2[0])
        and (pixel1[1] != pixel2[1])
    ):
        return 1
    return 0

def P(frontier: List[List]) -> int:
    """Short summary:
        Fonction that compute the perimeter of Omega using standard dl

    Parameters
    ----------
    frontier : List[List]
        Description of parameter `frontier`.

    Returns
    -------
    int
        Description of returned object.

    """

    return len(frontier)

def H1(w: np.ndarray, frontier: List[List]) -> float:

    """Short summary:
        Fonction that compute the H1 term in the M-S fonctional.

    Parameters
    ----------
    w : np.ndarray
        Description of parameter `w`.
    frontier : List[List]
        Description of parameter `frontier`.

    Returns
    -------
    float
        Description of returned object.

    """
    s = 0
    image_shape = w.shape
    w = np.pad(w, 1, mode="edge")
    for i in range(image_shape[0]):
        for j in range(image_shape[1]):
            if [i, j] not in frontier:
                partial_x = w[i + 1, j] - w[i, j]
                partial_y = w[i, j + 1] - w[i, j]
                s += partial_x ** 2 + partial_y ** 2
    return s

def norm(w: np.ndarray, u: np.ndarray) -> float:
    """Short summary:
        Fonction that compute the last term of M-S fonctional.

    Parameters
    ----------
    w : np.ndarray
        Description of parameter `w`.
    u : np.ndarray
        Description of parameter `u`.

    Returns
    -------
    float
        Description of returned object.

    """

    return np.linalg.norm(w - u) ** 2

def munford_shah(w: np.ndarray, u: np.ndarray, frontier: List[List]) -> float:

    """Short summary:
        Fonction that compute de M-F fonctional

    Parameters
    ----------
    w : np.ndarray
        Description of parameter `w`.
    u : np.ndarray
        Description of parameter `u`.
    frontier : List[List]
        Description of parameter `frontier`.

    Returns
    -------
    float
        Description of returned object.

    """

    return P(frontier) + H1(w, frontier) + norm(w, -u)

def dl2(
    pixel1: np.ndarray,
    pixel2: np.ndarray,
    frontier: List[tuple],
    w: np.ndarray,
    dx: np.ndarray,
    dy: np.ndarray,
) -> float:
    """Short summary:

       Fonction that compute piece of frontier perimeter with the contribution of the gradient of w.

    Parameters
    ----------
    pixel1 : np.ndarray
        Description of parameter `pixel1`.
    pixel2 : np.ndarray
        Description of parameter `pixel2`.
    frontier : List[tuple]
        Description of parameter `frontier`.
    w : np.ndarray
        Description of parameter `w`.
    dx : np.ndarray
        Description of parameter `dx`.
    dy : np.ndarray
        Description of parameter `dy`.

    Returns
    -------
    float
        Description of returned object.

    """

    partial_x = w[pixel1[0] + 1, pixel1[1]] - w[pixel1[0], pixel1[1]]
    partial_y = w[pixel1[0], pixel1[1] + 1] - w[pixel1[0], pixel1[1]]

    return (np.ones(w.shape) - (dx ** 2 + dy ** 2))[pixel1[0], pixel1[1]]

def H_eps(t: float, eps: float) -> float:

    """Short summary:

        Function that eval H_eps function (see chapter 6).

    Parameters
    ----------
    t : float
        Description of parameter `t`.
    eps : float
        Description of parameter `eps`.

    Returns
    -------
    float
        Description of returned object.

    """

    if t >= eps:
        return 1

    elif t >= -eps and t <= eps:
        return (1 / 2) * (1 + (t / eps) + (1 / math.pi) * math.sin(math.pi * t / eps))

    else:
        return 0

def H_eps_derivative(t: float, eps: float) -> float:

    """Short summary:

        Function that eval H_eps derivative function (see chapter 6).

    Parameters
    ----------
    t : float
        Description of parameter `t`.
    eps : float
        Description of parameter `eps`.

    Returns
    -------
    float
        Description of returned object.

    """

    if t >= eps:
        return 0

    elif t >= -eps and t <= eps:
        return (1 / 2 * eps) * (1 + math.cos(math.pi * t / eps))

    else:
        return 0

def in_frontier(pixel: List, phi: np.ndarray) -> bool:
    """Short summary:

       Fonction that return True if a pixel is in the frontier, else False

    Parameters
    ----------
    pixel : List
        Description of parameter `pixel`.
    phi : np.ndarray
        Description of parameter `phi`.

    Returns
    -------
    bool
        Description of returned object.

    """

    for [i, j] in get_neighbour(pixel, phi):
        if sign(phi[i, j]) == sign(phi[pixel[0], pixel[1]]):
            return False
    return True

def grad_x(img: np.ndarray, adjoint: int) -> np.ndarray:
    """Short summary:

       Fonction that compute the first partial derivative of w.

    Parameters
    ----------
    img : np.ndarray
        Description of parameter `img`.
    adjoint : int
        Description of parameter `adjoint`.

    Returns
    -------
    np.ndarray
        Description of returned object.

    """
    sx, sy = np.shape(img)
    diff_x = np.copy(img)

    if adjoint == 0:
        for x in range(sx):
            if x == sx - 1:
                xnext = 0
            else:
                xnext = x + 1
            for y in range(sy):
                diff_x[x, y] = img[xnext, y] - img[x, y]
    else:
        for x in range(sx):
            if x == 0:
                xprev = sx - 1
            else:
                xprev = x - 1
            for y in range(sy):
                diff_x[x, y] = img[xprev, y] - img[x, y]

    return diff_x

def grad_y(img: np.ndarray, adjoint: int) -> np.ndarray:
    """Short summary:

       Fonction that compute the second partial derivative of w.

    Parameters
    ----------
    img : np.ndarray
        Description of parameter `img`.
    adjoint : int
        Description of parameter `adjoint`.

    Returns
    -------
    np.ndarray
        Description of returned object.

    """
    sx, sy = np.shape(img)
    diff_y = np.copy(img)

    if adjoint == 0:

        for y in range(sy):
            if y == sy - 1:
                ynext = 0
            else:
                ynext = y + 1
            for x in range(sx):
                diff_y[x, y] = img[x, ynext] - img[x, y]
    else:
        for y in range(sy):
            if y == 0:
                yprev = sy - 1
            else:
                yprev = y - 1
            for x in range(sx):
                diff_y[x, y] = img[x, yprev] - img[x, y]

    return diff_y

def grad_w_part(
    w: np.ndarray, u: np.ndarray, lambda_: float, mu: float, phi: np.ndarray,
) -> np.ndarray:

    """Short summary:
       Fonction that compute gradient of w part of the gradient.

    Parameters
    ----------
    w : np.ndarray
        Description of parameter `w`.
    u : np.ndarray
        Description of parameter `u`.
    frontier : List[List]
        Description of parameter `frontier`.
    lambda_ : float
        Description of parameter `lambda_`.
    mu : float
        Description of parameter `mu`.
    phi: np.ndarray
        Description of parameter `phi`.

    Returns
    -------
    np.ndarray
        Description of returned object.

    """
    image_size = w.shape

    data_term = 2 * (w - u)
    tmpx = grad_x(w, 0)
    tmpx1 = grad_x(tmpx, 1)
    tmpy = grad_y(w, 0)
    tmpy1 = grad_y(tmpy, 1)

    grad = 2 * (tmpx1 + tmpy1)

    for i in range(grad.shape[0]):
        for j in range(grad.shape[1]):
            if in_frontier([i, j], phi):
                grad[i, j] = 0

    return lambda_ * grad + mu * data_term

def get_neighbour(pixel: List, img: np.ndarray) -> List[List]:
    """Short summary:
        Fonction that compute the neighborhood of a pixel according to the 4-connexity.

    Parameters
    ----------
    pixel : List
        Description of parameter `pixel`.
    img : np.ndarray
        Description of parameter `img`.

    Returns
    -------
    List[List]
        Description of returned object.

    """

    neighborhood = [
        [pixel[0] + 1, pixel[1]],
        [pixel[0], pixel[1] + 1],
        [pixel[0] - 1, pixel[1]],
        [pixel[0], pixel[1] - 1],
    ]
    real_neighborhood = []
    for elt in neighborhood:
        if in_shape(img, elt):
            real_neighborhood.append(elt)
    return real_neighborhood

def grad_phi_part(
    phi: np.ndarray, w: np.ndarray, omega_frontier: List[List], eps: float
):
    """Short summary:
       Fonction that compute gradient of phi part of the gradient.

    Parameters
    ----------
    phi : np.ndarray
        Description of parameter `phi`.
    w : np.ndarray
        Description of parameter `w`.
    omega_frontier : List[List]
        Description of parameter `omega_frontier`.
    eps : float
        Description of parameter `eps`.

    Returns
    -------
    type
        Description of returned object.

    """
    size = phi.shape
    omega_term = np.zeros(size)
    w = np.pad(w, 1, mode="edge")
    tmpx = grad_x(w, 0)
    tmpx1 = grad_x(tmpx, 1)
    tmpy = grad_y(w, 0)
    tmpy1 = grad_y(tmpy, 1)
    for i in range(size[0]):
        for j in range(size[1]):
            for e in get_neighbour([i, j], phi):
                omega_term[i, j] += (
                    dl2([i, j], e, omega_frontier, w, tmpx1, tmpy1)
                    * H_eps_derivative(phi[i, j], eps)
                    * (1 - 2 * H_eps(phi[e[0], e[1]], eps))
                )

    return omega_term

def get_frontier_phi(omega: List[List], phi: np.ndarray) -> List[List]:
    """Short summary:
       Fonction that compute the frontier of omega.

    Parameters
    ----------
    omega : List[List]
        Description of parameter `omega`.
    phi : np.ndarray
        Description of parameter `phi`.

    Returns
    -------
    List[List]
        Description of returned object.

    """
    frontier = []
    for pixel in omega:
        i = pixel[0]
        j = pixel[1]

        if (
            not in_shape(phi, (i + 1, j))
            or not in_shape(phi, (i, j + 1))
            or not in_shape(phi, (i - 1, j))
            or not in_shape(phi, (i, j - 1))
        ):
            frontier.append([i, j])

        elif (
            sign(phi[i, j]) == -sign(phi[i + 1, j])
            or sign(phi[i, j]) == -sign(phi[i, j + 1])
            or sign(phi[i, j]) == -sign(phi[i - 1, j])
            or sign(phi[i, j]) == -sign(phi[i, j - 1])
        ):
            frontier.append([i, j])
    return frontier

def gradient_descent(
    u: np.ndarray,
    step_w: float,
    step_phi: float,
    eps: float,
    lambda_: float,
    mu: float,
    it: int,
    verbose: bool,
    mode: str,
) -> Dict[str, Union[np.ndarray, List]]:

    """Short summary:

       Function that compute simple gradient descent algorithm.

    Parameters
    ----------
    u : np.ndarray
        Description of parameter `u`.
    step_w : float
        Description of parameter `step_w`.
    step_phi : float
        Description of parameter `step_phi`.
    eps : float
        Description of parameter `eps`.
    lambda_ : float
        Description of parameter `lambda_`.
    mu : float
        Description of parameter `mu`.
    it : int
        Description of parameter `it`.
    verbose : bool
        Description of parameter `verbose`.
    mode : str
        Description of parameter `mode`.

    Returns
    -------
    Dict[str,Union[np.ndarray,List]]
        Description of returned object.

    """

    phi = np.copy(u)
    # phi = np.random.uniform(-1, 1, u.shape)
    omega = np.argwhere(phi >= 0).tolist()
    frontier = get_frontier_phi(omega=omega, phi=phi)
    norm_grad_phi = []
    norm_grad_w = []
    functional = []
    w = u

    if mode == "standard":
        for i in tqdm_notebook(range(it)):
            print(f"itération {i}/{it}")
            grad_w = grad_w_part(w, u, lambda_, mu, phi)
            w = w - (step_w * grad_w)

            grad_phi = grad_phi_part(phi=phi, w=w, omega_frontier=frontier, eps=eps)
            phi = phi - (step_phi * grad_phi)

            omega = np.argwhere(phi >= 0).tolist()
            frontier = get_frontier_phi(omega=omega, phi=phi)

            norm_grad_phi.append(np.linalg.norm(grad_phi))
            norm_grad_w.append(np.linalg.norm(grad_w))
            functional.append(munford_shah(w, u, frontier))
            if verbose:
                print(f"itération {i} : w gradient: {norm_grad_w[-1]}")
                print(f"itération {i} : phi gradient: {norm_grad_phi[-1]}")
                print(f"itération {i} munford_shah functional: {functional[-1]}")

    return {
        "w": w,
        "omega": omega,
        "phi": phi,
        "frontier": frontier,
        "norm_grad_phi": norm_grad_phi,
        "norm_grad_w": norm_grad_w,
        "functional": functional,
    }


#!/usr/bin/env python3

# Example on scattering
from mpi4py import MPI

# Define the communicator
world_comm = MPI.COMM_WORLD

# Get workd size
world_size = world_comm.Get_size()

# Get the rank
my_rank = world_comm.Get_rank()

# Generate data in rank = 0 to be scattered

if my_rank == 0:
    sample_data = [(4.*y + 1.)**y for y in range(world_size)]

else:
    sample_data = None

# Scatter the data from rank = 0
sample_data = world_comm.scatter(sample_data, root = 0)

# Printing the info from each rank
print("Rank: " + str(my_rank) + " sees: " + str(sample_data))


import xlrd

wb = xlrd.open_workbook('C:\\Users\\ppirogov\\Desktop\\Паше\\tab.xlsx')
sheet_names = wb.sheet_names()
sh = wb.sheet_by_name(sheet_names[0])
nmin = sh.row_values(6)[2]
for rownum in range(7, 27):
    temp = sh.row_values(rownum)
    nmin = min(nmin, temp[2])
print(nmin)
print (sh.row_values(0)[0])


from typing import List

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        a = 0
        for num in nums:
            # xor
            # the bit of the number itself will be reversed when xor
            a ^= num
        return a


from google.cloud import bigquery

client = bigquery.Client()

table_id = "datafold-dev-2.data_diff.tmp_rating"
dataset_name = "data_diff"

client.create_dataset(dataset_name, exists_ok=True)

job_config = bigquery.LoadJobConfig(
    source_format=bigquery.SourceFormat.CSV,
    skip_leading_rows=1,
    autodetect=True,
)

with open("ratings.csv", "rb") as source_file:
    job = client.load_table_from_file(source_file, table_id, job_config=job_config)

job.result()  # Waits for the job to complete.

table = client.get_table(table_id)  # Make an API request.
print("Loaded {} rows and {} columns to {}".format(table.num_rows, len(table.schema), table_id))

# run_sql("ALTER TABLE `datafold-dev-2.data_diff.Rating` ADD COLUMN id BYTES")
# run_sql("UPDATE `datafold-dev-2.data_diff.Rating` SET id = cast(GENERATE_UUID() as bytes) WHERE True")


from genetic_algorithm import run_genetic_algorithm
from utils import load_csv, get_cost, print_output, plot_progress, plot_solution, output_to_csv
import time
import numpy as np
import csv
import random

tests = [
	{
		'data':'5_cities.csv',
		'num_stations':1
	},
	{
		'data':'data.csv',
		'num_stations':6
	},
	{
		'data':'20_cities.csv',
		'num_stations':8
	},
	{
		'data':'50_cities.csv',
		'num_stations':20
	},
	# {
	# 	'data':'100_cities.csv',
	# 	'num_stations':40
	# },
	# {
	# 	'data':'500_cities.csv',
	# 	'num_stations':100
	# },
]

test_runs = 50
test_ctr = 0

while test_ctr < test_runs:
	print(test_ctr)
	test_results = []
	test_ctr +=1

	num_generations = random.randint(50, 400)
	population_size = random.choice(range(50, 400, 2))
	crossover_rate = random.uniform(0, 1)
	mutation_rate = random.uniform(0, 1)
	num_elites = random.randint(0, population_size)

	for test in tests:
		results = []
		cities = load_csv(f"./data/{test['data']}")
		num_stations = test['num_stations']
		num_cities = len(cities)
		start = time.time()
		best_solution, best_solutions, gen_solutions = run_genetic_algorithm(
			cities=cities,
			num_generations=num_generations,
			population_size=population_size,
			crossover_rate=crossover_rate,
			mutation_rate=mutation_rate,
			n_bits=num_cities,
			n_true=num_stations,
			num_elites=num_elites,
			stuck_max=100
		)
		runtime = time.time() - start

		best_dist = get_cost(best_solution, cities, num_stations)
		# print(f"Total stations: {np.sum(best_solution)}")
		# print_output("Genetic Algorithm", runtime, best_dist, num_cities, num_stations)
		# solutions = [get_cost(s, cities, num_stations) for s in gen_solutions]
		# plot_progress(solutions, f'genetic_{num_cities}_{num_stations}.png')
		# plot_solution(best_solution, cities, f'genetic_{num_cities}_{num_stations}.png')

		test_results.append([
			f"{num_cities}/{num_stations}",
			f"{runtime:0.3f}",
			int(best_dist),
			num_generations,
			population_size,
			f"{crossover_rate:0.3f}",
			f"{mutation_rate:0.3f}",
			num_elites,
		])

	output_to_csv(f"genetic-{test_ctr}", test_results)


from typing import Any, Optional, Union

from reactivex import Observable, abc
from reactivex.scheduler import ImmediateScheduler

def throw_(
    exception: Union[str, Exception], scheduler: Optional[abc.SchedulerBase] = None
) -> Observable[Any]:
    exception_ = exception if isinstance(exception, Exception) else Exception(exception)

    def subscribe(
        observer: abc.ObserverBase[Any], scheduler: Optional[abc.SchedulerBase] = None
    ) -> abc.DisposableBase:
        _scheduler = scheduler or ImmediateScheduler.singleton()

        def action(scheduler: abc.SchedulerBase, state: Any) -> None:
            observer.on_error(exception_)

        return _scheduler.schedule(action)

    return Observable(subscribe)

__all__ = ["throw_"]


import os
import cv2

def main():
    for srcpath, _, files in os.walk('photos'):
        if len(_):
            continue
        dstpath = srcpath.replace('photos', 'faces')
        if not os.path.exists(dstpath):
            os.makedirs(dstpath)
        for filename in files:
            if filename.startswith('.'):
                continue
            try:
                detect_faces(srcpath, dstpath, filename)
            except:
                continue

def detect_faces(srcpath, dstpath, filename):
    face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
    image = cv2.imread('{}/{}'.format(srcpath, filename))
    gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) #cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(gray_image, 1.3, 5)
    # Extract when just one face is detected
    print('{}/{} {}'.format(srcpath, filename, len(faces) == 1))
    if (len(faces) == 1):
        (x, y, w, h) = faces[0]
        image = image[y:y+h, x:x+w]
        image = cv2.resize(image, (100, 100))
        cv2.imwrite('{}/{}'.format(dstpath, filename), image)

    # face_cascade_path = '{}/{}'.format(srcpath, filename)
    # face_cascade = cv2.CascadeClassifier(os.path.expanduser(face_cascade_path))
    # face_cascade.load("./haarcascade_frontalface_alt.xml")

    # scale_factor = 1.1
    # min_neighbors = 3
    # min_size = (30, 30)
    # flags = cv2.cv.CV_HAAR_SCALE_IMAGE

    # for infname in sys.argv[2:]:
    #     image_path = os.path.expanduser(infname)
    #     image = cv2.imread(image_path)

    #     faces = face_cascade.detectMultiScale(image, scaleFactor = scale_factor, minNeighbors = min_neighbors, minSize = min_size, flags = flags)
    #     if (len(faces) == 1):
    #         (x, y, w, h) = faces[0]
    #         image = image[y:y+h, x:x+w]
    #         image = cv2.resize(image, (100, 100))
    #         cv2.imwrite('{}/{}'.format(dstpath, filename), image)

if __name__ == '__main__':
    main()