import asyncio
import collections
import functools
import math
import random
import time
from enum import Enum
from io import BytesIO

import aiohttp
import typing

import discord
from PIL import ImageFont, ImageDraw, ImageOps, Image
from discord.ext import commands, tasks
from jishaku.functools import executor_function

from .classes import other
from .classes.converters import AmountConverter
from .utils import fuzzy, get_language

class SlotsEmojis(Enum):
    CACTUS = "\U0001f335"
    GEM = "\U0001f48e"
    HEART = "\U00002764"
    SPARKLING_HEART = "\U0001f496"
    STAR = "\U00002b50"
    ROSE = "\U0001f339"

class CatError(commands.CommandError):
    def __init__(self, type_):
        self.type = type_

class CatIsDead(CatError):
    def __init__(self):
        super().__init__('dead')

class MemberDoesNotHaveCat(CatError):
    def __init__(self):
        super().__init__('no_cat')

class DefaultCat:
    """Default representation for cats"""
    def __init__(self, bot, cat):
        self.bot = bot
        self.cat = cat

    def __getattr__(self, attr):
        if attr == "owner":
            return self._owner
        if attr == "stamina":
            attr = "sta"
        if attr == "health":
            attr = "hp"

        return self.cat[attr]

    @property
    def _owner(self):
        user = self.bot.get_user(self.cat['owner_id'])
        return user

    async def buy(self, item):
        try:
            cost = COST[item]
        except KeyError:
            cost = WEAPONS_PRICE[item]

        self.cat['inventory'].append(item)

        await self.bot.db.execute("UPDATE cats SET money = money - $1, inventory = $2 WHERE owner_id = $3", cost,
                                  self.inventory, self.cat['owner_id'])

        return self.money - cost

    async def sell(self, item):
        try:
            price = COST[item]
        except KeyError:
            price = WEAPONS_PRICE[item]

        self.cat['inventory'].remove(item)

        await self.bot.db.execute("UPDATE cats SET money = money + ($1 / 2), inventory = $2 WHERE owner_id = $3", price,
                                  self.inventory, self.cat['owner_id'])

        return self.money + round(price / 2)

WEAPON_DAMAGE_MAP = {
    "glock-6": 17,
    "shovel": 9,
    "glock-9": 12,
    "usp-s": 17,
    "axe": 13,
    "p90": 16,  # 999
    "mp7": 17,
    "mac-10": 27300,
    "mp9": 17,
    "m4a1": 23,
    "deagle": 66,
    "glock-17": 19,
    "ak-47": 24,
    "beretta": 25,
    "thompson": 28,
    "m16": 34,
    "awp": 79,
    "luger": 72
}

WEAPON_RELOAD_MAP = {
    "glock-6": 1,
    "shovel": 2,
    "glock-9": 1,
    "usp-s": 1,
    "axe": 2,
    "p90": 1,
    "mp7": 1,
    "mac-10": 1,
    "mp9": 1,
    "m4a1": 1,
    "deagle": 4,
    "glock-17": 1,
    "ak-47": 1,
    "beretta": 2,
    "thompson": 1,
    "m16": 2,
    "awp": 3,
    "luger": 3
}

class Weapon:
    def __init__(self, type_):
        self.type = type_

        self.reloaded = True

        self._reload_in = 0  # rounds
        if type_ not in WEAPON_RELOAD_MAP:
            raise ValueError(f"{type_} not in reload_map")
        self.__default_reload = WEAPON_RELOAD_MAP[type_]

    def __repr__(self):
        return self.__str__()

    def __str__(self):
        return f'<Weapon type={self.type}>'

    @property
    def raw(self):
        return self.type

    @property
    def damage(self):
        try:
            return WEAPON_DAMAGE_MAP[self.type]
        except KeyError:
            return None

    @property
    def reload_in(self):
        return self._reload_in

    def _shoot(self, enemy):
        enemy.hp -= random.randint(self.damage - 5, self.damage + 4)

    def shoot(self, enemy: collections.namedtuple):
        if self.reloaded:
            self.reloaded = False
            self._reload_in = self.__default_reload

            self._shoot(enemy)

            self._reload_in -= 1

        elif self.__default_reload == 1:
            self._shoot(enemy)
        elif self._reload_in == 0:
            self.reloaded = True
        else:
            self._reload_in -= 1

ALL_WEAPONS = ['ak-47', 'knife', 'm4a1', 'm16', 'glock-17', 'glock-9', 'glock-6', 'desert eagle', 'awp', 'usp-s',
               'thompson', 'beretta', 'luger', 'p90', 'mp7', 'mac-10', 'mp9', 'axe', 'shovel']

class Box:
    def __init__(self, type_):
        self.type = type_

    def __repr__(self):
        return self.__str__()

    def __str__(self):
        return f'<Box type={self.type}>'

    @property
    def raw(self):
        return self.type

ALL_BOXES = ['common_box', 'rare_box', 'epic_box', 'legendary_box', 'pretty_box']

USEABLE_ITEMS = ['karma', 'energy drink', 'health drink', 'food drink']

class ItemsConverter(commands.Converter):
    def __init__(self, type_):
        self.type = type_

    async def convert(self, ctx, argument):
        if self.type == 'box':
            box = fuzzy.extract_one(argument, ALL_BOXES, score_cutoff=60)

            if not box:
                return None

            box = box[0]

            return Box(box)

        elif self.type == 'weapon':
            weapon = fuzzy.extract_one(argument, ALL_WEAPONS, score_cutoff=60)

            if not weapon:
                return None

            weapon = weapon[0]

            return Weapon(weapon)

        elif self.type == 'item':
            item = fuzzy.extract_one(argument, ALL_ITEMS, score_cutoff=60)

            if not item:
                return None

            item = item[0]

            return item

        elif self.type == 'useable':
            item = fuzzy.extract_one(argument, USEABLE_ITEMS, score_cutoff=60)

            if not item:
                return None

            item = item[0]

            return item

        else:
            raise NotImplemented(f"{self.type} is not implemented in this converter.")

COST = {
    "karma": 2000,
    "energy drink": 22000,
    "health drink": 24000,
    "food drink": 20000,

    "common_box": 7000,
    "rare_box": 14500,
    "epic_box": 46000,
    "legendary_box": 320000,
}

WEAPONS_PRICE = {
    "glock-6": 12500,
    "shovel": 9500,
    "glock-9": 14000,
    "usp-s": 17000,
    "axe": 10000,
    "p90": 12000,
    "mp7": 16000,
    "mac-10": 27300,
    "mp9": 32000,
    "m4a1": 29200,
    "deagle": 26700,
    "glock-17": 22420,
    "ak-47": 92000,
    "beretta": 62000,
    "thompson": 175000,
    "m16": 340000,
    "awp": 420000,
    "luger": 1700000
}

ALL_ITEMS = ["karma", "energy drink", "food drink", "health drink"]
ALL_ITEMS.extend(ALL_BOXES)
ALL_ITEMS.extend(ALL_WEAPONS)

BOX_MAP = {
    "common_box": ['glock-6', 'shovel', 'glock-9', 'usp-s', 'p90'],
    "rare_box": ['axe', 'm4a1', 'desert eagle', 'glock-17', 'mp7'],
    "epic_box": ['ak-47', 'beretta', 'thompson', 'm16', 'mac-10', 'mp9'],
    "legendary_box": ['awp', 'luger'],
    "pretty_box": ['legendary_box']  # todo ...
}

BOX_COLOR_MAP = {
    "common_box": discord.Color.greyple(),
    "rare_box": discord.Color.blue(),
    "epic_box": discord.Color.red(),
    "legendary_box": discord.Color.gold(),
    "pretty_box": discord.Color.dark_purple()
}

