from __future__ import annotations
from disnake.ext import commands
from disnake import ApplicationCommandInteraction, RawReactionActionEvent, Message, Member
from utils.player import Player
from utils.approvals import Approval
from utils.characters import CharacterChooseView, Character
from utils.help import Menu
from config import ENTRY_POINTS, APPROVAL_REACTION, DENIAL_REACTION, DEFAULT_PC_AVATAR
from typing import List

# TODO add variants and familiars
class CharacterCommands(commands.Cog, name='Character Commands'):

    def __init__(self, bot):
        self.bot = bot

    def get_player_characters(self, author: Member) -> (Player, List[Character]):
        me: Player = [player for player in self.bot.players if player.member.id == author.id][0]
        characters = [character for character in me.characters if character.approved]
        return me, characters

    def decode_footer(self, msg: Message) -> (str, Member):
        name = msg.embeds[0].footer.text.split("|")[0]
        approvee = msg.guild.get_member(int(msg.embeds[0].footer.text.split("|")[1]))
        return name, approvee

    @commands.slash_command()
    async def character(self, inter: ApplicationCommandInteraction):
        """ Commands dealing with player characters"""
        # this check is for the message listener to make sure the same person responds
        self.m_check = lambda m: inter.author == m.author
        pass

    # TODO: Add a check for a limit on characters? We haven't decided yet I guess,
    #  for now i just added a character count on the approval

    @character.sub_command()
    async def add(
            self,
            inter: ApplicationCommandInteraction,
            entry_point: ENTRY_POINTS,
            name: str,
            backstory: str,
            prefix: str,
            avatar: str = DEFAULT_PC_AVATAR):
        """ Command to register a new Player Character

        Parameters
        ----------
        inter: message interaction
        entry_point: The point where you will start your RP, depends on your backstory
        name: Full name of your character
        backstory: Your tragic backstory
        prefix: this is what you will use to talk as your character, Tupperbox style.
        avatar: URL to an image you want to use as the player avatar
        """
        # Get the player object from the cache
        me = [player for player in self.bot.players if player.member.id == inter.author.id][0]
        entry_point = inter.guild.get_role(int(entry_point))

        # Make a character object and add it to the player object
        new_char = Character(player=me,
                             name=name.title(),
                             backstory=backstory,
                             avatar=avatar,
                             prefix=prefix.rstrip(":"),
                             location=entry_point,
                             )
        me.add_character(new_char)

        # Create a new approval and save it to the queue
        new_approval = Approval(character=new_char)
        self.bot.pending_approvals.append(new_approval)

        # sends confirmation to the player and approval embed to the approval channel
        await inter.send(embeds=new_approval.embed, ephemeral=True)
        await inter.bot.APPROVAL_CHANNEL.send(embeds=new_approval.embed)

    @character.sub_command()
    async def list(self, inter: ApplicationCommandInteraction):
        """ List all of your approved characters"""
        e = []

        me, characters = self.get_player_characters(inter.author)

        if not characters:
            await inter.send("**You currently have no characters use `/character add` or wait for an approval. "
                             "Characters take 1 minute from approvals to be ready**", ephemeral=True)
            return
        # pull all the embeds from each character and send them back
        for character in characters:
            e.append(character.embed) if character.approved else 0
        e[0].set_footer(text=f"Kerna - Path of the Wicked | Page 1 of {len(e)}")
        await inter.send(embed=e[0], view=Menu(e), ephemeral=True)

    @character.sub_command()
    async def edit(self,
                   inter: ApplicationCommandInteraction):
        """ Edit a part of your approved character """
        # get a list of your characters
        me, characters = self.get_player_characters(inter.author)
        if not characters:
            await inter.send("**You currently have no characters use `/character add` or wait for an approval. "
                             "Characters take 1 minute from approvals to be ready**", ephemeral=True)
            return

        # calls the View to display the selections
        view = CharacterChooseView(characters, "edit")
        await inter.send(content="Character Editor", view=view, ephemeral=True)
        await view.wait()

        # awaits for the new values
        msg: Message = await self.bot.wait_for('message', check=self.m_check)
        await msg.delete()

        # makes the changes
        view.character.update(view.attribute, msg.content)

        await inter.edit_original_message(view=None, embeds=[view.character.embed])
        await inter.bot.CHANGE_LOG_CHANNEL.send(content=f'`{view.character.name}` changed `{view.attribute}` to `{msg.content}`')

    @character.sub_command()
    async def delete(self, inter: ApplicationCommandInteraction):
        """ Delete a character """
        # get a list of your characters
        me, characters = self.get_player_characters(inter.author)

        if not characters:
            await inter.send("**You currently have no characters use `/character add` or wait for an approval. "
                             "Characters take 1 minute from approvals to be ready**", ephemeral=True)
            return

        # calls the View to display the selections
        view = CharacterChooseView(characters, "delete")
        await inter.send(content="Delete a Character", view=view, ephemeral=True)
        await view.wait()

        # makes the changes, moves character to delete queue and removes that location
        self.bot.character_delete_queue.append(me.delete_character(view.character))
        if view.character.location not in [character.location for character in me.characters]:
            await me.member.remove_roles(view.character.location)
        await inter.edit_original_message(content=f'`{view.character.name}` has been deleted!', view=None)
        await inter.bot.CHANGE_LOG_CHANNEL.send(content=f'`{view.character.name}` has been deleted')

    @commands.Cog.listener()
    async def on_raw_reaction_add(self, payload: RawReactionActionEvent):
        """ Listens for a thumbs up in the #approvals channel,
        adds their starting role and removes the new player role """
        # checks to make sure that only thumbs up or down in the correct channel
        if payload.channel_id == self.bot.APPROVAL_CHANNEL.id and payload.emoji in [APPROVAL_REACTION, DENIAL_REACTION]:
            msg: Message = self.bot.get_message(payload.message_id)

            # the approvee is the Member who submitted for approval
            name, approvee = self.decode_footer(msg)
            me, _ = self.get_player_characters(approvee)

            # pulls the approval from the queue
            approval: Approval = [approval for approval in self.bot.pending_approvals if approval.character.player.member == approvee][0]

            approval.process_approval(payload)

            # remove it from the queue
            self.bot.pending_approvals.pop(self.bot.pending_approvals.index(approval))

            if approval.approved:
                await approval.character.player.member.add_roles(approval.character.location)
                await approval.character.player.member.remove_roles(self.bot.NEW_PLAYER_ROLE)
            else:
                self.bot.character_delete_queue.append(approval.character)
                for index, character in enumerate(me.characters):
                    if character.id == approval.character.id:
                        me.characters.pop(index)
                        break
            await msg.edit(embeds=approval.embed)
            await payload.member.guild.system_channel.send(content=f'{approval.character.player.member.mention} Your character was {"Approved" if approval.approved else "Denied"}')

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


import os
import shutil
import logging

import minio

from . import utils
from . import tool
from . import sshkey

log = logging.getLogger(__name__)

def run(step, **kwargs):  # pylint: disable=unused-argument
    timeout = int(step.get('timeout', 60))
    url = step['checkout']
    dest = ''
    if 'destination' in step:
        dest = step['destination']

    # determine repo dir
    if dest:
        repo_dir = dest
    else:
        repo_dir = url.split('/')[-1]
        if repo_dir.endswith('.git'):
            repo_dir = repo_dir[:-4]

    # prepare accessing git repo
    ssh_agent = None
    access_token = None
    if 'ssh-key' in step:
        # username = step['ssh-key']['username']
        # url = '%s@%s' % (username, url)
        key = step['ssh-key']['key']
        ssh_agent = sshkey.SshAgent()
        ssh_agent.add_key(key)
    elif 'access-token' in step:
        access_token = step['access-token']
        if url.startswith('git@'):
            url = url[4:]
        url = 'https://%s@%s' % (access_token, url.replace(':', '/'))

    # prepare git config
    cfg_params = []
    git_cfg = step.get('git_cfg', {})
    for k, v in git_cfg.items():
        cfg_params.append('-c %s=%s' % (k, v))
    cfg_params = ' '.join(cfg_params)

    # setup connection to minio
    minio_addr = step['minio_addr']
    minio_access_key = step['minio_access_key']
    minio_secret_key = step['minio_secret_key']
    minio_bucket = step['minio_bucket']
    minio_folder = step['minio_folder']
    minio_repo_bundle_path = '%s/repo.bundle' % minio_folder
    mc = minio.Minio(minio_addr, access_key=minio_access_key, secret_key=minio_secret_key, secure=False)
    try:
        mc.bucket_exists(minio_bucket)
    except Exception as e:
        log.exception('problem with connecting to minio %s', minio_addr)
        msg = 'problem with connecting to minio %s: %s' % (minio_addr, str(e))
        return 1, msg

    # retrieve git repo bundle
    repo_bundle_path = 'repo.bundle'
    log.info('try to retrieve repo bundle %s / %s -> %s', minio_bucket, minio_repo_bundle_path, repo_bundle_path)
    try:
        mc.fget_object(minio_bucket, minio_repo_bundle_path, repo_bundle_path)
        bundle_present = True
    except Exception as e:
        if 'Object does not exist' in str(e):
            log.info('repo bundled not archived yet')
        else:
            log.exception('retriving repo from bundle failed, skipping it')
        bundle_present = False

    restore_ok = False
    if bundle_present:
        try:
            # restore git repo bundle
            utils.execute('git clone %s %s %s' % (cfg_params, repo_bundle_path, repo_dir), out_prefix='', timeout=timeout, raise_on_error=True)

            # restore original remote URL
            utils.execute('git remote set-url origin %s' % url, cwd=repo_dir, out_prefix='', timeout=timeout, raise_on_error=True)

            # pull latest stuff from remote
            utils.execute('git pull --ff-only', cwd=repo_dir, out_prefix='', timeout=timeout, raise_on_error=True)

            restore_ok = True
        except Exception:
            log.exception('cloning repo from bundle failed, skipping it')
            if os.path.exists(repo_dir):
                shutil.rmtree(repo_dir)

        # delete old bundle
        os.unlink(repo_bundle_path)

    # if restoring repo from bundle failed then do normal clone repo
    if not restore_ok:
        try:
            ret, _ = utils.execute('git clone %s %s %s' % (cfg_params, url, dest), mask=access_token, out_prefix='', timeout=timeout)
            if ret != 0:
                return ret, 'git clone exited with non-zero retcode'
        finally:
            if ssh_agent is not None:
                ssh_agent.shutdown()

    # bundle repo and cache it
    repo_bundle_path = os.path.abspath(os.path.join(repo_dir, '..', 'repo.bundle'))
    ret, _ = utils.execute('git bundle create %s --all' % repo_bundle_path, cwd=repo_dir, out_prefix='', timeout=300)
    if ret != 0:
        log.warning('repo bundle failed, skipping it')
    else:
        minio_bucket = step['minio_bucket']
        log.info('store repo bundle %s -> %s / %s', repo_bundle_path, minio_bucket, minio_repo_bundle_path)
        try:
            mc.fput_object(minio_bucket, minio_repo_bundle_path, repo_bundle_path)
        except Exception:
            log.exception('problem with storing repo bundle, skipping it')

    # checkout commit that comes from trigger, otherwise checkout master/main
    if 'trigger_data' in step and step['trigger_data'][0]['repo'] == step['http_url']:
        branch_or_commit = step['trigger_data'][0]['after']
    else:
        branch_or_commit = step.get('branch', 'master')  # TODO: detect if there is master, if not then checkout main

    # do checkout
    ret, _ = utils.execute('git checkout %s' % branch_or_commit, cwd=repo_dir, out_prefix='')
    if ret != 0:
        return ret, 'git checkout exited with non-zero retcode'

    return 0, ''

