import threading
import time
from tkinter import colorchooser
from tkinter.filedialog import asksaveasfilename

import customtkinter as ctk
import pyautogui as pyautogui
import pyperclip
import pytesseract as pytesseract
from PIL import ImageTk, Image

from custom_widgets.button_group import ImageButtonGroup
from custom_widgets.canvas.circle import Circle
from custom_widgets.canvas.line import Line
from custom_widgets.canvas.rectangle import Rectangle
from custom_widgets.canvas.rectangle_outside_dimming import RectangleOutsideDimming
from custom_widgets.canvas.text import Text
from custom_widgets.move_menu import MoveMenu
from handlers.clipboard_handler import copy_screenshot_to_clipboard

class ScreenWindow(ctk.CTkToplevel):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.configure(fg_color="black")

        self.attributes("-topmost", True)
        self.attributes("-fullscreen", True)

        self.screenshot = pyautogui.screenshot()
        self.resized_screenshot = ImageTk.PhotoImage(self.screenshot)

        self.canvas = ctk.CTkCanvas(self, highlightthickness=0, bg="black")
        self.canvas.pack(fill=ctk.BOTH, expand=True)
        self.canvas.create_image(0, 0, anchor="nw", image=self.resized_screenshot)
        self.canvas.tag_lower("image")

        self.dimming_rect = self.canvas.create_rectangle(
            0, 0, 0, 0, fill="black", stipple="gray50", tags="dimming_rect"
        )

        self.focus()

        self.undo_stack = []
        self.redo_stack = []

        self.corner_button_max_size = 10
        self.selection_min_size = 20

        self.current_mode = "selection"
        self.selection_rect = RectangleOutsideDimming(self.canvas)

        self.text_menu = False
        self.main_menu = None
        self.main_menu_position = None
        self.draw_menu = None
        self.drawing_element_menu = None
        self.textbox = ctk.CTkTextbox(master=self, corner_radius=0)

        self.color_picker_button = None

        self.texbox_menu = None
        self.move_menu = MoveMenu(
            self.canvas,
            self.selection_rect,
            pyautogui.screenshot(),
            corner_button_max_size=self.corner_button_max_size,
            additional_func=lambda: self.creating_menu(),
            del_func=lambda: self.del_func())

        self.drawing_element = None
        self.drawing_selection = Rectangle(self.canvas, color="gray50", tags="drawing_selection", dash=(5, 3),
                                           min_size=3)

        self.drawing_color = "#FF0000"
        self.is_filled = False
        self.is_dashed = False
        self.is_arrow = False

        self.holding_shift_l = False

        self.bind_events()

    # Binds

    def unbind_mouse(self) -> None:
        self.unbind("<ButtonRelease-1>")

    def bind_events(self):

        self.bind_change_element_width()
        key_up = "Up"
        key_left = "Left"
        key_right = "Right"
        key_down = "Down"
        self.bind_keys_move(key_up, key_left, key_right, key_down)
        self.bind_keys_move_release(key_up, key_left, key_right, key_down)

        self.bind_mouse_events()

        destroy = "Escape"
        self.bind_destroy(destroy)

        self.bind_unselect()
        self.bind_undo()
        self.bind_select_all()

        self.bind_control_l()
        self.bind_save_copy()

        self.bind_shift_l(key_up, key_left, key_right, key_down)
        self.bind_alt_l(key_up, key_left, key_right, key_down)

        self.bind_configure()

    def bind_select_all(self):
        self.bind("<Control-a>", lambda event: self.select_all())

    def select_all(self):
        self.selection_rect.set_coordinates(start_x=0, start_y=0, end_x=self.canvas.winfo_width(),
                                            end_y=self.canvas.winfo_height())
        self.selection_rect.create()
        self.create_menus()

    def bind_undo(self):
        self.bind("<Control-z>", lambda event: self.undo_action())
        self.bind("<Control-Shift-Z>", lambda event: self.redo_action())

    def bind_unselect(self):
        self.bind("<Return>", lambda event: self.unselect_drawing_element())

    def bind_save_copy(self):
        self.bind("<Control-c>", self.copy_image)
        self.bind("<Control-s>", self.save_image)

    def bind_keys_move(self, key_up: str, key_left: str, key_right: str, key_down: str):
        self.bind(f"<{key_up}>", self.move_menu.handle_up_move)
        self.bind(f"<{key_left}>", self.move_menu.handle_left_move)
        self.bind(f"<{key_right}>", self.move_menu.handle_right_move)
        self.bind(f"<{key_down}>", self.move_menu.handle_down_move)

    def bind_keys_move_release(self, key_up: str, key_left: str, key_right: str, key_down: str):
        self.bind(f"<KeyRelease-{key_up}>", self.create_menus)
        self.bind(f"<KeyRelease-{key_left}>", self.create_menus)
        self.bind(f"<KeyRelease-{key_right}>", self.create_menus)
        self.bind(f"<KeyRelease-{key_down}>", self.create_menus)

    def bind_mouse_events(self, event=None):
        self.canvas.bind("<Button-1>", self.start_selection)
        self.canvas.bind("<B1-Motion>", self.update_selection)
        self.canvas.bind("<ButtonRelease-1>", self.create_menus)

    def bind_destroy(self, destroy: str):
        self.bind(f"<{destroy}>", self.destroy_window)

    def bind_configure(self):
        self.canvas.bind("<Configure>", self.create_dimming_rectangle)

    def bind_control_l(self):
        self.bind("<KeyPress-Control_L>", self.bind_mouse_events)
        self.bind("<KeyRelease-Control_L>", self.disable_mouse_selection)

    def bind_shift_l(self, key_up: str, key_left: str, key_right: str, key_down: str):
        self.bind("<KeyPress-Shift_L>", lambda event: self.handle_stretch(event, key_up, key_left, key_right, key_down))
        self.bind("<KeyRelease-Shift_L>",
                  lambda event: self.handle_stretch_release(event, key_up, key_left, key_right, key_down))

    def bind_alt_l(self, key_up: str, key_left: str, key_right: str, key_down: str):
        self.bind("<KeyPress-Alt_L>",
                  lambda event: self.handle_stretch(event, key_up, key_left, key_right, key_down, -1))
        self.bind("<KeyRelease-Alt_L>",
                  lambda event: self.handle_stretch_release(event, key_up, key_left, key_right, key_down))

    def handle_stretch_release(self, event, key_up: str, key_left: str, key_right: str, key_down: str):
        self.holding_shift_l = False
        self.bind_keys_move(key_up, key_left, key_right, key_down)
        self.bind_keys_move_release(key_up, key_left, key_right, key_down)

    def handle_stretch(self, event, key_up: str, key_left: str, key_right: str, key_down: str, offset: int = 1):
        self.holding_shift_l = True
        self.bind_stretch(key_up, key_left, key_right, key_down, offset)
        self.bind_keys_move_release(key_up, key_left, key_right, key_down)

    def bind_stretch(self, key_up: str, key_left: str, key_right: str, key_down: str, offset: int):
        self.bind(f"<{key_up}>", lambda event: self.move_menu.handle_up_stretch(event, offset))
        self.bind(f"<{key_left}>", lambda event: self.move_menu.handle_left_stretch(event, offset))
        self.bind(f"<{key_right}>", lambda event: self.move_menu.handle_right_stretch(event, offset))
        self.bind(f"<{key_down}>", lambda event: self.move_menu.handle_down_stretch(event, offset))

    def bind_change_element_width(self):
        self.bind(f"<MouseWheel>", self.change_element_width)

    def disable_mouse_selection(self, event=None):
        self.bind_undo()
        self.canvas.unbind("<Button-1>")
        self.canvas.unbind("<B1-Motion>")
        self.canvas.unbind("<ButtonRelease-1>")

    def bind_draw_mouse_events(self, event=None):
        self.canvas.bind("<Button-1>", self.start_draw)
        self.canvas.bind("<B1-Motion>", self.update_draw)
        self.canvas.bind("<ButtonRelease-1>", self.create_menus)

    def change_element_width(self, event):
        if self.drawing_element is not None:
            self.drawing_element.change_width(event.delta / 120)
            self.drawing_element.create()
            self.move_menu.rise()
            self.canvas.tag_raise("drawing_selection")

    ##
    def start_selection(self, event):
        self.destroy_menus()
        self.move_menu.destroy()
        self.selection_rect.set_coordinates(start_x=event.x, start_y=event.y)

    def update_selection(self, event):
        self.selection_rect.set_coordinates(end_x=event.x, end_y=event.y)
        self.selection_rect.create()

    ##

    def start_draw(self, event):
        self.destroy_menus()
        self.move_menu.destroy()
        self.drawing_element.set_coordinates(start_x=event.x, start_y=event.y)
        self.drawing_selection.set_coordinates(start_x=event.x, start_y=event.y)
        if type(self.drawing_element).__name__ == "Text":
            self.drawing_element.set_coordinates(end_x=event.x + 25, end_y=event.y + 15)
            self.drawing_selection.set_coordinates(end_x=event.x + 25, end_y=event.y + 15)
            self.drawing_element.create()

    def update_draw(self, event):

        if type(self.drawing_element).__name__ == "Text":
            self.drawing_element.set_coordinates(start_x=event.x, start_y=event.y)
            self.drawing_selection.set_coordinates(start_x=event.x, start_y=event.y)
            self.drawing_element.set_coordinates(end_x=event.x + 25, end_y=event.y + 15)
            self.drawing_selection.set_coordinates(end_x=event.x + 25, end_y=event.y + 15)
        else:
            self.drawing_element.set_coordinates(end_x=event.x, end_y=event.y)
            self.drawing_selection.set_coordinates(end_x=event.x, end_y=event.y)
        self.drawing_element.create()
        self.drawing_selection.create()

        self.canvas.tag_raise(self.drawing_selection.get_tags())
        self.canvas.tag_raise(self.drawing_element.get_tags())

    ##
    def create_dimming_rectangle(self, event):
        self.canvas.coords(self.dimming_rect, 0, 0, event.width, event.height)

    def undo_action(self):
        self.canvas.config(cursor="")
        if self.undo_stack:
            element = self.undo_stack.pop()
            element.destroy()

            self.redo_stack.append(element)

            if len(self.undo_stack) > 0:
                self.drawing_element = self.undo_stack[-1]
                element = self.undo_stack[-1]

                if self.current_mode == "draw":
                    self.update_move_menu_and_selection(element)
            else:
                self.move_menu.destroy()
                self.drawing_selection.destroy()

    def redo_action(self):
        self.canvas.config(cursor="")
        if self.redo_stack:
            element = self.redo_stack.pop()
            element.create()
            self.undo_stack.append(element)
            self.drawing_element = element

            if self.current_mode == "draw":
                self.update_move_menu_and_selection(element)

    def update_move_menu_and_selection(self, element):
        self.move_menu.set_target(element)
        self.move_menu.create()
        new_selection_coordinates = element.get_current_corners_coordinates()
        self.drawing_selection.set_coordinates(
            start_x=new_selection_coordinates[0][0],
            start_y=new_selection_coordinates[0][1],
            end_x=new_selection_coordinates[1][0],
            end_y=new_selection_coordinates[1][1]
        )
        self.drawing_selection.create()

    # Menus

    def create_menus(self, event=None):

        self.selection_rect.expand_to_minimum_size()
        self.selection_rect.create()

        self.creating_menu()
        self.move_menu.destroy()
        if self.current_mode == "selection":
            self.move_menu.set_target(self.selection_rect)
            self.move_menu.set_mode("all")
            self.move_menu.set_limits(True)
            self.move_menu.create()
            self.destroy_canvas_elements()
        elif self.current_mode == "draw":
            if type(self.drawing_element).__name__ == "Text":
                self.bind("<Key>", lambda event: self.handle_text_input(event))

            if self.drawing_element is not None:
                self.move_menu.set_target(self.drawing_element)
                if type(self.drawing_element).__name__ == "Text":
                    self.move_menu.set_mode("move")
                else:
                    self.move_menu.set_mode("all")
                self.move_menu.set_limits(False)
                self.move_menu.create()

    def handle_text_input(self, event):
        if event.keycode == 8:
            self.drawing_element.subtract()
        else:
            self.drawing_element.add(event.char)
        self.drawing_element.create()

    def creating_menu(self):
        self.main_menu_position = self.create_menu()

        if self.current_mode == "draw":
            self.create_drawing_element_menu()
            self.create_color_picker_menu(self.main_menu_position)
            self.create_draw_menu(self.main_menu_position)
            if self.drawing_element is not None:
                corners = self.drawing_element.get_corners_coordinates()
                self.drawing_selection.set_coordinates(start_x=corners[0][0], start_y=corners[0][1],
                                                       end_x=corners[1][0], end_y=corners[1][1])
                self.drawing_selection.create()

        if self.text_menu:
            self.place_texbox()
        self.bind_control_l()
        self.disable_mouse_selection()

    def create_menu(self, event=None):
        self.destroy_menus()

        corners_coordinates = self.selection_rect.get_corners_coordinates()
        start_x, end_x = corners_coordinates[0][0], corners_coordinates[1][0]
        start_y, end_y = corners_coordinates[0][1], corners_coordinates[1][1]

        draw_icon = Image.open("images/draw-icon.png")
        move_icon = Image.open("images/move-icon.jpg")

        save_icon = Image.open("images/save-icon.png")
        copy_icon = Image.open("images/copy-icon.png")
        txt_icon = Image.open("images/txt-icon.png")
        undo_icon = Image.open("images/undo-icon.png")
        redo_icon = Image.open("images/redo-icon.png")

        images = None
        values = None

        if self.current_mode == "draw":
            images = (move_icon, save_icon, copy_icon, undo_icon, redo_icon)
            values = ["draw", "save", "copy", "undo", "redo"]
        elif self.current_mode == "selection":
            images = (draw_icon, save_icon, copy_icon, txt_icon)
            values = ["move", "save", "copy", "txt"]

        self.main_menu = ImageButtonGroup(self, border_width=0, orientation="horizontal",
                                          values=values, images=images, fg_color="gray50",
                                          command=self.main_menu_callback)

        possible_positions = [
            (start_x, start_y - self.main_menu.cget("height") + 5),
            (end_x - self.main_menu.cget("width"), end_y + 5),
            (end_x - self.main_menu.cget("width"), start_y - self.main_menu.cget("height") + 5),
            (start_x, end_y + 5),
            (end_x - self.main_menu.cget("width"), end_y - self.main_menu.cget("height") + 10)]

        position = self.find_suitable_position(possible_positions, self.main_menu.cget("width"),
                                               self.main_menu.cget("height"))
        self.main_menu.place_configure(x=position[0] + 5, y=position[1])

        return position

    def create_draw_menu(self, position):
        line_icon = Image.open("images/line-icon.png")
        rectangle_icon = Image.open("images/rectangle-icon.png")
        circle_icon = Image.open("images/circle-icon.png")
        textbox_icon = Image.open("images/textbox-icon.png")
        images = (textbox_icon, line_icon, rectangle_icon, circle_icon)
        values = ["text", "line", "rectangle", "circle"]

        self.draw_menu = ImageButtonGroup(self, border_width=0, orientation="horizontal",
                                          values=values, images=images, fg_color="gray50",
                                          command=self.draw_menu_callback)

        possible_positions = [(position[0], position[1] - self.draw_menu.cget("height")),
                              (position[0], position[1] + self.main_menu.cget("height")-self.main_menu.cget("height")/4)]

        position = self.find_suitable_position(possible_positions, self.main_menu.cget("width"),
                                               self.main_menu.cget("height"))
        self.draw_menu.place_configure(x=position[0], y=position[1] + 5)

    def create_drawing_element_menu(self):
        self.destroy_drawing_element_menu()

        arrow_icon = Image.open("images/arrow-icon.png")
        dashed_icon = Image.open("images/dashed-icon.png")
        fill_icon = Image.open("images/fill-icon.png")

        if type(self.drawing_element).__name__ == "Line":
            images = (arrow_icon, dashed_icon)
            values = ["arrow", "dash"]
        elif type(self.drawing_element).__name__ == "Text":
            images = (None,)
            values = None
        else:
            images = (dashed_icon, fill_icon)
            values = ["dash", "fill"]

        self.drawing_element_menu = ImageButtonGroup(self, border_width=0, orientation="horizontal",
                                                     values=values, images=images, fg_color="gray50",
                                                     command=self.drawing_element_menu_callback)

        self.drawing_element_menu.place_configure(x=0, y=0)

    def create_color_picker_menu(self, position):
        self.destroy_color_picker_menu()
        hover_color = self.lighten_color(self.drawing_color)
        self.color_picker_button = ctk.CTkButton(self, border_width=5, fg_color=self.drawing_color, text="",
                                                 border_color="gray50", width=25, height=25, bg_color="transparent",
                                                 hover=True, hover_color=hover_color, command=lambda: self.pick_color())
        possible_positions = [(position[0] - self.color_picker_button.cget("width"), position[1]),
                              (position[0] + 5, position[1] - self.color_picker_button.cget("height") - 5 - 1),
                              (position[0] + 5, position[1] + self.color_picker_button.cget("height") + 5 + 1),
                              (position[0] - self.color_picker_button.cget("width"), position[1])]

        position = self.find_suitable_position(possible_positions, self.main_menu.cget("width"),
                                               self.main_menu.cget("height"))
        self.color_picker_button.place_configure(x=position[0], y=position[1])

    def del_func(self):
        self.destroy_menus()
        self.destroy_canvas_elements()
        self.textbox.place_forget()
        self.destroy_texbox_menu()

    def lighten_color(self, hex_color: hex, brightness_increase: float = 0.2):
        red = int(hex_color[1:3], 16)
        green = int(hex_color[3:5], 16)
        blue = int(hex_color[5:7], 16)

        red += int((255 - red) * brightness_increase)
        green += int((255 - green) * brightness_increase)
        blue += int((255 - blue) * brightness_increase)

        red = min(red, 240)
        green = min(green, 240)
        blue = min(blue, 240)

        lightened_color = f"#{red:02X}{green:02X}{blue:02X}"
        return lightened_color

    def find_suitable_position(self, possible_positions, width: int, height: int):
        for position in possible_positions:
            x, y = position
            if self.check_screen_fit(x, y, width, height):
                return position

        return possible_positions[-1]

    def check_screen_fit(self, x: int, y: int, width: int, height: int):
        canvas_width = self.canvas.winfo_width()
        canvas_height = self.canvas.winfo_height()

        return x + width <= canvas_width and y + height <= canvas_height and x >= 0 and y >= 0

    def main_menu_callback(self, value):
        if value == "move":
            self.current_mode = "draw"
            self.create_menus()
        elif value == "draw":
            self.current_mode = "selection"
            self.create_menus()
        elif value == "save":
            self.save_image()
        elif value == "copy":
            self.copy_image()
        elif value == "txt":
            self.image_to_txt()
            self.text_menu = True
        elif value == "undo":
            self.undo_action()
        elif value == "redo":
            self.redo_action()

    def draw_menu_callback(self, value):
        self.bind_draw_mouse_events()
        self.unselect_drawing_element()

        if value == "line":
            self.drawing_element = Line(self.canvas, color=self.drawing_color, width=2, tags="line", min_size=0,
                                        is_arrow=self.is_arrow, is_dashed=self.is_dashed)
            self.undo_stack.append(self.drawing_element)
        elif value == "rectangle":
            self.drawing_element = Rectangle(self.canvas, color=self.drawing_color, width=2, tags="rectangle",
                                             min_size=1, is_dashed=self.is_dashed, is_filled=self.is_filled)
            self.undo_stack.append(self.drawing_element)
        elif value == "circle":
            self.drawing_element = Circle(self.canvas, color=self.drawing_color, width=2, tags="circle", min_size=1,
                                          is_dashed=self.is_dashed, is_filled=self.is_filled)
            self.undo_stack.append(self.drawing_element)
        elif value == "text":
            self.drawing_element = Text(self.canvas, color=self.drawing_color, tags="text", min_size=1)
            self.undo_stack.append(self.drawing_element)
        self.create_drawing_element_menu()

    def drawing_element_menu_callback(self, value):
        if value == "arrow":
            if self.drawing_element is not None:
                self.drawing_element.switch_arrow()
            self.is_arrow = self.flip_flap(self.is_arrow)
        elif value == "dash":
            if self.drawing_element is not None:
                self.drawing_element.switch_dash()
            self.is_dashed = self.flip_flap(self.is_dashed)
        elif value == "fill":
            if self.drawing_element is not None:
                self.drawing_element.switch_fill()
            self.is_filled = self.flip_flap(self.is_filled)
        if self.drawing_element is not None:
            self.drawing_element.create()
            self.move_menu.create()

    def texbox_menu_callback(self, value):
        if value == "copy":
            text = self.textbox.get("0.0", "end")
            pyperclip.copy(text)
        elif value == "close":
            self.text_menu = False
            self.textbox.place_forget()
            self.destroy_texbox_menu()

    def flip_flap(self, value: bool):
        return False if value else True

    #

    def pick_color(self):
        self.attributes("-topmost", False)

        drawing_color = colorchooser.askcolor()
        if drawing_color[1] is not None:
            self.drawing_color = drawing_color[1]

        self.attributes("-topmost", True)
        self.create_color_picker_menu(self.main_menu_position)

        if self.drawing_element is not None:
            self.drawing_element.set_color(self.drawing_color)
            self.drawing_element.create()
            self.move_menu.create()

    def save_image(self, event=None):
        corners_coordinates = self.selection_rect.get_corners_coordinates()
        start_x, end_x = corners_coordinates[0][0], corners_coordinates[1][0]
        start_y, end_y = corners_coordinates[0][1], corners_coordinates[1][1]

        width = self.selection_rect.get_width()
        height = self.selection_rect.get_height()

        self.unbind_mouse()

        self.move_menu.destroy()
        self.destroy_menus()
        self.destroy_canvas_elements()

        selection = self.canvas.find_withtag("selection")
        self.canvas.itemconfig(selection, width=0)
        self.attributes("-topmost", False)
        ticks = str(time.time()).replace('.', '')[:13]
        default_filename = f"{ticks}_screenshot.png"
        save_path = asksaveasfilename(defaultextension='', filetypes=[("All Files", "*.*")],
                                      initialfile=default_filename, parent=self)

        def delay_and_screenshot():
            time.sleep(0.2)
            screenshot = pyautogui.screenshot()
            screenshot = screenshot.crop((start_x, start_y, start_x + width, start_y + height))
            screenshot = screenshot.resize((int(width * 2), int(height * 2)))
            if save_path:
                screenshot.save(save_path)
            self.attributes("-topmost", True)
            if not self.holding_shift_l and save_path:
                self.destroy_window()

        screenshot_thread = threading.Thread(target=delay_and_screenshot)
        screenshot_thread.start()

        self.after(100, self.create_menus)

    def copy_image(self, event=None):
        corners_coordinates = self.selection_rect.get_corners_coordinates()
        start_x, end_x = corners_coordinates[0][0], corners_coordinates[1][0]
        start_y, end_y = corners_coordinates[0][1], corners_coordinates[1][1]

        width = self.selection_rect.get_width()
        height = self.selection_rect.get_height()

        self.unbind_mouse()

        self.move_menu.destroy()
        self.destroy_menus()
        self.destroy_canvas_elements()

        selection = self.canvas.find_withtag("selection")
        self.canvas.itemconfig(selection, width=0)

        def delay_and_screenshot():
            time.sleep(0.1)
            screenshot = pyautogui.screenshot()
            screenshot = screenshot.crop(
                (start_x, start_y, start_x + width, start_y + height))
            copy_screenshot_to_clipboard(screenshot)
            self.destroy_window()

        screenshot_thread = threading.Thread(target=delay_and_screenshot)
        screenshot_thread.start()

    def image_to_txt(self, event=None):
        corners_coordinates = self.selection_rect.get_corners_coordinates()
        start_x, end_x = corners_coordinates[0][0], corners_coordinates[1][0]
        start_y, end_y = corners_coordinates[0][1], corners_coordinates[1][1]

        width = self.selection_rect.get_width()
        height = self.selection_rect.get_height()

        self.unbind_mouse()

        self.move_menu.destroy()
        self.destroy_menus()
        self.destroy_canvas_elements()

        selection = self.canvas.find_withtag("selection")
        self.canvas.itemconfig(selection, width=0)

        def delay_and_screenshot():
            time.sleep(0.1)
            screenshot = pyautogui.screenshot()
            screenshot = screenshot.crop(
                (start_x, start_y, start_x + width, start_y + height))

            pytesseract.pytesseract.tesseract_cmd = "D:/tesseract/tesseract.exe"
            text = pytesseract.image_to_string(screenshot)
            textbox_width = self.selection_rect.get_width() - self.selection_rect.get_width() / 5
            textbox_height = self.selection_rect.get_height() - self.selection_rect.get_height() / 5

            textbox_width = min(self.canvas.winfo_width() / 2 - self.canvas.winfo_width() / 5, textbox_width)
            textbox_height = min(self.canvas.winfo_height() / 2 - self.canvas.winfo_height() / 5, textbox_height)

            self.textbox.configure(width=textbox_width,
                                   height=textbox_height)

            self.textbox.insert("0.0", text)

            self.place_texbox()

            self.create_menus()

        screenshot_thread = threading.Thread(target=delay_and_screenshot)
        screenshot_thread.start()

    # Destroy
    def create_texbox_menu(self, texbox_position):
        self.destroy_texbox_menu()

        close_icon = Image.open("images/close-icon.png")
        copy_icon = Image.open("images/copy-icon.png")

        images = (copy_icon, close_icon)
        values = ["copy", "close"]

        self.texbox_menu = ImageButtonGroup(self, border_width=0, orientation="horizontal",
                                            values=values, images=images, fg_color="gray50",
                                            command=self.texbox_menu_callback)

        possible_positions = [
            (texbox_position[0],
             texbox_position[1] + self.textbox.cget("height") + self.textbox.cget("height") / 5 + self.texbox_menu.cget(
                 "height") / 4),
            (texbox_position[0] + self.textbox.cget("width") + self.textbox.cget("width") / 5 - self.texbox_menu.cget(
                "width"),
             texbox_position[1] + self.textbox.cget("height") + self.textbox.cget("height") / 5 - self.texbox_menu.cget(
                 "height") / 2)
        ]

        position = self.find_suitable_position(possible_positions, self.texbox_menu.cget("width"),
                                               self.texbox_menu.cget("height"))
        self.texbox_menu.place_configure(x=position[0] + 5, y=position[1])

        return position

    def place_texbox(self):
        coordinates = self.selection_rect.get_corners_coordinates()

        possible_positions = [(coordinates[0][0], coordinates[1][1]),
                              (coordinates[1][0], coordinates[0][1]),
                              (coordinates[0][0] - self.textbox.cget("width") - self.selection_rect.get_width() / 5,
                               coordinates[0][1]),
                              (coordinates[0][0] - self.textbox.cget("width") - self.selection_rect.get_width() / 5,
                               self.canvas.winfo_height() - self.textbox.cget("height")),
                              (coordinates[1][0], self.canvas.winfo_height() - self.textbox.cget("height")),
                              (coordinates[0][0], coordinates[0][1])]

        position = self.find_suitable_position(possible_positions,
                                               self.textbox.cget("width") + self.textbox.cget("width") / 5,
                                               self.textbox.cget("height") + self.textbox.cget("height") / 5)

        self.textbox.place_configure(x=position[0], y=position[1])

        self.create_texbox_menu(position)

    def destroy_menus(self):
        items_to_destroy = {
            "main_menu": self.main_menu,
            "color_picker_button": self.color_picker_button,
            "draw_menu": self.draw_menu,
            "drawing_element_menu": self.drawing_element_menu,
        }
        for attr_name, item in items_to_destroy.items():
            if item is not None:
                item.destroy()
                setattr(self, attr_name, None)

    def destroy_canvas_elements(self):
        items_to_destroy = [self.drawing_selection]
        for item in items_to_destroy:
            if item is not None:
                item.destroy()

    def destroy_color_picker_menu(self):
        items_to_destroy = {
            "color_picker_button": self.color_picker_button,
        }
        for attr_name, item in items_to_destroy.items():
            if item is not None:
                item.destroy()
                setattr(self, attr_name, None)

    def destroy_texbox_menu(self):
        items_to_destroy = {
            "texbox_menu": self.texbox_menu,
        }
        for attr_name, item in items_to_destroy.items():
            if item is not None:
                item.destroy()
                setattr(self, attr_name, None)

    def destroy_drawing_element_menu(self):
        items_to_destroy = {
            "drawing_element_menu": self.drawing_element_menu,
        }
        for attr_name, item in items_to_destroy.items():
            if item is not None:
                item.destroy()
                setattr(self, attr_name, None)

    def unselect_drawing_element(self):
        self.move_menu.destroy()
        self.drawing_selection.destroy()
        self.drawing_element = None
        self.unbind("<Key>")

    def destroy_window(self, event=None):
        self.destroy()


