from ltk.actions.action import *

class RequestAction(Action):
    def __init__(self, actionPath, doc_name, requestPath, entered_locales, to_cancel, to_delete, due_date, workflow, document_id=None, surpressMessage=False):
        Action.__init__(self, actionPath)

        self.document_name = doc_name
        self.requestPath = requestPath
        self.entered_locales = entered_locales
        self.to_cancel = to_cancel
        self.to_delete = to_delete
        self.workflow = workflow
        self.due_date = due_date
        self.document_id = document_id
        self.surpressMessage = surpressMessage

        self.expected_code = ''
        self.failure_message = ''
        self.info_message = ''
        self.change_db_entry = ''
        self.docs = []

    def target_action(self):
        try:
            is_successful = False
            locales = []
            if self.entered_locales:
                for locale in self.entered_locales:
                    locales.extend(locale.split(','))
                if self.to_delete:
                    locales = get_valid_locales(self.api, locales, 'deleted')
                elif self.to_cancel:
                    locales = get_valid_locales(self.api, locales, 'cancelled')
                else:
                    locales = get_valid_locales(self.api, locales, 'added')
            elif self.watch_locales:
                locales = self.watch_locales
            elif self.surpressMessage:
                # don't print out anything when on watch
                return False
            else:
                logger.info('No locales have been set. Locales can be passed in as arguments or set as target locales in ltk config.')
                return False
            if self.requestPath:
                self.document_id = None
                self.document_name = None
            self.change_db_entry = True
            if self.to_delete:
                if not self.entered_locales:
                    logger.error("Please enter a target locale to delete")
                    return
                self.expected_code = 204
                self.failure_message = 'Failed to delete target'
                self.info_message = 'Deleted locale'
            elif self.to_cancel:
                if not self.entered_locales:
                    logger.error("Please enter a target locale to cancel")
                    return
                self.expected_code = 204
                self.failure_message = 'Failed to cancel target'
                self.info_message = 'Cancelled locale'
            else:
                self.expected_code = 201
                self.failure_message = 'Failed to add target'
                self.info_message = 'Added target'
            # print("doc_name: "+str(document_name))
            if not self.requestPath and not self.document_name and not self.document_id:
                self.docs = self.doc_manager.get_all_entries()
            elif self.requestPath:
                self.docs = self.get_docs_in_path(self.requestPath)
            else:
                if self.document_id:
                    entry = self.doc_manager.get_doc_by_prop('id', self.document_id)
                    if not entry:
                        logger.error('Document specified for target doesn\'t exist: {0}'.format(self.document_id))
                        return
                elif self.document_name:
                    entry = self.doc_manager.get_doc_by_prop('name', self.document_name)
                    if not entry:
                        logger.error('Document name specified for target doesn\'t exist: {0}'.format(self.document_name))
                        return
                        # raise exceptions.ResourceNotFound("Document name specified doesn't exist: {0}".format(document_name))
                if not entry:
                    logger.error('Could not add target. File specified is invalid.')
                    return
                self.docs.append(entry)
            if len(self.docs) == 0:
                if self.requestPath and len(self.requestPath) > 0:
                    logger.info("File "+str(self.requestPath)+" not found")
                else:
                    logger.info("No documents to request a target locale")

            is_successful = self._request_translations(locales)
            return is_successful
        except Exception as e:
            log_error(self.error_file_name, e)
            if 'string indices must be integers' in str(e) or 'Expecting value: line 1 column 1' in str(e):
                logger.error("Error connecting to Lingotek's TMS")
            else:
                logger.error("Error on request: "+str(e))

    def _request_translations(self, locales):
        for entry in self.docs:
            if not self._handleEntryRequest(entry, locales):
                return False
        return True

    def _handleEntryRequest(self, entry, locales):
        is_successful = False
        self.document_id = entry['id']
        self.document_name = entry['file_name']
        existing_locales = []
        if 'locales' in entry and entry['locales']:
            existing_locales = entry['locales']
        for locale in locales:
            locale = locale.replace('_','-')
            if self.to_delete:
                response = self.api.document_delete_target(self.document_id, locale)
            elif self.to_cancel:
                response = self.api.document_cancel_target(self.document_id, locale)
            else:
                response = self.api.document_add_target(self.document_id, locale, self.workflow_id, self.due_date)
            if self.expected_code == 201: # Request target
                if response.status_code == 202:
                    if 'next_document_id' in response.json():
                        self.doc_manager.update_document('id', response.json()['next_document_id'], self.document_id)
                        self.document_id = response.json()['next_document_id']
                elif response.status_code == 402:
                    raise_error(response.json(), "", True)
                elif response.status_code == 410:
                    logger.info("Document has been archived. Reuploading...")
                    target_locales = existing_locales
                    if locale not in existing_locales:
                        target_locales.append(locale)
                    title = entry['name']
                    self.doc_manager.remove_element(self.document_id)
                    self.add_document(self.document_name, title, self.default_metadata, translation_locale_code=target_locales)
                    return
                elif response.status_code == 423:
                    if 'next_document_id' in response.json():
                        self.doc_manager.update_document('id', response.json()['next_document_id'], self.document_id)
                        self.document_id = response.json()['next_document_id']
                        self._handleEntryRequest(entry, [locale])
                    else:
                        raise_error(response.json(), "Document was locked but no next document id provided", False)
            if response.status_code != self.expected_code:
                if (response.json() and response.json()['messages']):
                    response_message = response.json()['messages'][0]
                    response_message = response_message.replace(self.document_id, self.document_name + ' (' + self.document_id + ')')
                    response_message = response_message.replace('.', ' ')
                    response_message = response_message + 'for document ' + self.document_name
                    print(response_message + "\n")
                    #if 'not found' in response_message:
                        #return
                else:
                    raise_error(response.json(), '{message} {locale} for document {name}\n'.format(message=self.failure_message, locale=locale, name=self.document_name), True)
                if not 'already exists' in response_message:
                    self.change_db_entry = False
                # self.update_doc_locales(document_id)
                continue
            logger.info('{message} {locale} for document {name}\n'.format(message=self.info_message, locale=locale, name=self.document_name))
        remote_locales = self.get_doc_locales(self.document_id, self.document_name) # Get locales from Lingotek Cloud
        locales_to_add = []
        existing_locales = []
        if 'locales' in entry and entry['locales']:
            existing_locales = entry['locales']
        if self.change_db_entry:
            # Make sure that the locales that were just added are added to the database as well as the previous remote locales (since they were only just recently added to Lingotek's system)
            if (self.to_delete or self.to_cancel) and self.entered_locales:
                locales_to_add = locales
            else:
                if remote_locales:
                    for locale in remote_locales:
                        if locale not in locales:
                            locales_to_add.append(locale)

                for locale in locales:
                    locale = locale.replace('_', '-')
                    if locale not in existing_locales and locale not in locales_to_add:
                        locales_to_add.append(locale)
            if self.to_delete:
                self._target_action_db(self.to_delete, locales_to_add, self.document_id)
            else:
                self._target_action_db(self.to_cancel, locales_to_add, self.document_id)
            #self._target_action_db((self.to_delete or self.to_cancel), locales_to_add, self.document_id)
            is_successful = True

        return is_successful


