#!/usr/bin/env python

import argparse
import numpy as np
import tables
from os.path import basename, splitext

##def draw_slices(volume, nr, nc, fname=None):
##    import itertools
##    import matplotlib.pyplot as plt
##    fig = plt.figure()
##    tmin = volume.min()
##    tmax = volume.max()
##    ###
##    ledges = np.linspace(0, 1, nc+1)[:-1]
##    bedges = np.linspace(1, 0, nr+1)[1:]
##    width = 1/float(nc)
##    height = 1/float(nr)
##    ###
##    bottoms,lefts = zip(*list(itertools.product(bedges, ledges)))
##    ###
##    for ni,sl in enumerate(np.split(volume, len(volume))):
##        ax = fig.add_axes((lefts[ni], bottoms[ni], width, height))
##        ax.imshow(sl.squeeze(), vmin=tmin, vmax=tmax, interpolation="nearest")
##        ax.set_xticks([])
##        ax.set_yticks([])
##    if not fname is None:
##        plt.savefig(fname)
##        plt.close()

def define_weights(mask, volume_shape, corr_len):
    # define the (fake) coordinate system
    nx, ny, nz = volume_shape
    x, y, z = np.mgrid[0:nx, 0:ny, 0:nz]
    x = x.astype(float)
    y = y.astype(float)
    z = z.astype(float)
    # generate weight matrix ...
    W = np.zeros(mask.shape)
    nnodes, nvoxels = mask.shape
    for n in range(nnodes):
        # locate voxel and evaluate square distance to others
        i, j, k = np.nonzero(mask[n,:].reshape(volume_shape))
        s = (x - i) ** 2 + (y - j) ** 2 + (z - k) ** 2
        # compute normalized weights for this node (row of W)
        w  = np.exp(- s / (2 * corr_len ** 2))
        w /= w.sum()
        W[n,:] = w.ravel()
    return W

def load_voxel_data(fname_voxel_data):
    with tables.open_file(fname_voxel_data) as f:
        data = f.root.data.read()
    return np.transpose(data, axes=(3,2,1,0))

def resample_brain_data(fname_voxel_data, fname_mask, corr_len, fname_node_data):
    # load input data: (nt, nxvoxels, nyvoxels, nzvoxels)
    voxel_data = load_voxel_data(fname_voxel_data)
    nt, nx, ny, nz = voxel_data.shape
    print('voxel volume is (%i,%i,%i) over %i time samples' % (
        nx, ny, nz, nt))
    # load the mask: (nnodes, nvoxels)
    mask = np.load(fname_mask)
    nnodes, nvoxels = mask.shape
    assert nvoxels == nx * ny * nz
    # compute the weight matrix (nnodes, nvoxels)
    W = define_weights(mask, (nx, ny, nz), corr_len)
    # resample and save; node data will be: (nt, nnodes)
    voxel_data_flat = voxel_data.reshape((nt, nvoxels))
    node_data = np.dot(voxel_data_flat, W.T)
    np.save(fname_node_data, node_data)

##    # plot the brain data for an arbitrary time point and the weights for an
##    # also-arbitrary couple of nodes
##    t_plot = 20
##    draw_slices(voxel_data[t_plot,:,:,:], 10, 10, 'brain.t_%i.png' % (t_plot))
##    for n in range(0, nnodes, 30):
##        print n
##        w_n = W[n,:].reshape((nx,ny,nz))
##        draw_slices(w_n, 10, 10,
##            'weights.corrlen_%2.2i.node_%3.3i.png' % (corr_len, n))

def main():
    p = argparse.ArgumentParser(
        description='resample voxel data onto a known mask with gaussian smoothing')
    p.add_argument('--voxel-data', type=str, required=True,
            metavar='voxel-data-file',
            help='numpy file containing voxel data (nt, nxvoxels, nyvoxels, nzvoxels)')
    p.add_argument('--mask', type=str, required=True,
            metavar='mask-file',
            help='numpy file containing the mask (nnodes, nvoxels)')
    p.add_argument('--corr-len', type=float, required=True,
            metavar='voxel-corr-len',
            help='correlation length for smoothing (units: voxel widths)')
    args = p.parse_args()
    fname, _ = splitext(args.voxel_data)
    outfile = 'node-data.corr-len-%i.%s' % (args.corr_len, basename(fname))
    resample_brain_data(args.voxel_data, args.mask, args.corr_len, outfile)

if __name__ == '__main__':
    main()


from django.db.models import Q
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework import status
from guardian.shortcuts import assign_perm

from permissions.services import APIPermissionClassFactory
from books.models import Book
from books.serializers import BooksSerializer
from users.models import Reader
from notes.models import Note
from notes.serializers import NoteSerializer
from analysis.models import Analysis
from analysis.serializers import AnalysisSerializer
from reviews.serializers import ReviewSerializer
from reviews.models import Review

class BookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BooksSerializer
    permission_classes = (
        APIPermissionClassFactory(
            name='BookPermission',
            permission_configuration={
                'base': {
                    'create': True,
                    'list': True,
                },
                'instance': {
                    'retrieve': True,
                    'destroy': False,
                    'update': False,
                    'partial_update': True,
                    'reviews': True,
                }
            }
        ),
    )

    @action(detail=True, url_path='analysis', methods=['get'])
    def analysis(self, request, pk=None):
        analysis = Analysis.objects.all().filter(Q(book=pk))
        serialized = AnalysisSerializer(analysis, many=True)
        return Response(serialized.data)

    @action(detail=True, url_path='reviews', methods=['get'])
    def reviews(self, request, pk=None):
        reviews = Review.objects.all().filter(Q(book=pk))
        serialized = ReviewSerializer(reviews, many=True)
        return Response(serialized.data)

    @action(detail=False, url_path='book-time', methods=['post'])
    def book_time(self, request, pk = None):
        start = request.data.get('start')
        end = request.data.get('end')
        if start and end:
            books = Book.objects.all().filter(Q(pub_date__gt=start), Q(pub_date__lt=end))
        elif start and not end:
            books = Book.objects.all().filter(Q(pub_date__gt=start))
        elif not start and end:
            books = Book.objects.all().filter(Q(pub_date__lt=end))
        else:
            return Response(status=status.HTTP_204_NO_CONTENT)
        serialized = BooksSerializer(books, many=True)
        return Response(serialized.data)


import shutil
import tkinter as tk
from tkinter import ttk
import re
from tkinter.constants import DISABLED
from PIL import Image, ImageTk, ImageGrab
import os
import csv

from draggable_quad import DrawShapes
from draggable_square import DrawSquare
from tkinter import filedialog
from tkinter import messagebox as mb
import os
import math
import json
from tissue_grid import Tissue
import cv2
import numpy as np
import matplotlib
import matplotlib.cm
from shutil import copy, move, rmtree, copytree
from tkinter.filedialog import askopenfile, askopenfilename
Image.MAX_IMAGE_PIXELS = None

def center(tL,tR,bR,bL):
        top = [(tL[0]+tR[0])/2,(tL[1]+tR[1])/2]
        bottom = [(bL[0]+bR[0])/2,(bL[1]+bR[1])/2]
        x = (top[0]+bottom[0])/2
        y = (top[1]+bottom[1])/2
        return x,y
#Function for dividing line segemnt according to ratio
def ratio50l(xc,yc,xr,yr,num):
    txp = xc + (1/(num))*(xr-xc)
    typ = yc + (1/(num))*(yr-yc)
    return [txp , typ]
def from_rgb(rgb):
    """translates an rgb tuple of int to a tkinter friendly color code
    """
    r, g, b = rgb
    return f'#{r:02x}{g:02x}{b:02x}'

