#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
# Created by thomas on 2015/8/25
#

from django.core.management.base import BaseCommand
from store.models import Shop, Goods, Category
from exceltojson import excel2json, utils
from django.contrib.auth.models import User
from datetime import datetime

class Command(BaseCommand):
    help = '将给定的表，导入到数据库当中'

    def _format_time(self, str_time):
        return datetime.strptime(str_time, '%Y/%m/%d')

    def add_arguments(self, parser):
        parser.add_argument(
            '-p', '--path',
            dest='excel_path',
            help='需要导入到数据库的 excel 文件路径'
        )

    def handle(self, *args, **options):
        path = options['excel_path']
        sheet = utils.get_sheets(path)[0]
        alais = {'商品名称': 'good_name', '库存量': 'remain', '单位': 'unit',
                 '售价': 'sell_price', '所属类别': 'category', '有效期': 'time',
                 '供货商': 'shop', '进价': 'average_price'}
        sheet_process = excel2json._SheetProcess(sheet, alias=alais, merge_cell=False)
        shops = set()
        cates = set()
        add_people = User.objects.all()[0]
        goods = set()

        try:
            default_cate = Category.objects.get(name='未分类商品')
        except Exception as e:
            default_cate = Category.objects.create(name='未分类商品')

        for data in sheet_process():
            print('index--------' + str(data[0]))
            details = data[1]
            try:
                if not details['shop'].strip():
                    s = None
                else:
                    s = Shop.objects.get(shop_name=details['shop'])
                    if details['shop'] in shops:
                        pass
                    else:
                        print('已存在供货商: '+details['shop'])
            except Exception as e:
                s = Shop.objects.create(shop_name=details['shop'])
                shops.add(details['shop'])

            try:
                if not details['category'].strip():
                    cate = default_cate
                else:
                    cate = Category.objects.get(name=details['category'])
                    if details['category'] not in cates:
                        print('已存在类别: ' + details['category'])
            except Exception as e:
                cate = Category.objects.create(name=details['category'])
                cates.add(details['category'])

            try:
                Goods.objects.get(goods_name=details['good_name'])
                if details['good_name'] not in goods:
                    print('已存在商品: ' + details['good_name'])
            except Exception as e:
                try:
                    ap = 0 if not details['average_price'].strip() else float(details['average_price'])
                    lp = 0 if not details['sell_price'].strip() else float(details['sell_price'])
                    rm = 0 if not details['remain'].strip() else int(float(details['remain']))
                    time = self._format_time('2017/10/30') if not details['time'].strip() else self._format_time(details['time'])
                    print(details['average_price'])
                    print(details['sell_price'])
                    print(details['remain'])
                    g = Goods.objects.create(
                        goods_name=details['good_name'],
                        average_price=ap,
                        last_price=lp,
                        unit_name=details['unit'],
                        add_people=add_people,
                        remain=rm,
                        last_time=time,
                        shop=s
                    )

                    g.category.add(cate)
                    goods.add(details['good_name'])
                except Exception as e:
                    print(str(e))
                    print(data[1])
                    break


from const import NORMAL_FLOW, END_OF_CONSTRUCT, WHILE_CLAUSE
from decompile.constructs.conditionals import \
	update_next_indexes_of_conditional, update_pop_clauses_of_conditional

BEFORE_SETUP_LOOP = 0
AFTER_SETUP_LOOP = 1

def turn_if_to_while(elem, next_index_in_sequence):
	elem['mnemo'] = 'WHILE_LOOP'
	# we must also update the clauses describing this construct
	jump_clause, forward_clause = (END_OF_CONSTRUCT, WHILE_CLAUSE)
	pop_cond = elem['pop_cond']
	forward_index = next_index_in_sequence
	jump_index = elem['jump_index']
	update_next_indexes_of_conditional(elem,
			jump_clause, jump_index, forward_clause, forward_index)
	update_pop_clauses_of_conditional(elem, pop_cond, jump_clause, forward_clause)

def recognise_while_loops(asm_indexes, indexed_asm):
	while_loop_indexes = []
	state = BEFORE_SETUP_LOOP
	for i in range(len(asm_indexes)):
		index = asm_indexes[i]
		elem = indexed_asm[index]
		mnemo = elem['mnemo']
		if state == BEFORE_SETUP_LOOP:
			if mnemo == 'SETUP_LOOP':
				state = AFTER_SETUP_LOOP
				loop_index = None
		else:
			if loop_index == None:
				loop_index = index # the index just after SETUP_LOOP
			if mnemo == 'FOR_LOOP':
				# this is actually a for loop, not while, give up
				state = BEFORE_SETUP_LOOP
			elif mnemo == 'IF_CONSTRUCT' and \
				'forced_index' not in elem:
				# this is actually a while loop! :)
				while_loop_indexes.append(loop_index)
				next_index_in_sequence = asm_indexes[i+1]
				turn_if_to_while(elem, next_index_in_sequence)
				state = BEFORE_SETUP_LOOP # done, look for next one
	for elem in indexed_asm.values():
		if 		elem['mnemo'] == 'JUMP_ABSOLUTE' and \
				elem['next_indexes'][NORMAL_FLOW] in while_loop_indexes:
			#print '#Changing a jump to %d into a "continue" instruction' % elem['next_indexes'][NORMAL_FLOW]
			elem['mnemo'] = 'CONTINUE'
			elem['next_indexes'] = {}


def countingValleys(n, s):
    count=base=0
    for i in s:
        if i=="D":
            count-=1
        else:
            count+=1
        if count==0 and i=="U":
            base+=1
    print(base)

countingValleys(8,"UDDDUDUU")


import cv2
import numpy as np
from skimage.filters import unsharp_mask

def get_labels(preprocessings):
    labels = ['nenhum', 'bilateral', 'clahe',
              'unsharp_mask', 'tophat', 'eqHist']

    return [labels[pre] for pre in preprocessings]

def params_labels():
    return ['sigma_color', 'sigma_space', 'clip_limit', 'tile_grid', 'radius', 'amount']

def chromossome_labels(chromossome):
    return get_labels(chromossome[:3])+params_labels()

def chromossome_values(chromossome):
    return get_labels(chromossome[:3])+chromossome[3:]

def normalize(image):

    return (image - np.min(image))/255

def apply3(id, image, sigma_color, sigma_space, clip_limit, tile_grid, radius, amount):
    tile_grid = int(tile_grid)
    radius = int(radius)
    amount = int(amount)
    for i in range(0, image.shape[2]):
        image[:, :, i] = apply(
            id, image[:, :, i], sigma_color, sigma_space, clip_limit, tile_grid, radius, amount)

    return image

def apply(id, image, sigma_color=0.5, sigma_space=0.5, clip_limit=0.5, tile_grid=30, radius=1, amount=1):
    kernel = (3, 3)
    if id == 0:
        pass  # não aplica nada
    elif id == 1:
        image = np.asarray(image, np.float32)
        image = cv2.bilateralFilter(image, -1, sigma_color, sigma_space)
    elif id == 2:
        image *= 255
        image = np.asarray(image, np.uint8)
        clahe = cv2.createCLAHE(clipLimit=clip_limit,
                                tileGridSize=(tile_grid, tile_grid))
        image = clahe.apply(image)
        image = normalize(image)
    elif id == 5:
        image *= 255
        image = np.asarray(image, np.uint8)
        image = cv2.equalizeHist(image)
        image = normalize(image)
    elif id == 4:

        filterSize = (3, 3)
        kernel = cv2.getStructuringElement(cv2.MORPH_RECT,
                                           filterSize)
        image -= cv2.morphologyEx(image,
                                  cv2.MORPH_TOPHAT,
                                  kernel)
    elif id == 3:
        image = unsharp_mask(image, radius=radius, amount=amount)
    return image

def apply_preprocessing_list(image, params):
    list_pre = params[:3]
    pre_params = params[3:]
    for i in range(0, len(list_pre)):
        image = apply3(list_pre[i], image, sigma_color=pre_params[0],
                       sigma_space=pre_params[1], clip_limit=pre_params[2], tile_grid=pre_params[3], radius=pre_params[4], amount=pre_params[5])

    return image

if __name__ == '__main__':
    import matplotlib.pyplot as plt

    path = r'E:\DoutoradoLuana\datasets\gerados\Kits19_25D_with_tumor_masks\KiTS19_master_npz\case_00004\Images\case_00004-25.npz'

    im = np.load(path)
    im = im['arr_0']
    im = im.transpose(1, 2, 0)
    # im = apply(8, im)

    im = apply_preprocessing_list(
        im,  [4, 3, 4, 0.6830141089425715, 0.7784288771611926, 0.4676658223643955, 16, 6, 1])

    # print(im.max())
    # print(im.shape)
    plt.imshow(im[:, :, 0], cmap='gray')
    plt.show()


# -*- coding: utf-8 -*-
"""
Created on Wed Sep 15 16:16:18 2021

@author: annas
This script averages gene expressions for GenCode IDs which correspond to the same gene name.
"""

#Create a dictionary where the keys corresponds to gene names and the
#values corresponds to a list of lists of gene expressions for each gene name
def make_expression_dict(filename):
    dict_expression = {}
    #Read each line in the file
    for line in filename:
        #Convert line to list of strings
        split_line = line.rstrip().split('\t') #Split the line
        #First element in the line is the gene name
        gene_name = split_line[0]

        #Add the other elements in the line to a list of gene expressions
        expressions = []
        for i in range(1, len(split_line)):
            expressions.append(float(split_line[i]))
        try:
            dict_expression[gene_name].append(expressions)
        except:
            dict_expression[gene_name] = [expressions]
    return dict_expression

#Average expression values for gene names which correspond to more than one
    #gene names. Write the values directly to file.