from objs.cmd import Command

class CmdObj(Command):

    def cmd(self, ob, line):
        target = ob
        if line != '' and getInt(ob['관리자등급']) >= 1000:
            target = ob.env.findObjName(line)
            if target == None or is_player(target) == False:
                ob.sendLine('☞ 당신의 안광으로는 그런것을 볼수 없다네')
                return
        ob.sendLine('━━━━━━━━━━━━━━━━━')
        ob.sendLine('  ◁     소     지     품     ▷  ')
        ob.sendLine('─────────────────')
        if target.getInvenItemCount() == 0:
            ob.sendLine('☞ 아무것도 없습니다.')
        else:
            nStr = {} # { ' ': 1, ' ':2,  ... }
            for obj in target.objs:
                if obj.inUse:
                    continue

                if obj.checkAttr('아이템속성', '출력안함') and getInt(ob['관리자등급']) < 1000:
                    continue
                c = 0
                try:
                    c = nStr[obj.get('이름')]
                except:
                    nStr[obj.get('이름')] = 0
                nStr[obj.get('이름')] = c + 1

            for iName in nStr:
                c = nStr[iName]
                if c == 1:
                    ob.sendLine( '' + iName + '')
                else:
                    ob.sendLine( '' + iName + ' %d개' % c)

        ob.sendLine('─────────────────')
        ob.sendLine('▶ 은전 : %20d 개 ' % target.get('은전'))
        if ob['금전'] == '':
            ob['금전'] = 0
        if ob['금전'] > 0:
            ob.sendLine('▶ 금전 : %20d 개 ' % ob['금전'])
        ob.sendLine('─────────────────')


from torch.utils.data import DataLoader
from utils.constants import *
from typing import List, Tuple
from models.enums.Genre import Genre
import numpy as np
from torch.utils.data import DataLoader

from utils.constants import *

class Tester:
    # input: both network models
    # return average loss, acc; etc.

    def __init__(self,
                 model,
                 data_loader_test: DataLoader,
                 data_loader_sentence,
                 model_state_path='',
                 device='cpu'):

        # the saved network as an object
        self.model = model
        self.model_state_path = model_state_path
        self.data_loader_test = data_loader_test
        self.data_loader_sentence = data_loader_sentence
        self.device = device
        self.model.eval()

    def test(self):
        """
         main testing function
        """

        try:
            # loading saved trained weights
            if self.model_state_path:  # because if we are testing a CombinedClassifier the states are already loaded
                self.model.load_state_dict(torch.load(self.model_state_path))

            log = {'final_scores': [], 'combination': {
                'classifier_scores': [], 'vaes_scores': []},
                   'accuracies_per_batch': [],
                   'true_targets': [],
                   'length_lstm': [],
                   'length_vae': []
                   }

            for i, items in enumerate(zip(self.data_loader_test, self.data_loader_sentence)):
                (batch, targets, lengths), (batch2, targets2, lengths2) = items

                accuracy_batch = self._batch_iteration(batch, targets, lengths, log, (batch2, targets2, lengths2), i)

                log['accuracies_per_batch'].append(accuracy_batch)
                log['true_targets'].append(targets)

                # if i % 100 == 0:
                    # print('combined accuracy so far', np.mean(log['accuracies_per_batch']), i)

            return log
        except KeyboardInterrupt as e:
            print(f"Killed by user: {e}")

            return False
        except Exception as e:
            print(e)

            raise e

    def _batch_iteration(self,
                         batch: torch.Tensor,
                         targets: torch.Tensor,
                         lengths: torch.Tensor,
                         log,
                         sentencebatch, step):
        """
        runs forward pass on batch and backward pass if in train_mode
        """

        if (step % 100) == 0:
            print(step)

        batch2, targets2, lengths2 = sentencebatch
        batch = batch.to(self.device).detach()
        targets = targets.to(self.device).detach()
        lengths = lengths.to(self.device).detach()

        if batch2 is not None:
            batch2 = batch2.to(self.device).detach()
            targets2 = targets2.to(self.device).detach()
            lengths2 = lengths2.to(self.device).detach()

        output = self.model.forward(batch, targets, lengths, (batch2, targets2, lengths2), step)

        final_scores_per_class = output
        if 'Combined' in type(self.model).__name__:
            final_scores_per_class, (score_classifier, score_elbo) = output
            log['combination']['classifier_scores'].append(score_classifier.detach())
            log['combination']['vaes_scores'].append(score_elbo.detach())

        _, classifications = score_classifier.detach().max(dim=-1)
        accuracy = (targets.eq(classifications)).float().mean().item()

        log['final_scores'].append(final_scores_per_class.detach())
        log['length_lstm'].append(lengths.detach())
        log['length_vae'].append(lengths2.detach())

        return accuracy