import os
from pathlib import Path
# my_file = 'my_file.txt'
# base = os.path.splitext(my_file)[0]
# print(base)
# os.rename(my_file, base + '.bin')

# Get the list of all files and directories
path = "C://vdo from tube//"
dir_list = os.listdir(path)
# dir_list = path+str(dir_list)
# dir_list = dir_list.sort(key=os.path.getctime)
lists = (enumerate(dir_list))

# files = []
# for i in dir_list:
#     paths = path+str(i)
#     files.append(paths)
#     print(paths)

# sorting by Created time
paths = sorted(Path(path).iterdir(), key=os.path.getmtime)
pathss = (enumerate(paths))
for count, filename in pathss:
    src =f"{filename}"  # pathname/filename, if .py file is outside path

    # pathname/filename, if .py file is outside path
    dst =f"{os.path.dirname(filename )}\{count+1} {Path(filename).name}"
    print(src)
    print(dst)

    # rename() function will
    # rename all the files
    os.rename(src, dst)


import modules as mx

### OBJECTS ###
alert = mx.C()
alertText = mx.T()

### CONTENT ###
alert.content = [alertText]

### PROPERTIES ###
alert.id = 'alert'
alert.background_color = 'rgba(255, 255, 255, 0.9)'
alertText.id = 'alertText'


