from PIL import Image, ImageTk
import PIL
import tkinter as tk
from tkinter import filedialog, messagebox
import cv2
import numpy as np
from Farbaenderung import gammaCorrection, reverseGammaCorrection

root = tk.Tk()
simGrad = tk.IntVar(root)

class Dyschromasie:
    cb_image = np.array([]).astype('float64')
    sim_image = np.array([]).astype('uint8')

    def __init__(self, img_mat=np.array([]), rows=0, cols=0, kanaele=0,sim_faktor=0, sim_kind='d'):
        self.rows = rows
        self.cols = cols
        self.kanaele = kanaele
        self.img_mat = img_mat
        self.sim_faktor = sim_faktor
        self.sim_kind = sim_kind

    T = np.array([[0.31399022, 0.63951294, 0.04649755],
                  [0.15537241, 0.75789446, 0.08670142],
                  [0.01775239, 0.10944209, 0.87256922]])

    T_reversed = np.array([[5.47221206, -4.6419601, 0.16963708],
                           [-1.1252419, 2.29317094, -0.1678952],
                           [0.02980165, -0.19318073, 1.16364789]])

    def Simulate(self):
        if self.sim_kind == 'p':
            sim_mat = np.array([[(1 - self.sim_faktor), 1.05118294 * self.sim_faktor, -0.05116099 * self.sim_faktor],
                                [0, 1, 0],
                                [0, 0, 1]])
        elif self.sim_kind == 'd':
            sim_mat = np.array([[1, 0, 0],
                                [0.9513092 * self.sim_faktor, (1 - self.sim_faktor), 0.04866992 * self.sim_faktor],
                                [0, 0, 1]])
        else:
            sim_mat = np.array([[1, 0, 0],
                                [0, 1, 0],
                                [-0.86744736 * self.sim_faktor, 1.86727089 * self.sim_faktor, (1 - self.sim_faktor)]])

        # Gammakorrektur durchfuehren
        self.cb_image = np.copy(self.img_mat).astype('float64')

        for i in range(self.rows):
            for j in range(self.cols):
                for x in range(3):
                    self.cb_image[i, j, x] = gammaCorrection(self.img_mat[i, j, x])

        # Einzelne Pixelwertberechnung
        for i in range(self.rows):
            for j in range(self.cols):
                self.cb_image[i, j] = self.T_reversed.dot(sim_mat).dot(self.T).dot(self.cb_image[i, j])

        self.sim_image = np.copy(self.cb_image)
        self.sim_image = self.sim_image.astype('uint8')
        # Rücktransformation der Gammawerte
        for i in range(self.rows):
            for j in range(self.cols):
                for x in range(3):
                    self.sim_image[i, j, x] = reverseGammaCorrection(self.cb_image[i, j, x])

        return self.sim_image

class AutoScrollbar(tk.Scrollbar):
   # A scrollbar that hides itself if it's not needed.
   # Only works if you use the grid geometry manager!
    def set(self, lo, hi):
        if float(lo) <= 0.0 and float(hi) >= 1.0:
            # grid_remove is currently missing from Tkinter!
            self.tk.call("grid", "remove", self)
        else:
            self.grid()
        tk.Scrollbar.set(self, lo, hi)
    def pack(self, **kw):
        raise TclError("cannot use pack with this widget")
    def place(self, **kw):
        raise TclError("cannot use place with this widget")

class ScrollFrame:
    def __init__(self, master):

        self.vscrollbar = AutoScrollbar(master)
        self.vscrollbar.grid(row=0, column=1, sticky='ns')
        self.hscrollbar = AutoScrollbar(master, orient='horizontal')
        self.hscrollbar.grid(row=1, column=0, sticky='ew')

        self.canvas = tk.Canvas(master, yscrollcommand=self.vscrollbar.set,
                        xscrollcommand=self.hscrollbar.set)
        self.canvas.grid(row=0, column=0, sticky='nsew')

        self.vscrollbar.config(command=self.canvas.yview)
        self.hscrollbar.config(command=self.canvas.xview)

        # make the canvas expandable
        master.grid_rowconfigure(0, weight=1)
        master.grid_columnconfigure(0, weight=1)

        # create frame inside canvas
        self.frame = tk.Frame(self.canvas)
        self.frame.rowconfigure(1, weight=1)
        self.frame.columnconfigure(1, weight=1)

        # update the frame
        self.frame.bind("<Configure>", self.reset_scrollregion)

    def reset_scrollregion(self, event):
        self.canvas.configure(scrollregion=self.canvas.bbox('all'))

    def update(self):
        self.canvas.create_window(0, 0, anchor='nw', window=self.frame)
        self.frame.update_idletasks()
        self.canvas.config(scrollregion=self.canvas.bbox("all"))

        if self.frame.winfo_reqwidth() != self.canvas.winfo_width():
            # update the canvas's width to fit the inner frame
            self.canvas.config(width = self.frame.winfo_reqwidth())
        if self.frame.winfo_reqheight() != self.canvas.winfo_height():
            # update the canvas's width to fit the inner frame
            self.canvas.config(height = self.frame.winfo_reqheight())