class Gui():
    def __init__(self, root):
        self.newWindow = root
        self.screen_width = self.newWindow.winfo_screenwidth()
        self.screen_height = self.newWindow.winfo_screenheight()
        self.newWindow.title("AtlasXbrowser")
        self.newWindow.geometry("{0}x{1}".format(int(self.screen_width/1.5+290), self.screen_height))

        style = ttk.Style(root)
        root.tk.call('source', 'Azure-ttk-theme/azure/azure.tcl')
        style.theme_use('azure')

        background_image = Image.open("atlasbg.png")
        resized_image = background_image.resize((int(self.screen_width/1.5), self.screen_height), Image.ANTIALIAS)
        bg = ImageTk.PhotoImage(resized_image)

        menu = tk.Menu(self.newWindow)
        self.newWindow.config(menu=menu)
        filemenu = tk.Menu(menu)
        menu.add_cascade(label="File", menu=filemenu)

        filemenu.add_command(label="Begin Image Processing", command=self.load_images)
        filemenu.add_command(label="Open Spatial Folder", command=self.get_spatial)
        filemenu.add_command(label="New Instance", command=self.restart)
        filemenu.add_separator()
        filemenu.add_command(label="Exit", command=self.destruct)
        helpmenu = tk.Menu(menu)
        menu.add_cascade(label="Help", menu=helpmenu)
        helpmenu.add_command(label="About...", command="")

        self.names = []
        self.numTixels = 0
        self.excelName = None
        self.folder_selected = None
        self.topx, self.topy, self.botx, self.boty = 0, 0, 0, 0
        self.points = []
        self.Rpoints = []
        self.coords = None
        self.arr = None
        self.check_on = tk.IntVar()
        self.check_on.set(0)
        self.quad_coords = [0]
        self.rotated_degree = 0

        self.ROILocated = False

        #flag to determine if user is currently in the tixel classification step
        self.classification_active = False

        #containers
        self.my_canvas = tk.Canvas(self.newWindow, width = int(self.screen_width/3), height= self.screen_height, highlightthickness = 0, bd=0)
        self.my_canvas.pack(side=tk.LEFT, anchor=tk.NW)
        self.my_canvas.old_coords = None
        self.right_canvas = tk.Canvas(self.newWindow, width = int(self.screen_width/3) - self.screen_width, height= self.screen_height, highlightbackground="lightgray", highlightthickness=1)
        self.right_canvas.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
        button_frame = tk.Frame(self.right_canvas)
        button_frame.pack(side=tk.RIGHT, fill=tk.BOTH)

        self.lmain = tk.Label(self.my_canvas)
        self.lmain.pack()
        self.lmain.image = bg
        self.lmain.configure(image=bg)

        #f/crop
        self.cropframe = tk.LabelFrame(self.right_canvas, text="Cropping", padx="10px", pady="10px")
        self.cropframe.place(relx=.11, rely=.01)
        self.activateCrop_button = tk.Button(self.cropframe, text = "Activate", command = self.cropping, state=tk.DISABLED)
        self.activateCrop_button.pack(side=tk.LEFT)
        self.confirmCrop_button = tk.Button(self.cropframe, text = "Confirm", command = self.square_image, state=tk.DISABLED)
        self.confirmCrop_button.pack()

        #Rotation Panel
        self.rotateframe = tk.LabelFrame(self.right_canvas, text="Rotation", padx="10px", pady="10px")
        self.rotateframe.place(relx=.11, rely=.10)
        self.image_updated = tk.Button(self.rotateframe, text = "Confirm", command = self.image_position, state=tk.DISABLED)
        self.image_updated.pack(side=tk.BOTTOM)
        rotateleft = Image.open("rotateleft.png")
        bg = ImageTk.PhotoImage(rotateleft)
        self.left = tk.Button(self.rotateframe, image=bg, command= lambda:self.image_axis(0), state=tk.DISABLED)
        self.left.image = bg
        self.left.pack(side=tk.LEFT)
        rotateright = Image.open("rotateright.png")
        bg2 = ImageTk.PhotoImage(rotateright)
        self.right = tk.Button(self.rotateframe, image=bg2, command= lambda:self.image_axis(1), state=tk.DISABLED)
        self.right.image = bg2
        self.right.pack(side=tk.LEFT)

        #create Scales
        self.adframe = tk.LabelFrame(self.right_canvas, text="Adaptive Thresholding", padx="10px", pady="10px")
        self.adframe.place(relx=.11, rely=.23)

        #blocksize label
        self.blockSize_label = tk.Label(self.adframe, text="blockSize", font =("Courier", 14))
        self.blockSize_label.pack(anchor='w')

        self.blockSize_value = tk.IntVar()
        self.cMean_value = tk.IntVar()
        #initializing the blockSize and cMean values
        self.blockSize_value.set(13)
        self.cMean_value.set(11)
        #blocksize scale
        self.blockSize_scale = ttk.Scale(self.adframe, variable = self.blockSize_value, from_ = 3, to = 17, orient = tk.HORIZONTAL, command= self.showThresh, length=200, state=tk.DISABLED)
        self.blockSize_scale.pack(anchor='w')
        #creating cmean labels and cmean scales
        self.cMean_label = tk.Label(self.adframe, text="C (to subtract from mean)", font =("Courier", 14))
        self.cMean_label.pack(anchor='w')
        self.cMean_scale = ttk.Scale(self.adframe, variable = self.cMean_value, from_ = 0, to = 17, orient = tk.HORIZONTAL, command= self.showThresh, length=200, state=tk.DISABLED)
        self.cMean_scale.pack(anchor='w')

        self.activateThresh_button = tk.Button(self.adframe, text="Activate", command=self.activate_thresh,
                                               state=tk.DISABLED)
        self.activateThresh_button.pack(side=tk.LEFT)
        self.confirm_thresh = tk.Button(self.adframe, text="Confirm", command=self.save_thresholded_image,
                                        state=tk.DISABLED)
        self.confirm_thresh.pack()

        #buttons
        self.thframe = tk.LabelFrame(self.right_canvas, text="Locating ROI", padx="10px", pady="10px")
        self.thframe.place(relx=.11, rely= .42)
        self.begin_button = tk.Button(self.thframe, text = "Activate", command = self.find_points, state=tk.DISABLED)
        self.begin_button.pack(side=tk.LEFT)

        self.confirm_button = tk.Button(self.thframe, text = "Confirm", command = lambda: self.confirm(None), state=tk.DISABLED)
        self.confirm_button.pack()

        self.shframe = tk.LabelFrame(self.right_canvas, text="Overlay", padx="10px", pady="10px")
        self.shframe.place(relx=.11, rely=.51)

        self.grid_button = tk.Button(self.shframe, text = "BW", command = lambda: self.grid(self.picNames[2]), state=tk.DISABLED)
        self.grid_button.pack(side=tk.LEFT)

        self.gridA_button = tk.Button(self.shframe, text = "BSA", command = lambda: self.grid(self.picNames[0]), state=tk.DISABLED)
        self.gridA_button.pack(anchor='w')

        self.labelframe = tk.LabelFrame(self.right_canvas, text="On/Off Tissue", padx="10px", pady="10px")
        self.labelframe.place(relx=.11, rely= .60)
        self.value_labelFrame = tk.IntVar()
        self.value_labelFrame.set(1)
        self.onoff_button = tk.Button(self.labelframe, text="Activate", command=lambda: self.sendinfo(self.picNames[2]),
                                      state=tk.DISABLED)
        self.onoff_button.pack(anchor='w')
        tk.Radiobutton(self.labelframe, text="Point (flip)", variable=self.value_labelFrame, value=1, command = self.offon).pack(anchor='w')
        tk.Radiobutton(self.labelframe, text="Rectangle (flip)", variable=self.value_labelFrame, value=2, command = self.highlit).pack(anchor='w')
        tk.Radiobutton(self.labelframe, text="Rectangle (all on)", variable=self.value_labelFrame, value=3,
                       command=self.highliton).pack(anchor='w')
        tk.Radiobutton(self.labelframe, text="Rectangle (all off)", variable=self.value_labelFrame, value=4,
                       command=self.highlitoff).pack(anchor='w')

        self.value_sheFrame = tk.IntVar()
        self.value_sheFrame.set(1)
        self.sheframe = tk.LabelFrame(self.right_canvas, text="Visualization", padx="10px", pady="10px",width=100)
        self.sheframe.place(relx=.11, rely= .81)
        tk.Radiobutton(self.sheframe, text="Tixel", variable=self.value_sheFrame, value=1, command= lambda:self.sendinfo(self.picNames[2])).grid(row=0,column=0)
        tk.Radiobutton(self.sheframe, text="Feature", variable=self.value_sheFrame, value=2, command= lambda: self.count(7)).grid(row=0,column=1)
        tk.Radiobutton(self.sheframe, text="Count", variable=self.value_sheFrame, value=3, command= lambda: self.count(6)).grid(row=0,column=2)

        for child in self.labelframe.winfo_children():
            if child.winfo_class() == 'Radiobutton':
                child['state'] = 'disabled'
        for child in self.sheframe.winfo_children():
            if child.winfo_class() == 'Radiobutton':
                child['state'] = 'disabled'

        self.position_file = tk.Button(self.right_canvas, text = "Create the Spatial Folder", command = self.create_files, state=tk.DISABLED)
        self.position_file.place(relx=.11, rely= .9)

        #A list to store the order in which rotations and reflections are complete
        self.rotation_order = []

    def restart(self):
        self.newWindow.destroy()
        self.kill = True
        return self.kill
    def destruct(self):
        self.newWindow.destroy()

    def load_images(self):
        self.both_images_selected = False
        self.barcode_file_selected = False
        self.starting_window = tk.Toplevel(self.newWindow)
        self.starting_window.title("Selecting Images")
        self.starting_window_origwidth = 600
        self.starting_window_height = 400
        self.starting_window_width = self.starting_window_origwidth
        self.starting_window.geometry("600x400")

        x_padding = 2

        #defining a label to identify the option of selecting the BSA stained image
        label1 = tk.Label(self.starting_window,
        text = "Select BSA image:",
        font = ("Courier", 14),
        # width = 25
        )
        label1.grid(row = 0, column = 0, sticky = "e")

        #initializing an attibute to be modifed by get_image_file command upon button click
        self.user_selected_bsa = ""
        #button where user can select BSA
        bsa_button = tk.Button(self.starting_window, text = "File", command = lambda: self.get_image_file(0, label1a))
        bsa_button.grid(row = 0, column = 1, sticky = "w")

        #label to display the name of the selected BSA file to the user
        label1a = tk.Label(self.starting_window)
        label1a.grid(row = 0, column = 2, sticky = "w")

        label2 = tk.Label(self.starting_window,
        text = "Select PostB image:",
        font = ("Courier", 14),
        # width = 25,
        )
        label2.grid(row = 1, column = 0, sticky = "e")
        #label to display the name of the selected postB file to user

        label2a = tk.Label(self.starting_window)
        label2a.grid(row = 1, column =2, sticky = "w")

        #attibute to store postB image file name
        self.user_selected_postB = ""
        #button where user can select postB
        postB_button = tk.Button(self.starting_window, text = "File", command = lambda: self.get_image_file(1, label2a))
        postB_button.grid(row = 1, column = 1, sticky = "w")

        label3 = tk.Label(self.starting_window,
        text = "Select Barcode File:",
        font = ("Courier", 14))
        label3.grid(row = 2, column = 0, sticky = "e")

        label3a = tk.Label(self.starting_window)
        label3a.grid(row = 2, column = 2, sticky = "w")

        barcode_button = tk.Button(self.starting_window, text = "File", command = lambda: self.get_barcode_file(label3a))
        barcode_button.grid(row = 2, column = 1, sticky = "w")

        self.run_identifier = tk.StringVar()
        label4 = tk.Label(self.starting_window,
        text = "Run ID:",
        font = ("Courier", 14)
        # width = 25
        )

        entry_box = tk.Entry(self.starting_window, textvariable = self.run_identifier,
        )

        label4.grid(row = 3, column = 0, sticky = "e")
        entry_box.grid(row = 3, column = 1, sticky = "w")

        button = tk.Button(self.starting_window, text='Submit', font =("Courier", 14), command = lambda: self.configure_metadata())
        button.grid(row = 5, column = 1, sticky = "w", pady = 20)

        self.error_label = tk.Label(self.starting_window)
        self.error_label.grid(row = 6, column = 1, sticky = "w")

    def get_barcode_file(self, label):
        #taking file path
        file = askopenfilename()
        if file == "":
            return

        #checking if able to readlines of file
        try:
            f = open(file, "r")
            contents = f.readlines()
            total_num = len(contents)

            #taking square root of number of barcodes
            barcodes = math.sqrt(total_num)

            #ensuring this is a whole number, indicating proper barcode file
            if barcodes - int(barcodes) == 0:

                self.num_chan = int(barcodes)
                #finding name of file
                val = file.rfind("/")
                #slicing string to only be image name, not full path
                display_name = file[val + 1: ]
                #resizing popup accordingly
                self.resize_popup(display_name, label)
                #setting class variable
                self.barcode_filename = file

                self.barcode_file_selected = True

            # if the sqrt is not a whole number, we know this is not a proper barcode file
            else:
                print("Not valid barcode")
                message = "Invalid barcode file, must include a proper number of barcodes."
                self.resize_popup(message, label)
                label.config(text = message)
                self.barcode_file_selected = False

        # if not output error message on screen and ask to select text file
        except UnicodeDecodeError:
            print("Unable to open file")
            msg ="Invalid file type, must be of type .txt"
            self.resize_popup(msg, label)
            label.config(text = msg)
            self.barcode_file_selected = False

    #method used to resize the popup window to ensure the user is able to see the name of the file they selected
    def resize_popup(self, message, label):
        leng = len(message)
        #checking whether the length accomidated to this name is longer than current
        potential_width  = self.starting_window_origwidth + (leng * 4)
        current_width = self.starting_window.winfo_width()
        if potential_width > current_width:
            #if so the window is resized to this potential length
            self.starting_window_width = potential_width
            new_dims = str(self.starting_window_width) + "x" + str(self.starting_window_height)
            self.starting_window.geometry(new_dims)
        #adding the name of the message to the popup
        label.config(text = message)

    #method used to allow users to retrieve required image file. num is a 0 or 1 referring to whether the user is selecting a
    #BSA or postB image respectively, and the label refers to the Label object to be updated by the name upon retrieval
    def get_image_file(self, num, label):
        #allow user to select file
        file = askopenfilename()

        #if the user selects to cancel file selection then nothing changes
        if file == "":
            return

        #flag set to false, as unsure what the user will select
        self.both_images_selected = False

        #ensuring that the selected file is an image file
        if file.lower().endswith((".png", ".jpg", "jpeg", ".tiff", ".tif")):
            #for BSA
            if num == 0:
                self.user_selected_bsa = file
                if self.user_selected_postB != "":
                    self.both_images_selected = True

            #for postB
            else:
                self.user_selected_postB = file

                if self.user_selected_bsa != "":
                    self.both_images_selected = True

        else:
            if num == 0:
                self.user_selected_bsa = ""
            else:
                self.user_selected_postB = ""
            file = "Error! Must select an image of type .png .jpg, .jpeg .tiff or .TIF"

        #finding last / in the path
        val = file.rfind("/")
        #slicing string to only be image name, not full path
        display_name = file[val + 1: ]

        self.resize_popup(display_name, label)

    #method for checking whether the two photos selected by the the user are within the same folder
    def check_dirs(self, bsa_path, postB_path):
        last_back = bsa_path.rfind("/")
        bsa_folder = bsa_path[:last_back]

        last_back = postB_path.rfind("/")
        postB_folder = postB_path[:last_back]

        if bsa_folder == postB_folder:
            self.folder_selected = bsa_folder
            return True
        else:
            return False

    def configure_metadata(self):

        same_dir = self.check_dirs(self.user_selected_bsa, self.user_selected_postB)

        if same_dir:
            #retrieving variables from stored StringVar variables
            runID = self.run_identifier.get()
            if runID != "" and self.both_images_selected and self.barcode_file_selected:
                val = self.user_selected_bsa.rfind("/")
                self.bsa_short = self.user_selected_bsa[val + 1: ]

                val = self.user_selected_postB.rfind("/")
                self.postB_short = self.user_selected_postB[val + 1: ]

                self.metadata = {
                "run": runID
                }

                #setting excelName var, used later, to equal the user specifed run ID
                self.excelName = runID

                #calling method that puts images on canvas
                self.configure_images()

                self.starting_window.destroy()
                self.activateCrop_button['state'] = tk.ACTIVE

                self.newWindow.title("AtlasXbrowser (" + runID + ")")

            elif runID == "":
                self.error_label.config(text = "Error! Enter a Run Identifier")

            elif self.both_images_selected == False:
                self.error_label.config(text = "Error! Must select BSA and postB Images!")
        else:
            self.error_label.config(text = "Images must be located in the same directory!")

    #populates the canvas of the main page with the BSA image
    def configure_images(self):
        a = Image.open(self.user_selected_bsa)
        w, h = (a.width, a.height)
        newH = self.screen_height - 60

        self.image_array = cv2.imread(self.user_selected_bsa, 0)
        self.rotation_matrix = np.identity(len(self.image_array))

        #find ratio of 60 less than screenheight to the image height
        self.factor = newH/h
        #use ratio to calcuate the new width
        newW = int(round(w*newH/h))
        #resize the bsa image based on these calculations
        bsa = a.resize((newW, newH), Image.ANTIALIAS)
        self.qwimga = ImageTk.PhotoImage(bsa)
        #setting canvas height and width based on the size of images
        self.my_canvas.config(width = bsa.width, height= bsa.height)
        self.lmain.pack_forget()
        #loading the bsa image onto screen
        self.my_canvas.create_image(0, 0, image=self.qwimga, anchor="nw", tag ="image")
        self.newWindow.geometry("{0}x{1}".format(bsa.width + 300, self.screen_height))
        self.right_canvas.config(width = bsa.width + 300, height= h)

    #Ability to grab files from specified folder 'Spatial folder'
    def get_spatial(self):
        self.folder_selected = filedialog.askdirectory()

        if self.folder_selected != '':

            self.pWindow = tk.Toplevel(self.newWindow)
            self.pWindow.title("Loading images...")
            self.pWindow.geometry("400x90")
            self.bar = ttk.Progressbar(self.pWindow, orient="horizontal", length=360)
            self.bar.pack(pady=30)
            self.bar["value"] += 10
            self.pWindow.update_idletasks()
            self.pWindow.update()

            for file in os.listdir(self.folder_selected):
                if file.startswith(".") == False:
                     self.names.append(file)

            try:
                # self.barcode_file_spatial = open(self.folder_selected + "/barcode_file.txt")
                f = open(self.folder_selected + "/metadata.json")
                self.metadata = json.load(f)
                self.num_chan = int(self.metadata['numChannels'])
                self.numTixels = int(self.metadata['numTixels'])
                f2 = open(self.folder_selected + "/scalefactors_json.json")
                self.metadata2 = json.load(f2)
                self.tissue_hires_scalef = float(self.metadata2['tissue_hires_scalef'])
                self.bar["value"] = 20
                self.pWindow.update()
                self.second_window()
            except FileNotFoundError:
                mb.showwarning("Error", "metadata.json file is not present")
                self.pWindow.destroy()
        else:
            #Add error message
            pass

    #Initalize images that will be in container
    def init_images(self):

        #opening images directly from previously stored path
        a = Image.open(self.bsa_figure_path)
        b = Image.open(self.postB_figure_path)

        w, h = (a.width, a.height)
        self.rawHeight = h
        self.width, self.height = (a.width, a.height)
        newH = self.screen_height - 60
        self.factor = newH/h

        newW = int(round(w*newH/h))
        floor = a.resize((newW, newH), Image.ANTIALIAS)
        postB = b.resize((newW, newH), Image.ANTIALIAS)

        self.refactor = a
        self.newWidth = floor.width
        self.newHeight = floor.height

        img = cv2.imread(self.postB_figure_path, cv2.IMREAD_UNCHANGED)

        flippedImage = img

        try:
            self.scale_image = cv2.cvtColor(flippedImage, cv2.COLOR_BGR2GRAY)
        except cv2.error:
            self.scale_image = flippedImage

        self.imgA = ImageTk.PhotoImage(floor)
        self.imgB = ImageTk.PhotoImage(postB)
        self.picNames = [self.imgA, self.imgB]

        #my_canvas populated with the BSA stained image instead of the post-B image
        self.my_canvas.config(width = floor.width, height= floor.height)
        self.lmain.configure(image=self.imgA)
        self.newWindow.geometry("{0}x{1}".format(floor.width + 300, self.screen_height))
        self.right_canvas.config(width = floor.width + 300, height= h)

    #Rotate and flip the images
    def image_axis(self, num):
        (h,w) = self.cropped_image.shape[:2]
        cX, cY = (w // 2, h //2)

        if num == 0:
            M = cv2.getRotationMatrix2D((cX, cY), 90, 1.0)
            updated = cv2.warpAffine(self.cropped_image, M, (w,h))
            I = cv2.cvtColor(updated, cv2.COLOR_BGR2RGB)
            # updated = cv2.rotate(self.cropped_image, cv2.ROTATE_90_COUNTERCLOCKWISE)
            formatted = Image.fromarray(I)
            sized = formatted.resize((self.newWidth, self.newHeight), Image.ANTIALIAS)
            imgtk = ImageTk.PhotoImage(sized)
            self.lmain.image = imgtk
            self.lmain.configure(image=imgtk)
            self.cropped_image = updated
            # self.rotated_degree+=-90
            self.rotated_degree += 90
            self.rotation_order.append(90)

        if num == 1:
            M = cv2.getRotationMatrix2D((cX, cY), 270, 1.0)
            updated = cv2.warpAffine(self.cropped_image, M, (w,h))
            I = cv2.cvtColor(updated, cv2.COLOR_BGR2RGB)
            # updated = cv2.rotate(self.cropped_image, cv2.ROTATE_90_CLOCKWISE)
            formatted = Image.fromarray(I)
            sized = formatted.resize((self.newWidth, self.newHeight), Image.ANTIALIAS)
            imgtk = ImageTk.PhotoImage(sized)
            self.lmain.image = imgtk
            self.lmain.configure(image=imgtk)
            self.cropped_image = updated
            # self.rotated_degree+=90
            self.rotated_degree += 270
            self.rotation_order.append(270)

    #Update postB and BSA images to new image orientation
    def image_position(self):
        image = cv2.imread(self.bsa_figure_path)
        image1 = cv2.imread(self.postB_figure_path)
        (h,w) = image.shape[:2]

        (h1, w1) = image.shape[:2]

        cX, cY = (w // 2, h //2)
        degrees = self.rotated_degree % 360
        M = cv2.getRotationMatrix2D((cX, cY), degrees, 1.0)
        image = cv2.warpAffine(image, M, (w,h))
        image1 = cv2.warpAffine(image1, M, (w,h))

        cv2.imwrite(self.bsa_figure_path, image)
        cv2.imwrite(self.postB_figure_path, image1)

        self.metadata["orientation"] = {"rotation": degrees}

        #self.metadata["orientation"] = {"horizontal_flip": self.flipped_horz,"rotation": 90 * degree,"vertical_flip": self.flipped_vert}

        self.left['state'] = tk.DISABLED
        self.right['state'] = tk.DISABLED
        self.image_updated['state'] = tk.DISABLED
        self.activateThresh_button['state'] = tk.ACTIVE

        self.init_images()

    def cropping(self):
        #creating cropping square on screen, defined as b
        self.b = DrawSquare(self.my_canvas)
        # self.my_canvas.bind('<Button-1>', self.b.on_click_quad)
             #DOES THIS NEED TO BE INCLUDED^^^
        self.my_canvas.bind('<Button1-Motion>', self.b.on_motion)
        self.my_canvas.bind('<ButtonRelease-1>', self.b.on_release)

        #deactivating the 'activate' button, activating the 'confirm' button

        self.activateCrop_button['state'] = tk.DISABLED
        self.confirmCrop_button['state'] = tk.ACTIVE

    #Confirm cropping and reinitalize images in the containers
    def square_image(self):

        self.figure_folder = os.path.join(self.folder_selected, "figure")
        #try making a figure folder
        try:
            os.mkdir(self.figure_folder)
        #exception if the folder already exists. If so, remove and remake
        except FileExistsError:
            rmtree(self.figure_folder)
            os.mkdir(self.figure_folder)

        #source is the source folder of the spatial images
        source = self.folder_selected
        coords = self.my_canvas.coords('crop')

        #copying the image files into the figure folder in within the same larger folder
        # for i in self.names:
        #     copy(source + "/" + i, self.figure_folder)

        copy(source + "/" + self.bsa_short, self.figure_folder)
        copy(source + "/" + self.postB_short, self.figure_folder)

        self.bsa_figure_path = self.figure_folder + "/" + self.bsa_short
        image1 = Image.open(self.bsa_figure_path)
        im1 = image1.crop((int(coords[0]/self.factor),int(coords[1]/self.factor),int(coords[2]/self.factor),int(coords[3]/self.factor)))
        bsa = im1.save(self.bsa_figure_path)

        self.postB_figure_path = self.figure_folder + "/" + self.postB_short
        image2 = Image.open(self.postB_figure_path)
        im2 = image2.crop((int(coords[0]/self.factor),int(coords[1]/self.factor),int(coords[2]/self.factor),int(coords[3]/self.factor)))
        post = im2.save(self.postB_figure_path)

        self.my_canvas.unbind('<Button-1>')
        self.my_canvas.unbind('<Button1-Motion>')

        # self.up['state'] = tk.ACTIVE
        self.left['state'] = tk.ACTIVE
        self.right['state'] = tk.ACTIVE
        # self.flip['state'] = tk.ACTIVE
        self.image_updated['state'] = tk.ACTIVE
        self.confirmCrop_button['state'] = tk.DISABLED

        b = im1

        w, h = (b.width, b.height)
        #newH is 60 less than the image height
        newH = self.screen_height - 60
        #newW is the ratio of newH to H times the width
        newW = int(round(w*newH/h))
        #creating a new image of resized BSA image base don above calculations
        floor = b.resize((newW, newH), Image.ANTIALIAS)

        #setting object height and width to the BSA images
        self.newWidth = floor.width ; self.newHeight = floor.height

        #PhotoImage of the resized BSA
        imgA = ImageTk.PhotoImage(floor)

        self.my_canvas.config(width = floor.width, height= floor.height)

        img = cv2.imread(self.bsa_figure_path, cv2.IMREAD_UNCHANGED)
        self.cropped_image = img

        self.lmain.pack()

        self.lmain.image = imgA
        self.lmain.configure(image=imgA)
        self.my_canvas.delete("image")
        self.newWindow.geometry("{0}x{1}".format(floor.width + 300, self.screen_height))
        self.right_canvas.config(width = floor.width + 300, height= h)

    def activate_thresh(self):

        self.classification_active = False
        #boolean returns true if lmain does not exist
        if self.lmain.winfo_exists() == 0:
            #disable all buttons except for the "confirm"
            self.begin_button['state'] = tk.DISABLED
            self.grid_button['state'] = tk.DISABLED
            self.gridA_button['state'] = tk.DISABLED
            self.onoff_button['state'] = tk.DISABLED

            #Changing the selected radio button to display the first option of a point flip
            self.value_labelFrame.set(1)

            #removing images from the canvas
            self.my_canvas.delete("all")
            #re-creating the lmain tab which was previously destroyed
            self.lmain = tk.Label(self.my_canvas)
            self.lmain.pack()

            #ensuring the blockSize_value is odd
            numb = round(self.blockSize_value.get())
            if numb % 2 == 0:
                self.blockSize_value = tk.IntVar()
                self.blockSize_value.set(numb + 1)

        #disable all the satelitte buttons from that step
        #only relevent if coming from tixel thresholding step
        if self.picNames[0] != None:
            for child in self.labelframe.winfo_children():
                if child.winfo_class() == 'Radiobutton':
                    child['state'] = 'disabled'

        self.blockSize_scale['state'] = tk.ACTIVE
        self.cMean_scale['state'] = tk.ACTIVE
        self.activateThresh_button['state'] = tk.DISABLED
        self.confirm_thresh['state'] = tk.ACTIVE
        self.my_canvas.unbind('<Button-1>')
        self.my_canvas.unbind('<B1-Motion>')
        self.my_canvas.unbind('<ButtonRelease-1>')

        #finding the initial bw image from thresholding

        thresh = cv2.adaptiveThreshold(self.scale_image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, self.blockSize_value.get(), self.cMean_value.get())
        bw_image = Image.fromarray(thresh)
        sized_bw = bw_image.resize((self.newWidth, self.newHeight), Image.ANTIALIAS)
        imgtk = ImageTk.PhotoImage(sized_bw)
        self.lmain.image = imgtk
        self.lmain.configure(image=imgtk)

    # "Open spatial folder" window
    def second_window(self):
        self.sendinfo_flag = False
        for i in self.names:
            if "meta" in i:
                self.json = self.folder_selected + "/" + i

            elif "list" in i:
                self.position = self.folder_selected + "/" + i

        try:
            self.excelName = self.metadata['run']
        except KeyError:
            self.excelName = "Test"

        self.newWindow.title("AtlasXbrowser (" + self.excelName+")")

        self.postB_Name = self.folder_selected + "/tissue_hires_image.png"
        a = Image.open(self.postB_Name)
        self.bar["value"] = 30
        self.pWindow.update()
        self.bar["value"] = 40
        self.pWindow.update()

        w, h = (a.width, a.height)
        self.width, self.height = (a.width, a.height)
        resizeNumber = self.screen_height - 60
        if h > resizeNumber:
            self.factor = resizeNumber/h
            newW = int(round(w*resizeNumber/h))
            floor = a.resize((newW, resizeNumber), Image.ANTIALIAS)
        else:
            floor = a
            self.factor = 1

        self.refactor = a
        self.newWidth = floor.width ; self.newHeight = floor.height

        img = cv2.imread(self.postB_Name, cv2.IMREAD_UNCHANGED)
        self.bar["value"] = 50
        self.pWindow.update()
        self.bar["value"] = 60
        self.pWindow.update()
        try:
            self.scale_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        except cv2.error:
            self.scale_image = img
        self.bar["value"] = 80
        self.pWindow.update()
        self.imgA = ImageTk.PhotoImage(floor)
        self.picNames = [None, None]

        #update canvas and frame
        self.my_canvas.config(width = floor.width, height= floor.height)
        self.lmain.destroy()
        self.newWindow.geometry("{0}x{1}".format(floor.width + 300, self.screen_height))
        self.right_canvas.config(width = floor.width + 300, height= h)
        try:
            newFactor = resizeNumber/self.metadata['rawHeight']
        except KeyError:
            newFactor = 1
        self.Rpoints = [i*newFactor for i in self.metadata['points']]

        self.coords = [[[] for i in range(self.num_chan)] for i in range(self.num_chan)]
        self.arr = [[[] for i in range(self.num_chan)] for i in range(self.num_chan)]

        #Buttons
        self.begin_button['state'] = tk.DISABLED
        self.confirm_button['state'] = tk.DISABLED
        self.blockSize_scale['state'] = tk.DISABLED
        self.cMean_scale['state'] = tk.DISABLED
        self.grid_button["state"] = tk.DISABLED
        self.onoff_button["state"] = tk.DISABLED
        self.check_on = tk.IntVar()
        self.check_on.set(0)
        #tk.Radiobutton(self.right_canvas, text="Count On", variable=self.check_on, value=1, state=tk.DISABLED).place(relx=.5, rely=.68)
        self.update_file = tk.Button(self.right_canvas, text = "Update the Spatial folder", command = self.update_pos)
        self.update_file.place(relx=.11, rely= .9)

        thresh = cv2.adaptiveThreshold(self.scale_image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, int(self.metadata['blockSize']), int(self.metadata['threshold']))
        self.bar["value"] = 100
        self.pWindow.update()
        bw_image = Image.fromarray(thresh)
        sized_bw = bw_image.resize((self.newWidth, self.newHeight), Image.ANTIALIAS)
        imgtk = ImageTk.PhotoImage(sized_bw)
        self.picNames.append(imgtk)
        self.my_canvas.create_image(0,0, anchor="nw", image = imgtk, state="disabled")
        self.pWindow.destroy()
        self.sendinfo(self.picNames[2])

    #Update Threshold sliders
    def showThresh(self, value):
        if float(value) > 11:
            self.my_canvas.delete("all")
        #sel set to block size value
            sel = int(self.blockSize_value.get())
        #sec set to C value
            sec = int(self.cMean_value.get())
            if sel %2 == 0:
                sel+=1

            #self.blockSize_label_value.config(text = str(sel), font =("Courier", 14))
            #self.cMean_label_value.config(text = str(sec), font =("Courier", 14))

        #re doing the thresholding for the newly set values
            thresh = cv2.adaptiveThreshold(self.scale_image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, sel, sec)
            bw_image = Image.fromarray(thresh)
            sized_bw = bw_image.resize((self.newWidth, self.newHeight), Image.ANTIALIAS)
            imgtk = ImageTk.PhotoImage(image=sized_bw)
            self.lmain.image = imgtk
            self.lmain.configure(image=imgtk)

        else:
            self.my_canvas.delete("all")
            #sel set to blocksize variable
            sel = int(self.blockSize_value.get())
            if sel %2 == 0:
                sel+=1
            #sec set to cMean variable
            sec = int(self.cMean_value.get())

            #new threshold created and loaded onto screen
            thresh = cv2.adaptiveThreshold(self.scale_image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, sel, sec)
            bw_image = Image.fromarray(thresh)
            sized_bw = bw_image.resize((self.newWidth, self.newHeight), Image.ANTIALIAS)
            imgtk = ImageTk.PhotoImage(image=sized_bw)
            self.lmain.image = imgtk
            self.lmain.configure(image=imgtk)

    #Find Roi coordinates
    def find_points(self):

        #Disable  buttons that should not be activated
        self.blockSize_scale['state'] = tk.DISABLED
        self.cMean_scale['state'] = tk.DISABLED
        self.begin_button['state'] = tk.DISABLED
        self.activateThresh_button['state'] = tk.DISABLED
        self.grid_button['state'] = tk.DISABLED
        self.gridA_button['state'] = tk.DISABLED
        self.onoff_button['state'] = tk.DISABLED

        self.lmain.destroy()
        self.my_canvas.create_image(0,0, anchor="nw", image = self.imgA, state="disabled")

        self.c = DrawShapes(self.my_canvas, self.quad_coords)
        self.my_canvas.bind('<Button-1>', self.c.on_click_quad)

        self.my_canvas.bind('<Button1-Motion>', self.c.on_motion)

        self.confirm_button["state"] = tk.ACTIVE

    #Confirms coordinates choosen
    def confirm(self, none):
        self.ROILocated = True
        #self.fromOverlay = True
        self.activateThresh_button['state'] = tk.ACTIVE

        #List of Lists containing a list for every tixel
        self.coords = [[[] for i in range(self.num_chan)] for i in range(self.num_chan)]

        self.arr = [[[] for i in range(self.num_chan)] for i in range(self.num_chan)]

        self.Rpoints = self.my_canvas.coords(self.c.current)
        self.quad_coords = self.my_canvas.coords(self.c.current)

        self.my_canvas.delete("all")
        self.my_canvas.create_image(0,0, anchor="nw", image = self.imgA, state="normal")
        self.my_canvas.unbind("<B1-Motion>")
        self.my_canvas.unbind("<Button-1>")

        self.confirm_button["state"] = tk.DISABLED
        self.begin_button["state"] = tk.ACTIVE
        self.grid_button["state"] = tk.ACTIVE
        self.gridA_button["state"] = tk.ACTIVE
        self.onoff_button["state"] = tk.ACTIVE

    def save_thresholded_image(self):

        #if ROI is located enable tixel overlays, activate thresh button, and tixel thersholding
        if self.ROILocated:
            self.grid_button['state'] = tk.ACTIVE
            self.gridA_button['state'] = tk.ACTIVE
            self.onoff_button['state'] = tk.ACTIVE
            self.activateThresh_button['state'] = tk.ACTIVE

        #activating the button to beging ROI location
        self.begin_button['state'] = tk.ACTIVE
        self.confirm_thresh['state'] = tk.DISABLED

        #ensuring blocksize is odd
        tvalue = self.blockSize_value.get()
        svalue = self.cMean_value.get()
        if tvalue %2 ==0:
            tvalue +=1

        thresh = cv2.adaptiveThreshold(self.scale_image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, tvalue, svalue)
        bwFile_Name = self.excelName + "BW.png"
        cv2.imwrite(bwFile_Name, thresh)
        bw = Image.open(bwFile_Name)
        sized_bw = bw.resize((self.newWidth, self.newHeight), Image.ANTIALIAS)
        bw_Image = ImageTk.PhotoImage(sized_bw)

        #checking if there is already a bw_image and replacing it if so
        if (len(self.picNames) >= 3):
            #if it is replaced with the new bw_Image
            self.picNames[2] = bw_Image
        else:
            #otherwise the new image is added to the end, which will be the 2nd index
            self.picNames.append(bw_Image)

        return bw_Image

    def grid(self,pic):
        #if the lmain label exists, we are coming from thresholding
        if self.lmain.winfo_exists() == 1:
            self.lmain.destroy()
            self.activateThresh_button['state'] = "active"
            self.blockSize_scale['state'] = "disabled"
            self.cMean_scale['state'] = "disabled"

        self.my_canvas.delete("all")
        self.my_canvas.create_image(0,0, anchor="nw", image = pic, state="disabled")

        ratioNum = (self.num_chan*2) - 1
        leftS = ratio50l(self.Rpoints[0],self.Rpoints[1],self.Rpoints[6],self.Rpoints[7],ratioNum)
        topS = ratio50l(self.Rpoints[0],self.Rpoints[1],self.Rpoints[2],self.Rpoints[3],ratioNum)
        slope = [round(leftS[1]-self.Rpoints[1], 5), round(leftS[0]-self.Rpoints[0], 5)]
        slopeT = [round(topS[1]-self.Rpoints[1], 5), round(topS[0]-self.Rpoints[0], 5)]

        slopeO = [slope[0]*2, slope[1]*2]
        slopeTO = [slopeT[0]*2, slopeT[1]*2]

        top = [0,0]
        left = [0,0]
        flag = False
        prev = [self.Rpoints[0],self.Rpoints[1]]
        excelC = 1
        for i in range(self.num_chan):
            top[0] = prev[0]+slopeT[1]
            top[1] = prev[1]+slopeT[0]
            flag = False

            for j in range(self.num_chan):
                if flag == False:
                    left[0] = prev[0]
                    left[1] = prev[1]
                    tL = [left[0],left[1]]
                    tR = [top[0],top[1]]
                    bL = [tL[0]+slope[1],tL[1]+slope[0]]
                    bR = [tR[0]+slope[1],tR[1]+slope[0]]
                    flag =  True
                else:
                    left[0] += slopeO[1]
                    left[1] += slopeO[0]
                    tL = [left[0],left[1]]
                    tR = [top[0],top[1]]
                    bL = [tL[0]+slope[1],tL[1]+slope[0]]
                    bR = [tR[0]+slope[1],tR[1]+slope[0]]
                position = str(j+1) + "x" + str(i)
                pointer = [tL[0],tL[1],    tR[0],tR[1],     bR[0],bR[1],   bL[0],bL[1],    tL[0],tL[1]]
                self.my_canvas.create_polygon(pointer, fill='', outline="black", tag = position, width=1, state="disabled")
                centerx, centery = center(tL,tR,bR,bL)
                self.coords[j][i].append(centerx/self.factor)
                self.coords[j][i].append(centery/self.factor)
                top[0] += slopeO[1]
                top[1] += slopeO[0]
                excelC += 1

                #allowing on and off tissues on overlay
                #if self.classification_active:
                if self.classification_active:
                    if self.arr[j][i] == 1:
                        try:
                            tags = self.my_canvas.find_withtag(position)
                            self.my_canvas.itemconfig(tags[0], fill='red', state="normal")
                        except IndexError:
                            self.my_canvas.itemconfig((self.num_chan*i+5)+j, fill='red', state="normal")
            prev[0] += slopeTO[1]
            prev[1] += slopeTO[0]

    #Send parameters to tissue_grid.py
    def sendinfo(self,pic):
        self.classification_active = True

        #if the lmain label still exists, destroy it
        if self.lmain.winfo_exists() == 1:
            self.lmain.destroy()

        #self.activateThresh_button['state'] = tk.DISABLED
        self.check_on.set(0)
        self.my_canvas.delete("all")
        self.my_canvas.create_image(0,0, anchor="nw", image = pic, state="disabled")

        ratioNum = (self.num_chan*2) - 1
        leftS = ratio50l(self.Rpoints[0],self.Rpoints[1],self.Rpoints[6],self.Rpoints[7],ratioNum)
        topS = ratio50l(self.Rpoints[0],self.Rpoints[1],self.Rpoints[2],self.Rpoints[3],ratioNum)
        slope = [round(leftS[1]-self.Rpoints[1], 5), round(leftS[0]-self.Rpoints[0], 5)]
        slopeT = [round(topS[1]-self.Rpoints[1], 5), round(topS[0]-self.Rpoints[0], 5)]

        slopeO = [slope[0]*2, slope[1]*2]
        slopeTO = [slopeT[0]*2, slopeT[1]*2]

        top = [0,0]
        left = [0,0]
        flag = False
        prev = [self.Rpoints[0],self.Rpoints[1]]
        excelC = 1
        for i in range(self.num_chan):
            top[0] = prev[0]+slopeT[1]
            top[1] = prev[1]+slopeT[0]
            flag = False

            for j in range(self.num_chan):
                if flag == False:
                    left[0] = prev[0]
                    left[1] = prev[1]
                    tL = [left[0],left[1]]
                    tR = [top[0],top[1]]
                    bL = [tL[0]+slope[1],tL[1]+slope[0]]
                    bR = [tR[0]+slope[1],tR[1]+slope[0]]
                    flag =  True
                else:
                    left[0] += slopeO[1]
                    left[1] += slopeO[0]
                    tL = [left[0],left[1]]
                    tR = [top[0],top[1]]
                    bL = [tL[0]+slope[1],tL[1]+slope[0]]
                    bR = [tR[0]+slope[1],tR[1]+slope[0]]

                position = str(j+1) + "x" + str(i)
                pointer = [tL[0],tL[1],    tR[0],tR[1],     bR[0],bR[1],   bL[0],bL[1],    tL[0],tL[1]]
                self.my_canvas.create_polygon(pointer, fill='', outline="black", tag = position, width=1, state="disabled")
                centerx, centery = center(tL,tR,bR,bL)
                self.coords[j][i].append(centerx/self.factor)
                self.coords[j][i].append(centery/self.factor)
                top[0] += slopeO[1]
                top[1] += slopeO[0]
                excelC += 1
            prev[0] += slopeTO[1]
            prev[1] += slopeTO[0]

        if self.picNames[0] != None:
            #setting all tixel chaning radio buttons to on
            for child in self.labelframe.winfo_children():
                if child.winfo_class() == 'Radiobutton':
                    child['state'] = 'active'

            #setting the mouse to flip a single tixel at time, in accordance with option 1
            self.my_canvas.bind('<Button-1>',self.on_off)

            self.position_file["state"] = tk.ACTIVE
            self.begin_button['state'] = tk.DISABLED
            self.onoff_button["state"] = tk.DISABLED

            dbit = self.excelName + "BW.png"
            points_copy = self.Rpoints.copy()

            tissue_information = Tissue(points_copy, self.factor, dbit, self.num_chan)
            self.arr,self.spot_dia, self.fud_dia = tissue_information.theAnswer()
            for i in range(len(self.arr)):
                for j in range(len(self.arr)):
                    position = str(j+1) + "x" + str(i)

                    if self.arr[j][i] == 1:
                        try:
                            tags = self.my_canvas.find_withtag(position)
                            self.my_canvas.itemconfig(tags[0], fill='red', state="normal")
                        except IndexError:
                            self.my_canvas.itemconfig((self.num_chan*i+5)+j, fill='red', state="normal")
        else:
            for child in self.labelframe.winfo_children():
                if child.winfo_class() == 'Radiobutton':
                    child['state'] = 'active'
            if "tissue_positions_list_log_UMI_Genes.csv" in self.names:
                for child in self.sheframe.winfo_children():
                    if child.winfo_class() == 'Radiobutton':
                        child['state'] = 'active'
            self.my_canvas.unbind("<Button-1>")
            self.my_canvas.unbind("<B1-Motion>")
            self.my_canvas.unbind("<ButtonRelease-1>")
            self.my_canvas.bind('<Button-1>',self.on_off)

            self.update_file["state"] = tk.ACTIVE
            if self.sendinfo_flag == False:
                with open(self.folder_selected + "/tissue_positions_list.csv") as csv_file:
                    csv_reader = csv.reader(csv_file)
                    for row in csv_reader:
                        j = int(row[3])+1
                        i = int(row[2])
                        if row[1] == "1":
                            self.arr[j-1][i] = 1
                            position = str(j)+"x"+str(i)
                            try:
                                tags = self.my_canvas.find_withtag(position)
                                self.my_canvas.itemconfig(tags[0], fill='red', state="normal")
                            except IndexError:
                                pass
                        else:
                            self.arr[j-1][i] = 0
                self.sendinfo_flag = True
            else:
                for i in range(len(self.arr)):
                    for j in range(len(self.arr)):
                        position = str(j+1) + "x" + str(i)
                        if self.arr[j][i] == 1:
                            try:
                                tags = self.my_canvas.find_withtag(position)
                                self.my_canvas.itemconfig(tags[0], fill='red', state="normal")
                            except IndexError:
                                self.my_canvas.itemconfig((self.num_chan*i+5)+j, fill='red', state="normal")
            self.onoff_button["state"] = tk.DISABLED

    """Functions used to update On/off Tissue ... creates a new quadrilateral"""
    def offon(self):
        self.my_canvas.unbind('<Button-1>')
        self.my_canvas.unbind('<B1-Motion>')
        self.my_canvas.unbind('<ButtonRelease-1>')
        self.my_canvas.bind('<Button-1>',self.on_off)
    def highlit(self):
        self.my_canvas.unbind('<Button-1>')
        self.my_canvas.bind('<Button-1>',self.highlight)
        self.my_canvas.bind('<B1-Motion>', self.update_sel_rect)
    def update_sel_rect(self, event):
        self.my_canvas.bind("<ButtonRelease-1>", self.release)
        self.botx, self.boty = event.x, event.y
        self.my_canvas.coords("highlight", self.topx, self.topy, self.botx, self.boty)  # Update selection rect.
    def highlight(self, event):
        self.topx, self.topy = event.x, event.y
        self.my_canvas.create_rectangle(self.topx, self.topy, self.topx, self.topy,dash=(2,2), fill='', tag= "highlight", outline='black')
    def release(self,event):
        for k in self.my_canvas.find_overlapping(self.topx, self.topy, self.botx, self.boty):
            position = event.widget.gettags(k)
            if len(position) > 0 and position[0]!="highlight":
                try:
                    where = position[0].split("x")
                except IndexError:
                    break

                state = self.my_canvas.itemcget(k,'state')
                i = where[0]
                j = where[1]
                if self.check_on.get() == 0:
                    if state == "normal":
                        self.my_canvas.itemconfig(k, fill="", state="disabled", width=1)
                        self.arr[int(i)-1][int(j)] = 0
                    else:
                        self.my_canvas.itemconfig(k, fill="red", state ="normal", width=1)
                        self.arr[int(i)-1][int(j)] = 1
                else:
                    if state == "normal":
                        self.my_canvas.itemconfig(k, state="disabled", outline="")
                        self.arr[int(i)-1][int(j)] = 0
                    else:
                        self.my_canvas.itemconfig(k, state ="normal", width=1, outline="black")
                        self.arr[int(i)-1][int(j)] = 1

        self.my_canvas.coords("highlight", 0,0,0,0)
        self.my_canvas.unbind("<ButtonRelease-1>")
    def highliton(self):
        self.my_canvas.unbind('<Button-1>')
        self.my_canvas.bind('<Button-1>',self.highlight)
        self.my_canvas.bind('<B1-Motion>', self.update_sel_recton)
    def update_sel_recton(self, event):
        self.my_canvas.bind("<ButtonRelease-1>", self.releaseon)
        self.botx, self.boty = event.x, event.y
        self.my_canvas.coords("highlight", self.topx, self.topy, self.botx, self.boty)  # Update selection rect.
    def releaseon(self,event):
        for k in self.my_canvas.find_overlapping(self.topx, self.topy, self.botx, self.boty):
            position = event.widget.gettags(k)
            if len(position) > 0 and position[0]!="highlight":
                try:
                    where = position[0].split("x")
                except IndexError:
                    break
                i = where[0]
                j = where[1]
                if self.check_on.get() == 0:
                    self.my_canvas.itemconfig(k, fill="red", state ="normal", width=1)
                    self.arr[int(i)-1][int(j)] = 1
                else:
                    self.my_canvas.itemconfig(k, width=1, state ="normal", outline="black")
                    self.arr[int(i)-1][int(j)] = 1

        self.my_canvas.coords("highlight", 0,0,0,0)
        self.my_canvas.unbind("<ButtonRelease-1>")
    def highlitoff(self):
        self.my_canvas.unbind('<Button-1>')
        self.my_canvas.bind('<Button-1>',self.highlight)
        self.my_canvas.bind('<B1-Motion>', self.update_sel_rectoff)
    def update_sel_rectoff(self, event):
        self.my_canvas.bind("<ButtonRelease-1>", self.releaseoff)
        self.botx, self.boty = event.x, event.y
        self.my_canvas.coords("highlight", self.topx, self.topy, self.botx, self.boty)  # Update selection rect.
    def releaseoff(self,event):
        for k in self.my_canvas.find_overlapping(self.topx, self.topy, self.botx, self.boty):
            position = event.widget.gettags(k)
            if len(position) > 0 and position[0]!="highlight":
                try:
                    where = position[0].split("x")
                except IndexError:
                    break
                i = where[0]
                j = where[1]
                if self.check_on.get() == 0:
                    self.my_canvas.itemconfig(k, fill="", state="disabled", width=1)
                    self.arr[int(i)-1][int(j)] = 0
                else:
                    self.my_canvas.itemconfig(k, state="disabled", outline="")
                    self.arr[int(i)-1][int(j)] = 0

        self.my_canvas.coords("highlight", 0,0,0,0)
        self.my_canvas.unbind("<ButtonRelease-1>")
    def on_off(self, event):
        tag = event.widget.find_closest(event.x,event.y)
        position = event.widget.gettags(tag)
        try:
            where = position[0].split("x")
        except IndexError:
            return None
        state = self.my_canvas.itemcget(tag,'state')
        i = where[0]
        j = where[1]
        if self.check_on.get()==0:
            if state == "normal":
                self.my_canvas.itemconfig(tag, fill="", state="disabled", width=1)
                self.arr[int(i)-1][int(j)] = 0
                self.numTixels -= 1
            else:
                self.my_canvas.itemconfig(tag, fill="red", state ="normal", width=1)
                self.arr[int(i)-1][int(j)] = 1
                self.numTixels += 1
        else:
            if state == "normal":
                self.my_canvas.itemconfig(tag, state="disabled", outline="")
                self.arr[int(i)-1][int(j)] = 0
                self.numTixels -= 1
            else:
                self.my_canvas.itemconfig(tag, state ="normal", width=1, outline="black")
                self.arr[int(i)-1][int(j)] = 1
                self.numTixels += 1

    #Creates files for spatial folder
    def create_files(self):
        try:
            path = os.path.join(self.folder_selected, "spatial")
            os.mkdir(path)
        except FileExistsError:
            path = self.folder_selected + "/spatial"

        #barcode_file = "bc" + str(self.num_chan) + "v" + self.barcodes + ".txt"
        my_file = open(self.barcode_filename,"r")
        excelC = 1
        with open(path + "/tissue_positions_list.csv", 'w') as f:
            writer = csv.writer(f)
            self.numTixels = 0
            for i in range(self.num_chan):
                for j in range(self.num_chan):
                    barcode = my_file.readline().split('\t')
                    if self.arr[j][i] == 1:
                        self.numTixels+=1
                        writer.writerow([barcode[0].strip(), 1, i, j, self.coords[j][i][1], self.coords[j][i][0]])
                    else:
                        writer.writerow([barcode[0].strip(), 0, i, j, self.coords[j][i][1], self.coords[j][i][0]])

                excelC += 1

        my_file.close()
        self.json_file(path)
        self.grid_button["state"] = tk.DISABLED
        self.gridA_button["state"] = tk.DISABLED
        try:
            move(self.figure_folder,path)
        except shutil.Error:
            rmtree(path+"/"+"figure")
            move(self.figure_folder,path)
        f.close()
        bwFile_Name = self.excelName + "BW.png"
        os.remove(bwFile_Name)
        # shutil.copyfile(self.barcode_filename, path + "/barcode_file.txt")
        mb.showinfo("Congratulations!", "The spatial folder is created!")

    #Creates Metadata.json
    def json_file(self,path):
        factorHigh = 0
        factorLow = 0

        if self.width > self.height:
            factorHigh = 2000/self.width
            factorLow = 600/self.width
            high_res = self.refactor.resize((2000, int(self.height*factorHigh)), Image.ANTIALIAS)
            low_res = self.refactor.resize((600, int(self.height*factorLow)), Image.ANTIALIAS)
        else:
            factorHigh = 2000/self.height
            factorLow = 600/self.height
            high_res = self.refactor.resize((int(self.width*factorHigh), 2000), Image.ANTIALIAS)
            low_res = self.refactor.resize((int(self.width*factorLow), 600), Image.ANTIALIAS)

        high_res.save(path+"/tissue_hires_image.png")
        low_res.save(path+"/tissue_lowres_image.png")

        dictionary = {"spot_diameter_fullres": self.spot_dia,
                        "tissue_hires_scalef": factorHigh,
                        "fiducial_diameter_fullres": self.fud_dia,
                        "tissue_lowres_scalef": factorLow}
        sel = int(self.blockSize_value.get())
        if sel %2 == 0:
            sel+=1
        sec = int(self.cMean_value.get())
        points_Raw = [i/self.factor for i in self.Rpoints]
        metaDict = {"points" : points_Raw,
                    "blockSize": sel,
                    "threshold": sec,
                    "numTixels": self.numTixels,
                    "rawHeight": self.rawHeight,
                    "numChannels": self.num_chan}
        metaDict.update(self.metadata)

        json_object = json.dumps(dictionary, indent = 4)
        with open(path+"/scalefactors_json.json", "w") as outfile:
            outfile.write(json_object)
            outfile.close()
        meta_json_object = json.dumps(metaDict, indent = 4)
        with open(path+"/metadata.json", "w") as outfile:
            outfile.write(meta_json_object)
            outfile.close()

    #Update changes to tissue_positions_list.csv
    def update_pos(self):
        p = open(self.folder_selected + "/metadata.json")
        meta = json.load(p)

        barcode_lis = []
        with open(self.folder_selected + "/tissue_positions_list.csv", "r") as csv_file:
            reader = csv.reader(csv_file, delimiter=",")

            for row in reader:
                curr_barcode = row[0]
                barcode_lis.append(curr_barcode)

        csv_file.close()

        with open(self.folder_selected + "/tissue_positions_list.csv", 'w') as f:
            writer = csv.writer(f)

            for i in range(self.num_chan):
                for j in range(self.num_chan):

                    inx = (i * self.num_chan) + j
                    print(barcode_lis[inx].strip())
                    if self.arr[j][i] == 1:
                        writer.writerow([barcode_lis[inx].strip(), 1, i, j, self.coords[j][i][1]/self.tissue_hires_scalef, self.coords[j][i][0]/self.tissue_hires_scalef])
                    else:
                        writer.writerow([barcode_lis[inx].strip(), 0, i, j, self.coords[j][i][1]/self.tissue_hires_scalef, self.coords[j][i][0]/self.tissue_hires_scalef])

        f.close()
        meta['numTixels'] = self.numTixels
        meta_json_object = json.dumps(meta, indent = 4)
        with open(self.folder_selected+ "/metadata.json", "w") as outfile:
            outfile.write(meta_json_object)
            outfile.close()

        mb.showinfo("Congratulations!", "The spatial folder has been updated!")

    #Create colorscheme for UMI/Gene count when loading tissue_positions_list_log_UMI_Genes.csv
    def count(self,which):
        name = ""
        if len(self.right_canvas.gettags("name0")) > 0:
            self.right_canvas.delete("name0")
            self.right_canvas.delete("name1")
            self.right_canvas.delete("name2")
            self.right_canvas.delete("name3")
            self.right_canvas.delete("name4")

        self.check_on.set(1)
        my_data = np.genfromtxt(self.folder_selected + "/tissue_positions_list_log_UMI_Genes.csv", delimiter=",")
        min_value = my_data.min(axis=0)[which]
        max_value = my_data.max(axis=0)[which]
        CBleft = min_value;
        with open(self.folder_selected + "/tissue_positions_list_log_UMI_Genes.csv", 'r') as f:
            csv_reader = csv.reader(f)
            for row in csv_reader:
                j = int(row[3])+1
                i = int(row[2])
                count = float(row[which])
                position = str(j)+"x"+str(i)
                level = round((count-CBleft)/(max_value-CBleft)*50)
                cmap = matplotlib.cm.get_cmap('jet', 50)
                rgba = cmap(level)
                new = [round(i * 255) for i in rgba[:-1]]
                var = from_rgb(new)
                if self.arr[j-1][i] == 1:
                    self.my_canvas.itemconfig(position, fill=var, width="1", state="normal")
                else:
                    self.my_canvas.itemconfig(position, fill=var, outline="", state="disabled")
        f.close()

        numsteps = 6
        colorbarLog = np.linspace(min_value, max_value, numsteps)
        colorbarNorm = [round(math.exp(i)-1) for i in colorbarLog]
        xvalues = np.linspace(15, 205, numsteps)
        yValue = 40

        self.cbframe = tk.LabelFrame(self.right_canvas, text="Colorbar", padx="5px", pady="14px")
        self.cbframe.place(relx=.11, rely=.42)

        c = tk.Canvas(self.cbframe, width=220, height=40)
        c.pack()
        c.delete("all")
        for i in range(len(colorbarNorm)):
            name = "name"
            name += str(i)
            c.create_text(xvalues[i], yValue, text = str(colorbarNorm[i]), font =("Courier", 14), angle = 70, anchor = "w", tag=name)

        # colorBar
        bar = Image.open("colorbar.png")
        resized_bar = bar.resize((200, 40), Image.ANTIALIAS)
        color = ImageTk.PhotoImage(resized_bar)
        self.color_bar = tk.Label(self.cbframe, image=color)
        self.color_bar.pack()
        self.color_bar.image = color
        self.color_bar.configure(image=color)


from elasticsearch.helpers.errors import ScanError
from elasticsearch_dsl import Search
from elasticsearch_dsl.connections import get_connection

from common.log import logger

def _scan(
    client,
    query=None,
    scroll="5m",
    raise_on_error=True,
    preserve_order=False,
    size=1000,
    request_timeout=None,
    clear_scroll=True,
    scroll_kwargs=None,
    **kwargs
):
    scroll_kwargs = scroll_kwargs or {}
    if not preserve_order:
        query = query.copy() if query else {}
        query["sort"] = "_doc"

    # initial search
    resp = client.search(body=query, scroll=scroll, size=size, request_timeout=request_timeout, **kwargs)
    scroll_id = resp.get("_scroll_id")

    try:
        while scroll_id and resp["hits"]["hits"]:
            for hit in resp["hits"]["hits"]:
                yield hit

            # Default to 0 if the value isn't included in the response
            shards_successful = resp["_shards"].get("successful", 0)
            shards_skipped = resp["_shards"].get("skipped", 0)
            shards_total = resp["_shards"].get("total", 0)

            # check if we have any errors
            if (shards_successful + shards_skipped) < shards_total:
                shards_message = "Scroll request has only succeeded on %d (+%d skipped) shards out of %d."
                logger.warning(
                    shards_message,
                    shards_successful,
                    shards_skipped,
                    shards_total,
                )
                if raise_on_error:
                    raise ScanError(
                        scroll_id,
                        shards_message
                        % (
                            shards_successful,
                            shards_skipped,
                            shards_total,
                        ),
                    )
            resp = client.scroll(body={"scroll_id": scroll_id, "scroll": scroll}, **scroll_kwargs)
            scroll_id = resp.get("_scroll_id")

    finally:
        if scroll_id and clear_scroll:
            client.clear_scroll(
                body={"scroll_id": [scroll_id]},
                ignore=(404,),
            )

class EsSearch(Search):
    def scan(self):
        es = get_connection(self._using)

        for hit in _scan(es, query=self.to_dict(), index=self._index, **self._params):
            yield self._get_result(hit)


"""
Logging for SimpleMonitor.

Loggers process every monitor, every iteration, to record their state in some fashion.
"""

import logging
import time
from typing import Any, Dict, List, Optional, Union, cast

import arrow

from ..Monitors.monitor import Monitor
from ..util import format_datetime, get_config_option, subclass_dict_handler

class Logger:
    """Abstract class basis for loggers."""

    logger_type = "unknown"

    supports_batch = False
    doing_batch = False
    batch_data = None  # type: Optional[Dict[str, Any]]
    connected = True
    _global_info = None  # type: Optional[Dict[str, Any]]

    def __init__(self, config_options: Dict[str, Any]) -> None:
        self._config_options = config_options
        self.name = cast(str, self.get_config_option("_name", default="unnamed"))
        self.logger_logger = logging.getLogger("simplemonitor.logger-" + self.name)
        self._dependencies = cast(
            List[str],
            self.get_config_option("depend", required_type="[str]", default=[]),
        )
        # only log for Monitors with one of these groups
        self._groups = self.get_config_option(
            "groups", required_type="[str]", default=["default"]
        )
        if self.batch_data is None:
            self.batch_data = {}
        self.tz = cast(Optional[str], self.get_config_option("tz", default="UTC"))
        self.dateformat = cast(
            Optional[str],
            self.get_config_option(
                "dateformat",
                required_type="str",
                allowed_values=["timestamp", "iso8601"],
                default="timestamp",
            ),
        )

        if self._global_info is None:
            self._global_info = {}
        self.heartbeat = cast(
            bool,
            self.get_config_option("heartbeat", required_type="bool", default=False),
        )

    def __enter__(self) -> None:
        """Context manager entry."""
        self.start_batch()

    def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
        """Context manager exit."""
        self.end_batch()

    def set_global_info(self, info: dict) -> None:
        """Receive global info about the SimpleMonitor state.

        Includes but not limited to refresh interval, known remote instances, etc"""
        self._global_info = info

    def get_config_option(
        self,
        key: str,
        *,
        default: Any = None,
        required: bool = False,
        required_type: str = "str",
        allowed_values: Any = None,
        allow_empty: bool = True,
        minimum: Optional[Union[int, float]] = None,
        maximum: Optional[Union[int, float]] = None,
    ) -> Any:
        """Get a config value.

        Throws the right flavour exception if something is wrong."""
        return get_config_option(
            self._config_options,
            key,
            default=default,
            required=required,
            required_type=required_type,
            allowed_values=allowed_values,
            allow_empty=allow_empty,
            minimum=minimum,
            maximum=maximum,
        )

    def hup(self) -> None:
        """Close and reopen our log file, if supported.

        This should be overridden where needed."""
        return  # pragma: no cover

    def save_result2(self, name: str, monitor: Monitor) -> None:
        """Record a result.

        Subclasses must override this with their implementation."""
        raise NotImplementedError

    def _get_datestring(self) -> str:
        """Format the current datetime according to the dateformat setting and timezone."""
        if self.dateformat == "iso8601":
            return format_datetime(arrow.now(), self.tz)
        return str(int(time.time()))

    @property
    def dependencies(self) -> list:
        """The dependencies of this Logger."""
        return self._dependencies

    @dependencies.setter
    def dependencies(self, dependency_list: List[str]) -> None:
        if not isinstance(dependency_list, list):
            raise TypeError("dependency_list must be a list")
        self._dependencies = dependency_list

    def check_dependencies(self, failed_list: List[str]) -> bool:
        """Compare a list of failed monitors to our dependencies, and mark
        the Logger as offline if one failed"""
        self.connected = True
        for dependency in failed_list:
            if dependency in self._dependencies:
                self.connected = False
        return self.connected

    @property
    def groups(self) -> List[str]:
        """The groups this Logger belongs to."""
        return self._groups

    def start_batch(self) -> None:
        """Prepare to process a batch of results"""
        if not self.supports_batch:
            return
        if self.doing_batch:
            self.logger_logger.error(
                "starting a batch while one was already in progress"
            )
        self.batch_data = {}
        self.doing_batch = True

    def end_batch(self) -> None:
        """End receiving a batch of results and process them"""
        if not self.supports_batch:
            return
        if not self.doing_batch:
            self.logger_logger.error("ending a batch when one wasn't in progress")
        self.process_batch()
        self.doing_batch = False

    def process_batch(self) -> None:
        """Process the batched data.
        This is blank for the base class."""
        return  # pragma: no cover

    def describe(self) -> str:
        """Explain what this logger does.
        We don't throw NotImplementedError here as it won't show up until something breaks,
        and we don't want to randomly die then."""
        return "(Logger did not write an auto-biography.)"  # pragma: no cover

    def __str__(self) -> str:
        return self.describe()

(register, get_class, all_types) = subclass_dict_handler(
    "simplemonitor.Loggers.logger", Logger, "logger_type"
)


'''
Created on Apr 19, 2016

@author: Rohan Achar
'''
import json
from time import sleep
from pcc.recursive_dictionary import RecursiveDictionary
from common.wire_formats import FORMATS
from datamodel.all import DATAMODEL_TYPES
from pcc.dataframe.dataframe_threading import dataframe_wrapper as dataframe
from pcc.dataframe.application_queue import ApplicationQueue
from common.modes import Modes
from common.converter import create_jsondict, create_complex_obj

FETCHING_MODES = set([Modes.Getter,
                      Modes.GetterSetter,
                      Modes.Taker])
TRACKING_MODES = set([Modes.Tracker])
PUSHING_MODES = set([Modes.Deleter,
                     Modes.GetterSetter,
                     Modes.Setter,
                     Modes.TakerSetter,
                     Modes.Producing])
ALL_MODES = set([Modes.Deleter,
                 Modes.GetterSetter,
                 Modes.Setter,
                 Modes.TakerSetter,
                 Modes.Producing,
                 Modes.Tracker,
                 Modes.Getter])

class dataframe_stores(object):
    def __init__(self, name2class):
        self.master_dataframe = dataframe()
        self.app_to_df = {}
        self.name2class = name2class
        self.pause_servers = False
        self.app_wire_format = {}

    def __pause(self):
        while self.pause_servers:
            sleep(0.1)

    def add_new_dataframe(self, name, df):
        self.__pause()
        self.app_to_df[name] = df

    def delete_app(self, app):
        self.__pause()
        del self.app_to_df[app]

    def register_app(self, app, type_map, wire_format = "json"):
        self.__pause()
        types_to_get = set()
        for mode in FETCHING_MODES:
            types_to_get.update(set(type_map.setdefault(mode, set())))
        types_to_track = set()
        for mode in TRACKING_MODES:
            types_to_track.update(set(type_map.setdefault(mode, set())))
        types_to_track = types_to_track.difference(types_to_get)
        real_types_to_get = [self.name2class[tpstr] for tpstr in types_to_get]
        real_types_to_track = [self.name2class[tpstr] for tpstr in types_to_track]
        self.master_dataframe.add_types(real_types_to_get + real_types_to_track)

        df = ApplicationQueue(app, real_types_to_get + real_types_to_track, self.master_dataframe)
        self.add_new_dataframe(app, df)
        # Add all types to master.
        types_to_add_to_master = set()
        for mode in ALL_MODES:
            types_to_add_to_master.update(set(type_map.setdefault(mode, set())))
        self.master_dataframe.add_types([self.name2class[tpstr] for tpstr in types_to_add_to_master])
        self.app_wire_format[app] = wire_format

    def disconnect(self, app):
        self.__pause()
        if app in self.app_to_df:
            self.delete_app(app)

    def reload_dms(self, datamodel_types):
        self.__pause()
        pass

    def update(self, app, changes):
        #print json.dumps(changes, sort_keys = True, separators = (',', ': '), indent = 4)
        self.__pause()
        dfc_type, content_type = FORMATS[self.app_wire_format[app]]
        dfc = dfc_type()
        dfc.ParseFromString(changes)
        if app in self.app_to_df:
            self.master_dataframe.apply_changes(dfc, except_app = app)

    def getupdates(self, app):
        self.__pause()
        dfc_type, content_type = FORMATS[self.app_wire_format[app]]
        final_updates = dfc_type()
        if app in self.app_to_df:
            final_updates = dfc_type(self.app_to_df[app].get_record())
            self.app_to_df[app].clear_record()
        return final_updates.SerializeToString(), content_type

    def get_app_list(self):
        return self.app_to_df.keys()

    def clear(self, tp = None):
        if not tp:
            self.__init__(self.name2class)
        else:
            if tp in self.master_dataframe.object_map:
                del self.master_dataframe.object_map[tp]
            if tp in self.master_dataframe.current_state:
                del self.master_dataframe.current_state[tp]

    def pause(self):
        self.pause_servers = True

    def unpause(self):
        self.pause_servers = False

    def gc(self, sim):
        # For now not clearing contents
        self.delete_app(sim)

    def get(self, tp):
        return [create_jsondict(o) for o in self.master_dataframe.get(tp)]

    def put(self, tp, objs):
        real_objs = [create_complex_obj(tp, obj, self.master_dataframe.object_map) for obj in objs.values()]
        tpname = tp.__realname__
        gkey =  self.master_dataframe.member_to_group[tpname]
        if gkey == tpname:
            self.master_dataframe.extend(tp, real_objs)
        else:
            for obj in real_objs:
                oid = obj.__primarykey__
                if oid in self.master_dataframe.object_map[gkey]:
                    # do this only if the object is already there.
                    # cannot add an object if it is a subset (or any other pcc type) type if it doesnt exist.
                    for dim in obj.__dimensions__:
                        # setting attribute to the original object, so that changes cascade
                        setattr(self.master_dataframe.object_map[gkey][oid], dim._name, getattr(obj, dim._name))


import os
import cv2
import numpy as np
from tensorflow.keras.layers import *
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.models import Model, Sequential

pic_size = 128
classes = 8

model = Sequential([
    Conv2D(64, 3, activation='relu', input_shape=(pic_size,pic_size,1)),
    MaxPooling2D(pool_size=(2, 2)),
    Conv2D(32, 3, activation='relu'),
    MaxPooling2D(pool_size=(2, 2)),
    Flatten(),
    Dense(128, activation='relu'),
    Dropout(0.5),

    Dense(classes, activation='softmax')
])

model.compile(optimizer=Adam(lr=0.001), loss='categorical_crossentropy', metrics=['accuracy'])
model.summary()

import json
model_json = model.to_json()
with open("model_trained.json", "w") as json_file:
    json.dump(model_json, json_file)


# encoding=utf-8

import re, time
import datetime

from jinja2 import evalcontextfilter, Markup

_paragraph_re = re.compile(r'(?:\r\n|\r|\n){2,}')

@evalcontextfilter
def linebreaks(eval_ctx, value):
    value = unicode(value)
    result = u'\n\n'.join(u'
%s
' % p.replace('\n', '
\n') \
        for p in _paragraph_re.split(value))
    if eval_ctx.autoescape:
        result = Markup(result)
    return result

def timesince(dt, default="just now"):
    """
    Returns string representing "time since" e.g.
    3 days ago, 5 hours ago etc.
    """

    now = datetime.datetime.utcnow()
    diff = now - dt

    periods = (
        (diff.days / 365, "year", "years"),
        (diff.days / 30, "month", "months"),
        (diff.days / 7, "week", "weeks"),
        (diff.days, "day", "days"),
        (diff.seconds / 3600, "hour", "hours"),
        (diff.seconds / 60, "minute", "minutes"),
        (diff.seconds, "second", "seconds"),
    )

    for period, singular, plural in periods:

        if period:
            return "%d %s ago" % (period, singular if period == 1 else plural)

    return default

def timedelta_seconds(td):
    return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6


import torch
import transformers
import pandas as pd
from torch.utils.data.dataset import Dataset
from torch.utils.data.dataloader import DataLoader
from transformers import BertTokenizer

from utils import remove_urls, convert_emojis, normalize_whitespaces

def create_data_loader(df: pd.DataFrame, tokenizer: transformers.BertTokenizer, max_len: int, batch_size: int):
    dataset = SentimentAnalysisDataset(
        texts=df.text.to_numpy(),
        labels=df.label.to_numpy(),
        tokenizer=tokenizer,
        max_len=max_len
    )

    return DataLoader(
        dataset,
        batch_size=batch_size
    )

class SentimentAnalysisDataset(Dataset):

    def __init__(self, texts: pd.Series, labels: pd.Series, tokenizer: BertTokenizer, max_len: int):
        self.texts = texts
        self.labels = labels
        self.tokenizer = tokenizer
        self.max_len = max_len

    def __len__(self):
        return len(self.texts)

    def __getitem__(self, item):
        text = str(self.texts[item])
        text = remove_urls(text)
        text = convert_emojis(text)
        text = normalize_whitespaces(text)
        label = self.labels[item] + 1  # cause of loss limitation

        encoding = self.tokenizer.encode_plus(
            text,
            add_special_tokens=True,
            max_length=self.max_len,
            return_token_type_ids=False,
            pad_to_max_length=True,
            return_attention_mask=True,
            return_tensors='pt',
            truncation=True
        )

        return {
            'text': text,
            'input_ids': encoding['input_ids'].flatten(),
            'attention_mask': encoding['attention_mask'].flatten(),
            'targets': torch.tensor(label, dtype=torch.long)
        }


from __future__ import absolute_import

import logging
import sys
import gevent
from volttron.platform.agent import utils
from volttron.platform.vip.agent import Agent, Core
from pnnl.pubsubagent.pubsub.agent import PubSubAgent
from datetime import datetime as dt
from datetime import timedelta as td

utils.setup_logging()
log = logging.getLogger(__name__)

class InterfaceAgent(PubSubAgent):
    '''
    This agent simply subscribes to a topic, then handles messages on that topic, forwarding a modified version to a different topic. This provides a convenient interface to the BMS from the application.
    '''
    RPC = 'RPC'
    DATE_FORMAT = '%m-%d-%y %H:%M:%S'

    def __init__(self, config_path, **kwargs):
        self.isActuating = False
        self.isConnected = False
        self.setAllPoints = False
        self.reservationLength = 60*1
        self.actuator_vip = None
        self.tzAware = True
        super(InterfaceAgent, self).__init__(config_path, **kwargs)

    @Core.receiver('onsetup')
    def setup(self, sender, **kwargs):
        super(InterfaceAgent, self).setup(sender, **kwargs)
        self.rpc_target = self
        self.setup_remote_actuation()

    def setup_remote_actuation(self):
        if self.actuator_vip:
            event = gevent.event.Event()
            agent = Agent(address=self.actuator_vip)
            gevent.spawn(agent.core.run, event)
            event.wait(timeout=15)
            self.rpc_target = agent

    def onUpdateTopic(self, peer, sender, bus, topic, headers, message):
        objs = self.getInputsFromTopic(topic)
        if objs is not None:
            for obj in objs:
                if obj.has_key('forward'):
                    self.forwardTopic(obj)
        self.updateComplete()

    def onMatchIsActuating(self, peer, sender, bus, topic, headers, message):
        super(InterfaceAgent, self).onMatchTopic(peer, sender, bus, topic, headers, message)
        self.isActuating = self.input('isActuating', 'value')
        if self.isActuating:
            log.info('Interface is Actuating')
        else:
            log.info('Interface is not Actuating')

    def onMatchIsConnected(self, peer, sender, bus, topic, headers, message):
        super(InterfaceAgent, self).onMatchTopic(peer, sender, bus, topic, headers, message)
        self.isConnected = self.input('isConnected', 'value')
        if self.isConnected:
            log.info('Interface is Connected')
        else:
            log.info('Interface is not Connected')

    def onMatchKill(self, peer, sender, bus, topic, headers, message):
        log.info('Received Kill Command')
        self.isActuating = False
        self.isConnected = False

    def forwardTopic(self, inputObj):
        forwards = inputObj.get('forward')
        for item in forwards:
            value = inputObj.get('value')
            if item.has_key('field'):
                value = value.get(item.get('field'))
            if item.has_key('transform'):
                value = self.transform(value, item.get('transform'))
            if not self.output(item.get('name')):
                return
            if self.output(item.get('name')).has_key('field'):
                value = {self.output(item.get('name')).get('field') : value}
            self.output(item.get('name'), 'value', value)
            outputObj = self.output(item.get('name'))
            if outputObj.has_key('handler'):
                if (hasattr(self, outputObj.get('handler')) and
                        callable(getattr(self, outputObj.get('handler'), None))):
                    callback = getattr(self, outputObj.get('handler'))
                    callback(outputObj)
            else:
                self.publish(outputObj)

    def handleCoolingSetPoint(self, outputObj):

        if not outputObj.has_key('topic'):
            return

        device = outputObj.get('topic')

        if (device[-1] == '/'):
            device = device[0:-1]

        value = outputObj.get('value')
        start_dt = self.now()
        start = utils.format_timestamp(start_dt)
        stop_dt = start_dt + td(seconds=self.reservationLength)
        stop = utils.format_timestamp(stop_dt)
        agent_id = 'agent_id'

        self.scheduleDevice(agent_id, device, start, stop)
        gevent.sleep(2)

        if self.isActuating:
            standby = False
            inputObjs = self.getInputsFromTopic('devices/'+device+'/all')
            if inputObjs:
                for inputObj in inputObjs:
                    valueObj = inputObj.get('value', None)
                    if valueObj:
                        standby = bool(valueObj.get('StandbyModeStatus', 0))

            occupied = True
            inputObjs = self.getInputsFromTopic('devices/'+device+'/all')
            if inputObjs:
                for inputObj in inputObjs:
                    valueObj = inputObj.get('value', None)
                    if valueObj:
                        occupied = bool(valueObj.get('OccupancyMode', 0))

            if standby:
                setpoints = self.calcSetpoints(value, self.standbyCoolMin, self.standbyCoolMax, self.standbyHeatMin, self.standbyHeatMax)
            elif not occupied:
                setpoints = self.calcSetpoints(value, self.unoccCoolMin, self.unoccCoolMax, self.unoccHeatMin, self.unoccHeatMax)
            else:
                setpoints = self.calcSetpoints(value, self.occCoolMin, self.occCoolMax, self.occHeatMin, self.occHeatMax)

            cooling = setpoints['cooling']
            heating = setpoints['heating']

        else :
            cooling = None
            heating = None

        self.setSetpoint(agent_id, device, "ZoneCoolingTemperatureSetPoint", cooling)
        self.setSetpoint(agent_id, device, "ZoneHeatingTemperatureSetPoint", heating)
        self.unscheduleDevice(agent_id, device)

    def calcSetpoints(self, value, coolMin, coolMax, heatMin, heatMax):
        # clamp the desired value
        cooling = max(min(value,coolMax),coolMin)
        heating = heatMin
        return {"cooling" : cooling, "heating" : heating}

    def scheduleDevice(self, agent_id, device, start, stop):

        if self.isConnected:
            try:
                result = self.rpc_target.vip.rpc.call(
                    'platform.actuator',    #Target agent
                    'request_new_schedule', #Method to call
                    agent_id,               #Requestor
                    device+'/set_point_task',                 #TaskID
                    'HIGH',                 #Priority
                    [[device, start, stop]] #Request message
                    ).get(timeout=10)
                if self.rpcFailed(result):
                    log.warn('Failed to schedule {} (unavailable) '.format(device))
            except Exception as ex:
                log.warning("Failed to schedule {} (Exception): {}".format(device, str(ex)))
        else:
            log.info("self.vip.rpc.call('platform.actuator', 'request_new_schedule', "+agent_id+", 'set_point_task', 'HIGH', [['"+device+"', '"+start+"', '"+stop+"']]).get(timeout=10)")

    def unscheduleDevice(self, agent_id, device):

        if self.isConnected:
            try:
                result = self.rpc_target.vip.rpc.call(
                    'platform.actuator',    #Target agent
                    'request_cancel_schedule', #Method to call
                    agent_id,               #Requestor
                    device+'/set_point_task'                 #TaskID
                    ).get(timeout=10)
                if self.rpcFailed(result):
                    log.warn('Failed to unschedule {} (unavailable) '.format(device))
            except Exception as ex:
                log.warning("Failed to unschedule {} (Exception): {}".format(device, str(ex)))
        else:
            log.info("self.vip.rpc.call('platform.actuator', 'request_cancel_schedule', "+agent_id+", 'set_point_task').get(timeout=10)")

    def setSetpoint(self, agent_id, device, point, value):

        if self.isConnected:
            try:
                result = self.rpc_target.vip.rpc.call(
                   'platform.actuator',    #Target agent
                   'set_point',            #Method to call
                   agent_id,               #Requestor
                   device+"/"+point,       #Point to set
                   value,                  #New value
                   ).get(timeout=10)
                if self.rpcFailed(result):
                    log.warn('Failed to set {} on {} (unavailable) '.format(point, device))
            except Exception as ex:
                log.warning("Failed to set {} on {} (Exception): {}".format(point, device, str(ex)))
        else:
            log.info("self.vip.rpc.call('platform.actuator', 'set_point', '"+agent_id+"', '"+device+"/"+point+"', '"+str(value)+"').get(timeout=10)")

    def rpcFailed(self, result):
        if isinstance(result, dict):
            if 'result' in result:
                if result['result'] == 'FAILURE':
                    return True
        return False

    def now(self):
        return dt.now() if not self.tzAware else utils.get_aware_utc_now()

    def transform(self, value, transformation):
        return UnitConverter.transform(value, transformation)

class UnitConverter(object):
    '''
    Converts units. Duh.
    '''
    C2F = "C2F"
    F2C = "F2C"
    CFM2KGS = "CFM2KGS"
    IN2PA = "IN2PA"

    def __init__(self, params):
        pass

    @staticmethod
    def transform(value, transformation):
        if value is None:
            return None
        if transformation == UnitConverter.C2F:
            return float(value)*9.0/5.0+32.0
        if transformation == UnitConverter.F2C:
            return (float(value)-32.0)*5.0/9.0
        if transformation == UnitConverter.CFM2KGS:
            return float(value)*0.000471947*1.2041
        if transformation == UnitConverter.IN2PA:
            return float(value)*248.84

def main(argv=sys.argv):
    '''Main method called by the eggsecutable.'''
    try:
        utils.vip_main(InterfaceAgent)
    except Exception as e:
        log.exception(e)

if __name__ == '__main__':
    # Entry point for script
    sys.exit(main())