if __name__ == '__main__':
    tool.main()


from multiprocessing.spawn import old_main_modules

import pygame

from sprite import Sprite

class Player(Sprite):
    def __init__(self, x, y, game, name, obstacles):
        super().__init__(x, y, game.PLAYER_WIDTH, game.PLAYER_HEIGHT, game,
                         "main_characters", name, animation_speed=0.5)
        self.obstacles = obstacles
        self.speed = 5
        self.velocity = pygame.math.Vector2(0, 0)
        self.flip_sprite = False
        self.grounded = False
        self.jump_force = 15
        self.jump_counter = 0
        self.jumping = False
        self.jump_time = 0
        self.jump_cooldown = 400

    def move(self, dx=0, dy=0):
        self.rect.x += dx
        self.rect.y += dy

    def move_left(self, running=False):
        if running:
            self.velocity.x = -self.speed * 2
        else:
            self.velocity.x = -self.speed
        self.flip_sprite = True

    def move_right(self, running=False):
        if running:
            self.velocity.x = self.speed * 2
        else:
            self.velocity.x = self.speed
        self.flip_sprite = False

    def jump(self):
        if self.jumping:
            return
        self.jumping = True
        if self.grounded:
            self.velocity.y = -self.jump_force / self.game.GRAVITY
            self.jump_counter = 1
            self.grounded = False
            self.jump_time = pygame.time.get_ticks()
        elif self.jump_counter < 2:
            self.velocity.y = -self.jump_force / self.game.GRAVITY
            self.jump_counter += 1
            self.jump_time = pygame.time.get_ticks()

    def handle_input(self):
        keys = pygame.key.get_pressed()
        self.velocity.x = 0
        if (keys[pygame.K_LEFT] or keys[pygame.K_a]) and (keys[pygame.K_RIGHT] or keys[pygame.K_d]):
            self.velocity.x = 0
        elif keys[pygame.K_LEFT] or keys[pygame.K_a]:
            if keys[pygame.K_LSHIFT] or keys[pygame.K_RSHIFT]:
                self.move_left(running=True)
            else:
                self.move_left()
        elif keys[pygame.K_RIGHT] or keys[pygame.K_d]:
            if keys[pygame.K_LSHIFT] or keys[pygame.K_RSHIFT]:
                self.move_right(running=True)
            else:
                self.move_right()
        if keys[pygame.K_SPACE] or keys[pygame.K_UP] or keys[pygame.K_w]:
            self.jump()

    def update_status(self):
        old_status = self.status
        if self.velocity.y > self.game.GRAVITY * 2:
            self.status = "fall"
        elif self.velocity.y < -self.game.GRAVITY * 2:
            self.status = "jump" if self.jump_counter == 1 else "double_jump"
        elif self.velocity.x != 0:
            self.status = "run"
        else:
            self.status = "idle"
        if old_status != self.status:
            self.frame_index = 0

    def handle_gravity(self):
        if not self.grounded:
            self.velocity.y += self.game.GRAVITY
            if self.velocity.y > self.game.MAX_GRAVITY:
                self.velocity.y = self.game.MAX_GRAVITY

    def check_horizontal_collisions(self):
        for obstacle in self.obstacles:
            if pygame.sprite.collide_mask(self, obstacle):
                self.move(-self.velocity.x, 0)
                break

    def check_vertical_collisions(self):
        self.grounded = False
        for obstacle in self.obstacles:
            if pygame.sprite.collide_mask(self, obstacle):
                if self.velocity.y > 0:
                    self.rect.bottom = obstacle.rect.top
                    self.velocity.y = 0
                    self.grounded = True
                    self.jump_counter = 0
                elif self.velocity.y < 0:
                    self.rect.top = obstacle.rect.bottom
                    self.velocity.y = -self.velocity.y

    def handle_cooldowns(self):
        current_time = pygame.time.get_ticks()
        if self.jumping and current_time - self.jump_time > self.jump_cooldown:
            self.jumping = False

    def update(self):
        self.handle_gravity()
        self.handle_cooldowns()
        self.handle_input()
        self.move(self.velocity.x, self.velocity.y)
        self.check_horizontal_collisions()
        self.check_vertical_collisions()
        self.update_status()
        self.animate(self.flip_sprite)


import sys
import os

# setting path
sys.path.append('../TM2_segmentation')

import numpy as np
import pandas as pd
import nibabel as nib
from skimage.transform import resize, rescale
from scipy.ndimage import zoom
from settings import target_size_unet, scaling_factor

import matplotlib.pyplot as plt
from scripts.preprocess_utils import load_nii,find_file_in_path

# helper function to get the id and path of the image and the mask
def get_id_and_path(row, image_dir, nested = False, no_tms=True):
    patient_id, image_path, ltm_file, rtm_file = "","","",""
    patient_id = str(row['Filename']).split(".")[0].split("/")[-1]
    path = find_file_in_path(patient_id, os.listdir(image_dir))

    scan_folder = image_dir+path

    for file in os.listdir(scan_folder):
        t = image_dir+path+"/"+file
        if "LTM" in file:
            ltm_file = t
        elif "RTM" in file:
            rtm_file = t
        elif "TM" in file:
            rtm_file = t
            ltm_file = t
        if patient_id in file:
            image_path = t
    return patient_id, image_path, ltm_file, rtm_file

# convert nifti to numpy array
def nifty_to_npy(df, path_images_array, path_masks_array):
    # create empty arrays for populating with image slices
    images_array  = np.zeros((df.shape[0]*4, target_size_unet[0], target_size_unet[1], 1))
    masks_array  = np.zeros((df.shape[0]*4, target_size_unet[0], target_size_unet[1], 1))

    for idx, row in df.iterrows():
        #print(idx)
        patient_id, image_path, tm_file, _ = get_id_and_path(row, image_dir)
        #NDAR processed differently

        if image_path != 0:
            seg = nib.load(tm_file)
            seg_data, seg_affine  = seg.get_fdata(), seg.affine
            if len(seg_data)>3:
                #print(np.asarray(nib.aff2axcodes(seg_affine)))

                if 'gz' in image_path :
                    os.rename(image_path,image_path.split('.gz')[0])
                    image_path = image_path.split('.gz')[0]
                    image_array, img_aff = load_nii(image_path)
                else:
                    image_array, img_aff = load_nii(image_path)

                if (np.asarray(nib.aff2axcodes(seg_affine))==['L', 'P', 'S']).all() or\
                    (np.asarray(nib.aff2axcodes(seg_affine))==['R', 'A', 'S']).all():
                    slice_label = np.asarray(np.where(seg_data != 0)).T[0, 2]
                else:
                    print("Wrong orientation cannot infer slice label")

                # rescale to 512x512
                rescaled_mask  = rescale(seg_data[:,15:-21,slice_label], scaling_factor).reshape(1,target_size_unet[0],target_size_unet[1],1)
                rescaled_image = rescale(image_array[:,15:-21,slice_label], scaling_factor).reshape(1,target_size_unet[0],target_size_unet[1],1)

                images_array[idx,:,:,:] = np.concatenate((rescaled_image[:,:256,:,:],np.zeros_like(rescaled_image[:,:256,:,:])),axis=1)
                masks_array[idx,:,:,:] = np.concatenate((rescaled_mask[:,:256,:,:],np.zeros_like(rescaled_mask[:,:256,:,:])),axis=1)
                images_array[df.shape[0]+idx,:,:,:] = np.concatenate((np.zeros_like(rescaled_image[:,256:,:,:]),rescaled_image[:,256:,:,:]),axis=1)
                masks_array[df.shape[0]+idx,:,:,:] = np.concatenate((np.zeros_like(rescaled_image[:,256:,:,:]),rescaled_mask[:,256:,:,:]),axis=1)
                images_array[2*df.shape[0]+idx,:,:,:] = np.concatenate((np.zeros_like(rescaled_image[:,:256,:,:]),rescaled_image[:,:256,:,:]),axis=1)
                masks_array[2*df.shape[0]+idx,:,:,:] = np.concatenate((np.zeros_like(rescaled_image[:,:256,:,:]),rescaled_mask[:,:256,:,:]),axis=1)
                images_array[3*df.shape[0]+idx,:,:,:] = np.concatenate((rescaled_image[:,256:,:,:],np.zeros_like(rescaled_image[:,256:,:,:])),axis=1)
                masks_array[3*df.shape[0]+idx,:,:,:] = np.concatenate((rescaled_mask[:,256:,:,:],np.zeros_like(rescaled_image[:,256:,:,:])),axis=1)

                #print(idx, patient_id, np.shape(images_array[idx,:,:,:]),np.shape(masks_array[idx,:,:,:]))
                if np.sum(masks_array[idx,:,:,:])<=15 or np.sum(masks_array[df.shape[0]+idx,:,:,:])<=15\
                    or np.sum(masks_array[2*df.shape[0]+idx,:,:,:])<=15 or np.sum(masks_array[3*df.shape[0]+idx,:,:,:])<=15:
                    print("smal", patient_id, image_path, tm_file,np.asarray(nib.aff2axcodes(seg_affine)))

                #break

    masks_array=masks_array.astype(np.uint8)
    np.save(path_images_array, images_array)
    np.save(path_masks_array, masks_array)