import pygame
import json
import time
import datetime as dt
import random
import socket
import os
import logging

### CONSTANTS

modeNames = ["basic_with_rainbow","changing_colors","random_flashes","flicker","tensionWithEcho","jasmine","ocean","risingStairs","polzynki","sleep","easterEgg"]
sound_groups = {"basic_with_rainbow":["basic_with_rainbow","tensionWithEcho"],
                'flicker':["flicker"],
                'ocean':["ocean"],
                'oceanletov':["random_flashes"],
                'polzynki':["risingStairs","polzynki"],
                'jasmine':["jasmine","changing_colors"],
                'sleep':['sleep'],
                'easterEgg':['easterEgg']}
NUM_CHANNELS = 5
NUM_LEDS = 40

### CONSTANTS

inv_sound_groups = {}
for key in sound_groups.keys():
    for val in sound_groups[key]:
        if val in inv_sound_groups.keys():
            logging.warning('mode {} is in multiple sound groups!'.format(val))
        else:
            inv_sound_groups[val] = key

t = time.time()
logging.basicConfig(format='%(asctime)s %(message)s', level=logging.INFO)

logging.info("Initialisation for {} channels".format(NUM_CHANNELS))

channels_ignore = [0 for i in range(0, NUM_CHANNELS)]
sounds = []
fadeout_ignore = False
cur_mode = "init"

cur_dir = (os.path.dirname(os.path.abspath(__file__)))

config_path = os.path.join(cur_dir, os.pardir, 'modes_config.json')
logging.info("Loading config from {}".format(config_path))
with open(config_path) as json_file:
    config = json.load(json_file)

FADEOUT_TIME = config['generalSoundConfig']['timeout']

logging.info("Trying to connect...")

# set up and open read from the socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while True:
    try:
        client.bind(('localhost', 8124))
        break
    except:
        logging.warning("Can't bind to 8124. Retry")
        time.sleep(1)

logging.info("Initialising mixer")

# init mixer
pygame.mixer.init(44100, -16, channels=2, buffer=4096)
pygame.mixer.set_num_channels(NUM_CHANNELS)
channels = [pygame.mixer.Channel(i) for i in range(0, NUM_CHANNELS)]  # argument must be int

exit = False