"""empty message

Revision ID: 93312191ad25
Revises: b956fe03918b
Create Date: 2018-12-01 23:43:01.288123

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = '93312191ad25'
down_revision = 'b956fe03918b'
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('Sales',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('user_id', sa.Integer(), nullable=True),
    sa.Column('item_id', sa.Integer(), nullable=True),
    sa.Column('num_item', sa.Integer(), nullable=True),
    sa.Column('amount', sa.Float(), nullable=True),
    sa.ForeignKeyConstraint(['item_id'], ['products.id'], ),
    sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
    sa.PrimaryKeyConstraint('id')
    )
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_table('Sales')
    # ### end Alembic commands ###


import asyncio
import enum
from contextlib import asynccontextmanager

import bleak

from . import protocol
from .events import Event, StartedEvent
from .types import *

async def discover_devices(timeout=1):
    return await bleak.discover(
        timeout=timeout,
        filters={'UUIDs': [protocol.root_identifier_uuid]},
    )

def get_client(device):
    return bleak.BleakClient(device)

def get_characteristics(client):
    uart = client.services.get_service(protocol.uart_service_uuid)
    rx = uart.get_characteristic(protocol.rx_char_uuid)
    assert 'write' in rx.properties
    tx = uart.get_characteristic(protocol.tx_char_uuid)
    assert 'notify' in tx.properties
    return rx, tx

@asynccontextmanager
async def get_driver(device):
    async with get_client(device) as client:
        rx, tx = get_characteristics(client)
        async with Driver(client, rx, tx) as driver:
            yield driver

class Driver:
    def __init__(self, client, rx, tx):
        self.client = client
        self.rx = rx
        self.tx = tx
        self._responses = {}
        self._event_queue = asyncio.Queue()
        self._event_queue.put_nowait(StartedEvent())

    async def __aenter__(self):
        await self.client.start_notify(self.tx, self._notification)
        return self

    async def __aexit__(self, exc_type, exc, tb):
        await self.client.stop_notify(self.tx)

    async def _send(self, cmd, *args, wait_response=True):
        message, hdr = protocol.format_command(cmd, *args)
        if wait_response:
            self._responses[hdr] = waiter = asyncio.Event()
        await self.client.write_gatt_char(self.rx, message)
        if wait_response:
            await waiter.wait()
            return self._responses.pop(hdr)

    def _notification(self, _sender, message):
        name, args, hdr = protocol.extract_event(message)
        waiter = self._responses.pop(hdr, None)

        event = Event.parse(name, *args)
        if waiter is None:
            self._event_queue.put_nowait(event)
        else:
            self._responses[hdr] = event
            waiter.set()

    async def get_events(self, loop=False):
        # + handle disconnection from robot
        q = self._event_queue
        while loop or not q.empty():
            event = await q.get()
            q.task_done()
            if event is None:
                break
            yield event

    async def get_version(self, board: Board):
        version = await self._send('get_version', board.value)
        return version

    async def set_name(self, name: str):
        await self._send('set_name', name.encode(protocol.encoding), wait_response=False)

    async def get_name(self):
        name, = await self._send('get_name')
        return name

    async def cancel(self):
        # + reset waiters to cancel jobs?
        await self._send('cancel', wait_response=False)

    async def disconnect(self):
        await self._send('disconnect', wait_response=False)
        self._event_queue.put_nowait(None)

    async def enable_events(self, devices: Devices):
        bitfield = devices.to_bytes()
        await self._send('enable_events', bitfield, wait_response=False)

    async def disable_events(self, devices: Devices):
        bitfield = devices.to_bytes()
        await self._send('disable_events', bitfield, wait_response=False)

    async def get_enabled_events(self):
        bitfield, = await self._send('get_enabled_events')
        return Devices.from_bytes(bitfield)

    async def get_serial_number(self):
        serial, = await self._send('get_serial_number')
        return serial

    async def get_sku(self):
        sku, = await self._send('get_sku')
        return sku

    async def set_motor_speed(self, left: int, right: int):
        await self._send('set_motor_speed', left, right, wait_response=False)

    async def set_left_motor_speed(self, speed: int):
        await self._send('set_left_motor_speed', speed, wait_response=False)

    async def set_right_motor_speed(self, speed: int):
        await self._send('set_right_motor_speed', speed, wait_response=False)

    async def set_gravity_compensation(self, state: GravityState, amount: int):
        await self._send('set_gravity_compensation', state.value, amount, wait_response=False)

    async def drive_distance(self, dist: int, wait=True):
        await self._send('drive_distance', dist, wait_response=wait)

    async def rotate_angle(self, angle: int, wait=True):
        await self._send('rotate_angle', angle, wait_response=wait)

    async def drive_arc(self, angle: int, radius: int, wait=True):
        await self._send('drive_arc', angle, radius, wait_response=wait)

    async def set_marker_eraser(self, position: MarkerEraserPosition, wait=True):
        ret = await self._send('set_marker_eraser', position.value, wait_response=wait)
        if wait:
            position, = ret
            return MarkerEraserPosition(position)

    async def get_color_data(self, sensor: ColorSensor, lightning: ColorLightning, format: ColorFormat):
        return await self._send('get_color_data', sensor.value, lightning.value, format.value)

    async def set_led_animation(self, anim: LEDAnimation, red: int, green: int, blue: int):
        await self._send('set_led_animation', anim.value, red, green, blue, wait_response=False)

    async def play_note(self, frequency: int, duration: int, wait=True):
        await self._send('play_note', frequency, duration, wait_response=wait)

    async def stop_note(self):
        await self._send('stop_note', wait_response=False)

    async def say_phrase(self, phrase: str, wait=True):
        await self._send('say_phrase', phrase.encode(protocol.encoding), wait_response=wait)

    async def get_battery_level(self):
        _, voltage, rate = await self._send('get_battery_level')
        return voltage, rate


import os
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

plt.rcParams['axes.unicode_minus']=False
plt.rcParams['font.sans-serif']=['SimHei']
plt.style.use('ggplot')

def loadDataByCSV(path):
	data = pd.read_csv(path)
	return data

def  trainData():
	path = 'F:\GitCodeBook\DataCompetiton/train.csv'
	return loadDataByCSV(path)

def  drawData(data):
	#用户动作类型数量统计
	fig = plt.figure(figsize=(10,10))
	fig.set(alpha=0.5)
	plt.subplot2grid((2,2),(0,0))
	data.action_type.value_counts().plot(kind='bar')
	plt.ylabel('action type number')
	plt.xlabel('action type')
	plt.show()


import random
import itertools
from constants import *

class Deck:
    def __init__(self):
        self.cards = []
        self.build()

    def build(self):
        for num in NUMBERS:
            for shape in SHAPES:
                for color in COLORS:
                    for pattern in FILL_PATTERNS:
                        self.cards.append((num, shape, color, pattern))

    def shuffle(self):
        random.shuffle(self.cards)

    def deal(self):
        if len(self.cards) > 0:
            return self.cards.pop()

    def isGameOver(self):
        return len(self.cards) == 39 #10 sets of 3 have been removed from the board, end game early

class Board:
    def __init__(self, deck):
        self.deck = deck
        self.cards = [self.deck.deal() for i in range(12)]
        self.card_img = []
        self.points = 0
        self.display_cards()
        self.index_subsets = [i for i in itertools.combinations({j for j in range(12)}, 3)]

    def add_3_cards(self, card1, card2, card3):
        self.cards.append(card1)
        self.cards.append(card2)
        self.cards.append(card3)

    def check_if_set(self, card1, card2, card3):
        #check if 3 cards are a set
        if (card1[0] == card2[0] and card2[0] == card3[0]) or (card1[0] != card2[0] and card2[0] != card3[0] and card1[0] != card3[0]):
            if (card1[1] == card2[1] and card2[1] == card3[1]) or (card1[1] != card2[1] and card2[1] != card3[1] and card1[1] != card3[1]):
                if (card1[2] == card2[2] and card2[2] == card3[2]) or (card1[2] != card2[2] and card2[2] != card3[2] and card1[2] != card3[2]):
                    if (card1[3] == card2[3] and card2[3] == card3[3]) or (card1[3] != card2[3] and card2[3] != card3[3] and card1[3] != card3[3]):
                        return True
        return False

    def check_if_no_set(self):
      l = len(self.cards)
      for subset in self.index_subsets:
        if self.check_if_set(self.cards[subset[0]],self.cards[subset[1]],self.cards[subset[2]]):
          self.points -= 1
          return True

      self.points += 5
      self.remove_3_cards(self.cards[l-1], self.cards[l-2], self.cards[l-3])
      self.add_3_cards(self.deck.deal(), self.deck.deal(), self.deck.deal())
      self.display_cards()
      return not self.deck.isGameOver()

    def play_round(self, card1, card2, card3):
        if self.check_if_set(card1, card2, card3):
            self.points += 5
            self.remove_3_cards(card1, card2, card3)
            self.add_3_cards(self.deck.deal(), self.deck.deal(), self.deck.deal())
            self.display_cards()
        else:
          self.points -= 1

        return not self.deck.isGameOver()

    def remove_3_cards(self, card1, card2, card3):
        self.cards.remove(card1)
        self.cards.remove(card2)
        self.cards.remove(card3)

    def display_cards(self):
        self.card_img = []
        for card in self.cards:
            cards = card[0] + "_" + card[1] + "_" + card[2] + "_" + card[3] + ".png"
            self.card_img.append(cards)

    def addPoint(self):
      self.points += 1

    def removePoint(self):
      self.points -= 1


# This is code to switch which rclone config section to use. This setting affects the entire bot(And at this time, the cloneHelper only support gdrive, so you should only choose to use gdrive config section)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# (c) xiaoqi-beta | gautamajay52

import logging
import os
import re
from configparser import ConfigParser

import pyrogram.types as pyrogram
from pyrogram.types import CallbackQuery
from tobrot import LOGGER, OWNER_ID

async def rclone_command_f(client, message):
    """/rclone command"""
    LOGGER.info(
        f"rclone command from chatid:{message.chat.id}, userid:{message.from_user.id}"
    )
    if message.from_user.id == OWNER_ID and message.chat.type == "private":
        config = ConfigParser()
        config.read("rclone_bak.conf")
        sections = list(config.sections())
        inline_keyboard = []
        for section in sections:
            ikeyboard = [
                pyrogram.InlineKeyboardButton(
                    section, callback_data=(f"rclone_{section}").encode("UTF-8")
                )
            ]
            inline_keyboard.append(ikeyboard)
        config = ConfigParser()
        config.read("rclone.conf")
        section = config.sections()[0]
        msg_text = f"""Default section of rclone config is: **{section}**\n\n
