import os
import time
import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox
from tkinter.font import Font

from _gui.get_geometry import get_center_geometry
from _tools.get_hash import get_hash
from _tools.is_valid_file import is_vaild_file
from _tools.move_file import move_file

__version__ = (1, 2, 1)


class HashPhotoApp(object):
    def __init__(self):
        self.root = tk.Tk()
        self.select_dir_entry_var = tk.StringVar()
        self.choose_hash_method_var = tk.IntVar(value=0)
        self.log_text_area_var = tk.StringVar()

        # 文件类型全局变量
        self.jpg_check_btn_var = tk.IntVar(value=1)
        self.png_check_btn_var = tk.IntVar(value=1)
        self.bmp_check_btn_var = tk.IntVar(value=1)
        self.gif_check_btn_var = tk.IntVar(value=1)

        self.big_font = Font(size=25, )
        self.mid_font = Font(size=16, )
        self.init_gui()
        tk.mainloop()

    def init_gui(self):
        self.root.geometry(get_center_geometry(self.root))
        self.root.title("hash photos v{}.{}.{}".format(*__version__))

        # 0. 选择要重命名图片/文件的文件夹
        select_dir_frame = tk.Frame(self.root)
        select_dir_frame.grid(row=0, column=0, columnspan=2)
        select_dir_entry = tk.Entry(select_dir_frame, width=59, textvariable=self.select_dir_entry_var)
        select_dir_entry.configure(font=self.mid_font)
        select_dir_entry.grid(row=0, column=0, padx=5)
        select_dir_btn = tk.Button(select_dir_frame, text="select dir", command=self.select_dir_btn_callback)
        select_dir_btn.configure(font=self.mid_font)  #
        select_dir_btn.grid(row=0, column=1)

        # 1. 选择哈希方法面板
        choose_hash_method_frame = tk.LabelFrame(self.root, text="choose hash method", font=self.mid_font)
        choose_hash_method_frame.grid(row=1, column=0)
        md5_radio_btn = tk.Radiobutton(choose_hash_method_frame, variable=self.choose_hash_method_var, value=0)
        md5_radio_btn.pack(side=tk.LEFT)
        md5_label = tk.Label(choose_hash_method_frame, text="md5", font=self.mid_font, )
        md5_label.bind("<Button-1>", lambda *args: self.choose_hash_method_var.set(0))
        md5_label.pack(side=tk.LEFT)
        sha1_radio_btn = tk.Radiobutton(choose_hash_method_frame, variable=self.choose_hash_method_var, value=1)
        sha1_radio_btn.pack(side=tk.LEFT)
        sha1_label = tk.Label(choose_hash_method_frame, text="sha1", font=self.mid_font)
        sha1_label.bind("<Button-1>", lambda *args: self.choose_hash_method_var.set(1))
        sha1_label.pack(side=tk.LEFT)
        sha256_radio_btn = tk.Radiobutton(choose_hash_method_frame, variable=self.choose_hash_method_var, value=2)
        sha256_radio_btn.pack(side=tk.LEFT)
        sha256_label = tk.Label(choose_hash_method_frame, text="sha256", font=self.mid_font)
        sha256_label.bind("<Button-1>", lambda *args: self.choose_hash_method_var.set(2))
        sha256_label.pack(side=tk.LEFT)
        sha512_radio_btn = tk.Radiobutton(choose_hash_method_frame, variable=self.choose_hash_method_var, value=3)
        sha512_radio_btn.pack(side=tk.LEFT)
        sha512_label = tk.Label(choose_hash_method_frame, text="sha512", font=self.mid_font)
        sha512_label.bind("<Button-1>", lambda *args: self.choose_hash_method_var.set(3))
        sha512_label.pack(side=tk.LEFT)

        # 2. 选择重命名文件类型面板
        choose_file_type_frame = tk.LabelFrame(self.root, text="choose file type", font=self.mid_font)
        choose_file_type_frame.grid(row=1, column=1)
        jpg_check_btn = tk.Checkbutton(choose_file_type_frame, variable=self.jpg_check_btn_var)
        jpg_check_btn.pack(side=tk.LEFT)
        jpg_label = tk.Label(choose_file_type_frame, text="jpg/jpeg", font=self.mid_font)
        jpg_label.bind("<Button-1>", lambda *args: self.jpg_check_btn_var.set(1 - self.jpg_check_btn_var.get()))
        jpg_label.pack(side=tk.LEFT)
        png_check_btn = tk.Checkbutton(choose_file_type_frame, variable=self.png_check_btn_var)
        png_check_btn.pack(side=tk.LEFT)
        png_label = tk.Label(choose_file_type_frame, text="png", font=self.mid_font)
        png_label.bind("<Button-1>", lambda *args: self.png_check_btn_var.set(1 - self.png_check_btn_var.get()))
        png_label.pack(side=tk.LEFT)
        bmp_check_btn = tk.Checkbutton(choose_file_type_frame, variable=self.bmp_check_btn_var)
        bmp_check_btn.pack(side=tk.LEFT)
        bmp_label = tk.Label(choose_file_type_frame, text="bmp", font=self.mid_font)
        bmp_label.bind("<Button-1>", lambda *args: self.bmp_check_btn_var.set(1 - self.bmp_check_btn_var.get()))
        bmp_label.pack(side=tk.LEFT)
        gif_check_btn = tk.Checkbutton(choose_file_type_frame, variable=self.gif_check_btn_var)
        gif_check_btn.pack(side=tk.LEFT)
        gif_label = tk.Label(choose_file_type_frame, text="gif", font=self.mid_font)
        gif_label.bind("<Button-1>", lambda *args: self.gif_check_btn_var.set(1 - self.gif_check_btn_var.get()))
        gif_label.pack(side=tk.LEFT)

        # 显示当前状态
        log_frame = tk.Frame(self.root)
        log_frame.grid(row=2, column=0, columnspan=2, sticky=tk.NSEW)
        self.log_text_area = tk.Text(log_frame, state=tk.DISABLED, width=70, height=21, font=self.mid_font)
        self.log_text_area.configure(wrap='none')
        self.log_text_area.grid(row=0, column=0, sticky=tk.NSEW)
        log_vert_scrollbar = tk.Scrollbar(log_frame)
        log_vert_scrollbar.grid(row=0, column=1, sticky=tk.NS)
        log_vert_scrollbar.configure(command=self.log_text_area.yview)
        self.log_text_area.configure(yscrollcommand=log_vert_scrollbar.set)
        log_hori_scorllbar = tk.Scrollbar(log_frame, orient=tk.HORIZONTAL)
        log_hori_scorllbar.grid(row=1, column=0, sticky=tk.EW)
        log_hori_scorllbar.configure(command=self.log_text_area.xview)
        self.log_text_area.configure(xscrollcommand=log_hori_scorllbar.set)

        # 日志底下的按钮
        buttons_frame = tk.Frame(self.root)
        buttons_frame.grid(row=3, column=0, sticky=tk.EW, columnspan=2)
        _padx = 65
        _width = 10
        # 进行转换
        rename_btn = tk.Button(buttons_frame, text="run", command=self.rename_file_btn_callback)
        rename_btn.config(font=self.mid_font, width=_width)
        rename_btn.grid(row=0, column=0, padx=_padx, )
        # 复制日志
        copy_log_btn = tk.Button(buttons_frame, text="copy log", command=self.copy_log_btn_callback)
        copy_log_btn.config(font=self.mid_font, width=_width)
        copy_log_btn.grid(row=0, column=1, padx=_padx)
        # 清除日志
        clear_log_btn = tk.Button(buttons_frame, text="clear log", command=self.clear_log_btn_callback)
        clear_log_btn.config(font=self.mid_font, width=_width)
        clear_log_btn.grid(row=0, column=2, padx=_padx)

    def select_dir_btn_callback(self):
        """选择文件夹按钮回调函数"""
        self.select_dir_entry_var.set(filedialog.askdirectory())

    def rename_file_btn_callback(self):
        """重命名按钮回调函数"""
        _workspace = self.select_dir_entry_var.get()
        # 如果没有选定就直接结束callback
        if _workspace == "":
            messagebox.showinfo(title="info", message="Please choose directory!")
            return
        # 如果文件夹不存在报错
        if not os.path.isdir(_workspace):
            messagebox.showerror(title="error", text="Directory\n{}\nnot exists!")
            return
        # 置为可修改状态
        self.log_text_area.configure(state=tk.NORMAL)
        self.log_text_area.insert(tk.END, "[{}] rename started\n".format(time.asctime()))
        # 得到需要重命名的文件列表
        abs_names = [os.path.join(_workspace, _) for _ in os.listdir(_workspace)]
        abs_file_names = [_ for _ in abs_names if is_vaild_file(self, _)]
        # 遍历文件
        for abs_filename in abs_file_names:
            # 得到新的文件名
            new_abs_filename = os.path.join(_workspace,
                                            get_hash(self, abs_filename) + os.path.splitext(abs_filename)[1])

            try:
                # 如果计算出的新文件名和旧文件名相同，跳过
                if abs_filename == new_abs_filename:
                    self.log_text_area.insert(tk.END, "[INFO] 已重命名过，跳过({})\n".format(abs_filename))
                    continue
                # 如果计算出的新文件名和旧文件名相同，但是新文件名已存在，将此文件移动到 ./backup/{time} 目录下
                if os.path.exists(new_abs_filename):
                    self.log_text_area.insert(tk.END, "[WARN] 文件名经存在，跳过并移入备份文件夹({})\n".format(abs_filename))
                    move_file(abs_filename)
                    continue
                # 重命名文件
                os.rename(abs_filename, new_abs_filename)
                self.log_text_area.insert(tk.END, "[INFO] 重命名：{} -> {}\n".format(abs_filename, new_abs_filename))

            except IOError as err:
                self.log_text_area.insert(tk.END, "[ERROR] {}\n".format(err))
        # 置为不可修改状态
        self.log_text_area.configure(state=tk.DISABLED)

    def copy_log_btn_callback(self):
        """复制日志到剪贴板"""
        self.root.clipboard_clear()
        self.root.clipboard_append(self.log_text_area.get("1.0", tk.END))
        messagebox.showinfo(title="info", message="Log has been copied to clipboard")

    def clear_log_btn_callback(self):
        """清楚日志按钮"""
        if messagebox.askyesno(title="clear log", message="Are you sure?"):
            self.log_text_area.config(state=tk.NORMAL)
            self.log_text_area.delete("1.0", tk.END)
            self.log_text_area.config(state=tk.DISABLED)