while not exit:
    try:
        logging.info('Listening for new connection...')
        client.listen(1)
        c, addr = client.accept()
        logging.info('Got connection from {}'.format(addr))

        while True: # infinite while-loop
            json_msg = c.recv(4096) # receives sensor value from the socket
            # drain buffer
            if len(json_msg) == 4096 or json_msg[:7] != b'{"mode"':
                continue
            #if two messages made it only take first
            msg_point = json_msg.find(b'}{"mode"')
            if msg_point != -1:
                json_msg = json_msg[:msg_point+1]

            logging.debug("{}:{}".format(dt.datetime.now().time(),json_msg))

            msg = json.loads(json_msg)

            if fadeout_ignore:
                if time.time()-t > FADEOUT_TIME:
                    logging.info('Fadeout complete')
                    fadeout_ignore = False
                    cur_mode = "init"
                    channels_ignore = [False for i in range(0,NUM_CHANNELS)] #init channel ignores
                else:
                    continue

            mode = msg['mode']
            if cur_mode == mode:
                for sensor in msg['sensorsData']:
                    try:
                        name = int(sensor['LEDShtuka']) - 1
                    except:
                        continue
                    if name not in range(0,NUM_CHANNELS):
                        continue

                    try:
                        if mode in inv_sound_groups.keys():
                            #Flicker
                            if inv_sound_groups[mode] == "flicker":
                                max_range = NUM_LEDS*config['flickerConfig']['factor']
                                # if name in [7, 8]:
                                #     slow = sensor['slow']
                                #     if slow > max_range*config['flickerConfig']['slowSoundTrigger']:
                                #         if time.time() > channels_ignore[name]:
                                #             channels[name].play(sounds[name])
                                #             channels_ignore[name] = time.time()+sounds[name].get_length()
                                #     if slow < 0:
                                #         slow = 0
                                #     if slow > max_range:
                                #         slow = max_range
                                #     channels[name].set_volume((slow / max_range)*config['flickerConfig']['soundFactor'])
                                # else:
                                if sensor['fast'] > max_range*config['flickerConfig']['soundTrigger']:
                                    if time.time() > channels_ignore[name]:
                                        channels[name].set_volume(config['flickerConfig']['soundFactor'])
                                        channels[name].play(sounds[name])
                                        channels_ignore[name] = time.time()+sounds[name].get_length()
                            #Polzynki
                            elif inv_sound_groups[mode] == "polzynki":
                                max_range = NUM_LEDS*config['polzynkiConfig']['factor']

                                # if name in [5,7,8,10]:
                                #     slow = sensor['slow']
                                #     if slow > max_range*config['polzynkiConfig']['slowSoundTrigger']:
                                #         if time.time() > channels_ignore[name]:
                                #             channels[name].play(sounds[name])
                                #             channels_ignore[name] = time.time()+sounds[name].get_length()
                                #     if slow < 0:
                                #         slow = 0
                                #     if slow > max_range:
                                #         slow = max_range
                                #     channels[name].set_volume((slow / max_range)*config['polzynkiConfig']['soundFactor'])
                                # else:
                                if sensor['fast'] > max_range*config['polzynkiConfig']['soundTrigger']:
                                    if time.time() > channels_ignore[name]:
                                        channels[name].set_volume(config['polzynkiConfig']['soundFactor'])
                                        channels[name].play(sounds[name])
                                        channels_ignore[name] = time.time()+sounds[name].get_length()
                            #Ocean
                            elif inv_sound_groups[mode] == "ocean":
                                max_range = NUM_LEDS*config['oceanConfig']['factor']

                                # if name in [3,4,5,7,8]:
                                #     slow = sensor['slow']
                                #     if slow > max_range*config['oceanConfig']['slowSoundTrigger']:
                                #         if time.time() > channels_ignore[name]:
                                #             channels[name].play(sounds[name])
                                #             channels_ignore[name] = time.time()+sounds[name].get_length()
                                #     if slow < 0:
                                #         slow = 0
                                #     if slow > max_range:
                                #         slow = max_range
                                #     channels[name].set_volume((slow / max_range)*config['oceanConfig']['soundFactor'])
                                # else:
                                if sensor['fast'] > config['oceanConfig']['tensionTrigger']:
                                    if time.time() > channels_ignore[name]:
                                        loc = random.uniform(0.65, 0.85)
                                        if sensor['where'] == 'right':
                                            channels[name].set_volume((1 - loc) * config['oceanConfig']['soundFactor'],loc * config['oceanConfig']['soundFactor'])
                                        else:
                                            channels[name].set_volume(loc * config['oceanConfig']['soundFactor'], (1 - loc) * config['oceanConfig']['soundFactor'])
                                        channels[name].play(sounds[name])
                                        channels_ignore[name] = time.time() + sounds[name].get_length()
                            elif inv_sound_groups[mode] == "oceanletov":
                                max_range = NUM_LEDS*config['oceanConfig']['factor']

                                if sensor['fast'] > config['oceanConfig']['tensionTrigger']:
                                    if time.time() > channels_ignore[name]:
                                        loc = random.uniform(0.65, 0.85)
                                        if sensor['where'] == 'right':
                                            channels[name].set_volume((1 - loc) * config['oceanConfig']['soundFactor'],loc * config['oceanConfig']['soundFactor'])
                                        else:
                                            channels[name].set_volume(loc * config['oceanConfig']['soundFactor'], (1 - loc) * config['oceanConfig']['soundFactor'])
                                        channels[name].play(sounds[name])
                                        channels_ignore[name] = time.time() + sounds[name].get_length()
                            #Basic
                            elif inv_sound_groups[mode] == "basic_with_rainbow":
                                max_range = config['basicWithRainbow']['maxTension']

                                # if name in [2,4,5,7,8,11]:
                                #     slow = sensor['slow']
                                #     if slow > max_range*config['basicWithRainbow']['slowSoundTrigger']:
                                #         if time.time() > channels_ignore[name]:
                                #             channels[name].play(sounds[name])
                                #             channels_ignore[name] = time.time()+sounds[name].get_length()
                                #     if slow < 0:
                                #         slow = 0
                                #     if slow > max_range:
                                #         slow = max_range
                                #     channels[name].set_volume((slow / max_range)*config['basicWithRainbow']['soundFactor'])
                                # else:
                                if sensor['fast'] > max_range*config['basicWithRainbow']['soundTrigger']:
                                    if time.time() > channels_ignore[name]:
                                        loc = random.uniform(0.55, 0.95)
                                        if sensor['where'] == 'right':
                                            channels[name].set_volume((1 - loc) * config['basicWithRainbow']['soundFactor'],loc * config['basicWithRainbow']['soundFactor'])
                                        else:
                                            channels[name].set_volume(loc * config['basicWithRainbow']['soundFactor'], (1 - loc) * config['basicWithRainbow']['soundFactor'])
                                        channels[name].play(sounds[name])
                                        channels_ignore[name] = time.time() + sounds[name].get_length()
                            #Jasmine
                            elif inv_sound_groups[mode] == "jasmine":
                                if sensor['fast'] > config['jasmineConfig']['tensionTrigger']:
                                    if time.time() > channels_ignore[name]:
                                        loc = random.uniform(0.55,0.95)
                                        if sensor['where'] == 'right':
                                            channels[name].set_volume((1-loc)*config['jasmineConfig']['soundFactor'],loc*config['jasmineConfig']['soundFactor'])
                                        else:
                                            channels[name].set_volume(loc*config['jasmineConfig']['soundFactor'],(1-loc)*config['jasmineConfig']['soundFactor'])
                                        channels[name].play(sounds[name])
                                        channels_ignore[name] = time.time()+sounds[name].get_length()
                    except Exception as e:
                        logging.warning('Problem playing sound - {}'.format(e))
                        pass

            else: #change of mode
                logging.info("Change of mode from {} to {}".format(cur_mode,mode))

                if not mode in inv_sound_groups.keys():
                    logging.warning("Unknown mode - {}".format(mode))

                    # play Sleep sound
                    try:
                        base_sound_path = os.path.join(cur_dir, 'sleep', 'Base.mp3')
                        pygame.mixer.music.load(base_sound_path)
                        logging.info("Finished loading base from {}".format(base_sound_path))
                    except:
                        logging.warning("Base sound not found at {}, loading default".format(base_sound_path))
                        pygame.mixer.music.load(os.path.join(cur_dir, 'system', 'Base.mp3'))
                    pygame.mixer.music.play(loops=-1)
                    pygame.mixer.music.set_volume(config['sleepConfig']['volume'])
                elif mode == "easterEgg":
                    logging.info("Easter Egg!")
                    # UNCOMMENT FOR REAL EASTER EGG :)
                    pygame.mixer.stop()

                    pygame.mixer.music.stop()
                    try:
                        pygame.mixer.music.load(os.path.join(cur_dir, 'easterEgg', 'Base.mp3'))
                    except:
                        pygame.mixer.music.load(os.path.join(cur_dir, 'system', 'Base.mp3'))
                    pygame.mixer.music.play(loops=1)
                    pygame.mixer.music.set_volume(config['easterEggConfig']['volume'])
                    cur_mode = mode
                elif cur_mode != "init":
                    if inv_sound_groups[mode] == inv_sound_groups[cur_mode]:
                        logging.info("Change to mode from the same group {}".format(inv_sound_groups[mode]))
                        cur_mode = mode
                    else:
                        #start Fadeout
                        logging.info("Start Fadeout")
                        t = time.time()
                        pygame.mixer.fadeout(FADEOUT_TIME * 1000)
                        pygame.mixer.music.fadeout(FADEOUT_TIME * 1000)
                        fadeout_ignore = True
                elif mode == "sleep":
                    logging.info("Loading Sleep")

                    # play Base sound
                    try:
                        base_sound_path = os.path.join(cur_dir, 'sleep', 'Base.mp3')
                        pygame.mixer.music.load(base_sound_path)
                        logging.info("Finished loading base from {}".format(base_sound_path))
                    except:
                        logging.warning("Base sound not found at {}, loading default".format(base_sound_path))
                        pygame.mixer.music.load(os.path.join(cur_dir, 'system', 'Base.mp3'))
                    pygame.mixer.music.play(loops=-1)
                    pygame.mixer.music.set_volume(config['sleepConfig']['volume'])
                    cur_mode = mode
                else:
                    logging.info("Loading {}".format(mode))
                    cur_mode = mode

                    sound_path = os.path.join(cur_dir, inv_sound_groups[mode])

                    #load sounds
                    sounds = []
                    for i in range(0,NUM_CHANNELS):
                        try:
                            sounds.append(pygame.mixer.Sound(os.path.join(sound_path,str(i)+'.ogg')))
                        except:
                            logging.warning("Sound {} not found, loading default".format(os.path.join(sound_path,str(i)+'.ogg')))
                            sounds.append(pygame.mixer.Sound(os.path.join(cur_dir, 'system','empty.ogg')))
                        finally:
                            channels[i].set_volume(1)

                    #load base sound
                    try:
                        base_sound_path = os.path.join(sound_path, 'Base.mp3')
                        pygame.mixer.music.load(base_sound_path)
                        logging.info("Finished loading base sound from {}".format(base_sound_path))
                    except:
                        logging.warning("Base sound not found at {}, loading default".format(base_sound_path))
                        pygame.mixer.music.load(os.path.join(cur_dir, 'system', 'Base.mp3'))
                    pygame.mixer.music.play(loops=-1)
                    pygame.mixer.music.set_volume(config['generalSoundConfig']['baseVolume'])

                    logging.info("Finished loading {}".format(mode))

    except Exception as e:
        logging.exception("Exception: {}".format(e))
        pass