def average_expressions(dict_expressions, outfile):
    #Go through each key in the input dictonary.
    for key in dict_expressions:
        outfile.write(key)

        #If the gene is unique, we keep the values from dict_expressions and
        #write them directly to the output file
        if len(dict_expressions[key]) == 1:
            for val in dict_expressions[key]:
                for el in val:
                    outfile.write('\t' + str(el))

        #If the gene is nonuniqe, calculate the average expressions
        else:
            for i in range(0, len(dict_expressions[key][0])):
                average = 0
                for j in range(0, len(dict_expressions[key])):
                    average += dict_expressions[key][j][i]
                average /= len(dict_expressions[key])
                outfile.write('\t'+str(average))
        outfile.write('\n')

#--------------------------------------------------------------#
"""Edit here"""
#Read files
infile = open("gene_names_not_sun.txt")
outfile = open("averaged_gene_names_not_sun.txt", 'w')

#Copy first line in infile to outfile
outfile.write(infile.readline())

#Create dictionary with gene names and list of expression values
dict_expression = make_expression_dict(infile)

#Write gene names and averaged expression values to out_files
average_expressions(dict_expression, outfile)

#Close files
infile.close()
outfile.close()


import sys
import pyqtgraph as pg
from PyQt5 import QtCore, QtGui, QtWidgets
from pyqtgraph.widgets.MatplotlibWidget import MatplotlibWidget
from core.gui_utils import validate_session, Communicate, validate_cut, find_tetrodes
from core.default_parameters import project_name, default_filename, defaultXAxis, defaultYAxis, defaultZAxis, openGL, \
    default_move_channel, max_spike_plots, alt_action_button
# from core.Tint_Matlab import find_tetrodes
from core.plot_functions import plot_session, cut_cell, get_index_from_roi
from core.waveform_cut_functions import moveToChannel, maxSpikesChange
from core.undo import undo_function
from core.feature_plot import feature_name_map
from core.PopUpCutting import PopUpCutWindow
from core.writeCut import write_cut, write_clu
import pyqtgraph.opengl as gl
import os
import json
import time
import numpy as np

version = "1.1.0"