class Cat(commands.Cog):
    def __init__(self, bot):
        self.bot = bot

        self.losing_food.start()
        self.losing_sta.start()
        self.sleeping_restore.start()

        self.rose_team = [185712375628824577, 403600724342079490]

        self._fights = list()

    def cog_unload(self):
        self.losing_food.cancel()
        self.losing_sta.cancel()
        self.sleeping_restore.cancel()

    # async def update_cache(self, cat):
    #     user = self.bot.get_user(cat.owner_id)
    #
    #     cat_ = await self.bot.db.fetchrow("SELECT * FROM cats WHERE owner_id = $1", cat.owner_id)
    #     new_cat = DefaultCat(self.bot, cat_)
    #
    #     if cat.owner_id in self._cats_cache:
    #         self._cats_cache[cat.owner_id] = new_cat
    #
    #     if cat.owner_id in self._processing_cache:
    #         path = r"assets/images/cats/{}/{}.png"
    #         image_path = path.format(new_cat.color, 1)
    #
    #         avatar_bytes = await self.get_avatar(user)
    #
    #         fn = functools.partial(self.processing, avatar_bytes, new_cat, image_path, user)
    #         final_buffer = await self.bot.loop.run_in_executor(None, fn)
    #
    #         self._processing_cache[user.id] = final_buffer

    async def _prepare_trivia(self, ctx, *, diff=None):
        trivia_url = "https://opentdb.com/api.php?amount=1500&type=multiple"
        if diff is not None:
            trivia_url += f'&difficulty={diff}'

        async with self.bot.session.get(trivia_url) as req:
            data = await req.json()

        trivia = random.choice(data['results'])

        e = discord.Embed(
            description=f"{ctx.lang['category']}: {trivia['category']}\n{ctx.lang['difficulty']}: "
                        f"{trivia['difficulty']}\n{ctx.lang['you_have']} **60** {ctx.lang['seconds']}.",
            timestamp=ctx.message.created_at)

        question = trivia['question'].replace(''', "'")
        question = question.replace('"', "“")

        e.set_author(name=question)

        numbers = [
            '1\N{combining enclosing keycap}',
            '2\N{combining enclosing keycap}',
            '3\N{combining enclosing keycap}',
            '4\N{combining enclosing keycap}'
        ]

        answers = [trivia['correct_answer']]

        answers.extend(trivia['incorrect_answers'])

        random.shuffle(answers)

        data = {}

        for number, quest in zip(numbers, answers):

            quest = quest.replace(''', "'")
            quest = quest.replace('"', "“")

            data[number] = quest

            e.add_field(name=number, value=data[number], inline=False)

        message = await ctx.send(embed=e)
        for number in numbers:
            await message.add_reaction(number)

        def check(reaction, user):
            return user == ctx.author and reaction.message.channel.id == ctx.channel.id

        try:
            r, u = await self.bot.wait_for('reaction_add', check=check, timeout=60)
        except asyncio.TimeoutError:
            return await ctx.send(ctx.lang['TimeoutError'])

        correct = None

        for key, value in data.items():
            if value == trivia['correct_answer']:
                correct = key

        if r.emoji == correct:
            return True, trivia['correct_answer'], trivia['difficulty']
        return False, trivia['correct_answer'], trivia['difficulty']

    async def get_cat(self, member):
        cat = await self.bot.db.fetchrow("SELECT * FROM cats WHERE owner_id = $1", member.id)
        guild = await self.bot.get_guild_settings(member.guild.id)
        lang = self.bot.get_language_object(guild.lang)
        if await self.is_dead(member):
            raise commands.BadArgument(f"{member}, {lang['dead_cat'].format(guild.prefix)}")
        if not cat:
            raise commands.BadArgument(f"{member}, {lang['no_cat'].format(guild.prefix)}")
        return DefaultCat(self.bot, cat)

    async def lvl_up(self, cat):
        if cat['exp'] > round(9222 * cat['level']):
            await self.bot.db.execute("UPDATE cats SET level = level + 1, money = money + 1000  WHERE owner_id = $1",
                                      cat['owner_id'])
            return True
        else:
            return False

    async def is_dead(self, member):
        cat = await self.bot.db.fetchrow("SELECT * FROM cats WHERE owner_id = $1", member.id)
        if not cat:
            return

        cat = DefaultCat(self.bot, cat)

        if cat.food <= 0:
            await self.bot.db.execute("UPDATE cats SET is_dead = True, is_sleeping = False WHERE owner_id = $1",
                                      member.id)
            return True

        if cat.stamina <= 0:
            await self.bot.db.execute("UPDATE cats SET is_dead = True WHERE owner_id = $1", member.id)
            return True

        if cat.health <= 0:
            await self.bot.db.execute("UPDATE cats SET is_dead = True, is_sleeping = False WHERE owner_id = $1",
                                      member.id)
            return True

        if cat.is_dead:
            return True

        return False

    @tasks.loop(minutes=180)
    async def losing_food(self):  # todo notify about low food,sta
        async with self.bot.db.acquire():
            await self.bot.db.execute("UPDATE cats SET food = food - 1 WHERE food > 0")
            await self.bot.db.execute("UPDATE cats SET is_dead = TRUE WHERE food = 0")

    @tasks.loop(seconds=60)
    async def sleeping_restore(self):
        async with self.bot.db.acquire():
            await self.bot.db.execute("UPDATE cats SET sta = sta + 1, sleeping_time = sleeping_time + 1 WHERE sta < 100 AND is_sleeping = true AND is_dead = false")
            await self.bot.db.execute("UPDATE cats SET sleeping_time = 0, is_sleeping = false WHERE is_sleeping = true AND sta = 100")

    @tasks.loop(minutes=75)
    async def losing_sta(self):
        async with self.bot.db.acquire():
            await self.bot.db.execute("UPDATE cats SET sta = sta - 1 WHERE sta > 0 AND is_sleeping = FALSE")
            await self.bot.db.execute("UPDATE cats SET is_dead = TRUE WHERE sta = 0")

    @losing_food.before_loop
    @sleeping_restore.before_loop
    @losing_sta.before_loop
    async def b4_tasks(self):
        await self.bot.wait_until_ready()

    @staticmethod
    def progress_bar(draw, y: int, color: tuple, progress: int):
        draw.rectangle(((41, y), (42 + (round(progress * 3.34)), y + 27)), fill=color)

    @staticmethod
    def write(image, text, cords: tuple, font, color: tuple = (0, 0, 0)):
        image.text(cords, text, fill=color, font=font)

    async def get_avatar(self, user: typing.Union[discord.User, discord.Member]) -> bytes:
        avatar_url = user.avatar_url_as(format="png")

        async with self.bot.session.get(str(avatar_url)) as response:
            avatar_bytes = await response.read()

        return avatar_bytes

    @executor_function
    def processing(self, avatar_bytes: bytes, cat, image_path, user) -> BytesIO:  # color: tuple,
        with Image.open(BytesIO(avatar_bytes)) as im:
            pic = r"assets/images/profile.png"
            size = 80, 80
            theme = cat.theme

            with Image.open(image_path) as caty:
                caty = caty.convert("RGBA")
                caty = caty.resize((240, 240))

                with Image.open(pic) as profile:
                    bg = Image.new('RGBA', (700, 800))
                    if theme:
                        end = ".png"
                        if theme == 'jungle1':
                            end = '.jpg'
                        theme = Image.open(r"assets/images/themes/" + theme + end)
                        bg.paste(theme)

                    bg.paste(profile, (0, 0), profile)

                    mask = Image.new('L', size, 0)
                    draw = ImageDraw.Draw(mask)
                    draw.ellipse((0, 0) + size, fill=255)

                    rgb_avatar = ImageOps.fit(im, size, centering=(0.5, 0.5))
                    rgb_avatar.putalpha(mask)
                    rgb_avatar.thumbnail(size)

                    bg.paste(caty, (44, 105), caty)
                    bg.paste(rgb_avatar, (35, 10), rgb_avatar)

                    PISTOLS = ['glock_17', 'glock-6', 'glock-9']

                    if cat.wore_gun:
                        if cat.wore_gun in PISTOLS:
                            x, y = 80, 200
                            size = (10, 10)
                        else:
                            x, y = 70, 240
                            size = (188, 120)

                        gun = Image.open(f'assets/images/guns/{cat.wore_gun}.png')
                        gun = gun.convert("RGBA")
                        gun = gun.resize(size, Image.ANTIALIAS)

                        bg.paste(gun, (x, y), gun)

                    d = ImageDraw.Draw(bg)

                    font = ImageFont.truetype(r"assets/images/fonts/light.otf", 45)
                    emoji_font = ImageFont.truetype(r"assets/images/fonts/emotes.otf", 45)

                    name = cat.name
                    if len(name) > 12:
                        name = name[:12] + "..."

                    self.write(d, name, (330, 100), font=font, color=(255, 255, 255))

                    if cat.owner.id in self.rose_team:
                        width = d.textsize(name, font=font)
                        self.write(d, "\U0001f339", (width[0] + 335, 110), font=emoji_font, color=(255, 255, 255))

                    self.write(d, str(cat.premium), (500, 211),
                               font=ImageFont.truetype(r"assets/images/fonts/medium.otf", 30))

                    self.write(d, '{:,d}'.format(int(cat.money)), (470, 254),
                               font=ImageFont.truetype(r"assets/images/fonts/medium.otf", 30))

                    self.write(d, str(cat.level), (460, 304),
                               font=ImageFont.truetype(r"assets/images/fonts/medium.otf", 30))

                    member_name = user.name
                    if len(member_name) > 18:
                        member_name = member_name[:18] + "..."
                    self.write(d, member_name, (10, 765), font=ImageFont.truetype(r"assets/images/fonts/medium.otf", 15))

                    self.progress_bar(d, 441, (52, 152, 219), cat.stamina)
                    self.write(d, str(cat.stamina), (175, 435), font=ImageFont.truetype(r"assets/images/fonts/medium.otf", 30))
                    self.progress_bar(d, 548, (46, 204, 113), cat.food)
                    self.write(d, str(cat.food), (175, 542), font=ImageFont.truetype(r"assets/images/fonts/medium.otf", 30))
                    self.progress_bar(d, 647, (233, 30, 64), cat.health)
                    self.write(d, str(cat.health), (175, 641), font=ImageFont.truetype(r"assets/images/fonts/medium.otf", 30))
                    final_buffer = BytesIO()
                    bg.save(final_buffer, "png")

        final_buffer.seek(0)
        return final_buffer

    @commands.group(invoke_without_command=True, aliases=['profile'])
    async def cat(self, ctx, member: discord.Member = None):
        """Pokazuje profil twojego kota."""
        member = member or ctx.author
        cat = await self.get_cat(member)

        if cat.is_sleeping:
            return await ctx.send(ctx.lang['cat_is_sleeping'])

        if cat.is_sleeping and cat.stamina == 100:
            return await ctx.send(ctx.lang['full_sta_sleeping_cat'])

        async with ctx.typing():
            start = time.time()

            # if ctx.author.id in self._processing_cache:
            #     buffer = self._processing_cache[ctx.author.id]
            #     buffer.seek(0)
            #     file = discord.File(filename=f"{ctx.author.id}.png", fp=buffer)
            #
            #     end = time.time()
            #     await ctx.send(f"Done in: {round(end-start, 4)}s", file=file)
            # else:
            path = r"assets/images/cats/{}/{}.png"
            image_path = path.format(cat.color, 1)

            avatar_bytes = await self.get_avatar(member)

            buff = await self.processing(avatar_bytes=avatar_bytes, cat=cat, image_path=image_path, user=ctx.author)

            # self._processing_cache[ctx.author.id] = final_buffer

            file = discord.File(filename=f"{ctx.author.id}.png", fp=buff)

            end = time.time()
            await ctx.send(f"Done in: {round(end-start, 2)}s", file=file)

    @cat.command()
    async def adopt(self, ctx):
        """Adoptuj swojego zwierzaka"""
        cat = await self.bot.db.fetchrow("SELECT * FROM cats WHERE owner_id = $1", ctx.author.id)
        if cat:
            return await ctx.send(ctx.lang['already_has_cat'])

        def check(m):
            return m.author == ctx.author and m.channel == ctx.channel

        color = random.choice(["czarnego",
                               "szarego",
                               "brązowego"])

        colors = {"czarnego": "black",
                  "szarego": "grey",
                  "brązowego": "brown"}

        await ctx.send(ctx.lang['adopted_cat'].format(ctx.lang[color]))

        try:
            msg = await self.bot.wait_for('message', check=check, timeout=30)
        except asyncio.TimeoutError:
            return await ctx.send(ctx.lang['TimeoutError'])

        name = msg.content
        name = name[:1].upper() + name[1:].lower()
        c = colors[color]
        await self.bot.db.execute("INSERT INTO cats (owner_id, name, color) VALUES ($1, $2, $3)",
                                  ctx.author.id, name, c)
        return await ctx.send(ctx.lang['cat_will_be_called'].format(name))

    @commands.command()
    async def roulette(self, ctx, pick: str, money):
        cat = await self.get_cat(ctx.author)

        z = ['green', 'red', 'black']
        if not pick.lower() in z:
            return await ctx.send(ctx.lang['not_correct_choose'].format(', '.join(z)))

        if money == "all":
            money = cat.money

        if money == "half":
            money = round(cat.money / 2)  # :)))

        if not str(money).isdigit():
            return await ctx.send(ctx.lang['not_correct_value'])

        money = int(money)

        if money < 5:
            return await ctx.send(ctx.lang['too_low_value'])

        if cat.money < money:
            return await ctx.send(ctx.lang['you_dont_have_so_much'])

        x = random.randint(0, 30)
        win = False
        won_money = None

        if pick.lower() == "green":
            if x == 0:
                won_money = money * 14
                win = True
            else:
                win = False
        elif pick.lower() == "black":
            if x >= 15:
                won_money = money * 2
                win = True
            else:
                win = False
        elif pick.lower() == "red":
            if x < 15:
                won_money = money * 2
                win = True
            else:
                win = False

        if win and won_money:
            msg = ctx.lang['you_won'].format(won_money, x)
            await self.bot.db.execute("UPDATE cats SET money = money + $1 WHERE owner_id = $2", won_money,
                                          ctx.author.id)
        else:
            msg = ctx.lang['you_lose'].format(x)
            await self.bot.db.execute("UPDATE cats SET money = money - $1 WHERE owner_id = $2", money,
                                          ctx.author.id)

        await ctx.send(msg)

    @commands.command()
    async def coinflip(self, ctx, money):
        """Postaw i wygraj."""
        cat = await self.get_cat(ctx.author)

        if money == "all":
            money = cat.money

        if money == "half":
            money = round(cat.money / 2)  # :)))

        if not str(money).isdigit():
            return await ctx.send(ctx.lang['not_correct_value'])

        if money < 5:
            return await ctx.send(ctx.lang['too_low_value'])

        if cat.money < money:
            return await ctx.send(ctx.lang['you_dont_have_so_much'])

        x = random.randint(0, 100)

        if x == 0:
            new_money = int(money * random.randint(2, 4))
            await ctx.send(ctx.lang['you_won_jackpot'].format(f"{new_money:,d}"))
        elif x >= 50:
            new_money = int(money + money)
            await self.bot.db.execute("UPDATE cats SET money = $1 WHERE owner_id = $2", new_money, ctx.author.id)
            await ctx.send(ctx.lang['you_won_'].format(f"{new_money:,d}"))
        else:
            new_money = int(money - money)
            await self.bot.db.execute("UPDATE cats SET money = $1 WHERE owner_id = $2", new_money, ctx.author.id)
            await ctx.send(ctx.lang['you_lose_'].format(f"{new_money:,d}"))

    @commands.command()
    @commands.cooldown(1, 5, commands.BucketType.user)
    async def slots(self, ctx, money):
        cat = await self.get_cat(ctx.author)

        if money == "all":
            money = cat.money

        if money == "half":
            money = round(cat.money / 2)  # :)))

        if not str(money).isdigit():
            return await ctx.send(ctx.lang['not_correct_value'])

        money = int(money)

        if money < 5:
            return await ctx.send(ctx.lang['too_low_value'])

        if cat.money < money:
            return await ctx.send(ctx.lang['you_dont_have_so_much'])

        all_slots_icons = [icon.value for icon in SlotsEmojis]

        x1 = random.choice(all_slots_icons)
        x2 = random.choice(all_slots_icons)
        x3 = random.choice(all_slots_icons)

        z = f"{x1} | {x2} | {x3}"

        muliplier_map = {
            "\U0001f335": 1,
            "\U0001f48e": 2,
            "\U00002764": 3,
            "\U0001f496": 4,
            "\U00002b50": 5,
            "\U0001f339": 7
        }

        muliplier = (muliplier_map[x1] +
                     muliplier_map[x2] + muliplier_map[x3]) / 10

        m = muliplier * money
        won_money = round(m) - money

        if won_money < 0:
            text = ctx.lang['slots_lose'].format(z, muliplier, f"{abs(won_money):,d}")

        elif won_money == 0:
            text = ctx.lang['slots_nothing'].format(z, muliplier)

        else:
            text = ctx.lang['slots_won'].format(z, muliplier, f"{won_money:,d}")

        await ctx.send(text)
        await self.bot.db.execute("UPDATE cats SET money = money + $1 WHERE owner_id = $2", won_money,
                                  ctx.author.id)

    @commands.command()
    @commands.cooldown(1, 1800, commands.BucketType.user)
    async def trivia(self, ctx, difficulty=None):
        if difficulty not in [None, "easy", "medium", "hard"]:
            raise commands.BadArgument("Wrong difficulty passed.")

        m = await self._prepare_trivia(ctx, diff=difficulty)
        cat = await self.get_cat(ctx.author)

        won_map = {
            'easy': random.randint(50, 120),
            'medium': random.randint(150, 320),
            'hard': random.randint(400, 650)
        }

        if m[0]:

            won = won_map[m[2]]

            await ctx.send(ctx.lang['trivia_won'].format(won))
            await self.bot.db.execute("UPDATE cats SET money = $1 WHERE owner_id = $2", cat.money + won,
                                      ctx.author.id)
        else:
            return await ctx.send(ctx.lang['trivia_lose'].format(m[1]))

    @cat.command(aliases=['inv', 'i'])
    @commands.cooldown(1, 3, commands.BucketType.user)
    async def inventory(self, ctx):
        cat = await self.get_cat(ctx.author)

        inv_map = dict()

        if not cat.inventory:
            return await ctx.send(ctx.lang['empty_inventory'])

        for item in cat.inventory:
            if item not in inv_map:
                inv_map[item] = 1
            else:
                inv_map[item] += 1

        text = []

        for key, value in inv_map.items():
            text.append(f"{key} x{value}")

        fmt = '\n'.join(text)

        return await ctx.send(f"```\n{fmt}\n```")

    @cat.command(aliases=['o'])
    @commands.cooldown(1, 5, commands.BucketType.user)
    async def open(self, ctx, box: ItemsConverter("box"), amount: AmountConverter = 1):
        cat = await self.get_cat(ctx.author)

        if not box:
            return await ctx.send(ctx.lang['no_box_like'])

        if not cat.inventory:
            return await ctx.send(ctx.lang['empty_inventory'])

        box = box.raw

        if box not in cat.inventory:
            return await ctx.send(ctx.lang['no_box_in_inventory'])

        all_user_boxes = len([item for item in cat.inventory if item == box])

        if amount == "all":
            amount = all_user_boxes

        amount = int(amount)

        if amount > all_user_boxes:
            return await ctx.send(ctx.lang['too_many_boxes'])

        won_items = []

        for _ in range(0, amount):
            won_item = random.choice(BOX_MAP[box])
            won_items.append('`' + won_item + '`')

            cat.inventory.append(won_item)
            cat.inventory.remove(box)

        z = '\n'.join(won_items)
        e = discord.Embed(description=f"{ctx.lang['you_opened']}:\n{z}.", color=BOX_COLOR_MAP[box])
        e.set_footer(text=ctx.author, icon_url=ctx.author.avatar_url)

        await ctx.send(embed=e)
        await self.bot.db.execute("UPDATE cats SET inventory = $1 WHERE owner_id = $2", cat.inventory, ctx.author.id)

    @cat.command()
    @commands.cooldown(1, 5, commands.BucketType.user)
    async def shop(self, ctx):
        cat = await self.get_cat(ctx.author)

        e = discord.Embed(description=f"{ctx.lang['balance']}: {int(cat.money):,d}$")
        e.set_author(name=str(ctx.author), icon_url=ctx.author.avatar_url)

        for item in COST:
            e.add_field(name=item, value=f'{int(COST[item]):,d}$', inline=True)

        e.add_field(name='premium', value='1,5$ pp')
        e.set_footer(text=ctx.lang['buy_example'].format(ctx.prefix, random.choice([x for x in COST])))
        return await ctx.send(embed=e)

    @cat.command()
    @commands.cooldown(1, 10, commands.BucketType.user)
    async def buy(self, ctx, amount: typing.Optional[int] = 1, *, item: ItemsConverter("item") = None):
        cat = await self.get_cat(ctx.author)

        if not item:
            return await ctx.send(ctx.lang['no_item_like'])

        orginal_item = item

        try:
            item = COST[item]
        except KeyError:
            item = WEAPONS_PRICE.get(item)
            if not item:
                return await ctx.send(ctx.lang['no_item_like'])

        if cat.money < item * amount:
            return await ctx.send(ctx.lang['no_money_for'].format(orginal_item, (item * amount) - cat.money))

        if orginal_item == 'karma':
            money = cat.money - (item * amount)
            karma = cat.karma + amount
            await self.bot.db.execute("UPDATE cats SET money = $1, karma = $2 WHERE owner_id = $3", money,
                                      karma, ctx.author.id)
            return await ctx.send(ctx.lang['bought_food'].format(amount))

        x = await ctx.confirm(ctx.lang['confirm_buying'].format(orginal_item, amount, item * amount), ctx.author)

        if x:
            for _ in range(0, amount):
                new_balance = await cat.buy(orginal_item)
            else:
                await ctx.send(ctx.lang['bought'].format(orginal_item, amount, item * amount, new_balance))
        else:
            await ctx.send(ctx.lang['abort'])

    @cat.command(enabled=False)
    async def wear(self, ctx, *, weapon: ItemsConverter("weapon")):
        cat = await self.get_cat(ctx.author)

        if not weapon:
            return await ctx.send(ctx.lang['no_item_like'])

        if weapon.raw not in cat.inventory:
            return await ctx.send(ctx.lang['no_item_in_inventory'])

        await self.bot.db.execute("UPDATE cats SET wore_gun = $1 WHERE owner_id = $2", weapon.raw, ctx.author.id)
        await ctx.send(":ok_hand:")

    @cat.command()
    async def sell(self, ctx, *, item: ItemsConverter("item")):
        cat = await self.get_cat(ctx.author)

        if not item:
            return await ctx.send(ctx.lang['no_item_like'])

        if item not in cat.inventory:
            return await ctx.send(ctx.lang['no_item_in_inventory'])

        orginal_item = item

        try:
            item = WEAPONS_PRICE[item]
        except KeyError:
            item = COST[item]

        price = round(item / 2)
        multiplier = (item / 2) / item * 100

        x = await ctx.confirm(ctx.lang['confirm_selling'].format(orginal_item, price, multiplier),
                              ctx.author)

        if x:
            new_balance = await cat.sell(orginal_item)
            await ctx.send(ctx.lang['sold'].format(orginal_item, new_balance))
        else:
            await ctx.send(ctx.lang['abort'])

    @cat.group(invoke_without_command=True, aliases=['change'])
    async def edit(self, ctx):
        z = []
        for cmd in ctx.command.commands:
            z.append(f"- {cmd.name}")

        return await ctx.send(ctx.lang['commands_group'].format('\n'.join(z)))

    @edit.command()
    async def name(self, ctx, *, new_name: str):
        """Zmień imię zwierzaka."""
        cat = await self.get_cat(ctx.author)

        if cat.money < 1000:
            return await ctx.send(ctx.lang['need_more_money_name'])

        new_name = new_name[:1].upper() + new_name[1:].lower()

        await self.bot.db.execute("UPDATE cats SET name = $1, money = $2 WHERE owner_id = $3", new_name,
                                  cat.money - 1000, ctx.author.id)
        await ctx.send(":ok_hand:")

    @edit.command()
    async def color(self, ctx, *, new_color: str = None):
        """Zmień kolor zwierzaka."""
        cat = await self.get_cat(ctx.author)
        if cat.money < 15000:
            return await ctx.send(ctx.lang['need_more_money_color'])

        colors = ['black', 'brown', 'grey', 'yellow', 'pink']
        premium_colors = ['gold', 'plamablue', 'plama_sea', 'plama_pretty_pink',
                          'plama_mint', 'light_green']
        if cat.premium:
            colors.extend(premium_colors)
        if await self.bot.is_owner(ctx.author):
            colors.append('owner_cat')

        if not new_color:
            return await ctx.send(ctx.lang['avalaible_colors'].format(', '.join(colors)))

        if new_color not in colors:
            return await ctx.send(ctx.lang['no_color_like_this'].format(', '.join(colors)))

        await self.bot.db.execute("UPDATE cats SET color = $1, money = $2 WHERE owner_id = $3", new_color,
                                  cat.money - 15000, ctx.author.id)
        await ctx.send(":ok_hand:")

    @edit.command()
    async def theme(self, ctx, *, new_theme: str = None):
        """Zmień tło na profilu zwierzaka."""
        cat = await self.get_cat(ctx.author)
        if cat.money < 100000:
            return await ctx.send(ctx.lang['need_more_money_theme'])

        themes = ["weed1", "weed2", "weed3", "sky3", "landscape2"]
        premium_themes = ["sky1", "sky2", "sky4", "sky5", "colors1", "jungle1", "void1", "space1", "landscape1",
                          "landscape3", "landscape4", "night_sky1"]
        if cat.premium:
            themes.extend(premium_themes)

        if not new_theme:
            return await ctx.send(ctx.lang['avalaible_themes'].format(", ".join(themes)))

        if new_theme not in themes:
            return await ctx.send(ctx.lang['no_theme_like_this'].format(", ".join(themes)))

        await self.bot.db.execute("UPDATE cats SET theme = $1, money = $3 WHERE owner_id = $2", new_theme,
                                  ctx.author.id, cat.money - 100000)
        await ctx.send(":ok_hand:")

    @cat.command()
    async def daily(self, ctx):
        await ctx.send(f"<https://discordbots.org/bot/538369596621848577/vote>, {ctx.lang['vote_pls']}")

    @cat.command()
    async def premium(self, ctx):  # $$$
        cost = 1.5
        owner = str(self.bot.get_user(self.bot.owner_id))

        e = discord.Embed(description=ctx.lang['premium_text'])
        e.set_footer(text=ctx.lang['info_premium'].format(cost, owner))

        await ctx.send(embed=e)

    @cat.command()
    async def transfer(self, ctx, member: discord.Member, amount: int):
        author = await self.get_cat(ctx.author)
        member_cat = await self.get_cat(member)

        if member.id == ctx.author.id:
            return await ctx.send(ctx.lang['cant_transfer_to_yourself'])

        if author.money < amount:
            return await ctx.send(ctx.lang['not_enough_money_transfer'])

        query_1 = "UPDATE cats SET money = money - $2 WHERE owner_id = $1"
        query_2 = "UPDATE cats SET money = money + $2 WHERE owner_id = $1"

        async with self.bot.db.acquire():
            await self.bot.db.execute(query_1, ctx.author.id, amount)
            await self.bot.db.execute(query_2, member.id, amount)

        await ctx.send(ctx.lang['transfered_money'].format(ctx.author.mention, f"{amount:,d}", member.mention))

    # def processing_fight(self, author, enemy):
    #     path = "assets/images/battle.png"

    @cat.command()
    async def fight(self, ctx, member: discord.Member):
        if member.id == ctx.author.id:
            return await ctx.send(ctx.lang['cant_fight_with_yourself'])

        if member.id in self._fights:
            return await ctx.send(ctx.lang['is_already_in_fight'].format(member))

        if ctx.author.id in self._fights:
            return await ctx.send(ctx.lang['you_already_in_fight'].format(ctx.author.mention))

        author = await self.get_cat(ctx.author)
        enemy_cat = await self.get_cat(member)

        self._fights.append(member.id)
        self._fights.append(ctx.author.id)

        confirmation = await ctx.confirm(ctx.lang['confirm_fight'].format(member.mention, ctx.author.mention), member,
                                         timeout=30)
        if not confirmation:
            self._fights.remove(member.id)
            self._fights.remove(ctx.author.id)
            return await ctx.send(ctx.lang['abort'])

        default_hp = 100
        hp = round(default_hp/20) * '\U0001f7e5'

        text = f"{author.name} ({ctx.author})\n**HP**: {hp} ({(default_hp / 100) * 100}%)\n{enemy_cat.name} ({member})\n**HP:** {hp} ({(default_hp / 100) * 100}%)"

        e = discord.Embed(description=text)
        e.set_author(name=f"{ctx.author} vs {member}")
        # e.set_image(url=f"attachment://fight_{ctx.author.id}vs{member.id}.png")

        # async with ctx.typing():
        # start = time.time()
        #
        #     author_bytes = await self.get_avatar(ctx.author)
        #     enemy_bytes = await self.get_avatar(member)
        #
        #     fn = functools.partial(self.processing_fight, author_bytes, enemy_bytes)
        #     final_buffer = await self.bot.loop.run_in_executor(None, fn)
        #
        #     file = discord.File(filename=f"fight_{ctx.author.id}vs{member.id}.png", fp=final_buffer)
        #
        # end = time.time()
        # f"Done in: {round(end-start, 2)}s",

        author_weapon, enemy_weapon = await self.choose_weapon(ctx, member)

        if author_weapon is None and enemy_weapon is None:
            self._fights.remove(member.id)
            self._fights.remove(ctx.author.id)
            return await ctx.send(ctx.lang['abort'])

        class Player:
            def __init__(self, id_, weapon, hp_, member_object, cat):
                self.id = id_
                self.weapon = weapon
                self.hp = hp_
                self.member_object = member_object
                self.cat = cat

        enemy = Player(member.id, enemy_weapon, default_hp, member, enemy_cat)
        ally = Player(ctx.author.id, author_weapon, default_hp, ctx.author, author)

        winner, loser = await self.start_fight(ctx.channel, e, enemy, ally)

        query = "UPDATE cats SET rating = $1 WHERE owner_id = $2"

        rating1, rating2 = other.match(author, enemy_cat, winner.cat)

        rating1 = round(rating1)
        rating2 = round(rating2)

        new_hp_query = "UPDATE cats SET hp = $1 WHERE owner_id = $2"

        async with self.bot.db.acquire():  # todo
            await self.bot.db.execute(query, rating1, ctx.author.id)
            await self.bot.db.execute(query, rating2, member.id)

            await self.bot.db.execute(new_hp_query, winner.cat.hp - 5, winner.id)
            await self.bot.db.execute(new_hp_query, loser.cat.hp - 5, loser.id)

        new_rating = f"\nNowy ranking\n{ctx.author.mention}: **{rating1}**.\n{member.mention}: **{rating2}**"
        await ctx.send(ctx.lang['win_fight'].format(winner.member_object.mention, loser.member_object.mention,
                                                    new_rating))

        self._fights.remove(enemy.id)
        self._fights.remove(ally.id)

    async def choose_weapon(self, ctx, member):
        author = await self.get_cat(ctx.author)
        enemy = await self.get_cat(member)

        author_weapon = None
        enemy_weapon = None

        def author_check(m):
            return m.channel == ctx.channel and m.author == ctx.author

        def enemy_check(m):
            return m.channel == ctx.channel and m.author == member

        while author_weapon is None:
            await ctx.send(ctx.lang['choose_weapon'].format(ctx.author.mention))

            try:
                message = await self.bot.wait_for('message', check=author_check, timeout=32)
            except asyncio.TimeoutError:
                return None, None

            weapon = message.content

            if weapon.lower() in ['cancel', 'anuluj']:
                return None, None

            if weapon not in ALL_WEAPONS:
                await ctx.send(ctx.lang['no_weapon_like'])

            if weapon not in author.inventory:
                await ctx.send(ctx.lang['no_weapon_in_inv'])

            else:
                author_weapon = weapon

        while enemy_weapon is None:
            await ctx.send(ctx.lang['choose_weapon'].format(member.mention))

            try:
                message = await self.bot.wait_for('message', check=enemy_check, timeout=32)
            except asyncio.TimeoutError:
                return None, None

            weapon = message.content

            if weapon in ['cancel', 'anuluj']:
                return await ctx.send(ctx.lang['abort'])

            if weapon not in ALL_WEAPONS:
                await ctx.send(ctx.lang['no_weapon_like'])

            if weapon not in enemy.inventory:
                await ctx.send(ctx.lang['no_weapon_in_inv'])

            else:
                enemy_weapon = weapon

        return author_weapon, enemy_weapon

    @staticmethod
    async def start_fight(channel, embed, enemy, author):
        enemy_weapon = Weapon(enemy.weapon)
        ally_weapon = Weapon(author.weapon)

        message = await channel.send(embed=embed)

        round_ = 1

        while True:
            enemy_weapon.shoot(author)
            if author.hp <= 0:
                winner = enemy
                loser = author
                break

            ally_weapon.shoot(enemy)
            if enemy.hp <= 0:
                winner = author
                loser = enemy
                break

            round_ += 1

            ally_hp = math.ceil(author.hp / 20) * '\U0001f7e5'
            enemy_hp = math.ceil(enemy.hp / 20) * '\U0001f7e5'

            text = f"{author.cat.name} ({author.member_object})\n**HP**: {ally_hp} ({round((author.hp/100)*100)}%)\n{enemy.cat.name} ({enemy.member_object})\n**HP:** {enemy_hp} ({round((enemy.hp/100)*100)}%)\n\nRunda: {round_}"

            embed.description = text
            await message.edit(embed=embed)

            await asyncio.sleep(4)

        ally_hp = math.ceil(author.hp / 20) * '\U0001f7e5'
        enemy_hp = math.ceil(enemy.hp / 20) * '\U0001f7e5'

        text = f"{author.cat.name} ({author.member_object})\n**HP**: {ally_hp} ({(author.hp/100)*100}%)\n{enemy.cat.name} ({enemy.member_object})\n**HP:** {enemy_hp} ({(enemy.hp/100)*100}%)\n\nRunda: {round_}"

        embed.description = text
        await message.edit(embed=embed)

        return winner, loser

    @cat.command()
    async def revive(self, ctx):
        cat = await self.bot.db.fetchrow("SELECT * FROM cats WHERE owner_id = $1", ctx.author.id)
        if not cat:
            raise commands.BadArgument(f"{ctx.author.mention}, {ctx.lang['no_cat'].format(ctx.prefix)}")

        cat = DefaultCat(self.bot, cat)

        if not cat.is_dead:
            return await ctx.send(ctx.lang['cat_alive'])
        n_money = round(cat.money / 2)
        await self.bot.db.execute(f"UPDATE cats SET food = 10, karma = 0, sta = 15, hp = 50, is_dead = false, "
                                  f"money = $1 WHERE owner_id = $2", n_money, ctx.author.id)
        await ctx.send(ctx.lang['revive_story'].format(cat.name, ctx.author))

    @cat.command()
    async def sleep(self, ctx):
        cat = await self.get_cat(ctx.author)
        if cat.stamina == 100 and cat.is_sleeping:
            await ctx.send(ctx.lang['regenered_sta'])
            await self.bot.db.execute('UPDATE cats SET is_sleeping = false, sleeping_time = 0 WHERE owner_id = $1',
                                      ctx.author.id)
        elif cat.stamina == 100 and not cat.is_sleeping:
            return await ctx.send(ctx.lang['max_energy'])

        if cat.is_sleeping:
            await ctx.send(ctx.lang['cat_woke_up'].format(cat.sleeping_time, cat.stamina))
            await self.bot.db.execute("UPDATE cats SET is_sleeping = false, sleeping_time = 0 WHERE owner_id = $1",
                                      ctx.author.id)

        elif not cat.is_sleeping:
            await self.bot.db.execute('UPDATE cats SET is_sleeping = true, sleeping_time = 0 WHERE owner_id = $1',
                                      ctx.author.id)
            await ctx.send(ctx.lang['started_restoring'].format(ctx.prefix))

    @cat.command()
    @commands.cooldown(1, 1800, commands.BucketType.user)
    async def rob(self, ctx, member: discord.Member):
        robber_cat = await self.get_cat(ctx.author)
        cat = await self.get_cat(member)

        if robber_cat.money < 150:
            return await ctx.send(ctx.lang['need_more_money_to_rob'])

        ratio = random.randint(10, 45)
        robbed = random.choice([True, False])

        if robbed:
            amount = int(cat.money) * (ratio / 100)
            async with self.bot.db.acquire():
                await self.bot.db.execute("UPDATE cats SET money = money - $1 WHERE owner_id = $2", amount, member.id)
                await self.bot.db.execute("UPDATE cats SET money = money + $1 WHERE owner_id = $2", amount, ctx.author.id)
            await ctx.send(ctx.lang['robbed'].format(ctx.author.mention, member.mention, amount, ctx.prefix))
        else:
            amount = int(robber_cat.money) * (ratio / 100)
            await self.bot.db.execute("UPDATE cats SET money = money - $1 WHERE owner_id = $2", amount, ctx.author.id)
            await ctx.send(ctx.lang['robbed_wrong'].format(ctx.author.mention, member.mention, amount))

    @cat.command(aliases=['dep'])
    async def deposit(self, ctx, money):
        cat = await self.get_cat(ctx.author)

        if money == "all":
            money = cat.money

        if money == "half":
            money = round(cat.money / 2)  # :)))

        if not str(money).isdigit():
            return await ctx.send(ctx.lang['not_correct_value'])

        money = int(money)

        if money > cat.money:
            return await ctx.send(ctx.lang['you_dont_have_so_much'])

        await self.bot.db.execute("UPDATE cats SET bank = bank + $1, money = money - $1 WHERE owner_id = $2",
                                  money, ctx.author.id)
        await ctx.send(ctx.lang['deposited'].format(money))

    @cat.command(aliases=['with'])
    async def withdraw(self, ctx, money):
        cat = await self.get_cat(ctx.author)

        if money == "all":
            money = cat.bank

        if money == "half":
            money = round(cat.bank / 2)  # :)))

        if not str(money).isdigit():
            return await ctx.send(ctx.lang['not_correct_value'])

        money = int(money)

        if money > cat.bank:
            return await ctx.send(ctx.lang['you_dont_have_so_much'])

        await self.bot.db.execute("UPDATE cats SET bank = bank - $1, money = money + $1 WHERE owner_id = $2",
                                  money, ctx.author.id)
        await ctx.send(ctx.lang['withdrawed'].format(money))

    @cat.command(aliases=['bal', 'bank'])
    async def balance(self, ctx, member: discord.Member = None):
        member = member or ctx.author

        cat = await self.get_cat(member)

        desc = f"{member.mention}\n\tBalance: **{cat.money}$**\nBank: **{cat.bank}$**"

        e = discord.Embed(description=desc, timestamp=ctx.message.created_at, color=self.bot.color)
        await ctx.send(embed=e)

    @cat.command(enabled=False)
    @commands.cooldown(1, 600, commands.BucketType.user)
    async def work(self, ctx):
        plus_sentences = [ctx.lang['plus_work_1'], ctx.lang['plus_work_2']]
        minus_sentences = [ctx.lang['minus_work_1'], ctx.lang['minus_work_2']]

        choice = random.choice([True, False])

        if choice:
            amount = random.randint(55, 170)
            sentence = random.choice(plus_sentences)
            query = "UPDATE cats SET money = money + $1 WHERE owner_id = $2"
        else:
            amount = random.randint(20, 120)
            sentence = random.choice(minus_sentences)
            query = "UPDATE cats SET money = money - $1 WHERE owner_id = $2"

        await self.bot.db.execute(query, amount, ctx.author.id)
        await ctx.send(sentence.format(amount))

    @cat.command()
    @commands.cooldown(1, 9, commands.BucketType.user)
    async def top(self, ctx, sort: str = "money"):
        sorts = ['money', 'bank', 'level', 'rating']
        if sort.lower() not in sorts:
            return await ctx.send(ctx.lang['wrong_type_of_sort'].format(', '.join(sorts)))

        desc = f"**TOP {ctx.lang['for_2']} `{sort}`**\n"

        cats = await self.bot.db.fetch(f"SELECT * FROM cats ORDER BY {sort.lower()} DESC LIMIT 10")

        for i, cat in enumerate(cats):

            ads_map = {
                "money": "$",
                "bank": "$",
                "level": " level",
                "rating": " rating",
            }

            desc += f"{cat['name']} ({cat['owner_id']}): **{cat[sort.lower()]}{ads_map[sort.lower()]}**\n"

        e = discord.Embed(description=desc, color=self.bot.color)
        await ctx.send(embed=e)

    @cat.command()
    @commands.cooldown(1, 2, commands.BucketType.user)
    async def use(self, ctx, *, item: ItemsConverter('useable')):
        cat = await self.get_cat(ctx.author)

        drinks_map = {
            "energy drink": "sta",
            "health drink": "hp",
            "food drink": "food"
        }

        if not cat.inventory:
            return await ctx.send(ctx.lang['empty_inventory'])

        if item not in self.cat.inventory:
            return await ctx.send(ctx.lang['no_thing_in_inventory'].format(item))

        if item in drinks_map:
            cat.inventory.remove(item)
            await self.bot.db.execute(f"UPDATE cats SET {drinks_map[item]} = 100, inventory = $1 WHERE owner_id = $2", cat.inventory, ctx.author.id)
            return await ctx.send(ctx.lang['fuel_drink'].format(drinks_map[item]))

        elif item in ['karma', 'food']:
            cat.inventory.remove(item)
            await self.bot.db.execute(f"UPDATE cats SET food = food + 15, karma = karma - 1 WHERE owner_id = $2", cat.inventory, ctx.author.id)
            return await ctx.send(ctx.lang['feed_cat_with_karma'].format(cat.food))

    @commands.Cog.listener()
    async def on_message(self, message):
        if message.author.bot:
            return

        cat = await self.bot.db.fetchrow("SELECT * FROM cats WHERE owner_id = $1", message.author.id)
        if not cat:
            return

        x = random.randint(0, 100)
        if x >= 20:
            exp = random.randint(5, 22)
            await self.bot.db.execute("UPDATE cats SET exp = $1 WHERE owner_id = $2", cat['exp'] + exp, cat['owner_id'])
        if await self.lvl_up(cat):

            language = await get_language(self.bot, message.guild)
            lang = self.bot.get_language_object(language)

            try:
                await message.channel.send(lang['level_up'].format(message.author.mention, cat['level'] + 1))
            except (discord.Forbidden, discord.HTTPException):
                return