if __name__=="__main__":
    input_annotation_file = 'itmt_v2/itmt2.0_joint.csv'
    image_dir  = 'data/itmt2.0/'

    df = pd.read_csv(input_annotation_file, header=0)
    df_train = df[df['train/test']=='train'].reset_index()
    #df_train=df_train[df_train['Ok registered? Y/N']=='Y'].reset_index()
    df_val = df[df['train/test']=='val'].reset_index()
    #df_val = df_val[df_val['Ok registered? Y/N']=='Y'].reset_index()

    nifty_to_npy(df_train, path_images_array='data/segmentations_itmt2.0/train_images.npy',
                 path_masks_array='data/segmentations_itmt2.0/train_masks.npy')
    nifty_to_npy(df_val, path_images_array='data/segmentations_itmt2.0/val_images.npy',
                 path_masks_array='data/segmentations_itmt2.0/val_masks.npy')


import datetime
import subprocess
import os
import time
import urllib2
from collections import OrderedDict
from math import floor, log
import logging

import psutil

logger = logging.getLogger(__name__)

def convert_bytes(value, unit, output_str=False, decimals=2, auto_determine=False):
    """

    :param value: int
    :param unit: str
    :param output_str: bool
    :param decimals: int
    :param auto_determine: bool
    :return: str or int or float
    """
    assert any([type(value) == int, type(value) == float, type(value) is long])
    assert all([type(decimals) is int, type(output_str) is bool, type(auto_determine) is bool, value >= 0])
    conversions = dict(B=0, KB=1, MB=2, GB=3, TB=4, PB=5, EB=6, ZB=7, YB=8)
    assert unit in conversions
    base = 1024.0
    converted_value = float(value) / base ** conversions[unit]
    if auto_determine and value > 0:
        # Generate automatic prefix by bytes
        base_power = floor(log(float(value)) / log(base))
        swap_conversion_values = {conversions[x]: x for x in conversions}
        while base_power not in swap_conversion_values:
            # future proofing. Not really necessary.
            base_power -= base_power
        unit = swap_conversion_values[base_power]
        converted_value = value / base ** conversions[unit]
    if output_str:
        if decimals < 0:
            decimals = 0
        return '{:,.{decimal}f} {unit}'.format(converted_value, decimal=decimals, unit=unit)
    else:
        return converted_value

def get_wan_ip(site='http://myip.dnsdynamic.org/'):
    return urllib2.urlopen(site).read()

def get_partitions(partitions=None):
    if partitions is None:
        partitions = psutil.disk_partitions(all=True)
    return {p[1]: psutil.disk_usage(p[1]) for p in partitions if p[0] != 0}