class MainWindow(QtWidgets.QWidget):

    def __init__(self):
        """
        initializes many of the variables
        """
        super(MainWindow, self).__init__()

        self.setWindowTitle("%s - Main Window" % project_name)  # sets the main window title

        # initializing attributes
        self.plotted_tetrode = None
        self.change_set_with_tetrode = True
        self.multiple_files = False
        self.cut_filename = None
        self.choose_cut_filename_btn = None
        self.feature_win = None
        self.quit_btn = None
        self.filename = None
        self.choose_filename_btn = None
        self.x_axis_cb = None
        self.y_axis_cb = None
        self.z_axis_cb = None
        self.tetrode_cb = None
        self.choice = None  # the current choice for the error popups
        self.plot_btn = None
        self.feature_plot = None

        # initialize list of actions to undo
        self.latest_actions = {}

        # bool for if an action has been made, I suppose we could take the length of the actions attribute
        self.actions_made = False

        # bool representing if the user is dragging the mouse (for drawing the line segments on the graphs)
        self.drag_active = False

        # the graph index that was last dragged upon with the mouse
        self.last_drag_index = None

        self.feature_data = None
        self.tetrode_data = None
        self.tetrode_data_loaded = False
        self.cut_data = None
        self.cut_data_loaded = False
        self.cut_data_original = None
        self.spike_times = None
        self.scatterItem = None
        self.glViewWidget = None
        self.feature_plot_added = False
        self.samples_per_spike = None

        # keep a list of the positions that the cells are plotted in
        self.unit_positions = {}

        # not all the spikes are plotted at once, so we will keep a dict of which subsample is plotted
        self.cell_subsample_i = {}

        self.unit_drag_lines = {}
        self.active_ROI = []
        self.unit_data = {}

        self.xline = None
        self.yline = None
        self.zline = None

        self.max_spike_plots = None

        self.n_channels = None

        self.invalid_channel = None

        self.cell_indices = {}

        self.spike_colors = None

        self.original_cell_count = {}

        self.unit_plots = {}
        self.vb = {}
        self.plot_lines = {}
        self.avg_plot_lines = {}
        self.unit_rows = 0
        self.unit_cols = 0

        self.LogError = Communicate()
        self.LogError.signal.connect(self.raiseError)

        # various setting files
        project_dir = os.path.dirname(os.path.abspath("__file__"))
        if os.path.basename(project_dir) != project_name:
            project_dir = os.path.dirname(sys.argv[0])

        # defining the directory filepath
        self.PROJECT_DIR = project_dir  # project directory
        self.SETTINGS_DIR = os.path.join(self.PROJECT_DIR, 'settings')  # settings directory

        self.settings_filename = os.path.join(self.SETTINGS_DIR, 'settings.json')
        self.settings = self.get_settings()

        self.IMG_DIR = os.path.join(self.PROJECT_DIR, 'img')  # settings directory

        # create Settings Directory
        if not os.path.exists(self.SETTINGS_DIR):
            os.mkdir(self.SETTINGS_DIR)

        # create settings file
        if not os.path.exists(self.settings_filename):
            with open(self.settings_filename, 'w') as f:
                json.dump({}, f)

        # setting PyQtGraph settings
        pg.setConfigOptions(antialias=True)

        self.PopUpCutWindow = {}

        QtWidgets.QApplication.setStyle(QtWidgets.QStyleFactory.create('GTK+'))

        self.setWindowIcon(QtGui.QIcon(os.path.join(self.IMG_DIR, 'GEBA_Logo.png')))  # declaring the icon image
        self.initialize()  # initializes the main window

    def keyPressEvent(self, event):
        """
        This method will occur when the main window is on top and the user presses a button

        :param event:
        :return:
        """
        if type(event) == QtGui.QKeyEvent:
            # here accept the event and do something
            if event.key() == alt_action_button:
                # check if there is a popup that is shown
                if len(self.PopUpCutWindow) > 0:
                    pass

                if len(self.active_ROI) == 1:
                    # get the index
                    index = get_index_from_roi(self, self.active_ROI[0])
                    cut_cell(self, index)
                elif len(self.active_ROI) > 1:
                    # there shouldn't be more than 1 ROI open
                    self.active_ROI = self.active_ROI[-1]
                    index = get_index_from_roi(self, self.active_ROI[0])
                    # this shouldn't happen, lets remove all the ROI's
                    cut_cell(self, index)

            event.accept()
        else:
            event.ignore()

    def isPopup(self):
        """
        This function is is for the cutting functionality as it will tell the cut function that it is not a popup
        window, and thus to treat it as such.
        """
        return False

    def initialize(self):
        """
        This method will initialize the Main Window, create all the widgets and what not
        :return:
        """

        # ---------------- session filename options ------------------------------------------

        filename_grid_layout = QtWidgets.QGridLayout()

        filename_label = QtWidgets.QLabel("Filename:")
        self.filename = QtWidgets.QLineEdit()
        self.filename.setText(default_filename)
        self.filename.textChanged.connect(self.filename_changed)
        self.filename.setToolTip('The name of the session that you will analyze in gebaSpike!')
        self.choose_filename_btn = QtWidgets.QPushButton("Choose Filename")
        self.choose_filename_btn.setToolTip('This button will allow you to choose the filename to analyze!')
        self.choose_filename_btn.clicked.connect(self.choose_filename)

        filename_grid_layout.addWidget(self.choose_filename_btn, *(0, 0))
        filename_grid_layout.addWidget(filename_label, *(0, 1), QtCore.Qt.AlignRight)

        # ------------------- cut filename options ---------------------------------

        cut_filename_label = QtWidgets.QLabel("Cut Filename:")
        self.cut_filename = QtWidgets.QLineEdit()
        self.cut_filename.setText(default_filename)
        self.cut_filename.setToolTip('The name of the cut file containing the sorted values!')
        self.choose_cut_filename_btn = QtWidgets.QPushButton("Choose Cut Filename")
        self.choose_cut_filename_btn.setToolTip('This button will allow you to choose a cut file to use!')
        self.choose_cut_filename_btn.clicked.connect(self.choose_cut_filename)

        line_edit_layout = QtWidgets.QVBoxLayout()
        line_edit_layout.addWidget(self.filename)
        line_edit_layout.addWidget(self.cut_filename)

        filename_grid_layout.addWidget(self.choose_cut_filename_btn, *(1, 0))
        filename_grid_layout.addWidget(cut_filename_label, *(1, 1), QtCore.Qt.AlignRight)

        filename_grid_layout.addLayout(line_edit_layout, *(0, 2), 2, 1)

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

        max_spike_label = QtWidgets.QLabel("Max Plot Spikes:")
        self.max_spike_plots_text = QtWidgets.QLineEdit()
        self.max_spike_plots_text.setToolTip("This is the maximum number of spikes to plot.")
        self.max_spike_plots_text.setText(str(max_spike_plots))
        self.max_spike_plots_text.textChanged.connect(lambda: maxSpikesChange(self, 'main'))

        max_spikes_layout = QtWidgets.QHBoxLayout()
        max_spikes_layout.addWidget(max_spike_label)
        max_spikes_layout.addWidget(self.max_spike_plots_text)

        # ------- move invalid -----------

        move_to_channel_label = QtWidgets.QLabel("Move to Cell:")
        self.move_to_channel = QtWidgets.QLineEdit()
        self.move_to_channel.setToolTip("This is the channel that you will move selected cells too.")
        self.move_to_channel.setText(default_move_channel)
        self.move_to_channel.textChanged.connect(lambda: moveToChannel(self, 'main'))

        move_to_channel_layout = QtWidgets.QHBoxLayout()
        move_to_channel_layout.addWidget(move_to_channel_label)
        move_to_channel_layout.addWidget(self.move_to_channel)

        # -------- spike parameter options -------------------------------------

        feature_options = ["None"] + list(feature_name_map.keys())

        spike_parameter_layout = QtWidgets.QHBoxLayout()
        x_axis_label = QtWidgets.QLabel("X-Axis")
        self.x_axis_cb = QtWidgets.QComboBox()
        for option in feature_options:
            self.x_axis_cb.addItem(option)
        self.x_axis_cb.setCurrentIndex(self.x_axis_cb.findText(defaultXAxis))

        self.x_axis_cb.setToolTip("Choose a feature to plot on the X-Axis")

        x_axis_layout = QtWidgets.QHBoxLayout()
        x_axis_layout.addWidget(x_axis_label)
        x_axis_layout.addWidget(self.x_axis_cb)

        y_axis_label = QtWidgets.QLabel("Y-Axis")
        self.y_axis_cb = QtWidgets.QComboBox()
        self.y_axis_cb.setToolTip("Choose a feature to plot on the Y-Axis")
        for option in feature_options:
            self.y_axis_cb.addItem(option)
        self.y_axis_cb.setCurrentIndex(self.y_axis_cb.findText(defaultYAxis))

        y_axis_layout = QtWidgets.QHBoxLayout()
        y_axis_layout.addWidget(y_axis_label)
        y_axis_layout.addWidget(self.y_axis_cb)

        z_axis_label = QtWidgets.QLabel("Z-Axis")
        self.z_axis_cb = QtWidgets.QComboBox()
        self.z_axis_cb.setToolTip("Choose a feature to plot on the Z-Axis")
        for option in feature_options:
            self.z_axis_cb.addItem(option)
        self.z_axis_cb.setCurrentIndex(self.z_axis_cb.findText(defaultZAxis))

        z_axis_layout = QtWidgets.QHBoxLayout()
        z_axis_layout.addWidget(z_axis_label)
        z_axis_layout.addWidget(self.z_axis_cb)

        axis_layout = QtWidgets.QHBoxLayout()
        axis_layout.addLayout(x_axis_layout)
        axis_layout.addLayout(y_axis_layout)
        axis_layout.addLayout(z_axis_layout)

        tetrode_layout = QtWidgets.QHBoxLayout()
        tetrode_label = QtWidgets.QLabel("Tetrode:")
        self.tetrode_cb = QtWidgets.QComboBox()
        self.tetrode_cb.currentIndexChanged.connect(self.tetrode_changed)
        tetrode_layout.addWidget(tetrode_label)
        tetrode_layout.addWidget(self.tetrode_cb)

        spike_parameter_widgets = [tetrode_layout, axis_layout, move_to_channel_layout, max_spikes_layout]

        spike_parameter_layout.addStretch(1)
        for i, widget in enumerate(spike_parameter_widgets):
            if 'Layout' in widget.__str__():
                spike_parameter_layout.addLayout(widget)
                spike_parameter_layout.addStretch(1)
            else:
                spike_parameter_layout.addWidget(widget, 0, QtCore.Qt.AlignCenter)
                spike_parameter_layout.addStretch(1)

        if openGL:
            self.feature_win = pg.GraphicsWindow()
            feature_win_layout = QtWidgets.QGridLayout()
            self.feature_win.setLayout(feature_win_layout)
            self.glViewWidget = gl.GLViewWidget()
            self.glViewWidget.setBackgroundColor('k')

            feature_win_layout.addWidget(self.glViewWidget)
        else:
            self.feature_win = MatplotlibWidget()
            self.feature_win.toolbar.hide()  # hide the toolbar

        self.unit_win = pg.GraphicsWindow()

        plot_layout = QtWidgets.QHBoxLayout()
        for _object in [self.feature_win, self.unit_win]:
            plot_layout.addWidget(_object)

        # ------------------------------------ version information -------------------------------------------------

        vers_label = QtWidgets.QLabel(f"gebaSpike V{version}")

        # --------- Create the Buttons at the bottom of the Main Window ------------- #

        button_layout = QtWidgets.QHBoxLayout()

        self.plot_btn = QtWidgets.QPushButton("Plot")
        self.plot_btn.clicked.connect(self.plotFunc)

        self.save_btn = QtWidgets.QPushButton("Save Cut")
        self.save_btn.clicked.connect(self.save_function)
        self.save_btn.setToolTip('Save to the current cut file')

        self.undo_btn = QtWidgets.QPushButton("Undo")
        self.undo_btn.clicked.connect(lambda: undo_function(self))
        self.undo_btn.setToolTip('Click to undo previous action!')

        self.quit_btn = QtWidgets.QPushButton("Quit")
        self.quit_btn.clicked.connect(self.close_app)
        self.quit_btn.setShortcut("Ctrl+Q")  # creates shortcut for the quit button
        self.quit_btn.setToolTip('Click to quit gebaSpike!')

        button_order = [self.plot_btn,
                        self.save_btn,
                        self.undo_btn,
                        self.quit_btn]

        for btn in button_order:
            button_layout.addWidget(btn)

        main_window_layout = QtWidgets.QVBoxLayout()

        layout_order = [filename_grid_layout, spike_parameter_layout, plot_layout, button_layout, vers_label]
        # do you want to add stretch to the widgets/layouts within the layout order?
        add_Stretch = [False, False, False, False, False]
        # do you want to center the widgets/layouts within the layout order?
        align_center = [True, True, True, True, False]

        # ---------------- add all the layouts and widgets to the Main Window's layout ------------ #

        # main_window_layout.addStretch(1)  # adds the widgets/layouts according to the order
        for widget, addStretch, alignCenter in zip(layout_order, add_Stretch, align_center):
            if 'Layout' in widget.__str__():
                main_window_layout.addLayout(widget)
                if addStretch:
                    main_window_layout.addStretch(1)
            else:
                if alignCenter:
                    main_window_layout.addWidget(widget, 0, QtCore.Qt.AlignCenter)
                else:
                    main_window_layout.addWidget(widget, 0)
                if addStretch:
                    main_window_layout.addStretch(1)

        self.setLayout(main_window_layout)  # defining the layout of the Main Window

        self.show()  # shows the window

    def addPopup(self, cell):
        """
        This method will modify the self.PopUpCutWindow, so that we keep track of which popup window belongs to which
        cell

        :param cell:
        :return:
        """
        self.PopUpCutWindow[cell] = PopUpCutWindow(self)

    def save_function(self):
        """
        this method will save the .cut file

        :return:
        """
        if self.cut_filename.text() == default_filename:
            return

        save_filename = os.path.realpath(self.cut_filename.text())

        if os.path.exists(save_filename):
            self.choice = None
            self.LogError.signal.emit('OverwriteCut!%s' % save_filename)
            while self.choice is None:
                time.sleep(0.1)

            if self.choice != QtWidgets.QMessageBox.Yes:
                return

        if len(self.tetrode_data) == 0:
            return

        # organize the cut data
        n_spikes_expected = self.tetrode_data.shape[1]
        n_spikes = len(np.asarray([item for sublist in self.cell_indices.values() for item in sublist]))

        # check that with the manipulation of the spikes, that we still have the correct number of spikes
        if n_spikes != n_spikes_expected:
            self.choice = None
            self.LogError.signal.emit('cutSizeError')
            while self.choice is None:
                time.sleep(0.1)
            return

        # we will check if we are missing some of the spikes somehow. If we kept track of them, then the indices from
        # the spikes, when sorted, should produce an array from 0 -> N-1 spikes.
        if not np.array_equal(np.sort(np.asarray([item for sublist in self.cell_indices.values() for item in sublist])),
                          np.arange(len(self.cut_data_original))):
            self.choice = None
            self.LogError.signal.emit('cutIndexError')
            while self.choice is None:
                time.sleep(0.1)
            return

        cut_values = np.zeros(n_spikes)
        for cell, cell_indices in self.cell_indices.items():
            cut_values[cell_indices] = cell

        if '.clu.' in save_filename:
            # save the .clu filename
            write_clu(save_filename, cut_values)
            self.choice = None
            self.LogError.signal.emit('saveCompleteClu')
            while self.choice is None:
                time.sleep(0.1)
            self.actions_made = False

        else:
            # save the cut filename
            write_cut(save_filename, cut_values)
            self.choice = None
            self.LogError.signal.emit('saveComplete')
            while self.choice is None:
                time.sleep(0.1)
            self.actions_made = False

    def close_app(self):
        """This method will prompt the user, asking if they would like to quit or not"""
        # pop up window that asks if you really want to exit the app ------------------------------------------------

        choice = QtWidgets.QMessageBox.question(self, "Quitting ",
                                                "Do you really want to exit?",
                                                QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)

        if choice == QtWidgets.QMessageBox.Yes:
            sys.exit()  # tells the app to quit
        else:
            pass

    def raiseError(self, error):
        """
        This method will be called whenever an error has occurred, and will generally raise Message Box that the user
        will interact with.

        :param error:
        :return:
        """
        if 'TetrodeExistError' in error:
            filename = error.split('!')[1]
            self.choice = QtWidgets.QMessageBox.question(self, "Tetrode Filename Does Not Exist!",
                                                         "The following tetrode filename does not exist: \n%s\nPlease" %
                                                         filename +
                                                         " ensure that the file exists before attempting to plot the"
                                                         " data!",
                                                         QtWidgets.QMessageBox.Ok)

        if 'CutExistError' in error:
            filename = error.split('!')[1]
            self.choice = QtWidgets.QMessageBox.question(self, "Cut/Clu File Exist ERror!",
                                                         "The following .cut/.clu filename does not exist: \n%s\nPlease" %
                                                         filename +
                                                         " ensure that the file exists before attempting to plot the"
                                                         " data!",
                                                         QtWidgets.QMessageBox.Ok)

        elif 'InvalidSession' in error:
            session = error.split('!')[1]
            self.choice = QtWidgets.QMessageBox.question(self, "Invalid Session Filename!",
                                                         "The following session filename is invalid: \n%s\nPlease" %
                                                         session +
                                                         " ensure that the appropriate files exist for this session.",
                                                         QtWidgets.QMessageBox.Ok)

        elif 'InvalidMultiSession' in error:
            cut_spikes = error.split('!')[1]
            tetrode_spikes = error.split('!')[2]
            self.choice = QtWidgets.QMessageBox.question(self, "Invalid Multi Sessions!",
                                                         "You are choosing to combine multiple session files! The "
                                                         "chosen .cut filename (with the current tetrode) has " + str(
                                                         cut_spikes) + " spikes"
                                                         " whereas the combined tetrode spikes for the chosen session "
                                                         "files add up to " + tetrode_spikes + " spikes! Make sure you "
                                                         "choose the correct .cut file for the chosen .set files!",
                                                         QtWidgets.QMessageBox.Ok)

        elif 'cutIndexError' in error:
            self.choice = QtWidgets.QMessageBox.question(self, "Cut Index Error!",
                                                         "The cut output is missing some of the spikes!",
                                                         QtWidgets.QMessageBox.Ok)

        elif 'cutSizeError' in error:
            self.choice = QtWidgets.QMessageBox.question(self, "Cut Size Error!",
                                                         "Trying to save an inappropriate number of spikes, cannot " +
                                                         "save cut file!",
                                                         QtWidgets.QMessageBox.Ok)

        elif 'InvalidCut' in error:
            session = error.split('!')[1]
            self.choice = QtWidgets.QMessageBox.question(self, "Invalid Cut/Clu Filename!",
                                                         "The following Cut filename is invalid: \n%s\nPlease" %
                                                         session +
                                                         " ensure that this .cut/clu filename belongs to this session!",
                                                         QtWidgets.QMessageBox.Ok)

        elif 'ChooseSession' in error:
            self.choice = QtWidgets.QMessageBox.question(self, "Choose Session Filename!",
                                                         "You have not chosen a session file yet! Please choose a"
                                                         " session filename before proceeding!",
                                                         QtWidgets.QMessageBox.Ok)

        elif 'InvalidMoveChannel' in error:
            self.choice = QtWidgets.QMessageBox.question(self, "Invalid Move to Cell Value!",
                                                         "The value you have chosen for the 'Move to Cell' value is "
                                                         "invalid, please choose a valid value before continuing!",
                                                         QtWidgets.QMessageBox.Ok)

        elif 'SameChannelInvalid' in error:
            self.choice = QtWidgets.QMessageBox.question(self, "Same Channel Error!",
                                                         "The value you have chosen for the 'Move to Cell' value is "
                                                         "the same as the cell you are cutting from! If you would like "
                                                         "to move these selected spikes to a different channel, please "
                                                         "choose another channel!",
                                                         QtWidgets.QMessageBox.Ok)

        elif 'ActionsMade' in error:
            self.choice = QtWidgets.QMessageBox.question(self, "Are you sure?",
                                                         "Any unsaved actions will be lost when you"
                                                         " reload this cut file. Are you sure you want to continue?",
                                                         QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)

        elif 'OverwriteCut' in error:
            cut_file = os.path.realpath(error.split('!')[1])
            self.choice = QtWidgets.QMessageBox.question(self, "Cut Filename Exists",
                                                         "The following cut filename exists:\n\n%s\n\n Are you sure you"
                                                         " want to overwrite this file?" % cut_file,
                                                         QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)

        elif 'saveComplete' in error:
            self.choice = QtWidgets.QMessageBox.question(self, "Save Complete",
                                                         "Your '.cut' file has been saved successfully!",
                                                         QtWidgets.QMessageBox.Ok)

        elif 'saveCompleteClu' in error:
            self.choice = QtWidgets.QMessageBox.question(self, "Save Complete",
                                                         "Your '.clu' file has been saved successfully!",
                                                         QtWidgets.QMessageBox.Ok)

        elif 'invalidMaxSpikes' in error:
            self.choice = QtWidgets.QMessageBox.question(self, "Invalid Max Spikes",
                                                         "The number chosen for Max Spikes is invalid!",
                                                         QtWidgets.QMessageBox.Ok)

    def get_settings(self):
        """
        This methoid will read the settings filename and return any settings

        :return:
        """
        settings = {}
        if os.path.exists(self.settings_filename):
            with open(self.settings_filename, 'r') as f:
               settings = json.load(f)
        return settings

    def overwrite_settings(self):
        """
        This method will overwrite the settings file with the current settings

        :return:
        """
        # overwrite settings file
        with open(self.settings_filename, 'w') as f:
            json.dump(self.settings, f, sort_keys=True, indent=4)

    def reset_parameters(self):
        """
        This method will reset the parameters, generally used when switching sessions so we can start fresh.
        :return:
        """
        self.plotted_tetrode = None
        self.feature_data = None
        self.tetrode_data = None
        self.tetrode_data_loaded = False
        self.cut_data = None
        self.cut_data_loaded = False
        self.cut_data_original = None
        self.n_channels = None
        self.spike_times = None

        self.max_spike_plots = None

        self.cell_indices = {}
        self.plot_lines = {}
        self.avg_plot_lines = {}
        self.vb = {}
        self.active_ROI = []
        self.unit_data = {}
        self.cell_subsample_i = {}
        self.unit_positions = {}
        self.original_cell_count = {}

        for popup in self.PopUpCutWindow.values():
            popup.close()

        self.PopUpCutWindow = {}

        self.latest_actions = {}

        self.actions_made = False

        self.last_drag_index = None

        self.drag_active = False

        self.unit_drag_lines = {}

        self.samples_per_spike = None
        self.spike_colors = None

        self.unit_plots = {}
        self.unit_rows = 0
        self.unit_cols = 0

        self.reset_plots()

    def reset_plots(self):
        """
        This method will clear the plots

        :return:
        """
        if hasattr(self, 'scatterItem'):
            if self.scatterItem is not None:
                self.glViewWidget.removeItem(self.scatterItem)
                self.scatterItem = None
        self.unit_win.clear()

    def choose_cut_filename(self):
        if 'file_directory' not in self.settings.keys():
            current_filename, filename_filter = QtWidgets.QFileDialog.getOpenFileName(
                self, caption="Select a '.Set' file!", directory='', filter='Set Files (*.set)')

        else:
            if os.path.exists(self.settings['file_directory']):
                current_filename, filename_filter = QtWidgets.QFileDialog.getOpenFileName(
                    self, caption="Select a '.Cut/.Clu' file!", directory=self.settings['file_directory'],
                    filter='Cut Files (*.cut *.clu*)')
            else:
                current_filename, filename_filter = QtWidgets.QFileDialog.getOpenFileName(
                    self, caption="Select a '.Cut/.Clu' file!", directory='', filter='Cut Files (*.cut *.clu*)')

        # if no file chosen, skip
        if current_filename == '':
            return

        chosen_directory = os.path.dirname(current_filename)

        self.settings['file_directory'] = chosen_directory

        self.overwrite_settings()

        self.reset_parameters()

        self.cut_filename.setText(os.path.realpath(current_filename))

    def plotFunc(self):
        """
        This method will be called when the Plot button is pressed.

        :return:
        """

        # validate the cut filename
        cut_valid, error_raised = validate_cut(self, self.filename.text(), self.cut_filename.text())

        if not cut_valid:
            self.choice = None
            self.LogError.signal.emit('InvalidCut!%s' % self.cut_filename.text())
            while self.choice is None:
                time.sleep(0.1)
            return

        # check if there were any actions made, this is because the attributes will be reset
        if self.actions_made is True:
            # there were actions made, raise the error so the user can decide to continue or not

            # we don't want this to pop-up whenever switch tetrodes, so check if the plotted data is from the
            # current chosen tetrode
            if self.tetrode_cb.currentText() == self.plotted_tetrode:
                self.choice = None
                self.LogError.signal.emit('ActionsMade')
                while self.choice is None:
                    time.sleep(0.1)

                # check which option the user chose
                if self.choice == QtWidgets.QMessageBox.Yes:
                    # user chose the re-plot anyways
                    self.reset_plots()
                    self.reset_parameters()
                    plot_session(self)
            else:
                # the tetrodes are different, just plot the session
                self.reset_plots()
                self.reset_parameters()
                plot_session(self)
        else:
            # there were no actions made, simply plot the session
            plot_session(self)

        self.plotted_tetrode = self.tetrode_cb.currentText()

    def choose_filename(self):
        """
        This method will allow you to choose a .set filename to analyze.
        :return:
        """

        if 'file_directory' not in self.settings.keys():
            current_filename, filename_filter = QtWidgets.QFileDialog.getOpenFileNames(
                self, caption="Select a '.Set' file!", directory='', filter='Set Files (*.set)')

        else:
            if os.path.exists(self.settings['file_directory']):
                current_filename, filename_filter = QtWidgets.QFileDialog.getOpenFileNames(
                    self, caption="Select a '.Set' file!", directory=self.settings['file_directory'],
                    filter='Set Files (*.set)')
            else:
                current_filename, filename_filter = QtWidgets.QFileDialog.getOpenFileNames(
                    self, caption="Select a '.Set' file!", directory='', filter='Set Files (*.set)')

        # if no file chosen, skip
        if len(current_filename) == 0:
            return

        if len(current_filename) == 1:
            # then the user has selected only one
            current_filename = current_filename[0]

            # check if the session is valid
            session_valid = validate_session(self, current_filename)

            if session_valid:
                self.multiple_files = False

                # updated the chosen directory settings value so we remember our latest chosen directory
                chosen_directory = os.path.dirname(current_filename)
                self.settings['file_directory'] = chosen_directory
                self.overwrite_settings()

                # replace the current .set field in the choose .set field with chosen filename
                self.filename.setText(os.path.realpath(current_filename))

                self.reset_parameters()

            else:
                # the session is not valid, raise the error message
                self.choice = None
                self.LogError.signal.emit('InvalidSession!%s' % current_filename)
                while self.choice is None:
                    time.sleep(0.1)
        elif len(current_filename) > 1:
            # then we have selected multiple files

            # check if the session is valid
            session_valid = validate_session(self, current_filename)

            if session_valid:
                self.multiple_files = True

                # updated the chosen directory settings value so we remember our latest chosen directory
                chosen_directory = os.path.dirname(current_filename[0])
                self.settings['file_directory'] = chosen_directory
                self.overwrite_settings()

                # replace the current .set field in the choose .set field with chosen filename
                self.filename.setText(os.path.realpath(', '.join(current_filename)))

                self.reset_parameters()

            else:
                # the session is not valid, raise the error message
                self.choice = None
                self.LogError.signal.emit('InvalidSession!%s' % ', '.join(current_filename))
                while self.choice is None:
                    time.sleep(0.1)
        else:
            return

    def set_cut_filename(self):
        """
        When you choose a session filename, it will trigger this function which will automatically set the .cut
        filename for the user.

        :return:
        """

        if not self.multiple_files:
            filename = self.filename.text()

            try:
                tetrode = int(self.tetrode_cb.currentText())
            except ValueError:
                return

            cut_filename = '%s_%d.cut' % (
                os.path.splitext(filename)[0], tetrode)
            clu_filename = '%s.clu.%d' % (
                os.path.splitext(filename)[0], tetrode)
            if os.path.exists(cut_filename):
                self.cut_filename.setText(os.path.realpath(cut_filename))
            elif os.path.exists(clu_filename):
                self.cut_filename.setText(os.path.realpath(clu_filename))

    def tetrode_changed(self):
        """
        Upon changing of the tetrode drop-menu, the .cut file will also need to be changed (trigger that change)

        :return:
        """
        # we will update the cut_filename
        if self.change_set_with_tetrode:
            self.set_cut_filename()
            # self.reset_parameters()

    def filename_changed(self):
        """
        This method will run when the filename LineEdit has been changed.

        It will essentially find the active tetrodes and populate the drop-down menu.
        """

        filename = self.filename.text()

        if self.multiple_files:
            filename = filename.split(', ')

        else:
            filename = [filename]

        # ensure that the files exist
        for file in filename:
            if not os.path.exists(file):
                return

        tetrodes = []

        self.tetrode_cb.clear()

        tetrode_list = find_tetrodes(self, self.filename.text())

        # get the extension value (excluding the .) so we can create a list of tetrode integers

        for file in tetrode_list:
            tetrode = os.path.splitext(file)[-1][1:]
            tetrodes.append(tetrode)

        # make a list of added tetrodes
        added_tetrodes = []
        for tetrode in sorted(tetrodes):
            # check if the tetrode value has been added already
            if tetrode in added_tetrodes:
                # continue if already added
                continue

            # add the item to the list containing the tetrode value
            self.tetrode_cb.addItem(tetrode)

            # add the tetrode value to the added_tetrodes list
            added_tetrodes.append(tetrode)

        # set the cut_filename
        self.set_cut_filename()