There are {len(sections)} sections in your rclone.conf file,
please choose which section you want to use:"""
        ikeyboard = [
            pyrogram.InlineKeyboardButton(
                "‼ Cancel ‼", callback_data=(f"rcloneCancel").encode("UTF-8")
            )
        ]
        inline_keyboard.append(ikeyboard)
        reply_markup = pyrogram.InlineKeyboardMarkup(inline_keyboard)
        await message.reply_text(text=msg_text, reply_markup=reply_markup)
    else:
        await message.reply_text("You have no permission!")
        LOGGER.warning(
            f"uid={message.from_user.id} have no permission to edit rclone config!"
        )

async def rclone_button_callback(bot, update: CallbackQuery):
    """rclone button callback"""
    if update.data == "rcloneCancel":
        config = ConfigParser()
        config.read("rclone.conf")
        section = config.sections()[0]
        await update.message.edit_text(
            f"Opration canceled! \n\nThe default section of rclone config is: **{section}**"
        )
        LOGGER.info(
            f"Opration canceled! The default section of rclone config is: {section}"
        )
    else:
        section = update.data.split("_", maxsplit=1)[1]
        with open("rclone.conf", "w", newline="\n", encoding="utf-8") as f:
            config = ConfigParser()
            config.read("rclone_bak.conf")
            temp = ConfigParser()
            temp[section] = config[section]
            temp.write(f)
        await update.message.edit_text(
            f"Default rclone config changed to **{section}**"
        )
        LOGGER.info(f"Default rclone config changed to {section}")


from zope.i18nmessageid import MessageFactory
from zope.interface import implementer
from icc.cellula.interfaces import ISingletonTask
from icc.cellula.workers import Task
from isu.enterprise.interfaces import IConfigurator
from zope.component import getUtility
from icc.cellula.interfaces import IRTMetadataIndex, IWorker
from icc.cellula import default_storage
import pprint
from pymarc import rusmarcxml
from marcds.importer.issuerecog import DJVUtoMARC
import logging
import tempfile
from . import MIME_TYPE
from icc.cellula.tasks import DocumentTask
from icc.contentstorage import hexdigest

logger = logging.getLogger('icc.cellula')

_ = _N = MessageFactory("icc.cellula")

@implementer(ISingletonTask)
class IssueDataTask(Task):

    def run(self):
        logger.info("Ran {}".format(self.__class__))
        metadata = getUtility(IRTMetadataIndex, "elastic")
        docs = metadata.query(variant="noisbn", count=1000)
        logger.debug("Found {} documents".format(docs.count))
        if docs.count == 0:
            logger.debug("No document for processing.")
            return
        storage = default_storage()
        queue_thread = getUtility(IWorker, name="queue")
        for doc in docs:
            logger.debug(doc["File-Name"])
            logger.debug(doc["mimetype"])
            id = doc["id"]
            content = storage.get(doc["id"])
            if isinstance(content, (str, bytes)):
                logger.debug("Content length: {}".format(len(content)))
                tmp = tempfile.NamedTemporaryFile(dir=queue_thread.tmpdir)
                tmp.write(content)
                tmp.flush()
            else:
                raise NotImplementedError("type is not supported")
            r = DJVUtoMARC(tmp.name)
            data = r.issue_data(noexc=True)
            if data is not None:
                logger.debug("Got some data ISBN {}".format(r.isbn))
                logger.debug("Lines: {}".format(r.lines))
            else:
                logger.debug("No data found.")
                continue
            # query isbn with isbnlib
            if r.isbn:
                rc = r.query_with_isbn(services=("wcat", "goob", "openl"))
            else:
                continue
            if rc:
                doc["isbn"] = r.isbn
            else:
                continue
            for k, fs in rc.items():
                if fs is None:
                    continue
                for fk, fv in fs.items():
                    fk = fk.lower()
                    doc[fk] = fv
                    logger.debug("{} = {}".format(fk, fv))
            metadata.put(doc, id)

            logger.debug(pprint.pformat(doc))
            logger.info(
                "Book {title} filename: {File-Name} stored!".format(doc))

class MARCStreamImportTask(Task):
    def __init__(self, stream, features=None,
                 *args, **kwargs):
        # FIXME: refactor headers -> features
        super(MARCStreamImportTask, self).__init__(*args, **kwargs)
        if features is None:
            features = {}
        features["mimetype"] = MIME_TYPE
        self.stream = stream
        self.features = features

    def run(self):
        self.records = rusmarcxml.parse_xml_to_array(self.stream)

    def finalize(self):
        if self.records:
            conf = getUtility(IConfigurator, "configuration")
            size = conf["marc"].getint("bunch_size", 10)
            MARCRecordsImportTask(records=self.records,
                                  count=size,
                                  features=self.features
                                  ).enqueue()

class MARCRecordsImportTask(Task):
    delay = 5

    def __init__(self, records, count, features):
        super(MARCRecordsImportTask, self).__init__()
        self.records = records
        self.count = count
        self.features = features
        self.processed = []

    def run(self):
        # process
        count = self.count
        if count == 0:
            raise ValueError("zero-sized bunch")
        while True:
            if count <= 0:
                break
            if not self.records:
                break

            rec = self.records.pop()
            # processing
            logger.debug("Processing record: {}".format(str(rec)))
            # logger.debug("As marc: {}".format(rec.as_marc()))
            rec.force_utf8 = True
            content = rec.as_marc()
            d = rec.as_dict()
            self.processed.append((content, d))
            count -= 1

    def finalize(self):
        if len(self.processed) < self.count:
            # Something bad happened or all the records already processed
            logger.debug("No more processing possible.")
        else:
            MARCRecordsImportTask(records=self.records,
                                  count=self.count,
                                  features=self.features).enqueue()
        if self.processed:
            MARCContentStoreTask(content=self.processed,
                                 headers=self.features).enqueue()

class MARCContentStoreTask(DocumentTask):
    def run(self):
        storage = default_storage()
        for rec in self.content:
            fs = rec[1]
            marc = rec[0]
            key = storage.put(marc)
            hkey = hexdigest(key)
            logger.debug("MARC storage: put MARC for key: {}".format(hkey))
            fs["id"] = hkey
            fs.update(self.headers)
            mrc = storage.get(key)
            assert mrc == marc

    def finalize(self):
        if self.content:
            MARCContentIndexTask(content=self.content,
                                 headers=self.headers).enqueue()

class MARCContentIndexTask(DocumentTask):
    def run(self):
        indexer = getUtility(IRTMetadataIndex, "marc")
        for rec in self.content:
            d = rec[1]
            id = d["id"]
            # logger.debug("Reord to be saved: {}".format(d))
            indexer.put(d, id)
            logger.debug("MARC index: put MARC for id: {}".format(id))


from datetime import datetime
from Cheetah.Template import Template
from action_mail_sender import send_mail
import pycron
import requests

resp_action_mail = requests.get('http://127.0.0.1:8000/api/mail/actions/').json()

for objects in range(len(resp_action_mail)):

    if resp_action_mail[objects]['is_enabled']:

        q_input = resp_action_mail[objects]['input']
        cron = resp_action_mail[objects]['cron']
        template_mail = resp_action_mail[objects]['template_mail']
        last_run = resp_action_mail[objects]['last_run']

        last_run = datetime.strptime(last_run, '%Y-%m-%dT%H:%M:%SZ')

        if pycron.is_now(cron, last_run):
            resp = requests.get(f'http://127.0.0.1:8000/api/elastic?query={q_input}').json()
            if bool(resp):
                HTML_BODY = str(Template(template_mail, {'response': resp}))
                #print(HTML_BODY)
                send_mail(HTML_BODY)
            else:
                print("NOT RUN, dict empty")
        else:
            print("NOT RUN, cron not true")
    else:
        print("Alert not enabled!")
        break


from datetime import datetime, timedelta, timezone

import pytest

from gyazo.image import Image, ImageList

image_1_dict = {
    'url': 'https://i.gyazo.com/2c9044330d710fca3da64b222eddf5b5.png',
    'type': 'png',
    'created_at': '2014-07-25T08:29:51+0000',
    'image_id': '2c9044330d710fca3da64b222eddf5b5',
    'thumb_url': 'https://i.gyazo.com/thumb/180/_242799a7d541869e0b73dc93ee113fb5.png',
    'permalink_url': 'http://gyazo.com/2c9044330d710fca3da64b222eddf5b5',
}
image_1 = Image(
    url='https://i.gyazo.com/2c9044330d710fca3da64b222eddf5b5.png',
    type='png',
    created_at=datetime(2014, 7, 25, 8, 29, 51, tzinfo=timezone.utc),
    image_id='2c9044330d710fca3da64b222eddf5b5',
    thumb_url='https://i.gyazo.com/thumb/180/_242799a7d541869e0b73dc93ee113fb5.png',
    permalink_url='http://gyazo.com/2c9044330d710fca3da64b222eddf5b5',
)
image_2_dict = {
    'type': 'png',
    'created_at': '2014-06-21T13:45:46+0900',
    'thumb_url': 'https://thumb.gyazo.com/thumb/200/Qa1W1MKHxBhbk-png.jpg',
}
image_2 = Image(
    type='png',
    created_at=datetime(2014, 6, 21, 13, 45, 46, tzinfo=timezone(timedelta(hours=9))),
    thumb_url='https://thumb.gyazo.com/thumb/200/Qa1W1MKHxBhbk-png.jpg',
)
image_2_dict_empty_str = {
    'url': '',
    'type': 'png',
    'created_at': '2014-06-21T13:45:46+0900',
    'image_id': '',
    'thumb_url': 'https://thumb.gyazo.com/thumb/200/Qa1W1MKHxBhbk-png.jpg',
    'permalink_url': ''
}
image_2_empty_str = Image(
    url='',
    type='png',
    created_at=datetime(2014, 6, 21, 13, 45, 46, tzinfo=timezone(timedelta(hours=9))),
    image_id='',
    thumb_url='https://thumb.gyazo.com/thumb/200/Qa1W1MKHxBhbk-png.jpg',
    permalink_url='',
)
image_3_partial = Image(
    url='',
    type='png',
    created_at=datetime(2014, 7, 20, 3, 9, 34, tzinfo=timezone.utc),
    image_id='',
    thumb_url='https://i.gyazo.com/thumb/180/_eadaaad52408b1e53c09111d6959139f.png',
    permalink_url='',
)
image_3 = Image(
    url='https://i.gyazo.com/9d04d2da1b4daaaa234c68b5219dc1e3.png',
    type='png',
    created_at=datetime(2014, 7, 20, 3, 9, 34, tzinfo=timezone.utc),
    image_id='9d04d2da1b4daaaa234c68b5219dc1e3',
    thumb_url='https://i.gyazo.com/thumb/180/_eadaaad52408b1e53c09111d6959139f.png',
    permalink_url='http://gyazo.com/9d04d2da1b4daaaa234c68b5219dc1e3'
)
image_4 = Image(
    image_id='14aa1dedcbafaa069943c3cf0631d5e5',
    type='png',
    created_at=datetime(2020, 2, 1, 13, 31, 37, 197000, tzinfo=timezone.utc),
    ocr={
        'locale': 'ja',
        'description': 'OCRの結果が\n入ってる',
    },
)
image_4_with_url = Image(
    url='https://i.gyazo.com/14aa1dedcbafaa069943c3cf0631d5e5.png',
    image_id='14aa1dedcbafaa069943c3cf0631d5e5',
    type='png',
    created_at=datetime(2020, 2, 1, 13, 31, 37, 197000, tzinfo=timezone.utc),
)
image_4_merged = Image(
    url='https://i.gyazo.com/14aa1dedcbafaa069943c3cf0631d5e5.png',
    image_id='14aa1dedcbafaa069943c3cf0631d5e5',
    type='png',
    created_at=datetime(2020, 2, 1, 13, 31, 37, 197000, tzinfo=timezone.utc),
    ocr={
        'locale': 'ja',
        'description': 'OCRの結果が\n入ってる',
    },
)
image_4_dict = {
    'image_id': '14aa1dedcbafaa069943c3cf0631d5e5',
    'type': 'png',
    'created_at': '2020-02-01T13:31:37+0000',
    'ocr': {
        'locale': 'ja',
        'description': 'OCRの結果が\n入ってる',
    }
}
image_4_dict_with_none = {
    'image_id': '14aa1dedcbafaa069943c3cf0631d5e5',
    'permalink_url': None,
    'thumb_url': None,
    'type': 'png',
    'created_at': '2020-02-01T13:31:37.197+0000',
    'comments': [],
    'ocr': {
        'locale': 'ja',
        'description': 'OCRの結果が\n入ってる',
    }
}

test_data_from_dict = [
    (image_1_dict, image_1),
    (image_2_dict, image_2),
    (image_2_dict_empty_str, image_2),
    (image_4_dict_with_none, image_4),
]

test_data_to_dict = [
    (image_1, image_1_dict),
    (image_2, image_2_dict),
    (image_2_empty_str, image_2_dict),
    (image_4, image_4_dict)
]

test_data_to_json = [
    (
        image_1,
        '{"created_at": "2014-07-25T08:29:51+0000", '
        '"image_id": "2c9044330d710fca3da64b222eddf5b5", '
        '"permalink_url": "http://gyazo.com/2c9044330d710fca3da64b222eddf5b5", '
        '"thumb_url": "https://i.gyazo.com/thumb/180/'
        '_242799a7d541869e0b73dc93ee113fb5.png", "type": "png", '
        '"url": "https://i.gyazo.com/2c9044330d710fca3da64b222eddf5b5.png"}'
    ),
]

test_data_filenames = [
    (
        image_1,
        '2c9044330d710fca3da64b222eddf5b5.png',
        '_242799a7d541869e0b73dc93ee113fb5.png',
    ),
    (
        image_2,
        None,
        'Qa1W1MKHxBhbk-png.jpg',
    ),
    (
        image_2_empty_str,
        None,
        'Qa1W1MKHxBhbk-png.jpg',
    ),
]

test_data_or = [
    (image_3_partial, image_3, image_3),
    (image_3, image_3_partial, image_3),
    (image_4, image_4_with_url, image_4_merged),
]

class TestImage:
    @pytest.mark.parametrize("d,image", test_data_from_dict)
    def test_from_dict(self, d, image):
        assert Image.from_dict(d) == image

    @pytest.mark.parametrize("image,filename,thumb_filename", test_data_filenames)
    def test_filenames(self, image, filename, thumb_filename):
        assert image.filename == filename
        assert image.thumb_filename == thumb_filename

    @pytest.mark.parametrize("image,expected", test_data_to_dict)
    def test_to_dict(self, image, expected):
        assert image.to_dict() == expected

    @pytest.mark.parametrize("image,expected", test_data_to_json)
    def test_to_json(self, image, expected):
        assert image.to_json() == expected

    @pytest.mark.parametrize("a,b,expected", test_data_or)
    def test_or(self, a, b, expected):
        assert a | b == expected

class TestImageList:
    def test_from_list(self):
        l = ImageList.from_list([image_1_dict, image_2_dict, image_2_dict_empty_str])
        assert l.images == [image_1, image_2, image_2]

    @pytest.mark.parametrize("image_list,expected", [
        (ImageList(total_count=23, per_page=10, current_page=0), False),
        (ImageList(total_count=23, per_page=10, current_page=3), False),
        (ImageList(total_count=20, per_page=10, current_page=1), True),
        (ImageList(total_count=20, per_page=10), None),
        (ImageList(total_count=20, current_page=3), None),
        (ImageList(per_page=10, current_page=3), None),
    ])
    def test_has_next_page(self, image_list, expected):
        assert image_list.has_next_page == expected

    @pytest.mark.parametrize("image_list,expected", [
        (ImageList(current_page=2), True),
        (ImageList(current_page=1), False),
        (ImageList(), None),
    ])
    def test_has_previous_page(self, image_list, expected):
        assert image_list.has_previous_page == expected

    def test_add(self):
        l1 = ImageList(images=[image_1, image_2])
        l2 = ImageList(images=[image_3])
        l = l1 + l2
        assert l.total_count == 3
        assert len(l.images) == 3
        assert l.current_page is None
        assert l.per_page is None
        assert l.user_type is None

    def test_set_attributes_from_headers(self):
        headers = {
            'server': 'nginx/1.11.9',
            'date': 'Sat, 01 Feb 2020 16:43:58 GMT',
            'content-type': 'application/json; charset=utf-8',
            'x-total-count': '1144',
            'x-current-page': '1',
            'x-per-page': '20',
            'x-user-type': 'ninja',
        }
        il = ImageList()
        il.set_attributes_from_headers(headers)
        assert il.total_count == 1144
        assert il.current_page == 1
        assert il.per_page == 20
        assert il.user_type == 'ninja'


from flask import Blueprint, render_template
import feedparser

from dotenv import load_dotenv

# from models.Video import Video

video_bp = Blueprint('videos', __name__, url_prefix='/videos')

load_dotenv()

@video_bp.route('/', methods=['GET'])
def index(dr_name:str):
    video_feed = ['oops wrong url']
    if dr_name == 'Howard':
        video_feed = feedparser.parse('https://www.youtube.com/feeds/videos.xml?channel_id=UCT0_JeyTysWfMp25xcJthMg')

    return render_template('videos.html', feed=video_feed)

# @video_bp.route('/<id>', methods=['GET', 'POST', 'DELETE'])
# def show_video():
#     if request.method == 'GET':
#         return render_template('videos/show.html')

#     elif request.method == 'POST':
#         pass

#     elif request.method == 'DELETE':
#         pass


from urllib import request,parse
import json

'''
目标：对百度翻译页面发送post请求，获得翻译的结果
0、form表单提交的数据，首先需要parse.urlencode()转码，转换成unicode编码格式的字符串，然后装换成utf-8的bytes格式编码
2、如果请求对象里面有data属性，则为发送post请求的请求
'''

# 翻译函数：
def fanyi(kw):

    base_url = 'http://fanyi.baidu.com/sug'

    # 1、 form表单数据准备
    form_data = {
        'kw':kw
    } # 构造请求的表单数据（post请求发送的东西）
    form_data = parse.urlencode(form_data) # 对表单数据进行Unicode编码

    # 构建请求对象
    req = request.Request(base_url,data=bytes(form_data,encoding='utf-8'))

    # 发送请求
    response = request.urlopen(req)

    data = response.read()

    data = json.loads(data)
    for i in data['data']:
        print('\t'+i['v'])

if  __name__=="__main__":
    print('输入"q"退出程序')
    while True:
        kw = input('请输入：')
        if kw == 'q':
            break
        else:
            fanyi(kw)


# -*- coding: utf-8 -*-
import json
import logging.config
import subprocess

from AddressInputer import HttpAddressInputer
from Util import Util

class PacBot:
    __adressInputer = None
    __directIps = set()
    __proxyIps = set()
    __noWayIps = set()
    proxyServers = list()

    def __init__(self):
        return

    def run(self):
        while (self.__adressInputer.hasNext()):

            address = self.__adressInputer.next()

            if (len(address) != 2):
                logging.error("invalid address: {0}".format(address))
                continue

            ip, port = address

            if (self.__directIps.__contains__(ip)):
                continue

            if (self.__proxyIps.__contains__(ip)):
                continue

            if (self.__noWayIps.__contains__(ip)):
                continue

            if (Util.tcpIsOk(address)):
                self.__directIps.add(ip)
                continue

            proxyServer = self.__matchProxyServer(address)
            if (proxyServer):
                self.addToOSPAC(address, proxyServer)
                self.__proxyIps.add(ip)
                logging.info("redirect {0}".format(ip))
            else:
                self.__noWayIps.add(ip)
                logging.warn("no way to address: {0}".format(ip))

    def __matchProxyServer(self, address):

        for proxyServer in self.proxyServers:
            if (Util.tcpIsOkByPorxy(address, proxyServer)):
                return proxyServer

        return None

    def addToOSPAC(self, address, proxyServer):

        file = open("clean.sh", "a+")

        try:
            cmd = "iptables -t nat -I PREROUTING -p TCP -d {0} -j DNAT --to {1}:{2}".format(address[0],
                                                                                proxyServer.get(
                                                                                'transparent_addr'),
                                                                                proxyServer.get(
                                                                                'transparent_port'))
            logging.debug("call '{0}'".format(cmd))
            file.write(cmd.replace("-I", "-D") + "\n")
            subprocess.call(cmd, shell=True)

        finally:
            file.close()

    def config(self, config_json_file):

        jsonfile = open(config_json_file)
        json_config = json.load(jsonfile)

        for proxyServer in json_config["proxyServers"]:
            self.proxyServers.append(proxyServer)

        inputer_config = json_config["inputer"]
        self.__adressInputer = HttpAddressInputer((inputer_config["addr"], inputer_config["port"]))

        jsonfile.close()

if __name__ == '__main__':
    logging.config.fileConfig('logging.conf')

    bot = PacBot()

    bot.config("config.json")

    bot.run()


from bibliopixel.animation.matrix import Matrix
from noise import pnoise3, snoise3

class PerlinSimplex(Matrix):

    def __init__(self, layout, freq=16, octaves=1, type=True, **kwds):
        super().__init__(layout, **kwds)
        self._step = 1
        self._freq = float(freq)
        self._octaves = octaves
        if type:
            self.func = snoise3
        else:
            self.func = pnoise3

    def step(self, amt):
        for y in range(self.height):
            for x in range(self.width):
                v = int(self.func(x / self._freq, y / self._freq, self._step / self._freq, octaves=self._octaves) * 127.0 + 128.0)
                c = self.palette(v)
                self.layout.set(x, y, c)

        self._step += amt


import numpy as np
import argparse
import os
from rdkit import Chem
from rdkit.Chem import AllChem
from rdkit.Chem import DataStructs

def create_parser():
    parser = argparse.ArgumentParser()
    parser.add_argument('input', type=str, help='finename of sdf')
    parser.add_argument('--fptype', type=str, help='ECFP, FCFP, ', default='ECFP')
    parser.add_argument('--radius', type=int, help='radius of ECFP, FCFP ', default=2)
    parser.add_argument('--nBits', type=int, help='number of bits ', default=1024)
    parser.add_argument('--molid', type=str, help='molid prop', default=None)
    parser.add_argument('--target', type=str, help='target name for predict', default=None)
    parser.add_argument('--output', type=str, help='output path', default='data')
    return parser

def fp2list(fp):
    arr = np.zeros((0,))
    DataStructs.ConvertToNumpyArray(fp, arr)
    return arr

def mol2fp(mol, fptype='ECFP', radius=2, nBits=1024):
    if fptype=='ECFP':
        fp = AllChem.GetMorganFingerprintAsBitVect(mol, radius=radius, nBits=nBits)
    elif fptype=='FCFP':
        fp = AllChem.GetMorganFingerprintAsBitVect(mol, radius=radius, nBits=nBits, useFeatures=True)
    else:
        raise NotImplementedError('This FP is not implemented!!!! pls use ECFP or FCFP')
    return fp

if __name__=='__main__':
    parser = create_parser()
    args = parser.parse_args()
    mols = Chem.SDMolSupplier(args.input)
    fps = []
    targets = []
    if not os.path.isdir(args.output):
        os.mkdir(args.output)

    w = open(os.path.join(args.output,'log.txt'), 'w')
    w.write('mol_id,smiles\n')
    for i, mol in enumerate(mols):
        if mol is not None:
            smiles = Chem.MolToSmiles(mol)
            if args.molid is not None:
                mol_id =mol.GetProp(args.molid)
            else:
                idx = 1+i
                mol_id = f'mol_{idx}'
            fp = mol2fp(mol,args.fptype, args.radius, args.nBits)
            fp_list = fp2list(fp)
            fps.append(fp_list)
            w.write(f'{mol_id},{smiles}\n')
            if args.target is not None:
                target = mol.GetProp(args.target)
                targets.append(np.float(target))
    w.close()
    X = np.asarray(fps)
    X = np.savez(f'{args.output}/{args.fptype}_{args.radius}_{args.nBits}_X.npz', X)
    if args.target is not None:
        Y = np.asarray(targets)
        np.savez(f'{args.output}/{args.target}_arr.npz', Y)
    else:
        pass


from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
import time
from auth_data import ok_email, ok_password
import pickle
import datetime

options = webdriver.ChromeOptions()

options.add_argument("--disable-blink-features=AutomationControlled")

driver = webdriver.Chrome(options=options)

try:

    start_time = datetime.datetime.now()

    driver.get("https://www.avito.ru/all?q=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE%D0%BA%D0%B0%D1%80%D1%82%D1%8B")
    driver.implicitly_wait(5)
    for i in range(0, 3):
        items = driver. find_elements(By.XPATH, "//div[@data-marker='item-photo']")
        items[i].click()
        driver.implicitly_wait(5)

        driver.switch_to.window(driver.window_handles[1])
        driver.implicitly_wait(5)

        username = driver.find_element(By.XPATH, "//div[@data-marker='seller-info/name']")
        print(f"User name: {username.text}")
        driver.implicitly_wait(5)

        driver.close()

        driver.switch_to.window(driver.window_handles[0])

    finish_time = datetime.datetime.now()
    spent_time = finish_time-start_time
    print(spent_time)

except Exception as ex:
    print(ex)
finally:
    driver.close()
    driver.quit()


from pprint import pprint

from sqlalchemy import create_engine, Table, MetaData
from sqlalchemy.sql import select

engine = create_engine("mysql://root@localhost/clanwars?use_unicode=0")
conn = engine.connect()
metadata = MetaData()
tanks = Table('wot_tanks_all_api2', metadata, autoload=True, autoload_with=engine)
tank_dict = {}
for row in list(conn.execute(select([tanks]))):
    tank_dict[row.tank_text_id] = {
        'tier': row.level
    }

pprint(tank_dict)


"""
Package for GPS module.
"""

import serial
from time import time

from geographic_position import *

class GPS():
    """
    Class for reading the geographic position from a GPS module.
    """
    def __init__(self):
        """
        Sets the type of sentence that will be read from GPS to GPGGA and the serial port for the GPS.
        GPGGA stands for Global Positioning System Fix Data. An example sentence is $GPGGA,134658.00,5106.9792,N,
        11402.3003,W,2,09,1.0,1048.47,M,-16.27,M,08,AAAA*60" where $GPGGA is a sentence identifier, 134658.00 is time
        (13:46:58 and 00 miliseconds), 5106.9792 is latitude (51 degrees and 06.9792 minutes), N is latitude direction
        (N = North), 11402.3003 is longitude (114 degrees and 02.3003 minutes) and W is longitude direction.
        """
        self._sentence_identifier = "$GPGGA,"
        self._serial_port = serial.Serial("/dev/ttyAMA0")

    def _read_GPS_information(self):
        """
        Reads a geographic position from the GPS module in the NMEA (National Marine Electronics Association) format.
        """
        # continue reading the GPS sentences until a sentence with `self._sentence_identifier` is found.
        while True:
            # read one sentence from the GPS module
            data_from_module = (str)(self._serial_port.readline())
            # the first 7 characters of the sentence contain the sentence identifier.
            if data_from_module[0:7] == self._sentence_identifier:
                gpgga_buffer = data_from_module.split(self._sentence_identifier, 1)[1]
                nmea_buffer = (gpgga_buffer.split(','))
                self._nmea_time = nmea_buffer[0]
                self._nmea_latitude = nmea_buffer[1]
                self.latitude_direction = nmea_buffer[2]
                self._nmea_longitude = nmea_buffer[3]
                self.longitude_direction = nmea_buffer[4]
                break

    def get_geographic_position(self):
        """
        Reads GPS position in the NMEA format and converts the position to `GeographicPosition` object.
        :return:
        """
        self._read_GPS_information()
        self.latitude_degrees = self.convert_nmea_to_degrees(self._nmea_latitude)
        self.longitude_degrees = self.convert_nmea_to_degrees(self._nmea_longitude)
        self.time = self.convert_nmea_to_time(self._nmea_time[0:6])
        self.position = GeographicPosition(self.latitude_degrees, self.latitude_direction, self.longitude_degrees,
                                           self.longitude_direction, self.time)
        return self.position

    @staticmethod
    def convert_nmea_to_degrees(nmea_value):
        """
        Converts NMEA position format to degrees.
        The NMEA position format is DDmm.mm for latitude and DDDmm.mm for longitude. DD or DDD stands for degrees and
        mm.mm stands for minutes
        :param nmea_value: string representing a position in the NMEA format
        :return: float representing the converted values of the NMEA string in degrees
        """
        # verify that `nmea_value` is either string that is convertible to float number or empty string
        assert(nmea_value == "" or nmea_value.replace('.','',1).isdigit())
        try:
            nmea_value = float(nmea_value)
        except ValueError:
            nmea_value = 0
        degrees = int(nmea_value / 100.00)
        minutes = (nmea_value - degrees * 100)
        coordinate_in_degrees = degrees + minutes / 60
        coordinate_in_degrees = round(coordinate_in_degrees, 6)
        assert(coordinate_in_degrees >= 0 and coordinate_in_degrees <= 180)
        return coordinate_in_degrees

    @staticmethod
    def convert_nmea_to_time(nmea_time):
        """
        Converts NMEA time format to `time` object.
        The NMEA time format is HHMMSS.SS where HH is hours, MM is minutes, SS.SS is seconds
        :param nmea_time: String representing a time in the NMEA format
        :return: `time` object that represents the time when the position was taken
        """
        assert(len(nmea_time) == 6)
        assert(isinstance(nmea_time, str) and nmea_time.isdigit())
        hours = int(nmea_time[0:2])
        minutes = int(nmea_time[2:4])
        seconds = int(nmea_time[4:6])
        return time(hours, minutes, seconds)

if __name__ == "__main__":
    myGPS = GPS()
    current_position = myGPS.get_geographic_position()
    print("Coordinates: ", current_position.get_coordinates())
    print("Time: ", current_position.get_time())


"""
compatability module for IPython subprocesses to close cleanly and pass handlers
to the next handlers.