def setup(bot):
    bot.add_cog(Cat(bot))


"""
A Python script to make beautiful plots
"""

#%% Imports
from contextlib import suppress
from scipy.io import loadmat
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
from matplotlib.ticker import AutoMinorLocator
import matplotlib
import tikzplotlib

#%% Import ipython and adjust for qt5 backend, keeping compatibility with
# non-ipython envs
with suppress(ImportError):
    from IPython import get_ipython
with suppress(AttributeError, NameError):
    # List available APIs
    get_ipython().run_line_magic("matplotlib", "-l")
    get_ipython().run_line_magic("matplotlib", "qt5")

print(plt.get_backend())
#%% Matplotlib adjustments
# Adjust matplotlib qt5 backend for high DPI monitors
if plt.get_backend() == "Qt5Agg":
    from matplotlib.backends.qt_compat import QtWidgets  # pylint: disable=C0412
    from sys import argv

    qApp = QtWidgets.QApplication(argv)
    plt.matplotlib.rcParams["figure.dpi"] = qApp.desktop().physicalDpiX()

# Set LaTeX compatibility settings
# matplotlib.use("pgf")
matplotlib.rcParams.update(
    {
        "pgf.texsystem": "pdflatex",
        "font.family": "sans-serif",
        "text.usetex": True,
        "pgf.rcfonts": False,
    }
)

