import tkinter

from extra_widgets import MyButton, MyLabel, MyOptionMenu, MyScrollbar
from extra_tools import GridCoords
from pacworms_global import CONST

toggle_button_scroll_erase = 0

class GridFrame(tkinter.LabelFrame):

    def __init__(self, parent, var_levels_elements):
        """
        creation cadre scrollable
        :param var_levels_elements:
        :param parent:
        """

        #
        #   initialisations
        #
        tkinter.LabelFrame.__init__(self, parent)
        self.parent = parent

        #
        #   récupérer le tableau des éléments a traiter
        #   walls ou gallery ou gums ou worms
        #   ex: -> self.grid_elements.show_foreground()
        #
        self.var_levels_elements = var_levels_elements

        #
        #   LabelFrame configure
        #
        self.config(foreground=CONST.WidgetsColor.grid_canvas_foreground, text="X = - Y = - (- x -)")
        self.config(relief=tkinter.FLAT)
        self.config(labelanchor="n")
        self.config(font="Monospace 8 bold italic")
        self.config(background=CONST.WidgetsColor.frame_grid_scroll)
        self.config(highlightthickness=CONST.WidgetsColor.frame_grid_highlight_thickness)
        self.config(highlightbackground=CONST.WidgetsColor.frame_grid_highlight_background)

        #
        #   init. variables
        #
        self.starting_drag_position = ()
        # self.starting_click_position = (1, 1)

        self.grid_pad = 1
        self.grid_width = CONST.GridEditor.width + self.grid_pad
        self.grid_height = CONST.GridEditor.height + self.grid_pad

        #
        #   creation objet : Grille
        #
        self.obj_grid_coords = GridCoords(self.grid_width, self.grid_height, CONST.GridEditor.size)

        #
        #   création du Canvas
        #
        self.canvas = tkinter.Canvas(self)

        #
        #   initialise scrollbars et canvas
        #   dessins de la grille et des regles
        #
        self.initialize()

    def initialize(self):
        """
        initialise scrollbars et canvas
        dessins de la grille et des guides
        :return:
        """

        #
        #   definition scrollbar vertical
        #
        vertical_scroll_bar = MyScrollbar(self, "SCROLLBAR_GRID", 'vertical')
        vertical_scroll_bar.config(command=self.canvas.yview, width=20)
        vertical_scroll_bar.pack(fill=tkinter.Y, side=tkinter.RIGHT, expand=tkinter.FALSE)

        #
        #   definition scrollbar horizontal
        #
        horizontal_scroll_bar = MyScrollbar(self, "SCROLLBAR_GRID", 'horizontal')
        horizontal_scroll_bar.config(command=self.canvas.xview, width=20)
        horizontal_scroll_bar.pack(fill=tkinter.X, side=tkinter.BOTTOM, expand=tkinter.FALSE)

        #
        #   configure canvas
        #
        canvas_width = self.grid_width * CONST.GridEditor.size
        canvas_height = self.grid_height * CONST.GridEditor.size
        self.canvas.config(bd=0, highlightthickness=0)
        self.canvas.config(width=canvas_width, height=canvas_height)
        self.canvas.config(yscrollcommand=vertical_scroll_bar.set, xscrollcommand=horizontal_scroll_bar.set)
        self.canvas.config(scrollregion=(0, 0, canvas_width, canvas_height))
        self.canvas.pack(side=tkinter.LEFT, fill=tkinter.NONE, expand=tkinter.TRUE)
        self.canvas.config(background=CONST.WidgetsColor.grid_canvas_background)

        #
        #   views a 0
        #
        self.canvas.xview_moveto(0)
        self.canvas.yview_moveto(0)

        #
        #   dragging canvas with mouse button 3
        #
        self.canvas.bind('<Motion>', self.show_mouse_coords)

        self.canvas.bind("<Button-3>", self.mouse_right_click)
        self.canvas.bind("<B3-Motion>", self.mouse_right_motion)
        self.canvas.bind("<ButtonRelease-3>", self.mouse_right_release)

        #
        #   dessin de la grille
        #
        for l in range(self.grid_pad, self.grid_height):
            for c in range(self.grid_pad, self.grid_width):
                self.canvas.create_rectangle(self.obj_grid_coords.x[c],
                                             self.obj_grid_coords.y[l],
                                             self.obj_grid_coords.x[c] + CONST.GridEditor.size - 1,
                                             self.obj_grid_coords.y[l] + CONST.GridEditor.size - 1,
                                             outline=CONST.WidgetsColor.grid_outline,
                                             fill=CONST.WidgetsColor.grid_background)

        #
        #   dessin des guides
        #
        offset = int(CONST.GridEditor.size / 2)
        text_color = ["#444444", "#888888"]
        for c in range(0, CONST.GridEditor.width):
            self.canvas.create_text(self.obj_grid_coords.x[c + self.grid_pad] + offset,
                                    self.obj_grid_coords.y[0] + offset,
                                    text="%d" % (c + 1),
                                    font="Monospace 6 bold",
                                    fill=text_color[c % 2])
        for l in range(0, CONST.GridEditor.height):
            self.canvas.create_text(self.obj_grid_coords.x[0] + offset,
                                    self.obj_grid_coords.y[l + self.grid_pad] + offset,
                                    text="%d" % (l + 1),
                                    font="Monospace 6 bold",
                                    fill=text_color[l % 2])

    def get_canvas(self):
        """
        :return: objet canvas
        """

        return self.canvas

    def get_grid_coords(self):
        """
        :return: objet grille
        """

        return self.obj_grid_coords

    def get_grid_position(self, x, y):
        """
        convertion (x, y) vers (colonne, ligne)
        :param x: position x
        :param y: positiom y
        :return: position dans la grille
        """

        column = int(self.canvas.canvasx(x) / CONST.GridEditor.size)
        line = int(self.canvas.canvasy(y) / CONST.GridEditor.size)
        return column, line

    def show_mouse_coords(self, event):
        """
        show mouse positions, column and line in the LabelFrame
        dans le LabelFrame
        :param event:
        :return:
        """

        column, line = self.get_grid_position(event.x, event.y)

        if self.test_mouse_coords(column, line):

            self.canvas.config(cursor="tcross")
            self.config(foreground=CONST.WidgetsColor.grid_canvas_foreground,
                        text="C = %d L = %d" % (column, line))

        else:

            self.canvas.config(cursor="")

    def mouse_right_click(self, event):
        """
        si toggle_button_scroll_erase = 0
            scroll de la grille
        si toggle_button_scroll_erase = 1
            effacer point par point dans la grille
                - column, line = self.get_grid_position(event.x, event.y)
                    recuperer les coordonnees colonne et ligne
                -  if self.test_mouse_coords(column, line)
                    si les coordonnees sont dans la grille
                - if self.grid_elements.get_foreground(column, line) == CONST.EditGridElements.walls_value
                    si le buffer level foreground vaut 1
                - self.draw_box_full(column, line, CONST.WidgetsColor.grid_background)
                - self.grid_elements.set_foreground(0, column, line)
                    effacer le point et fixer le buffer level a 0
        si toggle_button_scroll_erase = 2
            effacer une zone rectangulaire
        :param event:
        :return:
        """

        global toggle_button_scroll_erase

        if toggle_button_scroll_erase == 1:

            column, line = self.get_grid_position(event.x, event.y)

            if self.test_mouse_coords(column, line):

                if self.var_levels_elements.get_foreground(column, line) == CONST.EditGridElements.walls_value:

                    self.draw_box_full(column, line, CONST.WidgetsColor.grid_background)
                    self.var_levels_elements.set_foreground(0, column, line)

        elif toggle_button_scroll_erase == 2:

            pass

        else:

            self.canvas.config(xscrollincrement=3)
            self.canvas.config(yscrollincrement=3)
            self.starting_drag_position = (event.x, event.y)
            self.canvas.config(cursor="fleur")

    def mouse_right_motion(self, event):
        """
        :param event:
        :return:
        """

        global toggle_button_scroll_erase

        if toggle_button_scroll_erase == 0:

            delta_x = event.x - self.starting_drag_position[0]
            delta_y = event.y - self.starting_drag_position[1]
            self.canvas.xview('scroll', delta_x, 'units')
            self.canvas.yview('scroll', delta_y, 'units')
            self.starting_drag_position = (event.x, event.y)

        elif toggle_button_scroll_erase == 1:

            self.show_mouse_coords(event)

            column, line = self.get_grid_position(event.x, event.y)

            if self.test_mouse_coords(column, line):

                if self.var_levels_elements.get_foreground(column, line) == CONST.EditGridElements.walls_value:

                    self.draw_box_full(column, line, CONST.WidgetsColor.grid_background)
                    self.var_levels_elements.set_foreground(0, column, line)

        else:  # 2
            pass

    def mouse_right_release(self, event):
        """
        :param event:
        :return:
        """

        global toggle_button_scroll_erase

        if toggle_button_scroll_erase == 0:

            event.x = 0
            event.y = 0
            self.canvas.config(xscrollincrement=0)
            self.canvas.config(yscrollincrement=0)
            self.canvas.config(cursor="")

    def draw_box_outline(self, column, line, index):

        color = (CONST.WidgetsColor.grid_outline, "WHITE")
        self.canvas.create_rectangle(self.obj_grid_coords.x[column],
                                     self.obj_grid_coords.y[line],
                                     self.obj_grid_coords.x[column] + CONST.GridEditor.size - 1,
                                     self.obj_grid_coords.y[line] + CONST.GridEditor.size - 1,
                                     outline=color[index],
                                     fill='')

    def draw_box_full(self, column, line, color):

        self.canvas.create_rectangle(self.obj_grid_coords.x[column],
                                     self.obj_grid_coords.y[line],
                                     self.obj_grid_coords.x[column] + CONST.GridEditor.size - 1,
                                     self.obj_grid_coords.y[line] + CONST.GridEditor.size - 1,
                                     outline=CONST.WidgetsColor.grid_outline,
                                     fill=color)

    def draw_circle_full(self, column, line, color, size):

        self.canvas.create_oval(self.obj_grid_coords.x[column] + size,
                                self.obj_grid_coords.y[line] + size,
                                (self.obj_grid_coords.x[column] + CONST.GridEditor.size - 1) - size,
                                (self.obj_grid_coords.y[line] + CONST.GridEditor.size - 1) - size,
                                outline=CONST.WidgetsColor.grid_outline,
                                fill=color)

    def draw_worm_right(self):
        pass

    def draw_worm_left(self):
        pass

    def draw_worm_up(self):
        pass

    def draw_worm_down(self):
        pass

    @staticmethod
    def test_mouse_coords(column, line):
        """
        test if coords column and line is in the grid
        :param column:
        :param line:
        :return:
        """

        rules = [column > 0, line > 0, column <= CONST.GridEditor.width, line <= CONST.GridEditor.height]
        if all(rules):
            return True

        return False