def launch_gui():
    """
    This function will launch the gebaSpike GUI
    :return:
    """

    # need to create QApplication object for PyQt5 to work
    app = QtWidgets.QApplication(sys.argv)

    # call main window
    main_window = MainWindow()  # Creating the Main Window
    main_window.raise_()  # raises the Main Window

    sys.exit(app.exec_())  # prevents the window from immediately exiting out

if __name__ == '__main__':
    launch_gui()


import datetime
import unittest
import json

from util import Stock, Portfolio, is_weekday, create_payload

class StockTest(unittest.TestCase):
    stocks = [
        Stock("ＳＵＢＡＲＵ", "6株", "22,086円", "+0.00%"),
        Stock("日本セラミック","6株", "18,480円", "+0.82%"),
        Stock("デンソー", "2株", "14,076円", "-0.31%"),
        Stock("テクノスジャパン", "12株", "11,364円", "+0.53%"),
        Stock("トヨタ自動車", "1株", "7,608円", "+0.18%"),
        Stock("日産自動車", "5株", "5,910円", "+1.11%"),
        Stock("ゼンリン", "1株", "4,180円", "-1.18%"),
        Stock("ベリサーブ", "1株", "3,800円", "-2.56%"),
        Stock("クラリオン", "9株", "3,591円", "-1.48%"),
        Stock("ディー・エヌ・エー", "1株", "2,426円", "-0.12%"),
    ]

    def test_stock_to_slack_message(self):
        stock=Stock("meigara", "10", "kingaku", "+zenzitsuhi")
        self.assertEqual(stock.to_slack_msg(), "<http://google.co.jp/search?q=meigara ニュース|meigara>: kingaku (+zenzitsuhi)")

    def test_stock_big_n(self):
        big_3 = Stock.big_n(StockTest.stocks, 3)
        self.assertEqual(big_3[0].meigara, "日産自動車")
        self.assertEqual(big_3[1].meigara, "日本セラミック")
        self.assertEqual(big_3[2].meigara, "テクノスジャパン")

    def test_stock_small_n(self):
        small_3 = Stock.small_n(StockTest.stocks, 3)
        self.assertEqual(small_3[0].meigara, "ベリサーブ")
        self.assertEqual(small_3[1].meigara, "クラリオン")
        self.assertEqual(small_3[2].meigara, "ゼンリン")

    def test_stock_big_n_with_no_zenjitsu_hi(self):
        big_3 = Stock.big_n(StockTest.stocks + [
            Stock("前日比なし", "2株", "¥--円", "--%"),
        ], 3)
        self.assertEqual(big_3[0].meigara, "日産自動車")
        self.assertEqual(big_3[1].meigara, "日本セラミック")
        self.assertEqual(big_3[2].meigara, "テクノスジャパン")