See: http://stackoverflow.com/a/15472811 for more details
"""
from future import standard_library
standard_library.install_aliases()
import os
import imp
import ctypes
import _thread
import win32api
import sys

# Load the DLL manually to ensure its handler gets
# set before our handler.
basepath = imp.find_module('numpy')[1]
numpy_libmmd = os.path.join(basepath, 'core', 'libmmd.dll')
numpy_libifcoremd = os.path.join(basepath, 'core', 'libifcoremd.dll')
if os.path.exists(numpy_libmmd) and os.path.exists(numpy_libifcoremd):
    ctypes.CDLL(numpy_libmmd)
    ctypes.CDLL(numpy_libifcoremd)
else:
    import sys
    basepath = os.path.dirname(sys.executable)

    numpy_libmmd = os.path.join(basepath, 'Library/bin', 'libmmd.dll')
    numpy_libifcoremd = os.path.join(basepath, 'Library/bin', 'libifcoremd.dll')

    ctypes.CDLL(numpy_libmmd)
    ctypes.CDLL(numpy_libifcoremd)

# Now set our handler for CTRL_C_EVENT. Other control event
# types will chain to the next handler.
def handler(dwCtrlType, hook_sigint=_thread.interrupt_main):
    if dwCtrlType == 0:  # CTRL_C_EVENT
        hook_sigint()
        return 1         # chain to the next handler
    return 0             # chain to the next handler

win32api.SetConsoleCtrlHandler(handler, 1)


from typing import Optional

import pytorch_lightning as pl
from torch.utils.data import DataLoader

from src.dataset.acapella_dataset import AcapellaDataset

class AcapellaDataModule(pl.LightningDataModule):
    """
    DataModule for Acapella dataset (https://ipcv.github.io/Acappella/acappella/).

    Args:
        root_dir (str): Path to the root directory.
        batch_size (int): Batch size.
        num_workers (int): Number of workers for the data loader.
        sample_length (int, optional): Length of the sequence to be sampled. Defaults to 10 seconds.
    """

    def __init__(
            self,
            root_dir: str,
            batch_size: int,
            num_workers: int,
            sample_length: Optional[int] = 44100 * 10,
            shuffle_train: bool = True,
            train_aug_shift: bool = True,
            pin_memory: bool = False,
    ):
        super().__init__()

        self.sample_rate = 44100

        self.root_dir = root_dir
        self.batch_size = batch_size
        self.num_workers = num_workers
        self.sample_length = sample_length
        self.shuffle_train = shuffle_train
        self.train_aug_shift = train_aug_shift
        self.pin_memory = pin_memory

        self.train_dataset = None
        self.val_dataset = None
        self.test_dataset = None

    def setup(self, stage=None):
        self.train_dataset = AcapellaDataset(self.root_dir, split="train", sample_length=self.sample_length, aug_shift=self.train_aug_shift, initial_shuffle=True)
        self.val_dataset = AcapellaDataset(self.root_dir, split="validation", sample_length=self.sample_length, initial_shuffle=True)
        self.test_dataset = AcapellaDataset(self.root_dir, split="test", sample_length=self.sample_length)

    def train_dataloader(self):
        return DataLoader(self.train_dataset, batch_size=self.batch_size, shuffle=self.shuffle_train,
                          num_workers=self.num_workers, pin_memory=self.pin_memory)

    def val_dataloader(self):
        return DataLoader(self.val_dataset, batch_size=self.batch_size, shuffle=False,
                          num_workers=self.num_workers, pin_memory=self.pin_memory)

    def test_dataloader(self):
        return DataLoader(self.test_dataset, batch_size=self.batch_size, shuffle=True,
                          num_workers=self.num_workers, pin_memory=self.pin_memory)


import tkinter as tk
from point import *
from PIL import Image, ImageTk
from funcs import *
import time
from datetime import datetime
from math import sin, cos, pi

mas = []
lines = []
IMGSIZEX = 600
IMGSIZEY = IMGSIZEX
isLocked = True
localFirstPoint = []
newFigureLen = 0
tmp = None
zPixelPoint = ()
lineFlag = False
lineExistPoint = False
figureFlag = False

'''
whiteColor = Color(255, 255, 255)
redColor = Color(255, 0, 0)
blackColor = Color(1, 1, 1)
greenColor = Color(0, 255, 0)
blueColor = Color(0, 0, 255)
purpleColor = Color(166, 0, 255)
yellowColor = Color(247, 255, 0)
'''
whiteColor = "white"
redColor = "red"
blackColor = "black"
greenColor = "green"
blueColor = "blue"
purpleColor = "purple"
yellowColor = "yellow"

def colorRecognizer():
    color = typeDrawing.get()
    if color == "Синий":
        return blueColor
    elif color == "Красный":
        return redColor
    elif color == "Зеленый":
        return greenColor
    elif color == "Фиолетовый":
        return purpleColor
    elif color == "Жёлтый":
        return yellowColor
    else:
        return blackColor

def clearCanvasField():
    global mas, img, image_tk, isLocked
    canvasField.delete("all")
    mas.clear()
    img = Image.new('RGB', (IMGSIZEX, IMGSIZEY), "white")
    image_tk = ImageTk.PhotoImage(img)
    canvasField.create_image(img.size[0] // 2, img.size[1] // 2, image=image_tk)
    isLocked = True

def mouseClick(event):
    global isLocked, localFirstPoint, mas, newFigureLen, lineFlag,\
        zPixelPoint, figureFlag, lineExistPoint, lines, tmp
    color = colorRecognizer()
    x, y = int(event.x), int(event.y)
    #print(x, y)
    if typeDrawing.get() == "Отрезок":
        if lineExistPoint:
            lineExistPoint = False
            lines.append((tmp, Point(x=x, y=y)))
            lineDrawer(tmp, Point(x=x, y=y), canvasField, color)
        else:
            lineExistPoint = True
            tmp = Point(x=x, y=y)
    else:
        if isLocked:
            localFirstPoint = Point(x, y)
            mas.append(localFirstPoint)
            isLocked = False
            newFigureLen = 0
        else:
            if newFigureLen == 0:
                mas.append(Point(x, y))
                lineDrawer(Point(x, y), localFirstPoint, canvasField, color)
                newFigureLen += 1
            else:
                l = len(mas) - 1
                mas.append((Point(x=x, y=y)))
                lineDrawer(Point(x=x, y=y), mas[l], canvasField, color)
                newFigureLen += 1

def fakeMouseClick(x, y):
    pass

def lock():
    global isLocked, localFirstPoint, mas
    color = colorRecognizer()
    if isLocked:
        return
    else:
        l = len(mas) - 1
        lineDrawer(localFirstPoint, mas[l], canvasField, color)
        isLocked = True
        print(convex(mas))

def redrawEdges(canvas, color):
    global mas
    for edge in mas:
        lineDrawer(edge[0], edge[1], edge[2], edge[3], canvas, color)

def lineBtnClicked():
    global lineFlag
    lineFlag = True

def figureBtnCliced():
    global figureFlag
    figureFlag = True

def mainfunc():
    global lines
    norm = convex(mas)
    for line in lines:
        cyrus_beck(line, mas, norm, canvasField)

img = Image.new('RGB', (IMGSIZEX, IMGSIZEY), "white")

#########################################################################
##############################MAIN#######################################
#########################################################################

root = tk.Tk()
canvasField = tk.Canvas(root, width=img.size[0], height=img.size[1])
canvasField.pack()
image_tk = ImageTk.PhotoImage(img)
canvasField.create_image(img.size[0] // 2, img.size[1] // 2, image=image_tk)

canvasField.bind("<Button-1>", mouseClick)
# canvasField.bind("<Button-2>", testfunc)

typeDrawing = tk.StringVar()
typeDrawing.set("Отрезок")
typeMenu = tk.OptionMenu(root, typeDrawing, "Отрезок", "Отсекатель")
typeMenu.pack(side="right")
dynamic = tk.IntVar()
drawBtn = tk.Button(text="Поехали", command=mainfunc).pack(side="right")
clearBtn = tk.Button(text="Очистить", command=clearCanvasField).pack(side="right")
lockBtn = tk.Button(text="Замкнуть", command=lock).pack(side="right")
zatPixelButton = tk.Button(text="Ввести затравочный пиксел", command=lineBtnClicked).pack(side="right")
circleBtn = tk.Button(text="Окружность", command=figureBtnCliced).pack(side="right")
dynamicCheckbutton = tk.Checkbutton(text="С задержкой", variable=dynamic).pack(side="right")

root.mainloop()