def get_ping(host="8.8.8.8", kind='avg', num=4):
    # solution from http://stackoverflow.com/questions/316866/ping-a-site-in-python
    """
    returns ping time to selected site
        host: site, ip address to ping
        kind:
        num: number of pings to host

    :param host: string
    :param kind: string
    :param num: int
    :return: float
    """
    assert kind in ['max', 'avg', 'mdev', 'min']
    assert type(int(num)) is int
    ping = subprocess.Popen(["ping", "-c", str(num), host], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    out, error = ping.communicate()
    out = out.split('\n')
    try:
        out = [x for x in out if x.startswith('rtt')][0]
        out_mapped = zip(out.split()[1].split('/'), out.split()[3].split('/'))
        out_mapped = {x[0]: x[1] for x in out_mapped}
        out = out_mapped[kind]
    except IndexError:
        # most likely no ping returned, system offline
        out = 0
    return float(out)

def get_system_uptime():
    def append_type(x, kind):
        """
        Return 0 if days/hours/minutes equals 0 otherwise append correct plural "s" to type
        ex. if systems up for 2 hours, returns "2 hours" likewise return "1 hour" if system has been up for 1 hour
        """
        assert type(x) is int and type(kind) is str
        if x == 0:
            return x
        else:
            return '{} {}'.format(str(x), kind + 's' if x != 1 else kind)

    boot_time = datetime.datetime.fromtimestamp(psutil.boot_time()).replace(microsecond=0)
    time_now = datetime.datetime.now().replace(microsecond=0)
    delta = time_now - boot_time
    formatted_time = str(delta).split(',')
    try:
        # System's been up a day or more
        hours = formatted_time[1].strip().split(':')
    except IndexError:
        # System's been up for less than day
        hours = formatted_time[0].strip().split(':')
        formatted_time[0] = 0
    hours.pop(2)
    hours, mins = [int(hour) for hour in hours]
    formatted_time = dict(days=formatted_time[0], hours=append_type(hours, 'hour'), min=append_type(mins, 'minute'))
    output = dict(
        boottime=boot_time,
        uptime=delta,
        uptime_formatted=formatted_time)
    return output

def return_network_io():
    """
    returns Network bytes sent, and received
    :rtype : list
    """
    network_io = psutil.net_io_counters()
    return [network_io.bytes_sent, network_io.bytes_recv]

def get_network_speed(sleep=1):
    assert type(sleep) is int
    start_time = datetime.datetime.now()
    start_data = return_network_io()
    time.sleep(sleep)
    time_delta = datetime.datetime.now() - start_time
    end_data = return_network_io()
    bits = 8
    return dict(up=convert_bytes((end_data[0] - start_data[0]) / time_delta.seconds * bits, 'MB'),
                down=convert_bytes((end_data[1] - start_data[1]) / time_delta.seconds * bits, 'MB'))

def get_total_system_space(digits=1):
    """
    returns total system disk space formatted, ex.
        {'total': '8,781.9 GB', 'used': '3,023.0 GB', 'pct': 34.4, 'free': '5,313.4 GB'}

    :rtype : dict
    :param digits: int
    :return: dict
    """
    assert type(digits) is int
    all_partitions = psutil.disk_partitions(all=True)
    # limit total disk space to those paritions mounted in "/dev/"
    partitions_to_keep = [partition for partition in all_partitions if partition.device.startswith('/dev/')]
    partitions = get_partitions(partitions_to_keep)
    disk_space = dict(total=sum([partitions[partition].total for partition in partitions]),
                      used=sum([partitions[partition].used for partition in partitions]),
                      free=sum([partitions[partition].free for partition in partitions]))
    disk_space_formatted = {k: convert_bytes(disk_space[k], 'GB', True, digits, True) for k in disk_space}
    disk_space_formatted['pct'] = round(float(disk_space['used']) / float(disk_space['total']) * 100.0, digits)
    return disk_space_formatted

def get_partitions_space(partitions, digits=1, sort='alpha'):
    """
    {'Home': {'total': '168.8 GB', 'pct': 44.4, 'free': '85.3 GB', 'used': '74.9 GB'},
        'Incoming': {'total': '293.3 GB', 'pct': 48.2, 'free': '137.0 GB', 'used': '141.4 GB'}}
    :param partitions:
    :param digits:
    :return:
    """
    assert type(partitions) is dict
    system_partitions = get_partitions()
    # return disk space for each partition listed in config
    # test if listed partition actually exists in system first to avoid throwing an error
    disk_space = {p: system_partitions[partitions[p]] for p in partitions if partitions[p] in system_partitions}
    disk_space_formatted = {p: dict(total=convert_bytes(disk_space[p].total, 'GB', True, digits, True),
                                    used=convert_bytes(disk_space[p].used, 'GB', True, digits, True),
                                    free=convert_bytes(disk_space[p].free, 'GB', True, digits, True)) for p in
                            disk_space}
    for p in disk_space:
        disk_space_formatted[p]['pct'] = round(float(disk_space[p].used) / float(disk_space[p].total) * 100.0,
                                               digits)
    if sort.lower() == 'alpha':
        # place in ordered dictionary so paths always display in alphabetical order on page
        disk_space_formatted = OrderedDict(sorted(disk_space_formatted.items(), key=lambda x: x[0]))
    return disk_space_formatted

def get_load_average():
    os_averages = os.getloadavg()
    cpu_count = psutil.cpu_count()
    final_averages = [average / cpu_count for average in os_averages]
    return final_averages

class GetSystemInfo(object):
    def __init__(self):
        pass

    def get_info(self):
        """
        Returns system information in a dictionary
            mem_total: Total RAM in the system in megabytes as float, ex. "7876.88671875"
            mem_available: Unused RAM in the system in megabytes as float, ex. "4623.8671875"
            mem_used_pct: mem_available / mem_total as float, ex. "41.3"
            load_avg: tuple of avg loads at 1 min, 5 min, and 15 min, respectively, ex. "(0.52, 0.51, 0.43)"
            partitions: dictionary of partitions on system, truncated ex, {''/mnt/Entertainment'':
                        sdiskusage(total=56955559936, used=15403667456, free=38635122688, percent=27.0)}
            uptime_formatted: dictionary of uptime split in days, hours, min, ex.
                    {'hours': '2 hours', 'days': '6 days', 'min': '26 minutes'}
        :return: dict
        """
        mem_info = psutil.virtual_memory()
        system_uptime = get_system_uptime()
        load_avg = get_load_average()
        return dict(mem_total=convert_bytes(mem_info[0], 'MB'),
                    mem_available=convert_bytes(mem_info[1], 'MB'),
                    mem_used_pct=mem_info[2],
                    mem_bars=self._memory_bars(mem_info[2]),
                    load_avg=load_avg,
                    uptime_formatted=system_uptime['uptime_formatted'])

    @staticmethod
    def _memory_bars(val_pct):
        mid = 50
        upper = 80
        ret = dict(xmin=min(val_pct, mid),
                   xmid=min(val_pct - mid, upper - mid),
                   xmax=min(val_pct - upper, 100 - upper))
        return {k: max(ret[k], 0) for k in ret}

if __name__ == '__main__':
    pass


import numpy as np
from rlgym.envs import Match
from rlgym.utils.action_parsers import DiscreteAction
from stable_baselines3 import PPO
from stable_baselines3.common.callbacks import CheckpointCallback
from stable_baselines3.common.vec_env import VecMonitor, VecNormalize, VecCheckNan
from stable_baselines3.ppo import MlpPolicy

from rlgym.utils.obs_builders import AdvancedObs
from rlgym.utils.state_setters import DefaultState
from rlgym.utils.terminal_conditions.common_conditions import TimeoutCondition, NoTouchTimeoutCondition, GoalScoredCondition
from rlgym_tools.sb3_utils import SB3MultipleInstanceEnv
from rlgym_tools.extra_rewards.anneal_rewards import AnnealRewards, _DummyReward
from rlgym.utils.reward_functions.common_rewards.misc_rewards import EventReward
from rlgym.utils.reward_functions.common_rewards.player_ball_rewards import VelocityPlayerToBallReward, TouchBallReward
from rlgym.utils.reward_functions.common_rewards.ball_goal_rewards import VelocityBallToGoalReward
from rlgym.utils.reward_functions import CombinedReward

from rlgym_tools.extra_rewards.kickoff_reward import KickoffReward

from sb3_log_reward import SB3CombinedLogReward, SB3CombinedLogRewardCallback

import atexit
from torch.nn import Tanh

# V1->V2
# increased learning rate
# reduced epochs
# increased net size
# discrete actions instead of continuous
# obs includes other players
# better initial rewards for the first 100M steps
# 1v1 training against itself
# slower transitioning of rewards

if __name__ == '__main__':
    frame_skip = 8
    half_life_seconds = 5

    fps = 120 / frame_skip
    gamma = np.exp(np.log(0.5) / (fps * half_life_seconds))
    agents_per_match = 2
    num_instances = 1
    target_steps = 75_000
    steps = target_steps // (num_instances * agents_per_match)
    batch_size = steps

    def exit_save(model):
        model.save("models/exit_save")

    # train using the 2 velocity rewards until ~100M and then start using AnnealReward to phase into other rewards
    # need to make sure we don't drastically change rewards too quickly like we did on CarBallAI-V1
    # ... so use AnnealReward
    def get_match():
        return Match(
            team_size=1,
            tick_skip=frame_skip,
            reward_function=SB3CombinedLogReward
                (
                    (
                        VelocityPlayerToBallReward(),
                        VelocityBallToGoalReward(),
                        EventReward
                        (
                            team_goal=100.0
                        ),
                        EventReward
                        (
                            concede=-100.0
                        ),
                        EventReward
                        (
                            shot=5.0
                        ),
                        EventReward
                        (
                            save=30.0
                        ),
                        EventReward
                        (
                            demo=10.0
                        ),
                        TouchBallReward(),
                        KickoffReward()
                    ),
                        (0.1, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.15, 0.125)
                ),
            self_play=True,
            terminal_conditions=[TimeoutCondition(fps * 300), NoTouchTimeoutCondition(fps * 20), GoalScoredCondition()],
            obs_builder=AdvancedObs(),
            state_setter=DefaultState(),
            action_parser=DiscreteAction()
        )

    env = SB3MultipleInstanceEnv(get_match, num_instances)
    env = VecCheckNan(env)
    env = VecMonitor(env)
    env = VecNormalize(env, norm_obs=False, gamma=gamma)

    # load an existing model, or create a new one it doesn't exist
    try:
        print("Looking for existing model ...")
        model = PPO.load(
            "models/exit_save.zip",
            env,
            device="auto",
            custom_objects=dict(n_envs=env.num_envs, n_epochs=10, batch_size=75_000)
        )
        print("Existing model found.")
    except:
        from torch.nn import Tanh
        print("Creating new model ...")
        policy_kwargs = dict(
            activation_fn=Tanh,
            net_arch=[512, 512, dict(pi=[256, 256, 256], vf=[256, 256, 256])],
        )

        model = PPO(
            MlpPolicy,
            env,
            n_epochs=10,                 # PPO calls for multiple epochs
            policy_kwargs=policy_kwargs,
            learning_rate=5e-5,          # Around this is fairly common for PPO
            ent_coef=0.01,               # From PPO Atari
            vf_coef=1.,                  # From PPO Atari
            gamma=gamma,                 # Gamma as calculated using half-life
            verbose=3,                   # Print out all the info as we're going
            batch_size=batch_size,             # Batch size as high as possible within reason
            n_steps=steps,                # Number of steps to perform before optimizing network
            tensorboard_log="logs",  # `tensorboard --logdir logs/logs` in terminal to see graphs
            device="auto"                # Uses GPU if available
        )

    # Divide by num_envs (number of agents) because callback only increments every time all agents have taken a step
    callback = CheckpointCallback(round(2_500_000 / env.num_envs), save_path="models", name_prefix="CarBallAI-V2")
    rewardCallback = SB3CombinedLogRewardCallback(reward_names=["velocity_player_to_ball", "velocity_ball_to_goal", "team_goal", "opponent_goal", "shot", "save", "demolition", "ball_touch", "kickoff_reward"])

    atexit.register(exit_save, model)
    try:
        while True:
            model.learn(25_000_000, callback=[callback, rewardCallback], reset_num_timesteps=False)
            model.save("models/exit_save")
            model.save(f"mmr_models/{model.num_timesteps}")
    except Exception as e:
        print(e)


import wx
import wx.py as py
import sys

# Regular expression operations
import re
import os

# Conjurer
import pynebula
import childdialoggui
import freedialoggui
import nebulahelpevent as nh
import app
import stringtree
import servers

class TestListCtrl(wx.ListCtrl):
    def __init__(self, parent, ID, pos=wx.DefaultPosition,
                 size=wx.DefaultSize, style=0):
        wx.ListCtrl.__init__(self, parent, ID, pos, size, style)

class StringLister (wx.Panel):

    def __init__(self, parent, ID, style=0):
        wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS)

        tID = wx.NewId()

        self.string_list = {}

        self.scale = (64, 64)
        self.il = wx.ImageList(64, 64)
        self.list = TestListCtrl(self, tID,
                                 style=wx.LC_ICON
                                 | wx.BORDER_SUNKEN
                                 | wx.LC_EDIT_LABELS
                                 | wx.LC_SORT_ASCENDING
                                 | wx.LC_AUTOARRANGE
                                 )

        self.list.SetImageList(self.il, wx.IMAGE_LIST_NORMAL)

        # Bind events
        self.Bind(wx.EVT_SIZE, self.on_size)
        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.on_item_selected, self.list)
        self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.on_item_activated, self.list)

        self.list.Bind(wx.EVT_LEFT_DCLICK, self.on_double_click)
        self.list.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.on_right_click)

    def display_normal (self):
        self.scale = (64, 64)
        self.il = wx.ImageList(64, 64)
        self.list.SetImageList(self.il, wx.IMAGE_LIST_NORMAL)
        self.list.SetWindowStyleFlag(wx.LC_ICON
                                    | wx.BORDER_SUNKEN
                                    | wx.LC_EDIT_LABELS
                                    | wx.LC_SORT_ASCENDING
                                    | wx.LC_AUTOARRANGE
                                    )

    def display_list (self):
        self.scale = (16, 16)
        self.il = wx.ImageList(16, 16)
        self.list.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
        self.list.SetWindowStyleFlag(wx.LC_LIST
                                    | wx.BORDER_SUNKEN
                                    | wx.LC_EDIT_LABELS
                                    | wx.LC_SORT_ASCENDING
                                    | wx.LC_AUTOARRANGE
                                    )

    def display_large (self):
        self.scale = (128, 128)
        self.il = wx.ImageList(128, 128)
        self.list.SetImageList(self.il, wx.IMAGE_LIST_NORMAL)
        self.list.SetWindowStyleFlag(wx.LC_ICON
                                    | wx.BORDER_SUNKEN
                                    | wx.LC_EDIT_LABELS
                                    | wx.LC_SORT_ASCENDING
                                    | wx.LC_AUTOARRANGE
                                    )

    def on_item_selected(self, event):
        self.current_item = event.m_itemIndex

        event.Skip()

    def on_item_activated(self, event):
        self.current_item = event.m_itemIndex

    def on_double_click (self, event):
        event.Skip()

    def on_right_click (self, event):
        event.Skip()

    def populate_list(self, string_list):
        self.string_list = string_list
        items = string_list.items()
        self.list.DeleteAllItems()
        for key, data in items:
            bmp = wx.Bitmap(data[0])

            # scale if needed

            if self.scale != (128,128):
                image = bmp.ConvertToImage()
                bmp = wx.BitmapFromImage(image.Scale(self.scale[0], self.scale[1]))

            self.idx1 = self.il.Add(bmp)
            index = self.list.InsertImageStringItem(sys.maxint, data[1], self.idx1)
            self.list.SetItemData(index, key)

        self.current_item = 0

    def on_size(self, event):
        w,h = self.GetClientSizeTuple()
        self.list.SetDimensions(0, 0, w, h)

    def get_list (self):
        return self.list


# -*- coding: utf-8 -*-

import torch
from torch.utils.data import Dataset, DataLoader
import h5py
import numpy as np
import json

class VideoData(Dataset):
    def __init__(self, mode, split_index):
        self.mode = mode
        self.name = 'tvsum'
        self.datasets = ['../data/SumMe/eccv16_dataset_summe_google_pool5.h5',
                         '../data/TVSum/eccv16_dataset_tvsum_google_pool5.h5']
        self.splits_filename = ['../data/splits/' + self.name + '_splits.json']
        self.splits = []
        self.split_index = split_index # it represents the current split (varies from 0 to 4)
        temp = {}

        if 'summe' in self.splits_filename[0]:
            self.filename = self.datasets[0]
        elif 'tvsum' in self.splits_filename[0]:
            self.filename = self.datasets[1]
        self.video_data = h5py.File(self.filename, 'r')

        with open(self.splits_filename[0]) as f:
            data = json.loads(f.read())
            for split in data:
                temp['train_keys'] = split['train_keys']
                temp['test_keys'] = split['test_keys']
                self.splits.append(temp.copy())

    def __len__(self):
        self.len = len(self.splits[0][self.mode+'_keys'])
        return self.len

    # In "train" mode it returns the features; in "test" mode it also returns the video_name
    def __getitem__(self, index):
        video_name = self.splits[self.split_index][self.mode + '_keys'][index]
        frame_features = torch.Tensor(np.array(self.video_data[video_name + '/features']))
        if self.mode == 'test':
            return frame_features, video_name
        else:
            return frame_features

def get_loader(mode, split_index):
    if mode.lower() == 'train':
        vd = VideoData(mode, split_index)
        return DataLoader(vd, batch_size=1)
    else:
        return VideoData(mode, split_index)

if __name__ == '__main__':
    pass