class GridLeftToolsFrame(tkinter.Frame):

    def __init__(self, parent):
        """
        :param parent:
        """

        #
        #   initialisations
        #
        tkinter.Frame.__init__(self, parent)
        self.configure(background=CONST.WidgetsColor.frame_grid_buttons)

        #
        #   buttons CLEAR, ICON_ERASE_SCROLL, ICON_ERASE_POINT, ICON_ERASE_RECTANGLE
        #
        self.button_clear_grid = MyButton(self, "CLEAR")
        self.button_scroll = MyButton(self, "ICON_SCROLL")
        self.button_erase_point = MyButton(self, "ICON_ERASE_POINT")
        self.button_erase_rectangle = MyButton(self, "ICON_ERASE_RECTANGLE")

        self.button_clear_grid.config(command=lambda: self.action_button_clear_grid())
        self.button_scroll.config(command=lambda: self.action_button_scroll())
        self.button_erase_point.config(command=lambda: self.action_button_erase_point())
        self.button_erase_rectangle.config(command=lambda: self.action_button_erase_rectangle())

        self.button_clear_grid.grid(column=0, row=0, padx=2, pady=0)
        self.button_scroll.grid(column=1, row=0, padx=2, pady=0)
        self.button_erase_point.grid(column=2, row=0, padx=2, pady=0)
        self.button_erase_rectangle.grid(column=3, row=0, padx=2, pady=0)

        #
        #   par defaut erase scroll
        #
        self.action_button_erase_point()

    def action_button_clear_grid(self):
        """
        :return:
        """

        pass

    def action_button_scroll(self):
        """
        :return:
        """

        global toggle_button_scroll_erase

        self.button_erase_rectangle.set_state(0)
        self.button_erase_point.set_state(0)
        toggle_button_scroll_erase = 0
        self.button_scroll.set_state(1)

    def action_button_erase_point(self):
        """
        :return:
        """

        global toggle_button_scroll_erase

        self.button_erase_rectangle.set_state(0)
        self.button_scroll.set_state(0)
        toggle_button_scroll_erase = 1
        self.button_erase_point.set_state(1)

    def action_button_erase_rectangle(self):
        """
        :return:
        """

        global toggle_button_scroll_erase

        self.button_erase_point.set_state(0)
        self.button_scroll.set_state(0)
        toggle_button_scroll_erase = 2
        self.button_erase_rectangle.set_state(1)