# plt.rcParams["figure.autolayout"] = True

# Adjust figure default size
plt.rcParams["figure.figsize"] = (6, 4)  # Default fig size (w, h))

# Get the default color scheme
colors = plt.rcParams["axes.prop_cycle"].by_key()["color"]

awgn_xtickspacing = 5

# plt.ioff()

#%% Get AWGN results from files
# Load the file
results_awgn = loadmat("../results/results1.mat")

#%% Get variables
print(list(results_awgn.keys()))

mustry = results_awgn["mustry"][0]
nstry = results_awgn["nstry"][0]

ds = results_awgn["ds"]
ds[~np.isfinite(ds)] = 200
ds = np.clip(ds, -100, 100)
W = results_awgn["W"]
W[~np.isfinite(W)] = 200
W = np.clip(W, -100, 100)
e = results_awgn["e"]
e[~np.isfinite(e)] = 200
# e = np.clip(e, -100, 100)
ys = results_awgn["ys"]
ys[~np.isfinite(ys)] = 200
ys = np.clip(ys, -100, 100)

#%% Show beautiful figures
lw = 1
for k in range(3):
    for i, n in enumerate(nstry):
        for j, mu in enumerate(mustry):
            num = k * len(nstry) * len(mustry) + i * len(mustry) + j
            fig, axs = plt.subplots(num=num, nrows=3, ncols=1, sharex=True)
            axs[0].set_title(f"Ex. 1, signal {k+1}, $n={n}$, $\\mu = {mu}$")
            # Stuff to plot
            print(num)
            d = ds[k, 0]
            y = ys[k, i, j, 0]
            diff = d - y
            ws = W[k, i, j]
            edb = 10 * np.log10(e[k, i, j])
            # Plot signals
            axs[0].plot(d, label="original", linewidth=lw)
            axs[0].plot(y, label="recovered", linewidth=lw)
            axs[0].plot(diff, label="difference", linewidth=lw)
            axs[0].legend(framealpha=1, fontsize=6, loc="lower right")
            axs[0].set_ylabel("Signal level")
            axs[0].yaxis.set_minor_locator(AutoMinorLocator())
            axs[0].grid(b=True, which="major", color="silver", linestyle="-")
            axs[0].grid(b=True, which="minor", color="lightgray", linestyle="--")
            # Plot the weights
            for v in range(n):
                axs[1].plot(ws[:, v], linewidth=lw)
            axs[1].set_ylabel("Weight value")
            axs[1].yaxis.set_minor_locator(AutoMinorLocator())
            axs[1].grid(b=True, which="major", color="silver", linestyle="-")
            axs[1].grid(b=True, which="minor", color="lightgray", linestyle="--")
            # Plot the error (dB)
            axs[2].plot(edb, linewidth=lw)

            # Do adjustments
            # Like proper axis settings
            if k == 0:  # First signal
                axs[1].set_ylim(bottom=-2, top=2)
                axs[0].set_ylim(bottom=-10, top=10)
                if n == 3:
                    axs[2].set_ylim(bottom=-15, top=3)
                    axs[1].set_ylim(bottom=-5, top=5)
                if n == 5:
                    axs[2].set_ylim(bottom=-30, top=-3)
                if n == 10:
                    axs[2].set_ylim(bottom=-45, top=0)
            if k == 1:  # Second signal
                axs[1].set_ylim(bottom=-5, top=5)
                axs[0].set_ylim(bottom=-10, top=10)
                if n == 3:
                    axs[2].set_ylim(bottom=-43, top=5)
                if n == 5:
                    axs[2].set_ylim(bottom=-43, top=0)
                if n == 10:
                    axs[2].set_ylim(bottom=-45, top=0)
            if k == 2:  # Third signal
                axs[2].set_ylim(bottom=-40, top=-7)
                axs[1].set_ylim(bottom=-1, top=1)
                axs[0].set_ylim(bottom=-3, top=3)
                # On this signal, plot the theoretical weights
                T = len(d)
                t = np.arange(T)
                axs[1].plot(
                    0.2 + 0.3 * t / T, linestyle="--", color="black", linewidth=lw / 2
                )
                axs[1].plot(
                    0.7 * np.cos(4 * np.pi * t / T),
                    linestyle="--",
                    color="black",
                    linewidth=lw / 2,
                )
                axs[1].plot(
                    0.3 * np.sign(np.sin(10 * np.pi * t / T)) - 0.1,
                    linestyle="--",
                    color="black",
                    linewidth=lw / 2,
                )
                axs[1].plot(
                    -0.2 * np.ones(T), linestyle="--", color="black", linewidth=lw / 2
                )
            axs[0].set_xlim(left=0, right=len(d))
            axs[2].yaxis.set_minor_locator(AutoMinorLocator())
            axs[2].grid(b=True, which="major", color="silver", linestyle="-")
            axs[2].grid(b=True, which="minor", color="lightgray", linestyle="--")
            axs[2].set_ylabel("Error (dB)")
            fig.subplots_adjust(hspace=0.15)
            axs[-1].set_xlabel("Time/iteration")
            plt.savefig(
                f"../results/ex1_l{k+1}_n{n}_mu{int(mu*100):d}.png",
                dpi=600,
                bbox_inches="tight",
            )
            plt.savefig(
                f"../report/figures/pgf/ex1_l{k+1}_n{n}_mu{int(mu*100):d}.pgf",
                bbox_inches="tight",
            )
            plt.savefig(
                f"../report/figures/pdf/ex1_l{k+1}_n{n}_mu{int(mu*100):d}.pdf",
                bbox_inches="tight",
            )
            tikzplotlib.save(
                f"../report/figures/tikz/ex1_l{k+1}_n{n}_mu{int(mu*100):d}.tex"
            )
            plt.close()