import os
from shutil import copyfile
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--input_dataset', help='File path of dataset.', required=True)
parser.add_argument('--output_dir', help='File path of output folder.', required=True)
args = parser.parse_args()

def create_folders(input_dir, train_output_dir, test_output_dir):
  training_classes = {}
  for class_name in os.listdir(input_dir):
      train_folder_name = os.path.join(train_output_dir, class_name)
      test_folder_name = os.path.join(test_output_dir, class_name)
      if not os.path.exists(train_folder_name):
          os.makedirs(train_folder_name)
      if not os.path.exists(test_folder_name):
          os.makedirs(test_folder_name)
      class_dir_name = os.path.join(input_dir, class_name)
      for image_name in os.listdir(class_dir_name):
          input_file_name = os.path.join(class_dir_name, image_name)
          train_output_file_name = os.path.join(train_folder_name, image_name)
          test_output_file_name = os.path.join(test_folder_name, image_name)
          if class_name in training_classes and training_classes[class_name] >= 19:
              copyfile(input_file_name, test_output_file_name)
          else:
              copyfile(input_file_name, train_output_file_name)
              if class_name not in training_classes:
                  training_classes[class_name] = 1
              else:
                  training_classes[class_name] += 1

input_dir = args.input_dataset
train_output_dir = os.path.join(args.output_dir, "Train")
test_output_dir = os.path.join(args.output_dir, "Test")
if not os.path.exists(train_output_dir):
    os.makedirs(train_output_dir)