class PotfolioTest(unittest.TestCase):

    def test_portfolio_should_get_max_stock(self):
        portfolio = Portfolio(StockTest.stocks)
        self.assertEqual(portfolio.max_stock().meigara, "日産自動車")

    def test_portfolio_should_get_min_stock(self):
        portfolio = Portfolio(StockTest.stocks)
        self.assertEqual(portfolio.min_stock().meigara, "ベリサーブ")

class WeekDayTest(unittest.TestCase):

    def test_is_weekday_works(self):
        monday = datetime.datetime(2018, 7, 9)
        tuesday = datetime.datetime(2018, 7, 10)
        wednesday = datetime.datetime(2018, 7, 11)
        thursday = datetime.datetime(2018, 7, 12)
        friday = datetime.datetime(2018, 7, 13)
        saturday = datetime.datetime(2018, 7, 14)
        sunday = datetime.datetime(2018, 7, 15)
        self.assertTrue(is_weekday(monday))
        self.assertTrue(is_weekday(tuesday))
        self.assertTrue(is_weekday(wednesday))
        self.assertTrue(is_weekday(thursday))
        self.assertTrue(is_weekday(friday))
        self.assertFalse(is_weekday(saturday))
        self.assertFalse(is_weekday(sunday))

class CreatePayloadTest(unittest.TestCase):

    def test_create_payload_theme_only(self):
        shisan = {
            "all_shisan": "shisan",
            "all_theme": "all_theme",
            "omakase": None,
            "fukumi_soneki_percent": "fukumi_soneki%",
            "fukumi_soneki": "fukumi_soneki",
            "comp_yesterday_percent": "comp_yesterday%",
            "comp_yesterday": "comp_yesterday",
            "today_eiyu": "eiyu",
            "today_senpan": "senpan",
        }

        payload_str = create_payload("title", shisan)
        payload = json.loads(payload_str)
        attachment = payload["attachments"][0]
        self.assertEqual(attachment["title"], "title")

        fields = attachment["fields"]
        self.assertEqual(fields[0]["title"], "現在の資産")
        self.assertEqual(fields[0]["value"], "shisan")

        self.assertEqual(fields[1]["title"], "含み損益 (%)")
        self.assertEqual(fields[1]["value"], "fukumi_soneki（fukumi_soneki%）")

        self.assertEqual(fields[2]["title"], "前日比 (%)")
        self.assertEqual(fields[2]["value"], "comp_yesterday（comp_yesterday%）")

        self.assertEqual(fields[3]["title"], "テーマ内訳")
        self.assertEqual(fields[3]["value"], "all_theme")

        self.assertEqual(fields[4]["title"], "本日の英雄 :sunny:")
        self.assertEqual(fields[4]["value"], "eiyu")

        self.assertEqual(fields[5]["title"], "本日の戦犯 :umbrella_with_rain_drops:")
        self.assertEqual(fields[5]["value"], "senpan")

    def test_create_payload_omakase_only(self):
        shisan = {
            "all_shisan": "shisan",
            "all_theme": None,
            "omakase": "omakase",
            "fukumi_soneki_percent": "fukumi_soneki%",
            "fukumi_soneki": "fukumi_soneki",
            "comp_yesterday_percent": "comp_yesterday%",
            "comp_yesterday": "comp_yesterday",
            "today_eiyu": "eiyu",
            "today_senpan": "senpan",
        }

        payload_str = create_payload("title", shisan)
        payload = json.loads(payload_str)
        attachment = payload["attachments"][0]
        self.assertEqual(attachment["title"], "title")

        fields = attachment["fields"]
        self.assertEqual(fields[0]["title"], "現在の資産")
        self.assertEqual(fields[0]["value"], "shisan")

        self.assertEqual(fields[1]["title"], "含み損益 (%)")
        self.assertEqual(fields[1]["value"], "fukumi_soneki（fukumi_soneki%）")

        self.assertEqual(fields[2]["title"], "前日比 (%)")
        self.assertEqual(fields[2]["value"], "comp_yesterday（comp_yesterday%）")

        self.assertEqual(fields[3]["title"], "おまかせ投資内訳")
        self.assertEqual(fields[3]["value"], "omakase")

        self.assertEqual(len(fields), 4)

    def test_create_payload_theme_and_omakase(self):
        shisan = {
            "all_shisan": "shisan",
            "all_theme": "theme",
            "omakase": "omakase",
            "fukumi_soneki_percent": "fukumi_soneki%",
            "fukumi_soneki": "fukumi_soneki",
            "comp_yesterday_percent": "comp_yesterday%",
            "comp_yesterday": "comp_yesterday",
            "today_eiyu": "eiyu",
            "today_senpan": "senpan",
        }

        payload_str = create_payload("title", shisan)
        payload = json.loads(payload_str)
        attachment = payload["attachments"][0]
        self.assertEqual(attachment["title"], "title")

        fields = attachment["fields"]
        self.assertEqual(fields[0]["title"], "現在の資産")
        self.assertEqual(fields[0]["value"], "shisan")

        self.assertEqual(fields[1]["title"], "含み損益 (%)")
        self.assertEqual(fields[1]["value"], "fukumi_soneki（fukumi_soneki%）")

        self.assertEqual(fields[2]["title"], "前日比 (%)")
        self.assertEqual(fields[2]["value"], "comp_yesterday（comp_yesterday%）")

        self.assertEqual(fields[3]["title"], "テーマ内訳")
        self.assertEqual(fields[3]["value"], "theme")

        self.assertEqual(fields[4]["title"], "おまかせ投資内訳")
        self.assertEqual(fields[4]["value"], "omakase")

        self.assertEqual(fields[5]["title"], "本日の英雄 :sunny:")
        self.assertEqual(fields[5]["value"], "eiyu")

        self.assertEqual(fields[6]["title"], "本日の戦犯 :umbrella_with_rain_drops:")
        self.assertEqual(fields[6]["value"], "senpan")