# coding: utf-8

# In[1]:

# moist_ascent_latent_heating.py
#
#
# Computes moist adiabatic parcel ascent and
# latent heating rates
#
# Steven Cavallo
# University of Oklahoma
# September 2017
###########################
# imports
###########################
import matplotlib.pyplot as plt
import numpy as np
import sys
import pylab
import os, datetime

import weather_modules as wm
#import imp
#wm = imp.load_source('weather_modules','/Users/scavallo/scripts/python_scripts/weather_modules.py')
from mstats import *

###########################
# User options
###########################
pres1 = 70000. # Pa
pres2 = 30000. # Pa
omega = -1.0 # Pa s-1
reference_latitude = 45.

read_temperature_fromfile = 'True'
label_fontsize = 16
datadir = ''
imagedir = ''
infile1 = 'nnrp_t700_vs_lat_monthly.dat'

# In[3]:

###########################
# constants
###########################
cp = 1004.  # J K-1 kg-1
cv = 717.    # J K-1 kg-1
Rd = 287.    # J K-1 kg-1
Rv = 461.    # J K-1 kg-1
g  = 9.81    # m s-2
p0 = 100000. # Pa
epsi = Rd/Rv
Lv = 2.5*10**(6.0) # J kg-1
p0 = 100000. # Pa

# In[4]:

gammad = g/cp # Dry adiabatic lapse rate is a constant

if read_temperature_fromfile == 'True':
    ab = np.loadtxt(datadir+infile1, skiprows=1)
    lats = ab[:,0]
    T1a = ab[:,1]
    T1b = ab[:,7]
    [refind] = np.where(lats==reference_latitude)
else:
    T1 = np.arange(-40,41,0.25)+273.15 # Virtual temperatures
    T1a = T1
    [refind] = np.where(T1a == 273.15)
es1 = wm.claus_clap(T1a) # saturation vapor pressure
ws1a = (epsi*es1)/(pres1-es1) # saturation mixing ratio
es1 = wm.claus_clap(T1b) # saturation vapor pressure
ws1b = (epsi*es1)/(pres1-es1) # saturation mixing ratio

# Compute moist adiabatic lapse rate, first in z-coords
fa = (( (1 + (Lv*ws1a)/(Rd*T1a))) / (1.0 + (ws1a*(Lv**2)/(cp*Rv*T1a**2.0)) ) )
fb = (( (1 + (Lv*ws1b)/(Rd*T1b))) / (1.0 + (ws1b*(Lv**2)/(cp*Rv*T1b**2.0)) ) )
sat_lapse_a = gammad*fa
sat_lapse_b = gammad*fb

Rho_a=pres1/(Rv*T1a) # Density, moist air
Rho_b=pres1/(Rv*T1b)
wa = -omega/(Rho_a*g)
print('w in profile A is %8.5f m s-1' %(wa[refind]))
wb = -omega/(Rho_b*g)
print('w in profile B is %8.5f m s-1' %(wb[refind]))

deltap = pres2-pres1
deltaz_a = (-1.0*deltap)/(Rho_a*g)
deltaz_b = (-1.0*deltap)/(Rho_b*g)
print('Cloud depth is %7.2f m in profile A and %7.2f in profile B' % (deltaz_a[refind],deltaz_b[refind]))

#sat_lapse_isobaric = -sat_lapse/(Rho*9.81) # Convert to p-coords

# Temperature at top of ascent layer (T2) is equal to what it was initially (T1) plus slope (-gamma_m) * deltaz
#T2 = T1 - (sat_lapse_isobaric)*(pres2-pres1)
T2a = T1a + (-1.0*sat_lapse_a*deltaz_a)
T2b = T1b + (-1.0*sat_lapse_b*deltaz_b)
print('Lower- and upper-level temperatures in profile A are %7.2f K and %7.2f' %(T1a[refind],T2a[refind]))
print('Lower- and upper-level temperatures in profile B are %7.2f K and %7.2f' %(T1b[refind],T2b[refind]))

# Convert to Celsius (needed for plot if not reading from file)
#T1C = T1 - 273.15
#T2C = T2 - 273.15

# Convert to K/km
sat_lapse_a = sat_lapse_a*1000. # per km
sat_lapse_b = sat_lapse_b*1000. # per km

# Fractional departure from dry adiabatic
fd_a = 1.0 - fa
fd_b = 1.0 - fb

# In[5]:

exner = (((pres1+pres2)/2.0)/p0)**(Rd/cp)