if not os.path.exists(test_output_dir):
    os.makedirs(test_output_dir)

create_folders(input_dir, train_output_dir, test_output_dir)

#204
#210
#439


from django.forms import Form,ModelForm,widgets, ModelChoiceField,ChoiceField
from .models import *
from django.forms import IntegerField

class PostForm(ModelForm):
    class Meta:
        model=ArticleSheet
        fields=('title','content','tag','type')
        widgets={
            'title':widgets.TextInput(attrs={'placeholder':'title'}),
            'content':widgets.Textarea(attrs={'placeholder':'content'}),
            'tag':widgets.TextInput(attrs={'placeholder':'tag'}),
            'type':widgets.Select(),
        }


import uuid
from django.db import models
from django.contrib.postgres.fields import JSONField, ArrayField

class BrainLocation(models.Model):
    """Gives a brain location in stereotaxic coordinates, plus other information about location."""
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(max_length=255)
    stereotaxic_coordinates = ArrayField(models.FloatField(blank=True, null=True), size=3) # [Anterior, Right, Down], relative to bregma in µm
    description = models.TextField() # e.g. area, layer, comments on how estimated
    allen_location_ontology = models.CharField(max_length=255, null=True, blank=True) # using their vocabulary

    def __str__(self):
        return self.name

class CoordinateTransformation(models.Model):
    """
    This defines how to convert from a local coordinate system (e.g. of a silicon probe) to stereotaxic coordinates.
    It is an affine transformation:
    stereotaxic_coordinates = origin + transformation_matrix*local_coordinates.
    The decription and allen_location_ontology apply to the coordinate origin (e.g. electrode tip).
    """
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(max_length=255)
    description = models.TextField(null=True, blank=True)
    allen_location_ontology = models.CharField(max_length=1000)

    origin = ArrayField(models.FloatField(blank=True, null=True), size=3)
    transformation_matrix = ArrayField(ArrayField(models.FloatField(blank=True, null=True), size=3), size=3)

    def __str__(self):
        return self.name


#%%
'''
If we use (external) classification evalutation measures like F1 or
accuracy for clustering evaluation, problems may arise.
One way to fix is to perform label matching.
Here we performs kmeans clustering on the Iris dataset and proceed to use
the Hungarian (Munkres) algorithm to correct the mismatched labeling.
'''

import sys
import numpy as np
from sklearn.cluster import KMeans
from sklearn import datasets
from sklearn.metrics import confusion_matrix
from sklearn.preprocessing import scale

from munkres import Munkres

def make_cost_matrix(c1, c2):
    """
    """
    uc1 = np.unique(c1)
    uc2 = np.unique(c2)
    l1 = uc1.size
    l2 = uc2.size
    assert(l1 == l2 and np.all(uc1 == uc2))

    m = np.ones([l1, l2])
    for i in range(l1):
        it_i = np.nonzero(c1 == uc1[i])[0]
        for j in range(l2):
            it_j = np.nonzero(c2 == uc2[j])[0]
            m_ij = np.intersect1d(it_j, it_i)
            m[i,j] =  -m_ij.size
    return m

def translate_clustering(clt, mapper):
    return np.array([ mapper[i] for i in clt ])

def accuracy(cm):
    """computes accuracy from confusion matrix"""
    return np.trace(cm, dtype=float) / np.sum(cm)

def compute():
    """entry point"""
    from sklearn.datasets import fetch_openml
    data, classes = fetch_openml('mnist_784', version=1, return_X_y=True, data_home='mnist/')
    classes = np.asarray(list(map(int, classes)))
    data = np.asarray(data.astype(float))
    data = scale(data)
    algo = KMeans(n_clusters=10, random_state = 0)
    labels = algo.fit(data).labels_ # performs the algo and get the predicted labels
    num_labels = len(np.unique(classes))
    cm = confusion_matrix(classes, labels, labels=range(num_labels)) # gets the confusion matrix
    cost_matrix = make_cost_matrix(labels, classes)
    m = Munkres()
    indexes = m.compute(cost_matrix)
    mapper = { old: new for (old, new) in indexes }
    new_labels = translate_clustering(labels, mapper)
    new_cm = confusion_matrix(classes, new_labels, labels=range(num_labels))
    acc = accuracy(new_cm)
    return acc, new_cm, mapper
#%%
acc, new_cm, mapper = compute()

# %%


import json
import requests
from decouple import config

series = json.load(open("series.json"))

request_url = config("SERIES_URL") + "series" + "?api-key=" + config("SERIES_API_KEY")

for serie in series:
    title = serie['title']
    data = json.dumps({
        'tvdbId': serie['tvdbId'],
        'title': serie['title'],
        'profileId': serie['profileId'],
        'titleSlug': serie['titleSlug'],
        'images': serie['images'],
        'seasons': serie['seasons'],
        'seasonFolder': serie['seasonFolder'],
        'monitored': serie['monitored'],
        'path': serie['path'],
    })
    response = requests.post(url=request_url, data=data)
    if response.status_code is not 201:
        print(f'Failed to add \'{title}\'')
        print(response.text)
    else:
        print(f'Added \'{title}\'')