class GridRightToolsFrame(tkinter.Frame):

    def __init__(self, parent, grid_frame):
        """
        :param parent:
        """

        #
        #   initialisations
        #
        tkinter.Frame.__init__(self, parent)
        self.configure(background=CONST.WidgetsColor.frame_grid_buttons)
        self.obj_grid_frame = grid_frame

        #
        #   columns
        #
        self.column_numbers_guide = [0]
        self.get_guides_numbers(CONST.GridEditor.width, self.column_numbers_guide)
        self.column_guide = tkinter.StringVar()
        self.column_guide.set(self.column_numbers_guide[0])
        self.column_guide.trace('w', lambda *args: self.action_column_guide())

        #
        #   rows
        #
        self.row_numbers_guide = [0]
        self.get_guides_numbers(CONST.GridEditor.height, self.row_numbers_guide)
        self.row_guide = tkinter.StringVar()
        self.row_guide.set(self.row_numbers_guide[0])
        self.row_guide.trace('w', lambda *args: self.action_row_guide())

        #
        #
        #
        label_column_guide = MyLabel(self, "COLUMNS\nGUIDE")
        label_row_guide = MyLabel(self, "ROWS\nGUIDE")

        self.option_menu_column_guide = MyOptionMenu(self, "GUIDES", self.column_guide, *self.column_numbers_guide)
        self.option_menu_row_guide = MyOptionMenu(self, "GUIDES", self.row_guide, *self.row_numbers_guide)

        label_column_guide.grid(column=0, row=0, padx=2, pady=0)
        self.option_menu_column_guide.grid(column=1, row=0, padx=2, pady=0)

        label_row_guide.grid(column=2, row=0, padx=2, pady=0)
        self.option_menu_row_guide.grid(column=3, row=0, padx=2, pady=0)

    def action_column_guide(self):
        """

        :return:
        """
        nb_columns = int(self.column_guide.get())
        if nb_columns > 0:
            column_cursor = 1
            nb_spaces = int(self.get_spaces(CONST.GridEditor.width, nb_columns))
            print(nb_columns, nb_spaces)
            for column in range(nb_columns):
                column_cursor += nb_spaces + 1
                self.obj_grid_frame.draw_box_full(column_cursor, 2, CONST.EditGridElements.guides_color_fg)

    def action_row_guide(self):
        """

        :return:
        """

        """
        selection = int(self.row_guide.get())
        if selection > 0:
            step = int(CONST.GridEditor.height / (selection + 1)) - 1
        for number in self.row_numbers_guide:
            print(self.get_step_guide(CONST.GridEditor.height, number))
        """

        pass

    def set_vertical_line_guide(self):
        """

        :return:
        """

        for column_index in range(1, CONST.GridEditor.height):

            self.obj_grid_frame.draw_box_full(2, 2, CONST.EditGridElements.guides_color_fg)

    def set_horizontal_line_guide(self):
        pass

    def get_guides_numbers(self, size, guides_numbers):

        guide_number = 1

        while True:

            spaces = self.get_spaces(size, guide_number)
            if spaces == int(spaces):
                guides_numbers.append(guide_number)
            if spaces == 1:
                break
            guide_number += 1

    @staticmethod
    def get_spaces(grid_editor_size, guide_number):

        return (grid_editor_size - (guide_number + 2)) / (guide_number + 1)