###################
# Profile A
###################
es2 = wm.claus_clap(T2a)
ws2 = (epsi*es2)/(pres2-es2)

qs1 = ws1a/(1+ws1a)
qs2 = ws2/(1+ws2)

deltaqs = (qs2 - qs1)
deltap = pres2 - pres1
deltat = deltap/omega # Time it takes parcel to travel deltap (through cloud)

dthetadt_a = -1.0*(Lv/(exner*cp))*(deltaqs/deltat)
dthetadt_perday_a = dthetadt_a * 86400.

###################
# Profile B
###################
es2 = wm.claus_clap(T2b)
ws2 = (epsi*es2)/(pres2-es2)

qs1 = ws1b/(1+ws1b)
qs2 = ws2/(1+ws2)

deltaqs = (qs2 - qs1)
deltap = pres2 - pres1
deltat = deltap/omega # Time it takes parcel to travel deltap (through cloud)

dthetadt_b = -1.0*(Lv/(exner*cp))*(deltaqs/deltat)
dthetadt_perday_b = dthetadt_b * 86400.

# In[6]:

y0 = np.zeros_like(T1a).astype('f') #
x = np.linspace(0,len(T1a),np.size(T1a))
if read_temperature_fromfile == 'True':
    xplot = lats
    xlabel = r'Latitude ($^{\circ}$N)'
    xlims = [np.min(lats), np.max(lats)]
else:
    xplot = T1C
    xlims = [-40.,40.]
    xlabel = r'Temperature ($^{\circ}$C)'

golden = (pylab.sqrt(5)+1.)/2.
figprops = dict(figsize=(8., 8./ golden ), dpi=128)    # Figure properties for single and stacked plots
adjustprops = dict(left=0.15, bottom=0.1, right=0.90, top=0.93, wspace=0.2, hspace=0.2)

# In[7]:

nticks = 9
yticks_ax1 = np.linspace(2,10,nticks)
yticks_ax2 = np.linspace(0,0.8,nticks)

fig = pylab.figure(**figprops)   # New figure
ax1 = fig.add_subplot(1, 1, 1)
ax2 = ax1.twinx()
for tick in ax1.xaxis.get_major_ticks():
    tick.label1.set_fontsize(label_fontsize)
    tick.label1.set_fontweight('bold')
p1a, = ax1.plot(xplot,sat_lapse_a,'r',linewidth=3.0,label=r'$\Gamma_m$ (January)')
p1a, = ax1.plot(xplot,sat_lapse_b,'r--',linewidth=3.0,label=r'$\Gamma_m$ (July)')
p2a, = ax2.plot(xplot,fd_a,'g',linewidth=3.0,label='1-f (January)')
p2b, = ax2.plot(xplot,fd_b,'g--',linewidth=3.0,label='1-f (July)')

legend = ax1.legend(loc='lower left', shadow=True)
legend = ax2.legend(loc='upper left', shadow=True)

ax1.grid(True, linestyle='-')
ax1.set_xlim([xlims[0],xlims[1]])

ax1.set_ylim([yticks_ax1[0],yticks_ax1[1]])
ax2.set_ylim([yticks_ax2[0],yticks_ax2[1]])
ax1.yaxis.set_ticks(yticks_ax1)
ax1.set_yticklabels(yticks_ax1)
ax2.yaxis.set_ticks(yticks_ax2)
ax2.set_yticklabels(yticks_ax2)

ax1.set_ylabel('Moist adiabatic lapse rate',fontsize=label_fontsize)
ax2.set_ylabel('Fractional departure from dry adiabatic',fontsize=label_fontsize)
ax1.set_xlabel(xlabel,fontsize=label_fontsize)
save_name = imagedir + "moist_adiabatic_hw3_2017.png"
plt.savefig(save_name, bbox_inches='tight')
#plt.show()

# In[8]:

fig = pylab.figure(**figprops)   # New figure
ax1 = fig.add_subplot(1, 1, 1)
for tick in ax1.xaxis.get_major_ticks():
    tick.label1.set_fontsize(label_fontsize)
    tick.label1.set_fontweight('bold')
p1a, = ax1.plot(xplot,fd_a,'r',linewidth=3.0,label='1-f (January)')
p1b, = ax1.plot(xplot,fd_b,'r--',linewidth=3.0,label='1-f (July)' )
legend = ax1.legend(loc='lower left', shadow=True)
ax1.axvline(xplot[refind],linewidth=4, color='k')
ax1.grid(True, linestyle='-')
ax1.set_xlim([xlims[0],xlims[1]])
ax1.set_ylabel('Fractional departure from dry adiabatic',fontsize=label_fontsize)
ax1.set_xlabel(xlabel,fontsize=label_fontsize)
save_name = imagedir + "moist_adiabatic_factor_hw3_2017.png"
plt.savefig(save_name, bbox_inches='tight')
#plt.show()

# In[9]:

fig = pylab.figure(**figprops)   # New figure
ax1 = fig.add_subplot(1, 1, 1)
for tick in ax1.xaxis.get_major_ticks():
    tick.label1.set_fontsize(label_fontsize)
    tick.label1.set_fontweight('bold')
p1, = ax1.plot(xplot,dthetadt_perday_a,'b',linewidth=3.0,label=r'$\theta$ latent heating rate (January)')
p2, = ax1.plot(xplot,dthetadt_perday_b,'b--',linewidth=3.0,label=r'$\theta$ latent heating rate (July)')
legend = ax1.legend(loc='lower left', shadow=True)
ax1.grid(True, linestyle='-')
ax1.set_xlim([xlims[0],xlims[1]])
ax1.set_ylabel('Latent heating rate (K day-1)',fontsize=label_fontsize)
ax1.set_xlabel(xlabel,fontsize=label_fontsize)
save_name = imagedir + "latent_heating_rates_hw3_2017.png"
plt.savefig(save_name, bbox_inches='tight')
plt.show()


import os
import random
import shutil

from tqdm import tqdm

def mkdirs(path):
    if not os.path.exists(path):
        os.makedirs(path)

derain_path = "E:\\derain"
trainpath = 'E:\\watermark_dataset\\derain\\train'
validpath = 'E:\\watermark_dataset\\derain\\valid'
testpath = 'E:\\watermark_dataset\\derain\\test'
mkdirs(trainpath)
mkdirs(validpath)
mkdirs(testpath)

class DataProcess:
    def __init__(self, ori_path, mode="train") -> None:
        self.derain_imgs = []
        for root, subdir, files in os.walk(os.path.join(ori_path, mode)):
            if len(files)>0:
                print(root)
                #print(files[:5])
                for img in files:
                    #print(img)
                    self.derain_imgs.append((root, img))

        random.shuffle(self.derain_imgs)
        if mode!='test':
            self.derain_imgs = self.derain_imgs[:6000]
        else:
            self.derain_imgs = self.derain_imgs[:100]

        #print(self.derain_imgs)
        #print(len(self.derain_imgs))
    def copyimg(self, tarpath):
        index = 0
        for arr in tqdm(self.derain_imgs):
            #print(arr)
            #print(arr[0])
            #print(arr[1])
            old_path = os.path.join(arr[0], arr[1])
            #print(old_path)
            #print(ori_path)
            new_path = os.path.join(tarpath, f"{str(index)}.jpg")
            #print(new_path)
            shutil.copyfile(old_path, new_path)
            index+=1
            #print(index)

if __name__ == "__main__":
    for m in ['train', 'valid', 'test']:
        process = DataProcess(ori_path = derain_path, mode=m)
        process.copyimg(trainpath)
        process.copyimg(validpath)
        process.copyimg(testpath)


try:
    from lib import jed_janelamensagem
except ImportError:
    jed_janelamensagem = None
    print('jed_janfelamensagem não encontrada')
    exit(1)

try:
    import logging
except ImportError:
    print('Está faltando logging')
    logging = None
    exit(1)

class LogSistema():
    """
    Gravação de entrada no sistema e acompanhamento dos passos do usuario no sistema
    """

    def __init__(self, *arg, **kwarg):
        """
        inicialisacao dos campos do nível de acesso
        """

        self.ge_dic_param_sis = {}
        self.ge_dic_usuario = {}

        self.ge_ip_local = ""

        if kwarg['DICPARAMSIS']:
            self.ge_dic_param_sis = kwarg['DICPARAMSIS']
        else:
            jed_janelamensagem.erro_msg(janela=None,
                                        texto_primario='DIC_DB',
                                        texto_secundario='Não foi possivel trazer DIC_DB!')
            exit(1)

        x = 0
        if self.ge_dic_param_sis['TIPO_LOG'] == 'DEBUG':
            x = logging.DEBUG
        elif self.ge_dic_param_sis['TIPO_LOG'] == 'INFO':
            x = logging.INFO
        elif self.ge_dic_param_sis['TIPO_LOG'] == 'WARNING':
            x = logging.WARNING
        elif self.ge_dic_param_sis['TIPO_LOG'] == 'ERROR':
            x = logging.ERROR
        elif self.ge_dic_param_sis['TIPO_LOG'] == 'CRITICAL':
            x = logging.CRITICAL
        else:
            jed_janelamensagem.erro_msg(janela=None,
                                        texto_primario='tch.conf',
                                        texto_secundario='Opção inválida em [LOG]...LOG_CAMINHO =???!')
            exit(1)

        logging.basicConfig(level=x,
                            format='%(asctime)s %(filename)s %(funcName)s %(levelname)-8s linha:%(lineno)d %(message)s',
                            datefmt='%a, %d %b %Y %H:%M:%S',
                            filename=self.ge_dic_param_sis['LOG_CAMINHO'],
                            filemode='a'
                            )

        logging.info("LOG INICIADA PARA O IP:{ip}".format(ip=str(self.ge_dic_param_sis['IPLOCAL'])))


import gym

from gym import spaces
from gym.utils import seeding

from .utils_attack import *
from .attacker import *
import os