"""Definition and setup of the Omnilogic Sensors for Home Assistant."""
from homeassistant.components.sensor import (
    SensorDeviceClass,
    SensorEntity,
    STATE_CLASS_MEASUREMENT,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
    CONCENTRATION_PARTS_PER_MILLION,
    ELECTRIC_POTENTIAL_MILLIVOLT,
    MASS_GRAMS,
    PERCENTAGE,
    TEMP_CELSIUS,
    TEMP_FAHRENHEIT,
    VOLUME_LITERS,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from .common import OmniLogicEntity, OmniLogicUpdateCoordinator, check_guard
from .const import COORDINATOR, DEFAULT_PH_OFFSET, DOMAIN, PUMP_TYPES

async def async_setup_entry(
    hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
    """Set up the sensor platform."""

    coordinator = hass.data[DOMAIN][entry.entry_id][COORDINATOR]
    entities = []

    for item_id, item in coordinator.data.items():
        id_len = len(item_id)
        item_kind = item_id[-2]
        entity_settings = SENSOR_TYPES.get((id_len, item_kind))

        if not entity_settings:
            continue

        for entity_setting in entity_settings:
            for state_key, entity_class in entity_setting["entity_classes"].items():
                if check_guard(state_key, item, entity_setting):
                    continue

                entity = entity_class(
                    coordinator=coordinator,
                    state_key=state_key,
                    name=entity_setting["name"],
                    kind=entity_setting["kind"],
                    item_id=item_id,
                    device_class=entity_setting["device_class"],
                    state_class=entity_setting["state_class"],
                    icon=entity_setting["icon"],
                    unit=entity_setting["unit"],
                )

                entities.append(entity)

    async_add_entities(entities)

class OmnilogicSensor(OmniLogicEntity, SensorEntity):
    """Defines an Omnilogic sensor entity."""

    def __init__(
        self,
        coordinator: OmniLogicUpdateCoordinator,
        kind: str,
        name: str,
        device_class: str,
        state_class: str,
        icon: str,
        unit: str,
        item_id: tuple,
        state_key: str,
    ) -> None:
        """Initialize Entities."""
        super().__init__(
            coordinator=coordinator,
            kind=kind,
            name=name,
            item_id=item_id,
            icon=icon,
        )

        backyard_id = item_id[:2]
        unit_type = coordinator.data[backyard_id].get("Unit-of-Measurement")

        self._unit_type = unit_type
        self._device_class = device_class
        self._state_class = state_class
        self._unit = unit
        self._state_key = state_key

    @property
    def device_class(self):
        """Return the device class of the entity."""
        return self._device_class

    @property
    def state_class(self):
        """Return the state class of the entity."""
        return self._state_class

    @property
    def native_unit_of_measurement(self):
        """Return the right unit of measure."""
        return self._unit

class OmniLogicTemperatureSensor(OmnilogicSensor):
    """Define an OmniLogic Temperature (Air/Water) Sensor."""

    @property
    def native_value(self):
        """Return the state for the temperature sensor."""
        sensor_data = self.coordinator.data[self._item_id][self._state_key]

        hayward_state = sensor_data
        hayward_unit_of_measure = TEMP_FAHRENHEIT
        state = sensor_data

        if self._unit_type == "Metric":
            hayward_state = round((int(hayward_state) - 32) * 5 / 9, 1)
            hayward_unit_of_measure = TEMP_CELSIUS

        if int(sensor_data) == -1 or int(sensor_data) == 255:
            hayward_state = None
            state = None

        self._attrs["hayward_temperature"] = hayward_state
        self._attrs["hayward_unit_of_measure"] = hayward_unit_of_measure

        self._unit = TEMP_FAHRENHEIT

        return state

class OmniLogicPumpSpeedSensor(OmnilogicSensor):
    """Define an OmniLogic Pump Speed Sensor."""

    @property
    def native_value(self):
        """Return the state for the pump speed sensor."""

        pump_type = PUMP_TYPES[
            self.coordinator.data[self._item_id].get(
                "Filter-Type", self.coordinator.data[self._item_id].get("Type", {})
            )
        ]
        pump_speed = self.coordinator.data[self._item_id][self._state_key]

        if pump_type == "VARIABLE":
            self._unit = PERCENTAGE
            state = pump_speed
        elif pump_type == "DUAL":
            self._unit = None
            if pump_speed == 0:
                state = "off"
            elif pump_speed == self.coordinator.data[self._item_id].get(
                "Min-Pump-Speed"
            ):
                state = "low"
            elif pump_speed == self.coordinator.data[self._item_id].get(
                "Max-Pump-Speed"
            ):
                state = "high"

        self._attrs["pump_type"] = pump_type

        return state

class OmniLogicSaltLevelSensor(OmnilogicSensor):
    """Define an OmniLogic Salt Level Sensor."""

    @property
    def native_value(self):
        """Return the state for the salt level sensor."""

        salt_return = self.coordinator.data[self._item_id][self._state_key]
        unit_of_measurement = self._unit

        if self._unit_type == "Metric":
            salt_return = round(int(salt_return) / 1000, 2)
            unit_of_measurement = f"{MASS_GRAMS}/{VOLUME_LITERS}"

        self._unit = unit_of_measurement

        return salt_return

class OmniLogicChlorinatorSensor(OmnilogicSensor):
    """Define an OmniLogic Chlorinator Sensor."""

    @property
    def native_value(self):
        """Return the state for the chlorinator sensor."""
        state = self.coordinator.data[self._item_id][self._state_key]

        return state

class OmniLogicPHSensor(OmnilogicSensor):
    """Define an OmniLogic pH Sensor."""

    @property
    def native_value(self):
        """Return the state for the pH sensor."""

        ph_state = self.coordinator.data[self._item_id][self._state_key]

        if ph_state == 0:
            ph_state = None
        else:
            ph_state = float(ph_state) + float(
                self.coordinator.config_entry.options.get(
                    "ph_offset", DEFAULT_PH_OFFSET
                )
            )

        return ph_state

class OmniLogicORPSensor(OmnilogicSensor):
    """Define an OmniLogic ORP Sensor."""

    def __init__(
        self,
        coordinator: OmniLogicUpdateCoordinator,
        state_key: str,
        name: str,
        kind: str,
        item_id: tuple,
        device_class: str,
        state_class: str,
        icon: str,
        unit: str,
    ) -> None:
        """Initialize the sensor."""
        super().__init__(
            coordinator=coordinator,
            kind=kind,
            name=name,
            device_class=device_class,
            state_class=state_class,
            icon=icon,
            unit=unit,
            item_id=item_id,
            state_key=state_key,
        )

    @property
    def native_value(self):
        """Return the state for the ORP sensor."""

        orp_state = int(self.coordinator.data[self._item_id][self._state_key])

        if orp_state == -1:
            orp_state = None

        return orp_state

SENSOR_TYPES = {
    (2, "Backyard"): [
        {
            "entity_classes": {"airTemp": OmniLogicTemperatureSensor},
            "name": "Air Temperature",
            "kind": "air_temperature",
            "device_class": SensorDeviceClass.TEMPERATURE,
            "state_class": STATE_CLASS_MEASUREMENT,
            "icon": None,
            "unit": TEMP_FAHRENHEIT,
            "native_unit_of_measurement": TEMP_FAHRENHEIT,
            "guard_condition": [{}],
        },
    ],
    (4, "BOWS"): [
        {
            "entity_classes": {"waterTemp": OmniLogicTemperatureSensor},
            "name": "Water Temperature",
            "kind": "water_temperature",
            "device_class": SensorDeviceClass.TEMPERATURE,
            "state_class": STATE_CLASS_MEASUREMENT,
            "icon": None,
            "unit": TEMP_FAHRENHEIT,
            "native_unit_of_measurement": TEMP_FAHRENHEIT,
            "guard_condition": [{}],
        },
    ],
    (6, "Filter"): [
        {
            "entity_classes": {"filterSpeed": OmniLogicPumpSpeedSensor},
            "name": "Speed",
            "kind": "filter_pump_speed",
            "device_class": None,
            "state_class": None,
            "icon": "mdi:speedometer",
            "unit": PERCENTAGE,
            "guard_condition": [
                {"Filter-Type": "FMT_SINGLE_SPEED"},
            ],
        },
    ],
    (6, "Pumps"): [
        {
            "entity_classes": {"pumpSpeed": OmniLogicPumpSpeedSensor},
            "name": "Pump Speed",
            "kind": "pump_speed",
            "device_class": None,
            "state_class": None,
            "icon": "mdi:speedometer",
            "unit": PERCENTAGE,
            "guard_condition": [
                {"Type": "PMP_SINGLE_SPEED"},
            ],
        },
    ],
    (6, "Chlorinator"): [
        {
            "entity_classes": {"Timed-Percent": OmniLogicChlorinatorSensor},
            "name": "Setting",
            "kind": "chlorinator",
            "device_class": None,
            "state_class": None,
            "icon": "mdi:gauge",
            "unit": PERCENTAGE,
            "guard_condition": [
                {
                    "Shared-Type": "BOW_SHARED_EQUIPMENT",
                    "status": "0",
                },
                {
                    "operatingMode": "2",
                },
            ],
        },
        {
            "entity_classes": {"avgSaltLevel": OmniLogicSaltLevelSensor},
            "name": "Average Salt Level",
            "kind": "average_salt_level",
            "device_class": None,
            "state_class": STATE_CLASS_MEASUREMENT,
            "icon": "mdi:gauge",
            "unit": CONCENTRATION_PARTS_PER_MILLION,
            "guard_condition": [
                {
                    "Shared-Type": "BOW_SHARED_EQUIPMENT",
                    "status": "0",
                },
            ],
        },
        {
            "entity_classes": {"instantSaltLevel": OmniLogicSaltLevelSensor},
            "name": "Instant Salt Level",
            "kind": "instant_salt_level",
            "device_class": None,
            "state_class": STATE_CLASS_MEASUREMENT,
            "icon": "mdi:gauge",
            "unit": CONCENTRATION_PARTS_PER_MILLION,
            "guard_condition": [
                {
                    "Shared-Type": "BOW_SHARED_EQUIPMENT",
                    "status": "0",
                },
            ],
        },
    ],
    (6, "CSAD"): [
        {
            "entity_classes": {"ph": OmniLogicPHSensor},
            "name": "pH",
            "kind": "csad_ph",
            "device_class": None,
            "state_class": STATE_CLASS_MEASUREMENT,
            "icon": "mdi:gauge",
            "unit": "pH",
            "guard_condition": [
                {"ph": ""},
            ],
        },
        {
            "entity_classes": {"orp": OmniLogicORPSensor},
            "name": "ORP",
            "kind": "csad_orp",
            "device_class": None,
            "state_class": STATE_CLASS_MEASUREMENT,
            "icon": "mdi:gauge",
            "unit": ELECTRIC_POTENTIAL_MILLIVOLT,
            "guard_condition": [
                {"orp": ""},
            ],
        },
    ],
}


# TUTORIAL
# https://www.youtube.com/watch?v=hDu8mcAlY4E

import pygame, sys

class Crosshair(pygame.sprite.Sprite):
    def __init__(self, picture_path):
        super().__init__()
        self.image = pygame.image.load(picture_path)
        self.rect = self.image.get_rect()
        self.gunshoot = pygame.mixer.Sound('./assets/Shot.wav')

    def shoot(self):
        self.gunshoot.play()

    def update(self):
        self.rect.center = pygame.mouse.get_pos()

# General Setup
pygame.init()
clock = pygame.time.Clock()

# Game Screen
screen_width = 1920 / 2
screen_height = 1080 / 2
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption('Dianes')
background = pygame.image.load('./assets/space.png')
pygame.mouse.set_visible(False)

# Crosshair
crosshair = Crosshair('./assets/green.png')
crosshair_group = pygame.sprite.Group()
crosshair_group.add(crosshair)

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.MOUSEBUTTONDOWN:
            crosshair.shoot()

    screen.blit(background, (0,0))
    crosshair_group.draw(screen)
    crosshair_group.update()
    pygame.display.flip()
    clock.tick(60)


import webapp2
from google.appengine.api import users
from model import CssiUser

class MainHandler(webapp2.RequestHandler):
  def get(self):
    user = users.get_current_user()
    if user:
      signout_link_html = 'sign out' % (
                users.create_logout_url('/'))
      email_address = user.nickname()
      cssi_user = CssiUser.query().filter(CssiUser.email == email_address).get()
      if cssi_user:
        self.response.write(
          "Looks like you're registered. Thanks for using our site!")
      else:
        # Registration form for a first-time visitor:
        self.response.write('''
            Welcome to our site, %s!  Please sign up!

            <form method="post" action="/">
            <input type="text" name="first_name">
            <input type="text" name="last_name">
            <input type="submit">
            </form>
 %s

            ''' % (email_address, signout_link_html))

    else:
      # If the user isn't logged in...
      login_url = users.create_login_url('/')
      login_html_element = 'Sign in' % login_url
      self.response.write('Please log in.
' + login_html_element)
  def post(self):
    user = users.get_current_user()
    # Create a new CSSI user.
    cssi_user = CssiUser(
        first_name=self.request.get('first_name'),
        last_name=self.request.get('last_name'),
        email=user.nickname())
    # Store that Entity in Datastore.
    cssi_user.put()
    # Show confirmation to the user. Include a link back to the index.
    self.response.write('Thanks for signing up, %s!
Home' %
        cssi_user.first_name)

app = webapp2.WSGIApplication([
    ('/', MainHandler),
], debug=True)


from torch.utils.tensorboard import SummaryWriter
import torch.nn.functional as F
import torch
import datetime
from os.path import join
import numpy as np
from torch.utils.data.sampler import SubsetRandomSampler

pixel_coords = None

class AttrDict(dict):
    def __init__(self, *args, **kwargs):
        super(AttrDict, self).__init__(*args, **kwargs)
        self.__dict__ = self

def split(joint_dataset,val_percent, sampler=SubsetRandomSampler,random_seed=42):

    '''
    function useful there is no explicit valitdation scripts available
    joint_dataset = train + val items
    returns train and validation samplers based on sampling strategy
    '''
    dataset_size = len(joint_dataset)
    indices = list(range(dataset_size))
    split = int(np.floor(val_percent * dataset_size))
    np.random.seed(random_seed)
    np.random.shuffle(indices)
    train_indices, val_indices = indices[split:], indices[:split]
    train_sampler = SubsetRandomSampler(train_indices)
    valid_sampler = SubsetRandomSampler(val_indices)

    return train_sampler, valid_sampler

def get_log_dir():
    '''
    New log dir at every run according to the time at that point in time.
    '''
    now = datetime.datetime.now()
    return "logs/run-%d-%d-%d-%d-%d-%d"%(now.year,now.month,now.day,now.hour,now.minute,now.second)

def get_summary_writer(rootdir):

    return SummaryWriter(join(rootdir,get_log_dir()))

def grad(im):
    gradx = F.pad((im[:, :, :, 2:] - im[:, :, :, :-2]) / 2.0, (1, 1, 0, 0))
    grady = F.pad((im[:, :, 2:, :] - im[:, :, :-2, :]) / 2.0, (0, 0, 1, 1))
    return gradx, grady

def sobel(im):
    c = im.size()[1]
    fx = torch.Tensor([[1, 0, -1], [2, 0, -2], [1, 0, -1]])
    fx = fx.view(1, 1, 3, 3).expand(1, c, 3, 3)
    fy = torch.Tensor([[1, 2, 1], [0, 0, 0], [-1, -2, -1]])
    fy = fy.view(1, 1, 3, 3).expand(1, c, 3, 3)
    if im.is_cuda:
        fx = fx.cuda()
        fy = fy.cuda()
    gradx = F.pad(F.conv2d(im, fx), (1, 1, 1, 1))
    grady = F.pad(F.conv2d(im, fy), (1, 1, 1, 1))
    return gradx, grady

def set_id_grid(depth):
    global pixel_coords
    b, _,  h, w = depth.size()
    i_range = torch.arange(0, h).view(1, h, 1).expand(1, h, w).type_as(depth)  # [1, H, W]
    j_range = torch.arange(0, w).view(1, 1, w).expand(1, h, w).type_as(depth)  # [1, H, W]
    ones = torch.ones(1, h, w).type_as(depth)

    pixel_coords = torch.stack((j_range, i_range, ones), dim=1)  # [1, 3, H, W]

def euler2mat(angle):
    B = angle.size(0)
    x, y, z = angle[:, 0], angle[:, 1], angle[:, 2]

    cosz = torch.cos(z)
    sinz = torch.sin(z)

    zeros = z.detach()
    ones = zeros.detach()+1
    zmat = torch.stack([cosz, -sinz, zeros,
                        sinz,  cosz, zeros,
                        zeros, zeros,  ones], dim=1).reshape(B, 3, 3)

    cosy = torch.cos(y)
    siny = torch.sin(y)

    ymat = torch.stack([cosy, zeros,  siny,
                        zeros,  ones, zeros,
                        -siny, zeros,  cosy], dim=1).reshape(B, 3, 3)

    cosx = torch.cos(x)
    sinx = torch.sin(x)

    xmat = torch.stack([ones, zeros, zeros,
                        zeros,  cosx, -sinx,
                        zeros,  sinx,  cosx], dim=1).reshape(B, 3, 3)

    rotMat = xmat @ ymat @ zmat
    return rotMat

def quat2mat(quat):
    norm_quat = torch.cat([quat[:, :1].detach()*0 + 1, quat], dim=1)
    norm_quat = norm_quat/norm_quat.norm(p=2, dim=1, keepdim=True)
    w, x, y, z = norm_quat[:, 0], norm_quat[:, 1], norm_quat[:, 2], norm_quat[:, 3]

    B = quat.size(0)

    w2, x2, y2, z2 = w.pow(2), x.pow(2), y.pow(2), z.pow(2)
    wx, wy, wz = w*x, w*y, w*z
    xy, xz, yz = x*y, x*z, y*z

    rotMat = torch.stack([w2 + x2 - y2 - z2, 2*xy - 2*wz, 2*wy + 2*xz,
                          2*wz + 2*xy, w2 - x2 + y2 - z2, 2*yz - 2*wx,
                          2*xz - 2*wy, 2*wx + 2*yz, w2 - x2 - y2 + z2], dim=1).reshape(B, 3, 3)
    return rotMat

def pose_vec2mat(vec, rotation_mode='euler'):
    translation = vec[:, :3].unsqueeze(-1)  # [B, 3, 1]
    rot = vec[:, 3:]
    if rotation_mode == 'euler':
        rot_mat = euler2mat(rot)  # [B, 3, 3]
    elif rotation_mode == 'quat':
        rot_mat = quat2mat(rot)  # [B, 3, 3]
    transform_mat = torch.cat([rot_mat, translation], dim=2)  # [B, 3, 4]
    return transform_mat

def cam2pixel(cam_coords, proj_c2p_rot, proj_c2p_tr):
    b, _, h, w = cam_coords.size()
    cam_coords_flat = cam_coords.reshape(b, 3, -1)  # [B, 3, H*W]
    if proj_c2p_rot is not None:
        pcoords = proj_c2p_rot @ cam_coords_flat
    else:
        pcoords = cam_coords_flat

    if proj_c2p_tr is not None:
        pcoords = pcoords + proj_c2p_tr  # [B, 3, H*W]
    X = pcoords[:, 0]
    Y = pcoords[:, 1]
    Z = pcoords[:, 2].clamp(min=1e-3)

    X_norm = 2*(X / Z)/(w-1) - 1  # Normalized, -1 if on extreme left, 1 if on extreme right (x = w-1) [B, H*W]
    Y_norm = 2*(Y / Z)/(h-1) - 1  # Idem [B, H*W]

    pixel_coords = torch.stack([X_norm, Y_norm], dim=2)  # [B, H*W, 2]
    return pixel_coords.reshape(b, h, w, 2)

def pixel2cam(depth, intrinsics_inv):
    global pixel_coords
    b,_,h, w = depth.size()
    if (pixel_coords is None) or pixel_coords.size(2) < h:
        set_id_grid(depth)
    current_pixel_coords = pixel_coords[..., :h, :w].expand(b, 3, h, w).reshape(b, 3, -1)  # [B, 3, H*W]
    cam_coords = (intrinsics_inv @ current_pixel_coords).reshape(b, 3, h, w)
    return cam_coords * depth

def inverse_warp(img, depth, pose, intrinsics, rotation_mode='euler', padding_mode='zeros'):

    batch_size, _, img_height, img_width = img.size()

    cam_coords = pixel2cam(depth, intrinsics.inverse())  # [B,3,H,W]
    pose_mat = pose_vec2mat(pose, rotation_mode)  # [B,3,4]

    # Get projection matrix for tgt camera frame to source pixel frame
    proj_cam_to_src_pixel = intrinsics @ pose_mat  # [B, 3, 4]

    rot, tr = proj_cam_to_src_pixel[..., :3], proj_cam_to_src_pixel[..., -1:]
    src_pixel_coords = cam2pixel(cam_coords, rot, tr)  # [B,H,W,2]
    projected_img = F.grid_sample(img, src_pixel_coords, padding_mode=padding_mode, align_corners=True)

    valid_points = src_pixel_coords.abs().max(dim=-1)[0] <= 1

    return projected_img, valid_points


from omni.isaac.kit import SimulationApp

simulation_app = SimulationApp({"headless": False})

from omni.isaac.core import World
from omni.isaac.franka.franka import Franka
from omni.isaac.core.utils.stage import add_reference_to_stage
from omni.isaac.core.utils.types import ArticulationAction
import numpy as np
import math
import math_type_define.dyros_math as DyrosMath
import lula
import keyboard
import pandas as pd
from omni.isaac.core.articulations.articulation_view import ArticulationView

np.set_printoptions(precision=3, suppress=True)

# ---------------------------------------- Setting of Simulation -----------------------------------------------------------
hz = 100
model_path = "/home/dyros/Isaac_Sim/panda_controller/model"
world = World(stage_units_in_meters=1.0)
world.set_simulation_dt(1/hz, 1/hz)
asset_path = model_path + "/panda_arm_hand.usd"
add_reference_to_stage(usd_path=asset_path, prim_path="/World/panda")

# define the manipulator
franka = world.scene.add(Franka(prim_path="/World/panda", name="franka_robot",
                                end_effector_prim_name="panda_hand",
                                gripper_dof_names = ["panda_finger_joint1", "panda_finger_joint2"],
                                gripper_open_position = np.array([0.04, 0.04]),
                                gripper_closed_position = np.array([0, 0]),))
kinematic = lula.RobotDescription.kinematics(lula.load_robot(robot_description_file=model_path + "/panda_robot_description.yaml",
                                                             robot_urdf=model_path + "/panda_arm_hand.urdf"))

# define force sensor of each finger
# right_finger_ft = ArticulationView(prim_paths_expr="/World/panda/panda_rightfinger", enable_dof_force_sensors=True)
ft = ArticulationView(prim_paths_expr="/World/panda", name="ft_viewer")
world.scene.add(ft)
# ft.initialize()
# if ft.initialized:
#     print("true")

# set the default positions of the other gripper joints to be opened so
# that its out of the way of the joints we want to control when gripping an object for instance.
joints_default_positions = np.zeros(9)
joints_default_positions[3] = -math.pi/2
joints_default_positions[5] = math.pi/2
joints_default_positions[6] = math.pi/4
franka.set_joints_default_state(positions=joints_default_positions)
world.scene.add_default_ground_plane()
world.reset()
# ----------------------------------------------------------------------------------------------------------------------------

# ------------------------------------------ Initializing of Data -----------------------------------------------------------
q_init = joints_default_positions[:7]
q = q_init
q_desired = q_init
j = np.zeros((6,7))
j_qd = np.zeros((6,7))
pose_init = np.zeros((4,4))
pose = np.zeros((4,4))
pose_qd = np.zeros((4,4))
play_time = 0.0
control_start_time = 0.0
tick_init = 0
tick = 0
is_mode_changed = False
control_mode = "default"
# ----------------------------------------------------------------------------------------------------------------------------

# -------------------------------------------- Getting Trajecroty -----------------------------------------------------------
file_path = "/home/dyros/Isaac_Sim/panda_controller/trajectory"
traj_data = pd.read_table(file_path+"/circle.txt", sep=" ", header=None)
traj_data = traj_data.to_numpy()

x_traj = np.zeros(traj_data.shape[0])
y_traj = traj_data[:, 1]
z_traj = traj_data[:, 2]

vx_traj = np.zeros(traj_data.shape[0])
vy_traj = traj_data[:, 3]
vz_traj = traj_data[:, 4]
# ---------------------------------------------------------------------------------------------------------------------------

# -------------------------------------------------- Simulation -----------------------------------------------------------
while simulation_app.is_running():
    world.step(render=True)
    if world.is_playing():
        if world.current_time_step_index == 0:
            world.reset()

    if keyboard.is_pressed("i"):
        is_mode_changed = True
        control_mode = "joint_ctrl_home"
    elif keyboard.is_pressed("1"):
        is_mode_changed = True
        control_mode = "CLIK"

    if is_mode_changed:
        print("Change the Mode : " + control_mode)
        is_mode_changed = False
        q_init = franka.get_joint_positions()[:7].T
        q = q_init
        q_desired = q_init
        j = kinematic.jacobian(cspace_position=q.astype(np.float64), frame="panda_hand")
        j_qd = kinematic.jacobian(cspace_position=q_desired.astype(np.float64), frame="panda_hand")
        pose_init = kinematic.pose(cspace_position=q.astype(np.float64), frame="panda_hand").matrix()
        pose = pose_init
        pose_qd = pose_init
        control_start_time = world.current_time
        play_time = control_start_time
        tick_init = world.current_time_step_index
        tick = tick_init

        # x_traj += np.ones(x_traj.shape[0]) * pose_init[0, 3]
        # y_traj += np.ones(y_traj.shape[0]) * pose_init[1, 3]
        # z_traj += np.ones(z_traj.shape[0]) * pose_init[2, 3]

    # --------------------------------- Update States -----------------------------------------------
    q = franka.get_joint_positions()[:7].T
    j = kinematic.jacobian(cspace_position=q.astype(np.float64), frame="panda_hand")
    j_qd = kinematic.jacobian(cspace_position=q_desired.astype(np.float64), frame="panda_hand")
    pose = kinematic.pose(cspace_position=q.astype(np.float64), frame="panda_hand").matrix()
    pose_qd = kinematic.pose(cspace_position=q_desired.astype(np.float64), frame="panda_hand").matrix()
    # ------------------------------------------------------------------------------------------------

    #---------------------------------- CLIK -----------------------------------------
    if control_mode=="joint_ctrl_home":
        q_desired = DyrosMath.cubicVector(play_time, control_start_time, control_start_time+1,
                                          q_init, joints_default_positions[:7], np.zeros(7), np.zeros(7))
    elif control_mode=="CLIK":
        x_desired = np.zeros(3)  # position
        rotation_desired = np.zeros((3,3)) # rotation
        xd_desired = np.zeros(6) # v, w

        # ---------------------------------- Cubic Spline -------------------------------------------
        # duration = 2.0
        # target_pose = np.array([[1,  0,  0, 0.25],
        #                         [0, -1,  0, 0.28],
        #                         [0,  0, -1, 0.65],
        #                         [0,  0,  0, 1]])

        # for i in range(0,3):
        #     x_desired[i] = DyrosMath.cubic(play_time, control_start_time, control_start_time+duration,
        #                                    pose_init[i,3], target_pose[i,3], 0, 0)
        #     xd_desired[i] = DyrosMath.cubicDot(play_time, control_start_time, control_start_time+duration,
        #                                        pose_init[i,3], target_pose[i,3], 0, 0)
        # rotation_desired = DyrosMath.rotationCubic(play_time, control_start_time, control_start_time+duration,
        #                                            pose_init[:3,:3], target_pose[:3,:3])
        # xd_desired[3:] = DyrosMath.rotationCubicDot(play_time, control_start_time, control_start_time+duration,
        #                                             np.zeros(3), np.zeros(3), pose_init[:3,:3], target_pose[:3,:3])
        # -----------------------------------------------------------------------------------------------

        # --------------------------------- Traj from TXT -----------------------------------------------
        index = tick - tick_init

        if(index < 0):
            x_desired = pose_init[:3,3]
            rotation_desired = pose_init[:3,:3]
            xd_desired = np.zeros(6)
        elif(index >= traj_data.shape[0]):
            x_desired = np.array([x_traj[-1]+pose_init[0, 3], y_traj[-1]+pose_init[1, 3], z_traj[-1]+pose_init[2, 3]])
            rotation_desired = pose_init[:3,:3]
            xd_desired = np.zeros(6)
        else:
            x_desired = np.array([x_traj[index]+pose_init[0, 3], y_traj[index]+pose_init[1, 3], z_traj[index]+pose_init[2, 3]])
            rotation_desired = pose_init[:3,:3]
            xd_desired = np.array([vx_traj[index], vy_traj[index], vz_traj[index],
                                0, 0, 0])
        # -----------------------------------------------------------------------------------------------

        x_error = np.zeros(6)
        x_error[:3] = x_desired - pose_qd[:3,3]
        x_error[3:] = DyrosMath.getPhi(pose_qd[:3,:3], rotation_desired)

        kp = np.zeros((6,6))
        np.fill_diagonal(kp, val=[50, 50, 50, 10, 10, 10])

        pseudo_j_inv = np.dot( j_qd.T, np.linalg.inv( np.dot(j_qd, j_qd.T) ) )
        qd_desired = np.dot(pseudo_j_inv, xd_desired + np.dot(kp, x_error) )
        q_desired = q_desired + qd_desired/hz
    #-------------------------------------------------------------------------------------

    play_time = world.current_time
    tick = world.current_time_step_index
    franka.set_joint_positions(positions=np.concatenate((q_desired, np.zeros(2)), axis=0))

    #------------------------------- Print States ----------------------------------
    if( world.current_time_step_index % 50 == 0 ):
        print("position : ")
        print(pose[:3, 3].T)
        print("orientation : ")
        print(pose[:3,:3])
        print("\n\n")

        # print("right_ft")
        # print(right_finger_ft._physics_view.get_force_sensor_forces())
        print("left_ft")
        print(ft._physics_view.get_force_sensor_forces())
        # print("ft_sensor : ")
        # print(ft_sensor._physics_view)

    #-------------------------------------------------------------------------------

simulation_app.close()
# ----------------------------------------------------------------------------------------------------------------------------


import os
import sys
from pathlib import Path

import matplotlib
import matplotlib.pyplot as plt

import QPOEstimation
from QPOEstimation.get_data import *
from QPOEstimation.likelihood import get_kernel, get_mean_model, get_gp_likelihood
from QPOEstimation.parse import parse_args
from QPOEstimation.prior import get_priors
from QPOEstimation.prior.gp import *
from QPOEstimation.stabilisation import bar_lev
from QPOEstimation.utils import *

if len(sys.argv) > 1:
    parser = parse_args()
    args = parser.parse_args()

    data_source = args.data_source
    run_mode = args.run_mode
    sampling_frequency = args.sampling_frequency
    variance_stabilisation = boolean_string(args.variance_stabilisation)

    hares_and_hounds_id = args.hares_and_hounds_id
    hares_and_hounds_round = args.hares_and_hounds_round

    solar_flare_folder = args.solar_flare_folder
    solar_flare_id = args.solar_flare_id
    grb_id = args.grb_id
    grb_label = args.grb_label
    grb_binning = args.grb_binning
    grb_detector = args.grb_detector
    grb_energy_band = args.grb_energy_band
    magnetar_label = args.magnetar_label
    magnetar_tag = args.magnetar_tag
    bin_size = args.bin_size
    magnetar_subtract_t0 = boolean_string(args.magnetar_subtract_t0)
    magnetar_unbarycentred_time = boolean_string(args.magnetar_unbarycentred_time)

    rebin_factor = args.rebin_factor

    start_time = args.start_time
    end_time = args.end_time

    period_number = args.period_number
    run_id = args.run_id

    candidate_id = args.candidate_id

    polynomial_max = args.polynomial_max
    amplitude_min = args.amplitude_min
    amplitude_max = args.amplitude_max
    offset_min = args.offset_min
    offset_max = args.offset_max
    sigma_min = args.sigma_min
    sigma_max = args.sigma_max
    t_0_min = args.t_0_min
    t_0_max = args.t_0_max
    offset = boolean_string(args.offset)

    min_log_a = args.min_log_a
    max_log_a = args.max_log_a
    min_log_c_red_noise = args.min_log_c_red_noise
    min_log_c_qpo = args.min_log_c_qpo
    max_log_c_red_noise = args.max_log_c_red_noise
    max_log_c_qpo = args.max_log_c_qpo
    minimum_window_spacing = args.minimum_window_spacing

    injection_id = args.injection_id
    injection_mode = args.injection_mode
    injection_file_dir = args.injection_file_dir
    injection_likelihood_model = args.injection_likelihood_model
    base_injection_outdir = args.base_injection_outdir
    normalisation = boolean_string(args.normalisation)

    recovery_mode = args.recovery_mode
    likelihood_model = args.likelihood_model
    background_model = args.background_model
    n_components = args.n_components
    jitter_term = boolean_string(args.jitter_term)

    band_minimum = args.band_minimum
    band_maximum = args.band_maximum

    segment_length = args.segment_length
    segment_step = args.segment_step

    nlive = args.nlive
    sample = args.sample
    use_ratio = boolean_string(args.use_ratio)

    try_load = boolean_string(args.try_load)
    resume = boolean_string(args.resume)
    plot = boolean_string(args.plot)
    suffix = args.suffix
else:
    # matplotlib.use("Qt5Agg")

    data_source = "giant_flare"  # "magnetar_flare_binned"
    run_mode = "select_time"
    sampling_frequency = 64
    variance_stabilisation = False

    hares_and_hounds_id = "455290"
    hares_and_hounds_round = "HH2"

    solar_flare_folder = "goes"
    solar_flare_id = "go1520130512"
    # solar_flare_id = "go1520110314"
    grb_id = "090709A"
    grb_label = ""
    grb_binning = "1s"
    grb_detector = "swift"
    grb_energy_band = "all"

    magnetar_label = "SGR_0501"
    magnetar_tag = "080823478_lcobs"
    bin_size = 0.001
    magnetar_subtract_t0 = True
    magnetar_unbarycentred_time = False
    rebin_factor = 8

    start_time = 101.060 + 20.0
    end_time = 103.060 + 20.0
    # start_time = 138.915 - 0.3 + 20.378
    # end_time = 139.915 + 0.5 + 20.378
    # start_time = 132.3 - 0.5 + 20.0
    # end_time = 132.3 + 0.5 + 20.0
    # start_time = -4.0
    # end_time = 103.0
    # start_time = 88.775 + 20.378
    # end_time = 90.775 + 20.378
    # start_time = -20.0
    # end_time = 20.0
    # start_time = 0 * 1e-3
    # end_time = 5 * 1e-3

    period_number = 14
    run_id = 6

    candidate_id = 5

    injection_id = 1
    base_injection_outdir = "injections/injection"

    offset = False
    polynomial_max = 2
    amplitude_min = None
    amplitude_max = None
    offset_min = None
    offset_max = None
    sigma_min = None
    sigma_max = None
    t_0_min = None
    t_0_max = None

    min_log_a = None
    max_log_a = None
    min_log_c_red_noise = None
    min_log_c_qpo = None
    max_log_c_red_noise = None
    max_log_c_qpo = None
    minimum_window_spacing = 0

    injection_mode = "qpo_plus_red_noise"
    injection_file_dir = "injection_files_pop"
    injection_likelihood_model = "whittle"
    recovery_mode = "qpo_plus_red_noise"
    likelihood_model = "celerite_windowed"
    background_model = "skew_exponential"
    n_components = 1
    jitter_term = False
    normalisation = False

    band_minimum = None
    band_maximum = None
    segment_length = 3.5
    # segment_step = 0.945  # Requires 8 steps
    segment_step = 0.23625  # Requires 32 steps

    sample = "rslice"
    nlive = 1000
    use_ratio = False

    try_load = True
    resume = True
    plot = True

if variance_stabilisation:
    suffix = f"_variance_stabilised"
else:
    suffix = ""
suffix += f"_{n_components}_{background_model}s"

mean_prior_bound_dict = dict(
    amplitude_min=amplitude_min,
    amplitude_max=amplitude_max,
    offset_min=offset_min,
    offset_max=offset_max,
    sigma_min=sigma_min,
    sigma_max=sigma_max,
    t_0_min=t_0_min,
    t_0_max=t_0_max
)

band = f"{band_minimum}_{band_maximum}Hz"

truths = None

recovery_mode_str = recovery_mode
if jitter_term:
    recovery_mode_str += "_jitter"

times, y, yerr, outdir, label = get_data(
    data_source=data_source, band=band, segment_length=segment_length,
    sampling_frequency=sampling_frequency,
    period_number=period_number, run_id=run_id, segment_step=segment_step, start_time=start_time, end_time=end_time,
    run_mode=run_mode, recovery_mode=recovery_mode, recovery_mode_str=recovery_mode_str, likelihood_model=likelihood_model,
    magnetar_label=magnetar_label,  magnetar_tag=magnetar_tag, bin_size=bin_size,
    magnetar_subtract_t0=magnetar_subtract_t0, magnetar_unbarycentred_time=magnetar_unbarycentred_time,
    rebin_factor=rebin_factor, solar_flare_folder=solar_flare_folder, solar_flare_id=solar_flare_id,
    grb_id=grb_id, grb_binning=grb_binning, grb_detector=grb_detector, grb_label=grb_label, grb_energy_band=grb_energy_band,
    injection_file_dir=injection_file_dir, injection_mode=injection_mode, injection_id=injection_id,
    injection_likelihood_model=injection_likelihood_model, hares_and_hounds_id=hares_and_hounds_id,
    hares_and_hounds_round=hares_and_hounds_round, base_injection_outdir=base_injection_outdir
    )

if normalisation:
    y = (y - np.min(y))/(np.max(y) - np.min(y)) * 1
    yerr = yerr/(np.max(y) - np.min(y))

if plot:
    # plt.errorbar(times, y, yerr=yerr, fmt=".k", capsize=0, label="data")
    # plt.errorbar(times, y, yerr=yerr, capsize=0, label="data")
    plt.step(times, y, label="flux")
    # plt.xlabel("time [s]")
    # plt.ylabel("counts/sec/det")
    # plt.title("GRB 090709A Swift-BAT 15-350 keV")
    plt.show()
    plt.clf()

    fs = 1/(times[1] - times[0])

    from scipy.signal import periodogram
    freqs, powers = periodogram(y, fs=fs, window="hann")
    plt.loglog()
    plt.step(freqs[1:], powers[1:])
    # plt.axvline(1/8.1, color="black", linestyle="--", label="QPO?")
    plt.xlabel("frequency [Hz]")
    plt.ylabel("Power [arb. units]")
    plt.legend()
    plt.show()

priors = get_priors(times=times, y=y, yerr=yerr, likelihood_model=likelihood_model, kernel_type=recovery_mode,
                    min_log_a=min_log_a, max_log_a=max_log_a,
                    min_log_c_red_noise=min_log_c_red_noise, max_log_c_red_noise=max_log_c_red_noise,
                    min_log_c_qpo=min_log_c_qpo, max_log_c_qpo=max_log_c_qpo, band_minimum=band_minimum, band_maximum=band_maximum,
                    model_type=background_model, polynomial_max=polynomial_max, minimum_spacing=minimum_window_spacing,
                    n_components=n_components, offset=offset, jitter_term=jitter_term, **mean_prior_bound_dict)

# priors["kernel:terms[0]:log_f"] = bilby.core.prior.Uniform(minimum=np.log(3000), maximum=8.517193191416348, name="kernel:terms[0]:log_f", latex_label="kernel:terms[0]:log_f", unit=None, boundary="reflective")
# suffix += "restricted_freq"

mean_model = get_mean_model(model_type=background_model, n_components=n_components, y=y, offset=offset,
                            likelihood_model=likelihood_model)
kernel = get_kernel(kernel_type=recovery_mode, jitter_term=jitter_term)
likelihood = get_gp_likelihood(mean_model=mean_model, kernel=kernel, times=times, y=y, yerr=yerr,
                               likelihood_model=likelihood_model)

meta_data = dict(kernel_type=recovery_mode, mean_model=background_model, times=times,
                 y=y, yerr=yerr, likelihood_model=likelihood_model, truths=truths, n_components=n_components,
                 offset=offset, jitter_term=jitter_term)

label += suffix
result = None
if try_load:
    try:
        result = QPOEstimation.result.GPResult.from_json(outdir=f"{outdir}/results", label=label)
        result.outdir = f"{outdir}/results"
    except IOError:
        bilby.utils.logger.info("No result file found. Starting from scratch")
if result is None:
    Path(f"{outdir}/results").mkdir(parents=True, exist_ok=True)
    result = bilby.run_sampler(likelihood=likelihood, priors=priors, outdir=f"{outdir}/results",
                               label=label, sampler="dynesty", nlive=nlive, sample=sample,
                               resume=resume, use_ratio=use_ratio, result_class=QPOEstimation.result.GPResult,
                               meta_data=meta_data, save=True, gzip=False, nact=5)

if plot:
    result.plot_all(paper_style=True)

# clean up
for extension in ["_checkpoint_run.png", "_checkpoint_stats.png", "_checkpoint_trace.png", "_checkpoint_trace_unit.png",
                  "_dynesty.pickle", "_resume.pickle", "_result.json.old", "_samples.dat",
                  "_checkpoint_trace_unit.png"]:
    try:
        os.remove(f"{result.outdir}/{label}{extension}")
    except Exception:
        pass