import Tkinter as tk
import tkMessageBox
from PIL import Image, ImageTk


# This class is needed for button call-backs
# Idea and code taken from Bob Greschke
# https://mail.python.org/pipermail/tkinter-discuss/2007-February/001082.html
class Command:
    def __init__(self, func, *args, **kw):
        self.func = func
        self.args = args
        self.kw = kw

    def __call__(self, *args, **kw):
        args = self.args + args
        kw.update(self.kw)
        apply(self.func, args, kw)

class Gui():
    def __init__(self, settings, imghandler):
        self.settings = settings
        # we need the imagehandler only to call the function which moves an
        # image to our desired destination-directory
        self.imghandler = imghandler

        self.gui = tk.Tk()

        self.__set_title('Welcome')


        # load default (dummy) image
        self.cur_imgname = './default.png'
        self.cur_img = ImageTk.PhotoImage(Image.open(self.cur_imgname))
        self.bg_image = tk.Label(self.gui, image=self.cur_img)

        # We need to switch to fullscreen (temporarily) in order to get the
        # size of the current monitor (where our program is displayed)
        # Calling __set_fullscreen() twice (before and after adding the
        # dummy-image to the App) is a work-around. If we'd call it only once
        # we wouldn't be able to get correct values when calling
        # __get_size_of_active_monitor() later
        # Example: On my 1920x1080 screen it always returned 1920x1043 (probably
        # because of the taskbar of the OS)
        self.__set_fullscreen()
        self.bg_image.pack(side='top', fill='both', expand='yes')
        self.__set_fullscreen()
        self.__set_window_to_correct_size()

        frame = tk.Frame(self.bg_image)
        frame.pack(side='top')

        for idx, destination in enumerate(settings.dstdirs):
            b = tk.Button(frame,
                          text=destination,
                          width=destination.__len__(),
                          height=2,
                          command=Command(self.__move_img, idx))
            b.pack(side='left')

        tk.Button(frame,
                  text="Skip",
                  width="Skip".__len__(),
                  height=2,
                  command=Command(self.__skip_img)).pack(side='left')

        tk.Button(frame,
                  text="Delete",
                  width="Delete".__len__(),
                  height=2,
                  command=Command(self.__delete_img)).pack(side='left')

        # and finally display the first image
        self.__display_next_img()


    def start(self):
        self.gui.mainloop()

    def __set_fullscreen(self, newState=True):
        self.gui.attributes('-fullscreen', newState)
        self.gui.update()

    def __set_window_to_correct_size(self):
        monitor_width, monitor_height = self.__get_size_of_active_monitor()

        self.__set_fullscreen(False)

        # get most suitable 16:9-resolution (i.e: the largest possible, but
        # a bit smaller than the monitor size)
        resolutions = [
            [2560, 1440],
            [2045, 1152],
            [1920, 1080],
            [1600, 900],
            [1360, 765],
            [1280, 720],
            [800, 450],
        ]
        for res in resolutions:
            if res[0] < monitor_width and res[1] < monitor_height:
                self.resolution = res
                break;

        # set resolution and center the window
        posx = (monitor_width - res[0]) / 2
        posy = (monitor_height - res[1]) / 2
        self.pos = [posx, posy]
        self.gui.geometry("%dx%d+%d+%d" % (res[0], res[1], posx, posy))
        self.gui.update()

    def __get_size_of_active_monitor(self):
        # This function relies on the work-around explained in self.__init__()
        # i'm not really satisfied with the current approach
        # Hopefully I can come up with a cleaner way to do this some day..
        width = self.gui.winfo_width()
        height = self.gui.winfo_height()
        return width, height

    def __move_img(self, idx):
        if not self.imghandler.move_next_img_to_dst_x(idx):
            # move_next_img_to_dst() returns False if there's no image
            self.gui.quit()
            return

        self.__display_next_img()

    def __delete_img(self):
        confirmation = tkMessageBox.askyesno("Confirm deletion!",
        "Do you really want to delete %s?" % self.imghandler.get_next_imgname(),
                              default=tkMessageBox.NO,
                              icon=tkMessageBox.WARNING)

        if not confirmation:
            return

        if not self.imghandler.delete_img():
            self.gui.quit()
            return

        self.__display_next_img()

    def __skip_img(self):
        self.imghandler.skip_img()
        self.__display_next_img()

    def __set_title(self, title=''):
        self.gui.title('Interactive image sorter - ' + str(title))

    def __display_next_img(self):
        self.cur_imgname = self.imghandler.get_next_imgname()
        img = Image.open("%s/%s" % (self.settings.srcdir, self.cur_imgname))

        (w, h) = img.size
        # calculate the necessary rescale-factors
        wr = self.resolution[0] / float(w)
        hr = self.resolution[1] / float(h)

        # and choose the lowest one (so that the image fits into our
        # image-area without skewing the picture)
        rescale_factor = min(wr, hr)

        # wr and hr have values greater than 1 if the image is smaller than the
        # area. therefore we don't need to rescale
        if rescale_factor <= 1:
            w_new = int(w * rescale_factor)
            h_new = int(h * rescale_factor)

            img = img.resize((w_new, h_new), Image.ANTIALIAS)
        else:
            # needed for proper printing of the title
            rescale_factor = 1

        self.cur_img = ImageTk.PhotoImage(img)
        self.bg_image.configure(image=self.cur_img)
        self.__set_title("\"%s\" (%.2f%%)" % (self.cur_imgname,
                                              100 * rescale_factor))