class HighwayEnv(gym.Env):
    def __init__(self, low_cars=10, high_cars=30, low_att=0, high_att=3, device='cpu', task={}):
        super(HighwayEnv, self).__init__()

        self.num_action = 8
        self.num_state = 20
        self.num_attacker_state = 24

        self.action_space = spaces.Discrete(self.num_action)
        self.observation_space = spaces.Box(low=-1.0,
            high=1.0, shape=(self.num_state,), dtype=np.float32)

        # env init
        self.envCars = []
        self.safeCheck =  False  # for short horizon safety check of the host vehicle

        # seed
        self.np_random = seeding.np_random()
        self.seed()

        # for task
        self._task = task
        self._num_attacker = task.get('num_attacker',3)
        self._num_total_car = task.get('num_total_car',20)
        self._traffic_density = task.get('traffic_density', 1)

        # task sampler parameter
        self.low_cars = low_cars  # lower bound for the number of total cars
        self.high_cars = high_cars
        self.low_att = low_att  # lower bound for the number of attackers in the environment
        self.high_att = high_att

        # attacker's policy network
        self.device = device
        self.attacker_agent = attacker()
        self.attacker_agent.to(self.device)
        pathname_trained_Att = os.path.abspath('./maml_rl/envs/highway/AttackQNet.pth.tar')
        saved_net_Att = tr.load(pathname_trained_Att,  map_location=tr.device('cpu'))
        self.attacker_agent.Q_eval_net.load_state_dict(saved_net_Att['Q_eval_net'])
        self.attacker_agent.Q_eval_net.eval()

        # for render
        self.viewer = None

    def seed(self, seed=None):
        self.np_random, seed = seeding.np_random(seed)
        return [seed]

    def sample_tasks(self, num_tasks):
        num_attackers = self.np_random.randint(self.low_att, self.high_att, size=(num_tasks,))
        num_total_cars = self.np_random.randint(self.low_cars, self.high_cars, size=(num_tasks,))
        traffic_densities = self.np_random.random_sample(size=(num_tasks,)) + 0.5  # from 0.5 to 1.5

        tasks = [{'num_attacker':num_attacker,
                  'num_total_car': num_total_car,
                  'traffic_density': traffic_density}
                 for (num_attacker, num_total_car, traffic_density)
                 in zip(num_attackers, num_total_cars, traffic_densities)]

        return tasks

    def reset_task(self, task):
        # reset the task specific parameter, the true reset will be done in `reset`
        # together with the `sample_tasks` function
        self._task = task
        self._num_attacker = task['num_attacker']
        self._num_total_car = task['num_total_car']
        self._traffic_density = task['traffic_density']

    def step(self, action):
        # number of attackers is in the self._num_attacker
        # envCar: 0 (C.T_CAR) -> the target agent of the attackers and the training agent of the maml
        # envCar: 1 ~ 1+self._num_attacker -> the attakcers

        done = False
        # store the state for the current time step
        idC, _ = driveFuncs.getAffordInd(self.envCars)

        if self.safeCheck:
            # safety check
            newAct, rstPrfAct = driveFuncs.safeAct2(action, idC[C.T_CAR, :])

            # change the action according to safety check
            if newAct != action:
                # saftey controller overrides the first choice, set the original action for collision
                # print('safe action')
                action, actOld = newAct, action
                safeAct = True  # safety action was chosen
            else:
                safeAct = False

        if self._num_attacker == 0:

            driveFuncs.setEgoCarAction(self.envCars[C.T_CAR], action)  # set action for the ego car (target)

            driveFuncs.setAction(self.envCars[1:], idC[1:, :])  # set actions for env cars
            driveFuncs.appAction(self.envCars)  # Apply actions

        else:  # env with attackers
            # 0: target / training agent
            # 1 ~ 1 + self._num_attacker: attacker
            attackersID = [ i for i in range(1, 1 + self._num_attacker)]

            # for all the attackers in the env, set its action by the self.attacker_agent policy network
            for i in attackersID:
                # this function is for putting up state for the attacker
                attacker_i_state = getAffIndiOfTarget(self.envCars[i], self.envCars)
                s0_i_attacker = scaleStateAtt(attacker_i_state)

                Q, _, _ = self.attacker_agent.Q_eval_net(
                    Variable(tr.from_numpy(s0_i_attacker).to(self.device), requires_grad=False).float()[None, ...])
                attacker_i_action = int(tr.argmax(Q))

                # constraint on the action of the attacker for more efficient attacking
                lnAtt = idC[i, C.E_LN]
                if lnAtt == params.ROAD_RIGHT_LANE:
                    # on right lane
                    if attacker_i_action == C.A_BR or attacker_i_action == C.A_MR:
                        attacker_i_action = C.A_MM

                elif lnAtt == params.ROAD_LEFT_LANE:
                    # on left lane
                    if attacker_i_action == C.A_BL or attacker_i_action == C.A_ML:
                        attacker_i_action = C.A_MM

                # set the action for each attacker in this env
                # don't be confused by the function name
                driveFuncs.setEgoCarAction(self.envCars[i], attacker_i_action)

            # set action for the target car
            driveFuncs.setEgoCarAction(self.envCars[C.T_CAR], action)

            # set actions for other env cars
            driveFuncs.setAction(self.envCars[1+self._num_attacker:], idC[1+self._num_attacker:, :])

            # Apply actions
            driveFuncs.appAction(self.envCars)

        """ After applied the actions for all envCars, get the observation and reward """
        idC_N, _ = driveFuncs.getAffordInd(self.envCars)  # get next state for all cars

        # check for collision if collision then set rew to some large -ve value
        collision = driveFuncs.checkColi4Ego(idC[C.T_CAR, :], idC_N[C.T_CAR, :], action)
        # Get new scaled ego car state
        eIDC_N = idC_N[0, :]
        s1 = driveFuncs.scaleState(eIDC_N)
        rewV, rewY, rewX, cf_d, maxV, disY, eV, cf_v, midDis = driveFuncs.getRewCmp(eIDC_N)

        if self.safeCheck and safeAct:
            if action != C.A_MM:
                reward = -0.1
            else:
                # don't penalize maintain
                reward = 0
        else:
            reward = (rewV + rewY + rewX) / 3  # scale between -1 to 0
            if reward > -1e-2 and not collision:
                # give a small +ve reward for doing things in a correct manner
                reward = 0.01

        if collision:
            reward = -200  # for collision give more -ve reward
            done = True

        observation = s1

        return observation, reward, done, {'task': self._task}

    def reset(self):

        # reset the environement
        self.envCars = initCarsAtt(self._num_total_car, self._num_attacker, self._traffic_density)
        idC, _= driveFuncs.getAffordInd(self.envCars)
        observation = driveFuncs.scaleState(idC[C.T_CAR, :])

        return observation

    # for HPC: remove this function
    def render(self, mode='human', close=False):
        from gym.envs.classic_control import rendering  # for HPC: comment this line

        # horizotal: x axis; vertical: y axis
        # origin: left bottom corner

        if close:
            if self.viewer is not None:
                self.viewer.close()
                self.viewer = None
            return

        # for render
        if self.viewer is None:
            self.viewer = rendering.Viewer(1000, 100)

        # for transform and scale
        scale = 5
        trans = rendering.Transform(translation=(500, 25))

        # clean the canvas each frame
        self.viewer.geoms = []
        # lane boundary
        lane_boundary1 = rendering.Line((-100*scale, 0), (100*scale, 0))
        lane_boundary2 = rendering.Line((-100*scale, 3.6*scale), (100*scale, 3.6*scale))
        lane_boundary3 = rendering.Line((-100*scale, 7.2*scale), (100*scale, 7.2*scale))
        lane_boundary4 = rendering.Line((-100*scale, 10.8*scale), (100*scale, 10.8*scale))

        lane_boundary1.set_color(0,0,0)
        lane_boundary2.set_color(0,0,0)
        lane_boundary3.set_color(0,0,0)
        lane_boundary4.set_color(0,0,0)

        lane_boundary1.add_attr(trans)
        lane_boundary2.add_attr(trans)
        lane_boundary3.add_attr(trans)
        lane_boundary4.add_attr(trans)

        self.viewer.add_geom(lane_boundary1)
        self.viewer.add_geom(lane_boundary2)
        self.viewer.add_geom(lane_boundary3)
        self.viewer.add_geom(lane_boundary4)

        # cars
        for ind in range(len(self.envCars)):
            car = self.envCars[ind]
            l = car.xPos - 2.2
            r = car.xPos + 2.2
            b = car.yPos - 1.1
            t = car.yPos + 1.1

            l *= scale
            r *= scale
            b *= scale
            t *= scale

            if ind in [ i for i in range(1, 1 + self._num_attacker)]:
                car_render = rendering.FilledPolygon([(l, b), (l, t), (r, t), (r, b)])
                car_render.add_attr(trans)
                car_render.set_color(1,0,0)
                self.viewer.add_geom(car_render)
            elif ind == 0:
                car_render = rendering.FilledPolygon([(l, b), (l, t), (r, t), (r, b)])
                car_render.add_attr(trans)
                car_render.set_color(0,0,1)
                self.viewer.add_geom(car_render)
            else:
                car1 = rendering.Line((l, b), (l, t))
                car2 = rendering.Line((l, t), (r, t))
                car3 = rendering.Line((r, t), (r, b))
                car4 = rendering.Line((r, b), (l, b))

                car1.add_attr(trans)
                car2.add_attr(trans)
                car3.add_attr(trans)
                car4.add_attr(trans)

                self.viewer.add_geom(car1)
                self.viewer.add_geom(car2)
                self.viewer.add_geom(car3)
                self.viewer.add_geom(car4)

        return self.viewer.render(return_rgb_array = mode == 'rgb_array')