from __future__ import print_function
from __future__ import absolute_import
from __future__ import division

import torch
import torch.nn as nn
from torch.nn import Module, Sequential, Conv2d, ReLU,AdaptiveMaxPool2d, AdaptiveAvgPool2d, \
    BatchNorm2d, CrossEntropyLoss, AvgPool2d, MaxPool2d, Parameter, Linear, Sigmoid, Softmax, Dropout, Embedding
import torch.nn.functional as F
import torchvision.models as models

class SpatialAttention(Module):
    def __init__(self, in_dim, kernel_size=9):
        super(SpatialAttention, self).__init__()
        self.chanel_in = in_dim

        self.query_conv = Conv2d(in_channels=in_dim, out_channels=in_dim//8, kernel_size=1)
        self.key_conv = Conv2d(in_channels=in_dim, out_channels=in_dim//8, kernel_size=1)
        self.value_conv = Conv2d(in_channels=in_dim, out_channels=in_dim, kernel_size=1)
        self.gamma = Parameter(torch.zeros(1))
        self.softmax  = Softmax(dim=-1)

    def forward(self, x):

        x = F.interpolate(x, scale_factor=0.5, mode="bilinear")
        m_batchsize, C, height, width = x.size()
        proj_query = self.query_conv(x).view(m_batchsize, -1, width*height).permute(0, 2, 1)
        proj_key = self.key_conv(x).view(m_batchsize, -1, width*height)
        proj_value = self.value_conv(x).view(m_batchsize, -1, width*height)
        energy = torch.bmm(proj_query, proj_key)
        attention = self.softmax(energy)

        out = torch.bmm(proj_value, attention.permute(0, 2, 1))
        out = out.view(m_batchsize, C, height, width)

        out = self.gamma*out + x
        out = F.interpolate(x, scale_factor=2, mode="bilinear")
        return out

class ChannelwiseAttention(Module):
    def __init__(self, in_dim):
        super(ChannelwiseAttention, self).__init__()
        self.chanel_in = in_dim

        self.gamma = Parameter(torch.zeros(1))
        self.softmax  = Softmax(dim=-1)

    def forward(self, x):

        m_batchsize, C, height, width = x.size()
        proj_query = x.view(m_batchsize, C, -1)
        proj_key = x.view(m_batchsize, C, -1).permute(0, 2, 1)
        energy = torch.bmm(proj_query, proj_key)
        energy_new = torch.max(energy, -1, keepdim=True)[0].expand_as(energy)-energy
        attention = self.softmax(energy_new)
        proj_value = x.view(m_batchsize, C, -1)

        out = torch.bmm(attention, proj_value)
        out = out.view(m_batchsize, C, height, width)

        out = self.gamma*out + x

        attention_weight = F.adaptive_avg_pool2d(x, (1, 1)).view((m_batchsize, C))
        attention_weight = torch.mean(attention_weight)

        return out

class CPFE(Module):
    def __init__(self, feature_layer=None, out_channels=32):
        super(CPFE, self).__init__()

        self.dil_rates = [1, 2, 3]

        if feature_layer == 'conv5_3':
            self.in_channels = 512
            self.out_channels = 128 #512/4
        elif feature_layer == 'conv4_3':
            self.in_channels = 512
            self.out_channels = 128 #512/4
        elif feature_layer == 'conv3_3':
            self.in_channels = 256
            self.out_channels = 64 #256/4
        elif feature_layer == 'conv2_2':
            self.in_channels = 128
            self.out_channels = 32 #128/4
        elif feature_layer == 'conv1_2':
            self.in_channels = 64
            self.out_channels = 16 #64/4

        self.conv_1_1 = Conv2d(in_channels=self.in_channels, out_channels=self.out_channels, kernel_size=1, bias=True)
        self.conv_dil_3 = Conv2d(in_channels=self.in_channels, out_channels=self.out_channels, kernel_size=3,
                                    stride=1, dilation=self.dil_rates[0], padding=self.dil_rates[0], bias=True)
        self.conv_dil_5 = Conv2d(in_channels=self.in_channels, out_channels=self.out_channels, kernel_size=3,
                                    stride=1, dilation=self.dil_rates[1], padding=self.dil_rates[1], bias=True)
        self.conv_dil_7 = Conv2d(in_channels=self.in_channels, out_channels=self.out_channels, kernel_size=3,
                                    stride=1, dilation=self.dil_rates[2], padding=self.dil_rates[2], bias=True)

        self.bn = BatchNorm2d(self.out_channels*4)

    def forward(self, input_):

        conv_1_1_feats = self.conv_1_1(input_)
        conv_dil_3_feats = self.conv_dil_3(input_)
        conv_dil_5_feats = self.conv_dil_5(input_)
        conv_dil_7_feats = self.conv_dil_7(input_)

        # Aggregate features
        concat_feats = torch.cat((conv_1_1_feats, conv_dil_3_feats, conv_dil_5_feats, conv_dil_7_feats), dim=1)
        bn_feats = F.relu(self.bn(concat_feats))

        return bn_feats


from flask import render_template, session, redirect, url_for, request,jsonify
from database.mongodb import MongoDb
import controllers.ctl_history as hist
from bson.objectid import ObjectId
from controllers.validaciones import Validaciones as val
import controllers.encrypt as encrypt
import os
import uuid
#import qrcode
db = MongoDb().db()

def cerrar_sesion():
    if val.validar_session(session):
        hist.guardar_historial(
            "CORRECTO", "SALIR", 'CIERRE DE SESIÓN CON ÉXITO - CÉDULA: "'+session["cedula"]+'"')
        session.pop('ip', None)
        session.pop('id', None)
        session.pop('cedula', None)
        session.pop('nombre', None)
        session.pop('rol', None)
        return redirect(url_for('index'))
    else:
        return redirect(url_for('err_403'))

def index(request):

    alerts = {"tipo": "", "message": ""}

    try:

        if request.method == 'GET':
            if val.validar_session(session):
                return redirect(url_for("principal"))
            else:
                return render_template('/views/index.html')
        else:

            nom_usuario = val.val_vacio("usuario","",request)
            clave = val.val_vacio("clave","",request)

            if nom_usuario == os.getenv("USER_ADMIN") and clave == os.getenv("PWD_ADMIN"):
                session["ip"] = request.environ['REMOTE_ADDR']
                session["id"] = ObjectId().__str__()
                session["cedula"] = "0000000000"
                session["nombre"] = "SUPER-ADMIN"
                session["rol"] = "Super-Admin"

                hist.guardar_historial(
                    "CORRECTO", "INGRESO", 'INGRESO CON ÉXITO AL SISTEMA - SUPER-ADMIN: "'+session["cedula"]+'"')

                return redirect(url_for("principal"))

            usuario = list(db.usuarios.aggregate([
                {"$lookup": {"from": "servidores", "localField": "cedula",
                             "foreignField": "cedula", "as": "servidor"}},
                {"$unwind": "$servidor"},
                {"$project": {"servidor._id": 0}},
                {"$match": {"$or": [{"servidor.cedula": nom_usuario}, {"usuario": nom_usuario}, {
                    "servidor.correo": nom_usuario}]}},
            ]))

            if len(usuario) > 0:

                usuario = usuario[0]

                if clave == encrypt.decrypt(usuario["clave"]):

                    if usuario["estado"] == "ACTIVO":
                        session["ip"] = request.environ['REMOTE_ADDR']
                        session["id"] = str(usuario["_id"])
                        session["cedula"] = usuario["servidor"]["cedula"]
                        session["nombre"] = usuario["servidor"]["nombres"]
                        session["rol"] = usuario["rol"]

                        hist.guardar_historial(
                            "CORRECTO", "INGRESO", 'INGRESO CON ÉXITO AL SISTEMA - CÉDULA: "'+session["cedula"]+'"')

                        return redirect(url_for("principal"))
                    else:
                        alerts["tipo"] = "danger"
                        alerts["message"] = "Usuario Inactivo o No existe"
                        return render_template('/views/index.html', alert=alerts)
                else:
                    alerts["tipo"] = "danger"
                    alerts["message"] = "Clave incorrecta"
                    return render_template('/views/index.html', alert=alerts)
            else:
                alerts["tipo"] = "danger"
                alerts["message"] = "Usuario incorrecto"
                return render_template('/views/index.html', alert=alerts)
    except Exception as e:
        alerts["tipo"] = "danger"
        alerts["message"] = str(e)
        hist.guardar_historial(
            "ERROR", "INGRESO", 'ERROR DE INGRESO AL SISTEMA - "'+str(e)+'"')
        return redirect(url_for('err_500'))

def principal():
    if val.validar_session(session):
        return render_template('/views/principal.html', session=session)
    else:
        return redirect(url_for('index'))

#def ticket():
    try:

        if request.method == 'POST':

            foto = request.files['foto']

            if foto.filename != '':

                path_placa = ("static/placas")
                path_qr = ("static/qr")

                val.crear_directorio(os, path_placa)
                val.crear_directorio(os, path_qr)

                id = str(uuid.uuid1())
                file_ext = os.path.splitext(foto.filename)[1]
                url_foto = id+file_ext
                foto.save(os.path.join(path_placa, url_foto))

                qr = qrcode.QRCode(version=1,box_size=10,border=5)
                qr.add_data("ID: "+id+"\n Fecha de Ingreso: ")
                qr.make(fit=True)

                img = qr.make_image(fill="black",back_color="white")
                img.save(os.path.join(path_qr, id+".png"))

            else:
                return jsonify({"message": "Imagen no encontrada"}), 404
        else:
            return jsonify({"message": "Petición Incorrecta"}), 500

    except Exception as e:
            hist.guardar_historial(
                "ERROR", "INGRESO", 'ERROR AL GENERAR CÓDIGO QR - "'+str(e)+'"')
            return redirect(url_for('err_500'))


#!/usr/bin/env python
# coding: utf-8

# ## Practical Activity 3.2.8

# ### Prepare your workstation

# In[2]:

# Copy the YAML file and your Twitter keys over to this Jupyter Notebook before you start to work
get_ipython().system('pip install pyyaml')
import yaml
from yaml.loader import SafeLoader
get_ipython().system('pip install twitter')
from twitter import *

# Import the yaml file - remember to specify the whole path and use / between directories
twitter_creds = yaml.safe_load(open('Twitter.yaml', 'r').read())

# Pass your twitter credentials
twitter_api = Twitter(auth = OAuth(twitter_creds['access_token'],
                                  twitter_creds['access_token_secret'],
                                  twitter_creds['api_key'],
                                  twitter_creds['api_secret_key']))

# See if you are connected
print(twitter_api)

# In[3]:

# Run a test with #python
python_tweets = twitter_api.search.tweets(q="#python")

# View output
print(python_tweets)

# ### 1. Test connection

# In[8]:

# Query the term cheesecake
q = {'q':'cheesecake', 'count':100, 'result_type':'recent'}
results = []

while len(results) < 30:
    query = twitter_api.search.tweets(**q)
    q['max_id'] = query['search_metadata']['next_results'].split('&')[0].split('?max_id=')[1]
    results.append(query)

# Determine the number of results
len(results)

# ### 2. Create DataFrames

# In[10]:

# Import Pandas to join the DataFrames.
import pandas as pd

# Concat DataFrames.
results_list_pd = pd.concat([pd.DataFrame(_['statuses'])for _ in results])

# View the output.
results_list_pd.shape

# In[14]:

# Determine values of output.
results_list_values = results_list_pd['text'].values

results_list_values

# ### 3. Investigate tweets

# In[19]:

# Import necessary libraries.
import nltk
from nltk.corpus import stopwords
from nltk.corpus import words
nltk.download('stopwords')
nltk.download('words')
from nltk.tokenize import word_tokenize

stop_words = set(stopwords.words('english'))

# In[16]:

# Look at one raw tweet.
results_list_values[1]

# In[17]:

# Split up each tweet into individual words.
results_list_values_token = [word_tokenize(_) for _ in results_list_values]

# In[20]:

# Extract a list of all english words.
all_english_words = set(words.words())

# In[21]:

# Pre-process tweets:
# Get every word.
# Convert it to lowercase.
# Only include if the word is alphanumeric and if it is in the list
# of English words.
results_list_values_token_nostop = [[y.lower() for y in x if y.lower() not in stop_words and y.isalpha() and y.lower() in all_english_words] for x in results_list_values_token]

# In[22]:

# View output.
results_list_values_token_nostop[1]

# ## Continue to work from below for sentiment analysis

# ## NLTK sentiment analysis

# ### 1. Import NLTK

# In[23]:

# Import the prebuilt rules and values of the 'vader lexicon'.
nltk.download('vader_lexicon')

# In[24]:

# Import the vader class and create an object of the analyser called darth_vader.
from nltk.sentiment.vader import SentimentIntensityAnalyzer

# Create a variable to store the SIA.
darth_vader = SentimentIntensityAnalyzer()

# In[25]:

# Run through a dictionary comprehension to take every cleaned tweet.
# Next run the polarity score function on the string.
# This will return four values in a dictionary.
results_list_values_token_nostop_polarity = {" ".join(_) : darth_vader.polarity_scores(" ".join(_)) for _ in results_list_values_token_nostop}

# ### 2. Create a Pandas DataFrame

# In[26]:

# Convert the list of dictionary results to a pandas dataframe.
polarity_pd = pd.DataFrame(results_list_values_token_nostop_polarity).T

# In[27]:

# Get the top 5 most positive cleaned tweets related to cheesecake
polarity_pd.sort_values('pos', ascending = 0).head(5)

# In[28]:

# Get the top 5 most negative words related to cheesecake
polarity_pd.sort_values('neg', ascending = 0).head(5)

# In[29]:

# Show the distribution of sentiment values.
polarity_pd['compound'].describe()

# ### 3. Plot the output

# In[30]:

# Import matplotlib for visualisation.
get_ipython().run_line_magic('matplotlib', 'inline')
import matplotlib.pyplot as plt

# In[33]:

# Create barplot visualisation.
_plot = polarity_pd.reset_index()['compound'].sort_values()
_plot.plot(kind = 'bar')
ax1 = plt.axes()
x_axis = ax1.axes.get_xaxis()
x_axis.set_visible(False)

plt.show()
plt.close()

# In[34]:

# Visualise outliers with a boxplot.
_plot = polarity_pd.reset_index()['compound'].sort_values()
_plot.plot(kind = 'box')

# In[ ]:


import numpy as np

def read_signals(filename):
    ######################################################################################
    # Inputs:                                                                            #
    #   filename: A string contains the file name                                        #
    # Outputs:                                                                           #
    #   data: a list contains list of signal values                                      #
    ######################################################################################
    with open(filename, 'r') as fp:
        data = fp.read().splitlines()
        data = map(lambda x: x.rstrip().lstrip().split(), data)
        data = [list(map(float, line)) for line in data]
    return data

def read_labels(filename):
    ######################################################################################
    # Inputs:                                                                            #
    #   filename: A string contains the file name                                        #
    # Outputs:                                                                           #
    #   activities: a list contains activity label                                       #
    ######################################################################################
    with open(filename, 'r') as fp:
        activities = fp.read().splitlines()
        activities = list(map(int, activities))
    return activities

########## Define paths and file name ########################################
train_signal_folder_path = 'UCI HAR Dataset/train/Inertial Signals/'
test_signal_folder_path = 'UCI HAR Dataset/test/Inertial Signals/'

train_input_filename = ['body_acc_x_train.txt', 'body_acc_y_train.txt', 'body_acc_z_train.txt',
                     'body_gyro_x_train.txt', 'body_gyro_y_train.txt', 'body_gyro_z_train.txt',
                     'total_acc_x_train.txt', 'total_acc_y_train.txt', 'total_acc_z_train.txt']

test_input_filename = ['body_acc_x_test.txt', 'body_acc_y_test.txt', 'body_acc_z_test.txt',
                     'body_gyro_x_test.txt', 'body_gyro_y_test.txt', 'body_gyro_z_test.txt',
                     'total_acc_x_test.txt', 'total_acc_y_test.txt', 'total_acc_z_test.txt']

def read_train_signal():
    ######################################################################################
    # read all train signal file and save into a numpy array                             #
    # Outputs:                                                                           #
    #   train_signals: a numpy array contains list of window frame of signal             #
    #   a shape of train_signal is (7352, 128, 9). 7352 is number of train_signal,       #
    #   128 is window size and 9 is number of component( 3 acc, 3 gyro, 3 body acc)      #
    ######################################################################################
    train_signals = []
    for input_file in train_input_filename:
        signal = read_signals(train_signal_folder_path + input_file)
        train_signals.append(signal)
    train_signals = np.transpose(np.array(train_signals), (1, 2, 0))
    return train_signals

def read_test_signal():
    ######################################################################################
    # read all test signal file and save into a numpy array                              #
    # Outputs:                                                                           #
    #   train_signals: a numpy array contains list of window frame of signal             #
    #   a shape of train_signal is (2947, 128, 9). 2947 is number of train_signal,       #
    #   128 is window size and 9 is number of component( 3 acc, 3 gyro, 3 body acc)      #
    ######################################################################################
    test_signals = []
    for input_file in test_input_filename:
        signal = read_signals(test_signal_folder_path + input_file)
        test_signals.append(signal)
    print(type(test_signals))
    test_signals = np.transpose(np.array(test_signals), (1, 2, 0))
    return test_signals


from pathlib import Path
from typing import Optional

from click import argument

from . import app, option, option_workdir

@app.command()
@argument("section", required=False)
@argument("flavor", required=False)
@option("--unused/--no-unused", default=True, help="Display the unused flavors")
@option_workdir
def deps(
    section: Optional[str], flavor: Optional[str], unused: bool, workdir: Path
) -> None:
    """
    Display information about shared sections and flavors usage.

    You can specify the SECTION, and further, the FLAVOR arguments to restrict the \
        output.
    """
    from collections import defaultdict
    from typing import (
        DefaultDict,
        Dict,
        FrozenSet,
        Iterable,
        Mapping,
        Optional,
        Set,
        Tuple,
    )

    from rich.console import Console
    from rich.padding import Padding
    from rich.progress import Progress, track
    from rich.table import Table
    from yaml import safe_load as yaml_safe_load

    from ..paths import GlobalPaths, Paths
    from ..targets import Targets

    def _compute_shared_dependencies(
        dependencies: Set[Path], paths: GlobalPaths
    ) -> Set[str]:
        shared_dependencies = set()
        for dependency in dependencies:
            try:
                relative_dependency = dependency.relative_to(paths.shared_latex_dir)
                shared_dependencies.add(str(relative_dependency))
            except ValueError:
                pass
        return shared_dependencies

    def _process_targets(
        targets_path: Path,
        all_targets_dependencies: Dict[str, Dict[str, Set[str]]],
        by_sections: Mapping[str, Mapping[str, Set[Tuple[str, str]]]],
    ) -> None:
        paths = Paths.from_defaults(targets_path.parent)
        targets_name = str(paths.current_dir.relative_to(paths.git_dir))
        targets = Targets.from_file(paths)
        for target in targets:
            for section_path, dependencies in target.section_dependencies.items():
                section_flavors = target.section_flavors[section_path]
                shared = False
                for dependency_path in dependencies.used:
                    if (
                        _relative_to_shared_latex(paths, str(dependency_path))
                        is not None
                    ):
                        shared = True
                        break
                if shared:
                    for section_flavor in section_flavors:
                        by_sections[section_path][section_flavor].add(
                            (targets_name, target.name)
                        )
            shared_dependencies = _compute_shared_dependencies(
                target.dependencies.used, paths
            )
            all_targets_dependencies[targets_name][target.name] = shared_dependencies

    def _print_changed_report(
        touched: FrozenSet[str],
        all_targets_dependencies: Dict[str, Dict[str, Set[str]]],
    ) -> None:
        console = Console()
        console.print()
        console.print()
        console.rule("[bold]Decks affected by uncommited changes", align="left")
        console.print()
        table = Table("Deck", "Targets")
        for targets_name, targets_dependencies in all_targets_dependencies.items():
            touched_targets = []
            for target_name, target_dependencies in targets_dependencies.items():
                if touched.intersection(target_dependencies):
                    touched_targets.append(target_name)
            if touched_targets:
                table.add_row(targets_name, " ".join(touched_targets))
        console.print(Padding(table if table.row_count else "None.", (0, 0, 0, 2)))

    def _print_unused_report(
        section_paths: Iterable[Path],
        by_sections: Mapping[str, Mapping[str, Set[Tuple[str, str]]]],
        global_paths: GlobalPaths,
    ) -> None:
        console = Console()
        console.print()
        console.print()
        console.rule("[bold]Unused flavors", align="left")
        console.print()
        table = Table("Section", "Flavors")
        flavors = defaultdict(set)
        for section_path in section_paths:
            with section_path.open(encoding="utf8") as fh:
                section_config = yaml_safe_load(fh)
            section_name = "/".join(
                section_path.relative_to(global_paths.shared_latex_dir).parts[:-1]
            )
            flavors[section_name].update(section_config["flavors"])
        for section_name, section_flavors in sorted(flavors.items()):
            unused_flavors = [
                flavor
                for flavor in section_flavors
                if not by_sections[section_name][flavor]
            ]
            if unused_flavors:
                table.add_row(section_name, " ".join(sorted(unused_flavors)))
        console.print(Padding(table if table.row_count else "None.", (0, 0, 0, 2)))

    def _print_section_report(
        section: str,
        flavor: Optional[str],
        by_sections: Mapping[str, Mapping[str, Set[Tuple[str, str]]]],
    ) -> None:
        console = Console()
        console.print()
        console.print()
        title = section
        if flavor is not None:
            title += f" {flavor}"
        console.rule(f"[bold]Decks depending on [italic]{title}", align="left")
        console.print()
        table = Table("Deck", "Targets")
        if flavor is None:
            flavors_dependencies = by_sections[section]
            for deck_path, target_name in sorted(
                set.union(*flavors_dependencies.values())
            ):
                table.add_row(deck_path, target_name)
        else:
            flavors_dependencies = by_sections[section]
            for deck_path, target_name in sorted(flavors_dependencies[flavor]):
                table.add_row(deck_path, target_name)
        console.print(Padding(table if table.row_count else "None.", (0, 0, 0, 2)))

    def _relative_to_shared_latex(paths: GlobalPaths, file_path: str) -> Optional[str]:
        try:
            return str((paths.git_dir / file_path).relative_to(paths.shared_latex_dir))
        except ValueError:
            return None

    paths = GlobalPaths.from_defaults(workdir)
    with Progress() as progress:
        targets_progress = progress.add_task("Retrieving targets files", start=False)
        sections_progress = progress.add_task("Retrieving section files", start=False)

        targets_paths = list(paths.git_dir.glob("**/targets.yml"))
        progress.update(
            targets_progress, total=len(targets_paths), completed=len(targets_paths)
        )
        progress.start_task(targets_progress)
        ymls = paths.shared_latex_dir.glob("**/*.yml")
        section_paths = []
        for yml in ymls:
            with yml.open(encoding="utf8") as fh:
                content = yaml_safe_load(fh)
                if not isinstance(content, dict):
                    continue
                if {"title", "flavors"}.issubset(content):
                    section_paths.append(yml)

        progress.update(
            sections_progress, total=len(section_paths), completed=len(section_paths)
        )
        progress.start_task(sections_progress)

    all_targets_dependencies: Dict[str, Dict[str, Set[str]]] = defaultdict(dict)
    by_sections: DefaultDict[str, DefaultDict[str, Set[Tuple[str, str]]]] = defaultdict(
        lambda: defaultdict(set)
    )
    for targets_path in track(targets_paths, description="Processing targets files"):
        _process_targets(targets_path, all_targets_dependencies, by_sections)

    if unused:
        _print_unused_report(section_paths, by_sections, paths)
    if section is not None:
        _print_section_report(section, flavor, by_sections)


import os, csv
import numpy as np
import time #unnecessary, but good for curiosity

start_time = time.time()

path = 'C:/Users/jtgal/OneDrive/Documents/Pitt Summer 2019/Senior Design/sampleFileOutputsCSV/Combined'

ecgSample = np.array([[]])
ecgAnnotation = np.array([[]])

X = np.empty((0,6000), dtype=int)
y = np.empty((0,1), dtype=int)

for filename in os.listdir(path):

    if filename == 'a10.csv':
        break

    print(filename)

    #0 is for no apnea, 1 is for apnea

    i = 0
    j = 0 #debugging variable
    fullFN = path + '/' + filename

    with open(fullFN , newline='') as csvfile:
        spamreader = csv.reader(csvfile, delimiter=',', quotechar='|')
        for row in spamreader:
            if row[0] == 'hart':
                continue
            ecgSample = np.append(ecgSample, int(row[0]))
            if i == 0:
                if row[1] == 'A':
                    ecgAnnotation = np.append(ecgAnnotation, 1)
                else: # annotation is an N
                    ecgAnnotation = np.append(ecgAnnotation, 0)
            if i == 5999: #new annotation
                i = 0

                #add Samples and annotation to their npArrays,
                X = np.vstack((X, ecgSample))
                y = np.vstack((y, ecgAnnotation))

                j+=1

                #reset sample and annotation temp arrays
                ecgSample = np.array([[]])
                ecgAnnotation = np.array([[]])

                continue
            i += 1
            # if j == 10: #for debugging
            #     break
        break #**use this break if using just a single file**

print("DONE")
end_time = time.time()
time_spent = end_time - start_time
print("RUNTIME: " + str(time_spent) + " seconds")


# mkdat.py
#
# To make the list of monsters data.
#
import string

class enuming:
  def __init__(self, n, namekey, ch='?'):
    self.n = int(n)
    self.namekey = str(namekey)
    self.ch = ch = str(ch)
  def DEBUGP(self):
    print(self.n, self.namekey, self.ch)

class enuml:
  def __init__(self, filename, debugmode=False):
    f = open(filename, 'r')
    l = f.readlines()
    f.close()
    self.dat = []
    self.elist = []
    n = 0
    for i in l:
      stch = i[0]
      if stch == '#' or stch == '' or stch == '\n':
        continue
      n += 1
      i = i[:-1]
      stmp = i.split(':')

      if debugmode:
        for s in stmp:
          print(s, end=',')
        print(' : len ->' + str(len(stmp)))

      ch = '?'
      if len(stmp) >= 2:
        ch = stmp[1]
      else:
        ch = '?'
      d = enuming(n,stmp[0], ch)
      self.elist.append(d)
      self.dat.append(stmp)
  def get_elist(self):
    return self.elist
  def get_dat(self):
    return self.dat

def test():
  a = enuml('data/dat.txt')
  for i in a.elist:
    i.DEBUGP()

def test2():
  a = enuml('data/dat.txt')

test()
test2()


"""
https://github.com/eugenechevski
https://leetcode.com/problems/daily-temperatures/

Given an array of integers temperatures represents the daily temperatures,
return an array answer such that answer[i] is the number of days you have to wait after the ith day to get a warmer temperature.
If there is no future day for which this is possible, keep answer[i] == 0 instead.

Example 1:
    Input: temperatures = [73,74,75,71,69,72,76,73]
    Output: [1,1,4,2,1,1,0,0]

Example 2:
    Input: temperatures = [30,40,50,60]
    Output: [1,1,1,0]

Example 3:
    Input: temperatures = [30,60,90]
    Output: [1,1,0]

Constraints:
    * 1 <= temperatures.length <= 10^5
    * 30 <= temperatures[i] <= 100
"""

class Solution:
    def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
        stack = []  # indices
        result = [0] * len(temperatures)

        for i in range(0, len(temperatures)):
            while stack and temperatures[stack[-1]] < temperatures[i]:
                result[stack[-1]] = i - stack[-1]
                stack.pop()
            stack.append(i)

        return result