#!/usr/bin/env python
# (C) 2017 OpenEye Scientific Software Inc. All rights reserved.
#
# TERMS FOR USE OF SAMPLE CODE The software below ("Sample Code") is
# provided to current licensees or subscribers of OpenEye products or
# SaaS offerings (each a "Customer").
# Customer is hereby permitted to use, copy, and modify the Sample Code,
# subject to these terms. OpenEye claims no rights to Customer's
# modifications. Modification of Sample Code is at Customer's sole and
# exclusive risk. Sample Code may require Customer to have a then
# current license or subscription to the applicable OpenEye offering.
# THE SAMPLE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED.  OPENEYE DISCLAIMS ALL WARRANTIES, INCLUDING, BUT
# NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. In no event shall OpenEye be
# liable for any damages or liability in connection with the Sample Code
# or its use.
# @ <SNIPPET>
from openeye import oechem

# @ <SNIPPET>
tag = "SCREEN_DATA"
mol = oechem.OEGraphMol()
oechem.OESmilesToMol(mol, "c1ccccc1")

screen = oechem.OESubSearchScreen()
oechem.OEMakeSubSearchTargetScreen(screen, mol, oechem.OESubSearchScreenType_Molecule)

mol.SetData(tag, screen)
s = mol.GetData(tag)
stype = s.GetScreenType()
print("molecule has `{}` with `{}` identifier".format(stype.GetName(), tag))

# @ </SNIPPET>


from mibuild.generic_platform import *
from mibuild.xilinx.common import CRG_DS
from mibuild.xilinx.vivado import XilinxVivadoPlatform

_io = [
	("sys_clk", 0, Pins("X")),
	("sys_rst", 1, Pins("X")),

	("sata", 0,
		Subsignal("refclk_p", Pins("C8")),
		Subsignal("refclk_n", Pins("C7")),
		Subsignal("txp", Pins("D2")),
		Subsignal("txn", Pins("D1")),
		Subsignal("rxp", Pins("E4")),
		Subsignal("rxn", Pins("E3")),
	),
]

class Platform(XilinxVivadoPlatform):
	def __init__(self, crg_factory=lambda p: CRG_DS(p, "clk200", "cpu_reset"), **kwargs):
		XilinxVivadoPlatform.__init__(self, "xc7k325t-ffg900-2", _io, crg_factory)

	def do_finalize(self, *args, **kwargs):
		pass


from system.models import Configuration
from util import get_credentials_for, GetCredentialException
from dbaas_credentials.models import CredentialType
from physical.models import Environment

def external_links(request):
    iaas_status = Configuration.get_by_name('iaas_status')
    iaas_quota = Configuration.get_by_name('iaas_quota')

    try:
        credential = get_credentials_for(
            environment=Environment.objects.first(),
            credential_type=CredentialType.GRAFANA
        )

        sofia_dashboard = "{}/{}?var-datasource={}".format(
            credential.endpoint,
            credential.get_parameter_by_name('sofia_dbaas_dashboard'),
            credential.get_parameter_by_name('datasource')
        )
    except (IndexError, GetCredentialException):
        sofia_dashboard = ""

    return {'iaas_status': iaas_status,
            'iaas_quota': iaas_quota,
            'sofia_main_dashboard': sofia_dashboard}


from auto_yolo import envs
from auto_yolo.models import yolo_air

readme = "Running YOLO AIR experiment."

distributions = [
    dict(
        n_digits=n_digits,
        min_digits=n_digits,
        max_digits=n_digits,
        max_time_steps=n_digits)
    for n_digits in [1, 3, 5, 7, 9]]

durations = dict(
    long=dict(
        max_hosts=1, ppn=16, cpp=1, gpu_set="0,1,2,3", wall_time="36hours",
        project="rpp-bengioy", cleanup_time="10mins",
        slack_time="10mins", n_repeats=6, step_time_limit="36hours"),

    build=dict(
        max_hosts=1, ppn=1, cpp=2, gpu_set="0", wall_time="20mins",
        project="rpp-bengioy", cleanup_time="2mins",
        slack_time="2mins", n_repeats=1, step_time_limit="20mins",
        config=dict(do_train=False)),

    short=dict(
        max_hosts=1, ppn=3, cpp=2, gpu_set="0", wall_time="30mins",
        project="rpp-bengioy", cleanup_time="2mins",
        slack_time="2mins", n_repeats=1, config=dict(max_steps=100))
)

config = dict(
    curriculum=[dict()],
    n_train=64000,
    stopping_criteria="AP,max", threshold=0.99, patience=50000,
    render_hook=yolo_air.YoloAir_RenderHook(),
)

envs.run_experiment(
    "yolo_air_run", config, readme, distributions=distributions,
    alg="yolo_air_conv", task="arithmetic", durations=durations,
)


import matplotlib.pylab as plt
import numpy as np
import os
import sklearn
from sklearn.metrics import classification_report, confusion_matrix, accuracy_score
from sklearn.model_selection import  KFold
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
import pandas as pd
import itertools
from utils import plot_confusion_matrix
from sklearn.decomposition import PCA

# Set the number of decimal houses to show when printing
np.set_printoptions(precision = 2)

# Path to CSV feature file  - 'Neuroimaging', 'Clinical',   'Neuroimaging' + 'Clinical'
data_path = "./procan_ml_input_04.csv"

# Loading data
missing_values = ["NaN"]
df = pd.read_csv(data_path, header = None,na_values = missing_values)
data = df.apply(pd.to_numeric, errors='coerce').values

