#!/usr/bin/python
# -*- coding: utf-8 -*-
#
"""
  Nome: TkInterface.py
  Autor: Alessandro dos Santos Ferreira ( santosferreira.alessandro@gmail.com )

  Descricão: Classe que implementa os modulos de interface utilizando a biblioteca TkInter.
"""
import sys
if sys.version_info[0] < 3:
    import Tkinter as Tk
else:
    import tkinter as Tk
import tkMessageBox

import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib import pylab as plt

from Interface import Interface, InterfaceException as IException
from tk_interface import *

class TkInterface(Interface):
    
    utils = TkUtils.TkUtils

    title = None
    
    __root = None
    
    __menus = None
    __configs = None
    
    __im = None
    __canvas = None
    
    __logger = None
    
    __dialog = None


    def __init__(self, title):
        self.title = title
        
        self.__root = Tk.Tk()
        self.__root.wm_title(self.title)
        self.__root.geometry('%dx%d+%d+%d' % (800, 600, 0, 0))
        
        self.__menus = []
        self.__configs = []
        
    def set_subtitle(self, subtitle):
        self.__root.wm_title(self.title + ' - ' + subtitle)
    

    def add_menu(self, label):
        self.__menus.append( Menu.Menu(label) )
    
    def add_command(self, label, action, shortcut = None):
        self.__menus[-1].add_command( label = label, action = lambda *_: self.__apply( action ), shortcut = shortcut )

    def add_separator(self):
        self.__menus[-1].add_separator( )

    def render_menu(self):
        menubar = Tk.Menu(self.__root)
        
        shortcuts = []
        for menu in self.__menus:
            menubar = menu.render(menubar)
            shortcuts += menu.get_shorcuts()
          
        self.__root.config(menu=menubar)
        
        for sh in shortcuts:
            self.__root.bind("<Control-Key-" + sh["shortcut"] + ">", sh["action"])
            self.__root.bind("<Control-Key-" + sh["shortcut"].lower() + ">", sh["action"])

    
    def show(self):
        self.__root.protocol("WM_DELETE_WINDOW", self.quit)
        self.__root.mainloop()
        
    
    def add_image(self, image, title = None, onclick = None):
        if self.__canvas is None:
            self.__root.image = image
            
            fig = plt.figure(facecolor='white')
            self.__im = plt.imshow(self.__root.image) # later use a.set_data(new_data)
            #ax = plt.gca()
            #ax.set_xticklabels([]) 
            #ax.set_yticklabels([])

            # a tk.DrawingArea
            self.__canvas = FigureCanvasTkAgg(fig, master=self.__root)
            self.__canvas.show()
            self.__canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
            
            if onclick is not None:
                fig.canvas.mpl_connect('button_press_event', func = lambda event, *_: self.__apply( onclick, event ))
            
            if title is not None:
                self.set_subtitle(title)

        else:
            self.refresh_image(image, title)
        
    def refresh_image(self, image, title = 'None'):
        if self.__canvas is not None:
            self.__root.image = image
            self.__im.set_data(self.__root.image)
            self.__canvas.draw()

    def close_image(self):
        if self.__canvas is not None:
            if tkMessageBox.askokcancel("Quit", "Do you want to close the image?"):
                self.__root.image = None
                #self.__im.set_data(np.zeros((0,0,3), float))
                #self.__canvas.draw()
                self.__canvas.get_tk_widget().pack_forget();
                self.__canvas.get_tk_widget().destroy();
                
                self.__im = None
                self.__canvas = None
                
                return True
        return False
                
                
    def create_logger(self):
        self.__logger = Tk.Text(self.__root, width=0, height=10, bg="white", fg="black", padx=5, pady=5)
        self.__logger.insert(Tk.INSERT, "$ Pynovisao is ready!\n")
        self.__logger.config(state=Tk.DISABLED)
        self.__logger.pack(side=Tk.BOTTOM, fill=Tk.X, expand=False)
        
    def write_logger(self, fmt, *args):
        self.clean_logger()
        self.append_logger(fmt % args)
        
    def append_logger(self, fmt, *args):
        self.__logger.config(state=Tk.NORMAL)
        self.__logger.insert(Tk.END, fmt % args)
        self.__logger.insert(Tk.END, '\n')
        self.__logger.config(state=Tk.DISABLED)
        
    def clean_logger(self):
        self.__logger.config(state=Tk.NORMAL)
        self.__logger.delete('1.0', Tk.END)
        self.__logger.insert('1.0', '$ ')
        self.__logger.config(state=Tk.DISABLED)
        
    def destroy_logger(self):
        self.__logger.pack_forget();
        self.__logger.destroy();
        

    def popup(self):
        pass
        
    def log_and_popup(self, message):
        pass
        
    
    def show_error(self, fmt, *args):
        tkMessageBox.showerror("Error", fmt % args)
        
    def show_info(self, fmt, *args):
        tkMessageBox.showinfo("Info", fmt % args)
        
    def show_warning(self, fmt, *args):
        tkMessageBox.showwarning("Warning", fmt % args)


    def dialogue_config(self, title, configs, callback):
        n_configs = len(configs)
        
        self.__dialog = Tk.Toplevel(self.__root, padx=10, pady=10)
        self.__dialog.title(title)
        
        row = 0
        self.__configs = []
        for config in configs:
            Tk.Label(self.__dialog, text=config.title()).grid(row=row, padx=4, pady=4, sticky=Tk.W)
            
            entry = Tk.Entry(self.__dialog)
            entry.insert(0, str(configs[config].value))
            entry.grid(row=row, column=1, padx=4, pady=4, sticky=Tk.W)
            if row == 0:
                entry.focus_set()
            
            self.__configs.append( TkConfig.TkConfig(config, configs[config].value, c_type=configs[config].c_type, tk_entry=entry) )
            row += 1

        B1 = Tk.Button(self.__dialog, text="Ok", width=5, command = lambda *_: self.__apply( callback ))
        B1.grid(row=row, padx=6, pady=6, sticky=Tk.W)
        
        self.__dialog.bind("<Return>", lambda *_: self.__apply( callback ))
        
        B2 = Tk.Button(self.__dialog, text="Cancel", width=5, command = self.__dialog.destroy)
        B2.grid(row=row, column=1, padx=6, pady=6, sticky=Tk.W)
        
        self.__dialog.bind("<Escape>", lambda *_: self.__dialog.destroy())
        
        self.__dialog.grab_set()

        self.__dialog.protocol("WM_DELETE_WINDOW", self.__dialog.destroy)

        self.__dialog.geometry("+%d+%d" % (self.__root.winfo_width()/3,
                                          self.__root.winfo_height()/3))

    def get_config_and_destroy(self):
        try:
            configs = {}
            for config in self.__configs:
                config.value = config.get_entry_val()
                configs[config.label] = config
        except:    
            self.__dialog.destroy()
            raise IException("Illegal values, please try again")
        
        self.__dialog.destroy()
        
        return configs

        
    def quit(self):
        if tkMessageBox.askokcancel("Quit", "Do you want to quit?"):
            self.__root.quit()
            self.__root.destroy()
        

    def debug(self, event):
        print("DEBUG")
        

    def __apply(self, f, *args):
        try:
            f(*args)
        except IException as exc:
            self.__log_exception( str(exc), True )
        except:
            self.__log_exception( IException.format_exception() )
                
    
    def __log_exception(self, message, warning = False):
        if warning == True:
            self.show_warning( message )
        elif IException.DEBUG == True:
            self.append_logger( message )
        else:
            self.show_error( message )