#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Copyright: Deutsches Zentrum fuer Luft- und Raumfahrt e.V., 2015 (c)
Contact: daniel.boehnke@dlr.de and jonas.jepsen@dlr.de
'''
from cmath import pi, tan, sqrt

from VAMPzero.Handler.Parameter import parameter

rad = pi / 180.

class expArea(parameter):
    '''
    The exposed area of the wing

    :Unit: [m2]
    :Wiki: http://adg.stanford.edu/aa241/wingdesign/winggeometry.html
    '''

    def __init__(self, value=0., unit='m2', parent='', cpacsPath=''):
        super(expArea, self).__init__(value=value, unit=unit, doc=self.__doc__, status='init', parent=parent,
                                      cpacsPath=cpacsPath)
    def calc(self):
        '''
        Calculates the exposed Area of the horizontal tail depending on the location value.
        If the location value of the engine is equal to 1, configuration is conventional.
        else it is T-tail.
        '''
        location = self.parent.location.getValue()
        if location == 1.:
            self.calc = self.calcConventional
        else:
            self.calc = self.calcTtail

    def calcConventional(self):
        '''
        Calculates the exposed Area by subtracting a trapezoid from the reference area
        The trapezoid has the lengths a = cRoot, c = cInter, where cInter is the chord at the fuselage/wing intersection
        and h = yfus, where yfus is the y coordinate of the wing/fuselage intersection
        '''
        refArea = self.parent.refArea.getValue()
        cRoot = self.parent.cRoot.getValue()
        cTip = self.parent.cTip.getValue()
        span = self.parent.span.getValue()/2.
        dfus = self.parent.aircraft.fuselage.dfus.getValue()
        zRoot = self.parent.zRoot.getValue()

        # calculate the y position of the wing fuselage intersection
        yfus = sqrt(dfus ** 2 / 4. - zRoot ** 2)

        cInter = cRoot + (cTip - cRoot)/(span)*(yfus)

        # remaining area is the referenceArea mins the trapezoid from croot, cinter and h = yfus
        result = refArea - ((cRoot + cInter) / 2 * yfus) * 2.

        return self.setValueCalc(result)

    def calcTtail(self):
        '''

        '''
        refArea = self.parent.refArea.getValue()

        return self.setValueCalc(refArea)
        ###################################################################################################
        # EOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFEOFE#
        ###################################################################################################


# -*- coding:utf8 -*-
import tensorflow as tf
import numpy as np
from six.moves import cPickle as pickle

pickle_file="/usr/bigdata/data/notMNIST_data/notMNIST.pickle"
train_subset=30000
with open(pickle_file, "rb") as f:
    save=pickle.load(f)
    train_dataset=save["train_dataset"]
    train_labels=save["train_labels"]
    valid_dataset=save["valid_dataset"]
    valid_labels=save["valid_labels"]
    test_dataset=save["test_dataset"]
    test_labels=save["test_labels"]
    del save
    print("Training set",train_dataset.shape, train_labels.shape)
    print("Validation set",valid_dataset.shape, valid_labels.shape)
    print("Test set",test_dataset.shape, test_labels.shape)

image_size=28
num_labels=10

def reformat(dataset, labels):
    dataset=dataset.reshape((-1, image_size*image_size)).astype(np.float32)
    labels=(np.arange(num_labels) == labels[:,None]).astype(np.float32)
    return dataset,labels

train_dataset, train_labels=reformat(train_dataset, train_labels)
train_dataset=train_dataset[:train_subset, :]
train_labels=train_labels[:train_subset, :]
valid_dataset, valid_labels=reformat(valid_dataset, valid_labels)
test_dataset, test_labels=reformat(test_dataset, test_labels)
print("reshaped")
print("Training set", train_dataset.shape, train_labels.shape)
print("Validation set", valid_dataset.shape, valid_labels.shape)
print("Test set", test_dataset.shape, test_labels.shape)

def accuracy(predicitons, labels):
    return (100*np.sum(np.argmax(predictions,1)==np.argmax(labels,1))/predictions.shape[0])

def tf_accuracy(predictions, labels):
    acc=tf.equal(tf.argmax(predictions,1), tf.argmax(labels,1))
    acc=tf.cast(acc, tf.float32)
    return tf.reduce_sum(acc)*100/predictions.shape[0]

batch_size=128
num_steps=200
hidden_nodes=1024
x=tf.placeholder(tf.float32, shape=(batch_size, image_size*image_size),name="x")
y_=tf.placeholder(tf.float32, shape=(batch_size, num_labels),name="y")

weights1=tf.Variable(tf.truncated_normal((image_size*image_size,hidden_nodes)))
biases1=tf.Variable(tf.zeros((hidden_nodes)))

weights2=tf.Variable(tf.truncated_normal((hidden_nodes, num_labels)))
biases2=tf.Variable(tf.zeros((num_labels)))

fc1=tf.matmul(x, weights1)+biases1
fc1=tf.nn.relu(fc1)
fc1=tf.nn.dropout(fc1, keep_prob=0.5)

fc2=tf.matmul(fc1, weights2)+biases2
y=tf.nn.softmax(fc2)

cross_entropy=-tf.reduce_mean(y_ * tf.log(y))
loss=cross_entropy+0.01*(tf.nn.l2_loss(weights1) +tf.nn.l2_loss(weights2))

train_step=tf.train.GradientDescentOptimizer(0.1).minimize(loss)

with tf.Session() as sess:
    tf.global_variables_initializer().run()
    start_t=0
    for step in range(num_steps):
        xs,ys=train_dataset[start_t:(start_t + batch_size),:],train_labels[start_t:(start_t + batch_size),:]
        start_t=start_t + batch_size
        print("xs, ys", xs.shape,ys.shape)
        sess.run(train_step, feed_dict={x:xs, y_:ys})
        print("Loss of step %d is %f" % (step, sess.run(loss, feed_dict={x:xs,y_:ys})))


from mock import patch

from django.utils import timezone
from django.core import mail
from django.db import IntegrityError
from django.test.utils import override_settings

from bluebottle.bb_projects.models import ProjectPhase
from bluebottle.tasks.models import TaskMember
from bluebottle.test.utils import BluebottleTestCase
from bluebottle.test.factory_models.accounts import BlueBottleUserFactory
from bluebottle.test.factory_models.tasks import TaskFactory, TaskMemberFactory
from bluebottle.test.factory_models.donations import DonationFactory
from bluebottle.test.factory_models.fundraisers import FundraiserFactory
from bluebottle.test.factory_models.orders import OrderFactory
from bluebottle.test.factory_models.projects import ProjectFactory
from bluebottle.test.factory_models.geo import LocationFactory, CountryFactory

class BlueBottleUserManagerTestCase(BluebottleTestCase):
    """
    Test case for the model manager of the abstract user model.
    """

    def test_create_user(self):
        """
        Tests the manager ``create_user`` method.
        """
        user = BlueBottleUserFactory.create(
            email='john_doe@onepercentclub.com')

        self.assertTrue(user.is_active)
        self.assertFalse(user.is_superuser)
        self.assertFalse(user.is_staff)

    def test_create_user_no_email_provided(self):
        """
        Tests exception raising when trying to create a new user without
        providing an email.
        """
        with self.assertRaises(IntegrityError):
            user = BlueBottleUserFactory.build()
            user.email = None
            user.save()

    def test_location_sets_country(self):
        country = CountryFactory.create()
        location = LocationFactory.create(country=country)

        BlueBottleUserFactory.create(email='john_doe@onepercentclub.com', location=location)

class BlueBottleUserTestCase(BluebottleTestCase):
    """
    Test case for the implementation of the abstract user model.
    """

    def setUp(self):
        self.init_projects()
        self.user = BlueBottleUserFactory.create()

    @patch('django.utils.timezone.now')
    def test_update_deleted_timestamp(self, mock):
        """
        Tests the ``update_deleted_timestamp`` method, checking that the
        timestamp is properly set up when the user is not active any more.
        """
        timestamp = timezone.now()
        mock.return_value = timestamp

        self.user.is_active = False
        self.user.update_deleted_timestamp()

        self.assertEqual(self.user.deleted, timestamp)

    def test_update_deleted_timestamp_active_user(self):
        """
        Tests that the ``update_deleted_timestamp`` method resets the timestamp
        to ``None`` if the user becomes active again.
        """
        self.user.is_active = False
        self.user.update_deleted_timestamp()

        # Now the user is inactive, so ``deleted`` attribute is set. Let's
        # reactivate it again and check that is reset.
        self.user.is_active = True
        self.user.update_deleted_timestamp()

        self.assertIsNone(self.user.deleted)

    def test_generate_username_from_email(self):
        """
        Tests the ``generate_username`` method when no username was provided.
        It should set the email as username.
        """
        user = BlueBottleUserFactory.create(email='piet@puk.nl', username='',
                                            first_name='', last_name='')
        user.generate_username()
        self.assertEqual(user.username, user.email)

    def test_get_full_name(self):
        """
        Tests the ``get_full_name`` method.
        """
        self.user.first_name = 'John'
        self.user.last_name = 'Doe'
        self.user.save()

        self.assertEqual(self.user.get_full_name(), 'John Doe')

    def test_get_short_name(self):
        """
        Tests the ``get_short_name`` method.
        """
        self.user.first_name = 'John'
        self.user.last_name = 'Doe'
        self.user.save()

        self.assertEqual(self.user.get_short_name(), 'John')

    @override_settings(SEND_WELCOME_MAIL=True,
                       CELERY_MAIL=False)
    def test_welcome_mail(self):
        """
        Test that a welcome mail is sent when a user is created when the
        setting are enabled
        """

        mail.outbox = []

        self.assertEqual(len(mail.outbox), 0)
        new_user = BlueBottleUserFactory.create(
            email='new_user@onepercentclub.com',
            primary_language='en')
        self.assertEqual(len(mail.outbox), 1)
        # We need a better way to verify the right mail is loaded
        self.assertTrue("Welcome" in mail.outbox[0].subject)
        self.assertEqual(mail.outbox[0].activated_language, 'en')
        self.assertEqual(mail.outbox[0].recipients()[0], new_user.email)

    @override_settings(SEND_WELCOME_MAIL=True,
                       CELERY_MAIL=False)
    def test_welcome_mail_nl(self):
        """
        Test that a welcome mail is sent when a user is created when the
        setting are enabled (NL).
        """

        mail.outbox = []

        self.assertEqual(len(mail.outbox), 0)
        new_user = BlueBottleUserFactory.create(
            email='new_user@onepercentclub.com',
            primary_language='nl')
        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(mail.outbox[0].activated_language, 'nl')
        self.assertEqual(mail.outbox[0].recipients()[0], new_user.email)

    def test_no_welcome_mail(self):
        """
        Test that a welcome mail is sent when a user is created when the setting
        are disabled (= default)
        """
        mail.outbox = []

        # The setup function also creates a user and generates a mail
        self.assertEqual(len(mail.outbox), 0)
        BlueBottleUserFactory.create(email='new_user@onepercentclub.com')
        self.assertEqual(len(mail.outbox), 0)

    def test_calculate_task_count(self):
        """
        Test that the task_count property on a user is calculated correctly.
        We count a) tasks where a user is a task author and
        b) TaskMembers where a user is applied, accepted or realized
        """
        self.assertEqual(self.user.task_count, 0)

        task = TaskFactory.create(author=self.user)
        self.assertEqual(self.user.task_count, 1)

        TaskMemberFactory.create(
            member=self.user,
            status=TaskMember.TaskMemberStatuses.applied,
            task=task
        )

        self.assertEqual(self.user.task_count, 2)

        TaskMemberFactory.create(
            member=self.user,
            status=TaskMember.TaskMemberStatuses.withdrew,
            task=task
        )

        self.assertEqual(self.user.task_count, 3)

    def test_calculate_donation_count(self):
        """ Test the counter for the number of donations a user has done """
        self.assertEqual(self.user.donation_count, 0)

        order = OrderFactory.create(user=self.user)
        DonationFactory.create(amount=1000, order=order)

        # Only successful or pending orders/donations are counted
        self.assertEqual(self.user.donation_count, 0)

        # Set donation to pending to be included in count
        order.locked()
        order.save()
        order.pending()
        order.save()
        self.assertEqual(self.user.donation_count, 1)

    def test_calculate_project_count(self):
        """ Test the counter for the number of projects a user has started """
        self.assertEqual(self.user.project_count, 0)
        ProjectFactory.create(owner=self.user)

        self.assertEqual(self.user.project_count, 0)

        status = ProjectPhase.objects.get(slug='done-complete')

        ProjectFactory.create(owner=self.user, status=status)
        self.assertEqual(self.user.project_count, 1)

        ProjectFactory.create(owner=self.user, status=status)
        self.assertEqual(self.user.project_count, 2)

    def test_calculate_fundraiser_count(self):
        """ Test the counter for the number of fundraisers a user is owner of """
        self.assertEqual(self.user.fundraiser_count, 0)

        FundraiserFactory.create(amount=4000, owner=self.user)
        self.assertEqual(self.user.fundraiser_count, 1)
        FundraiserFactory.create(amount=4000, owner=self.user)
        self.assertEqual(self.user.fundraiser_count, 2)

    def test_base_user_fields(self):
        """ Test that a base user model has all the expected fields """
        from bluebottle.members.models import Member

        user_fields = set(
            ['email', 'username', 'is_staff', 'is_active', 'date_joined',
             'updated', 'deleted',
             'user_type', 'first_name', 'last_name', 'location', 'picture',
             'about_me',
             'primary_language', 'share_time_knowledge', 'share_money',
             'newsletter', 'phone_number',
             'gender', 'birthdate', 'disable_token', 'campaign_notifications'])

        self.assertEquals(
            set(f.name for f in Member._meta.fields) & user_fields, user_fields)

    def test_anonymize(self):
        self.user.anonymize()

        for prop in [
            'is_active',
            'user_name',
            'place',
            'picture',
            'avatar',
            'about_me',
            'gender',
            'location',
            'website',
            'facebook',
            'twitter',
            'skypename',
            'partner_organization',
        ]:
            self.assertFalse(getattr(self.user, prop))

        self.assertIsNone(self.user.address.pk)
        self.assertEqual(self.user.birthdate, '1000-01-01')
        self.assertTrue(self.user.email.endswith('anonymous@example.com'))
        self.assertEqual(self.user.first_name, 'Deactivated')
        self.assertEqual(self.user.last_name, 'Member')
        self.assertFalse(self.user.has_usable_password())

    def test_anonymize_twice(self):
        self.user.anonymize()

        other_user = BlueBottleUserFactory.create()
        other_user.anonymize()
        self.assertFalse(other_user.is_active)


#State Population Diagrom <Eric Williams>
#Creating a State Dictionary.
def make():
  s=['Alabama','Alaska','Arizona','Arkansas','California','Colorado',
   'Connecticut','Delaware','District of Columbia','Florida','Georgia',
   'Hawaii','Idaho','Illinois','Indiana','Iowa','Kansas','Kentucky','Louisiana',
   'Maine','Maryland','Massachusetts','Michigan','Minnesota','Mississippi',
   'Missouri','Montana','Nebraska','Nevada','New Hampshire','New Jersey',
   'New Mexico','New York','North Carolina','North Dakota','Ohio','Oklahoma',
   'Oregon','Pennsylvania','Rhode Island','South Carolina','South Dakota',
   'Tennessee','Texas','Utah','Vermont','Virginia','Washington','West Virginia',
   'Wisconsin','Wyoming']
  import urllib
  DATA = urllib.urlopen("https://www.census.gov/popest/data/state/totals/2014/tables/NST-EST2014-01.csv")
  while True:
    LINE = DATA.readline()
    if LINE == '':
      break
    L = LINE
    x=51
    H = {}
    if 'West' in L:
      h = 0
      P = []
#To make the List
      while x>0:
        LINE = DATA.readline()
        NEWLINE = LINE.replace(',','')
        NEWLINE = NEWLINE.replace('","',',')
        NEWLINE = NEWLINE.replace(s[h],'')
        NEWLINE = NEWLINE.replace('""',',')
        NEWLINE = NEWLINE.replace('.','')
        NEWLINE = NEWLINE.replace('\'','')
        NEWLINE = NEWLINE.replace('"','')
        NEWLINE = NEWLINE.replace('\r\n','')
        M = NEWLINE.split(',')
        P.append(M)
        h = h + 1
        x = x -1
#To make the Dictionary
  D = {'Alabama':P[0],'Alaska':P[1],'Arizona':P[2],'Arkansas':P[3],'California':P[4],
       'Colorado':P[5],'Connecticut':P[6],'Delaware':P[7],'District of Columbia':P[8],
       'Florida':P[9],'Georgia':P[10],'Hawaii':P[11],'Idaho':P[12],'Illinois':P[13],
       'Indiana':P[14],'Iowa':P[15],'Kansas':P[16],'Kentucky':P[17],'Louisiana':P[18],
       'Maine':P[19],'Maryland':P[20],'Massachusetts':P[21],'Michigan':P[22],
       'Minnesota':P[23],'Mississippi':P[24],'Missouri':P[25],'Montana':P[26],
       'Nebraska':P[27],'Nevada':P[28],'New Hampshire':P[29],'New Jersey':P[30],
       'New Mexico':P[31],'New York':P[32],'North Carolina':P[33],'North Dakota':P[34],
       'Ohio':P[35],'Oklahoma':P[36],'Oregon':P[37],'Pennsylvania':P[38],
       'Rhode Island':P[39],'South Carolina':P[40],'South Dakota':P[41],
       'Tennessee':P[42],'Texas':P[43],'Utah':P[44],'Vermont':P[45],'Virginia':P[46],
       'Washington':P[47],'West Virginia':P[48],'Wisconsin':P[49],'Wyoming':P[50]}
  return D
  DATA.close()