# Splitting features and labels into to arrays
feats = data[:,:-1]
labels = data[:,-1].astype(int)

#Obtain mean of columns as you need disregarding NaN values
col_mean = np.nanmean(feats, axis=0)

# Remove samples with more than  25 features
to_remove = ~((np.isnan(feats).sum(axis = 1)) > 25 )
feats = feats[to_remove]
labels = labels[to_remove]

#Find indicies that you need to replace
inds = np.where(np.isnan(feats))

#Place column means in the indices. Align the arrays using take
feats[inds] = np.take(col_mean, inds[1])

print("Number of samples:", feats.shape[0])
print("Number of features per sample:", feats.shape[1])
print("Number of classes:", np.unique(labels).size)
print("Classes:", np.unique(labels))
for ii in np.unique(labels):
    print("Number of samples class %d: %d" %(ii,(labels == ii).sum()))

# Remove features which are the same for all samples
indexes = np.where(feats.max(axis = 0) == 0)
print(indexes)

feats = np.delete(feats,indexes,axis = 1)

# Let's look into principal components
# Min-max normalization
feats_norm = (feats - feats.min(axis = 0))/(feats.max(axis = 0) - feats.min(axis = 0))
pca = PCA(n_components=5)
pca.fit(feats_norm)
print("Explained variange by each PCA component: \n", pca.explained_variance_ratio_)
feats_2d = pca.transform(feats_norm)

plt.figure(dpi = 300)
plt.scatter(feats_2d[labels==0,0],feats_2d[labels==0,1],marker="x",c = "y")
plt.scatter(feats_2d[labels==1,0],feats_2d[labels==1,1],marker="o",c = "g")
plt.scatter(feats_2d[labels==2,0],feats_2d[labels==2,1],marker="^",c = "b")
plt.scatter(feats_2d[labels==3,0],feats_2d[labels==3,1],marker="d",c = "r")
plt.xlabel("PCA 1 - explained variance - %f" %pca.explained_variance_ratio_[0])
plt.ylabel("PCA 2 - explained variance - %f" %pca.explained_variance_ratio_[1])
plt.grid()
plt.show()

# Cross-validation parameters
nfolds = labels.size # Leave-one-out cross-validation
nfolds2 = 4 # Inner number of folds in the cross-validation

# Compute confusion matrix
class_names = ['0','1','2','3'] # Name for the labels: control, risk 01, risk 02

# Variable to store the confusion matrix
cm = np.zeros((4,4),dtype = int)

# Random Forest
feature_importance = np.zeros((nfolds,feats.shape[1]))

# Grid Search parameters
# Number of trees in random forest
n_estimators = [80]#10,20,40,80]
# Number of features to consider at every split
max_features = ['auto']#, 'sqrt']
# Maximum number of levels in tree
max_depth = [int(x) for x in np.linspace(10, 110, num = 16)]
max_depth.append(None)
# Minimum number of samples required to split a node
min_samples_split = [2, 5, 10]
# Minimum number of samples required at each leaf node
min_samples_leaf = [1, 2, 4]
# Method of selecting samples for training each tree
bootstrap = [True, False]

random_grid = {'n_estimators': n_estimators,
               'max_features': max_features,
               'max_depth': max_depth,
               'min_samples_split': min_samples_split,
                'min_samples_leaf': min_samples_leaf,
               'bootstrap': bootstrap}

# K-fold cross-validation
skf = KFold(n_splits = nfolds,shuffle=True)
counter = 0
counter2 = 0
accu = np.zeros(nfolds)
yp = np.zeros(feats.shape[0])
yt = np.zeros(feats.shape[0])

for train_index, test_index in skf.split(feats):
    # Split train and test sets
    X_train, X_test = feats[train_index], feats[test_index]
    y_train, y_test = labels[train_index], labels[test_index]

    # Grid search
    clf = GridSearchCV(RandomForestClassifier(), random_grid, cv=nfolds2,
                       scoring='accuracy')
    clf.fit(X_train, y_train)

    # Best model in the grid search
    clf = clf.best_estimator_

    # Prediction and label storage
    y_pred = clf.predict(X_test)
    yp[counter:counter+test_index.size] = y_pred
    yt[counter:counter+test_index.size] = y_test
    accu[counter2] = accuracy_score(y_test,y_pred)
    counter2+=1
    counter+=test_index.size

cm = confusion_matrix(yp,yt)
print("Average accuracy: %f +/- %f" %(accu.mean(),accu.std()))

# Plot normalized confusion matrix
plt.figure(dpi =300)
plot_confusion_matrix(cm, classes=class_names, normalize=True,
                     title='Normalized confusion matrix')
plt.show()

# Plot non-normalized confusion matrix
plt.figure(dpi =300)
plot_confusion_matrix(cm, classes=class_names, normalize=False,
                      title='Normalized confusion matrix')
plt.show()

# ## Features Importance
clf = GridSearchCV(RandomForestClassifier(),random_grid,cv=nfolds2,scoring='accuracy')
clf.fit(feats, labels)
clf = clf.best_estimator_

fi = clf.feature_importances_

#Plotting 10 most important features
indices = np.argsort(fi)[::-1]
plt.figure()
plt.title("Feature importances")
plt.plot(fi[indices][0:10])
plt.xticks(range(10), indices[:10])
plt.xlim([-1, 10])
plt.show()
print(indices[:10].sum())