root.title("Projekt Dyschromasie")

SB = ScrollFrame(root)

img = np.array([])
rows = 0
cols = 0
kanaele = 0

sim_pro = tk.IntVar(root)
sim_deut = tk.IntVar(root)
sim_tri = tk.IntVar(root)

simulationsGradient = tk.Scale(SB.frame, from_=0, to_=100, variable=simGrad, orient='horizontal')
simulationsGradient.grid(column= 0, row = 1, columnspan=10)

def browse():
    # Auswahl des FilePaths
    try:
        path = tk.filedialog.askopenfilename(filetypes=[("Image File", '.jpg')])
        im = Image.open(path)
    except:
        tk.messagebox.showerror(title='Datenfehler', message='Kein Bild gefunden/ausgewählt')
    global simulateButton
    if len(path) > 0:
        simulateButton.config(state='active')

        # Anzeigen des Bildes
        tkimage = ImageTk.PhotoImage(im)
        myvar = tk.Label(SB.frame, image=tkimage)
        myvar.image = tkimage
        myvar.grid(columnspan=5)

        # Einspeichern der Path-Informationen
        global img, rows, cols, kanaele
        img = cv2.imread(path)
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        rows, cols, kanaele = img.shape


def simulate():
    global img, rows, cols, kanaele, sim_pro, sim_deut, sim_tri
    if sim_deut.get():
        d = Dyschromasie(img, rows, cols, kanaele, simGrad.get()/100, 'd')
        display_array_deut = np.copy(d.Simulate()).astype('uint8')

        T = tk.Text(SB.frame, height=1, width=15)
        T.grid(columnspan=5)
        print_string = "Deutranop(" + str(round(d.sim_faktor*100)) + "%)"
        T.insert('current', print_string)

        conv_SimulationPic_deut = ImageTk.PhotoImage(image=PIL.Image.fromarray(display_array_deut))
        sim_pic_deut = tk.Label(SB.frame, image=conv_SimulationPic_deut)
        sim_pic_deut.Image = conv_SimulationPic_deut
        sim_pic_deut.grid(columnspan=5)
    elif sim_tri.get():
        t = Dyschromasie(img, rows, cols, kanaele, simGrad.get()/100, 't')
        display_array_tri = np.copy(t.Simulate()).astype('uint8')

        T = tk.Text(SB.frame, height=1, width=15)
        T.grid(columnspan=5)
        print_string = "Tritanop(" + str(round(t.sim_faktor * 100)) + "%)"
        T.insert('current', print_string)

        conv_SimulationPic_tri = ImageTk.PhotoImage(image=PIL.Image.fromarray(display_array_tri))
        sim_pic_tri = tk.Label(SB.frame, image=conv_SimulationPic_tri)
        sim_pic_tri.Image = conv_SimulationPic_tri
        sim_pic_tri.grid(columnspan=5)
    elif sim_pro.get():
        p = Dyschromasie(img, rows, cols, kanaele, simGrad.get()/100, 'p')
        display_array_pro = np.copy(p.Simulate()).astype('uint8')

        T = tk.Text(SB.frame, height=1, width=15)
        T.grid(columnspan=5)
        print_string = "Protanop(" + str(round(p.sim_faktor * 100)) + "%)"
        T.insert('current', print_string)

        conv_SimulationPic_pro = ImageTk.PhotoImage(image=PIL.Image.fromarray(display_array_pro))
        sim_pic_pro = tk.Label(SB.frame, image=conv_SimulationPic_pro)
        sim_pic_pro.Image = conv_SimulationPic_pro
        sim_pic_pro.grid(columnspan=5)


btn = tk.Button(SB.frame, text="Browse", width=25, command=browse, bg='light blue')
btn.grid(column=0, row=0, columnspan=2)

simulateButton = tk.Button(SB.frame, text="Simulate", width=25, command=simulate, bg='light blue')
simulateButton.grid(column=1, row=0, columnspan=2)
simulateButton.config(state='disabled')

checkButton_p = tk.Checkbutton(SB.frame, text="Protanop", variable=sim_pro, onvalue=1, offvalue=0, height=5, width=20)
checkButton_d = tk.Checkbutton(SB.frame, text="Deutanop", variable=sim_deut, onvalue=1, offvalue=0, height=5, width=20)
checkButton_t = tk.Checkbutton(SB.frame, text="Tritanop", variable=sim_tri, onvalue=1, offvalue=0, height=5, width=20)

checkButton_p.grid(column=0, row=2)
checkButton_d.grid(column=1, row=2)
checkButton_t.grid(column=2, row=2)

SB.update()
root.mainloop()
