class ImageViewer:
    def __init__(self, root):
        self.SUPPORTED_EXTENSIONS = (".png", ".jpg", ".jpeg", ".gif", ".bmp", ".JPG", ".JPEG", ".BMP", ".GIF", ".webp", ".WEBP")
        self.button_style = {"font": ("consolas", 10), "fg": "white", "bg": "#3c3c3c", "relief": "flat"}
		
        self.image_loading_queue = Queue(maxsize=3)
        self.switch_timestamps = []
        self.is_button_press_in_progress = False  # Variable to track if button is pressed
		
        self.root = root
        self.root.geometry("800x600")  # Initial window size
        self.root.title("Jestur Viewer")
        self.root.configure(bg="#808080")  # Set window background color
        self.root.attributes("-topmost", True)  # Make the window stay on top

        self.image_folder = ""
        self.image_files = []
        self.current_image_index = 0

        self.main_frame = tk.Frame(self.root, bg="#808080")
        self.main_frame.pack()

        self.select_folder_button = tk.Button(self.main_frame, text="Select Folder", command=self.select_folder)
        self.select_folder_button.configure(**self.button_style)
        self.select_folder_button.pack(side=tk.LEFT, padx=5, pady=10)

        self.set_timer_button = tk.Button(self.main_frame, text="Timer", command=self.set_timer_interval)
        self.set_timer_button.configure(**self.button_style)
        self.set_timer_button.pack(side=tk.LEFT, padx=5, pady=10)

        self.start_button = tk.Button(self.main_frame, text="Start", command=self.start_pause_slideshow)
        self.start_button.configure(font=self.button_style["font"], bg="#909090", fg="#707070", relief=tk.FLAT)
        self.start_button.pack(side=tk.LEFT, padx=5, pady=10)

        self.mirror_button = tk.Button(self.main_frame, text=">|<", command=self.toggle_mirror_image)
        self.mirror_button.configure(**self.button_style)
        self.mirror_button.pack(side=tk.LEFT, padx=5, pady=10)
        
        self.greyscale_button = tk.Button(self.main_frame, text="B/W", command=self.toggle_greyscale)
        self.greyscale_button.configure(**self.button_style)
        self.greyscale_button.pack(side=tk.LEFT, padx=5, pady=10)
        
		
        self.random_next_image_var = tk.BooleanVar(value=False) # Checkbox variable
        self.random_next_image_checkbox = tk.Checkbutton(self.main_frame, text="Random", variable=self.random_next_image_var, command=self.toggle_colors)
        self.random_next_image_checkbox.configure(**self.button_style, bd=2)
        self.random_next_image_checkbox.pack(side=tk.LEFT, padx=5, pady=10)
		
		#image label
        self.canvas = tk.Canvas(self.root)
        self.is_mirrored = False
        self.is_greyscale = False
        self.is_paused = False
		
        self.timer_label = tk.Label(self.root, text="5", **self.button_style, anchor="ne") #fg="white", bg="black", font=("arial", 12), bd=1, relief=tk.RIDGE)
        self.timer_label.configure(font=("consolas",17))
        self.timer_label.place(relx=1, anchor="ne", x=-0, y=0)

        self.timer_interval = 5000  # Default time interval in milliseconds (5 seconds)
        self.set_timer_interval = 5000  # Store the set timer interval
        self.timer = None  # Timer ID
		
        self.window_size = (self.root.winfo_width(), self.root.winfo_height())
        self.resize_timer = None

        self.root.bind("<Right>", self.next_image)
        self.root.bind("<Left>", self.previous_image)
        self.root.bind("<space>", self.start_pause_slideshow)
        self.root.bind("<Configure>", self.update_image_size)
        self.root.bind("<KeyRelease-Left>", self.release_button_press)
        self.root.bind("<KeyRelease-Right>", self.release_button_press)
		
    def manage_button_press(self):
        self.is_button_press_in_progress = True
        if hasattr(self, "delayed_display_image_timer"):
            self.root.after_cancel(self.delayed_display_image_timer)
			
    def release_button_press(self, event=None):
        self.is_button_press_in_progress = False
        # Schedule the delayed display of the last intended image
        self.delayed_display_image_timer = self.root.after(100, self.display_current_image)
		
    def toggle_colors(self):
        if self.random_next_image_var.get():
            self.random_next_image_checkbox.configure(fg="#2c2c2c", bg="#d8d8d8")
        else:
            self.random_next_image_checkbox.configure(**self.button_style)

    def select_folder(self):
        self.image_folder = filedialog.askdirectory()
        if self.image_folder:
            image_files = os.listdir(self.image_folder) # Get all files in the selected folder
            self.image_files = [file for file in image_files if file.endswith(self.SUPPORTED_EXTENSIONS)] # Filter image files
            
            if len(self.image_files) > 0:
                self.current_image_index = 0
                self.canvas.pack(fill=tk.BOTH, expand=True)
                self.select_folder_button.pack(side=tk.LEFT, padx=5, pady=5)
                self.root.title("Jesturing in " + self.image_folder)
                self.canvas.config(bg="#808080", highlightthickness=0)
                self.display_image()   
                self.start_button.config(**self.button_style)
            else:
                messagebox.showinfo("No Image Files", "The selected folder does not contain any image files.")
                self.image_folder = ""
                self.root.title("Jestur")

    def set_timer_interval(self):
        self.root.attributes("-topmost", False)
        interval = simpledialog.askinteger("Set Timer Interval", "How many seconds?")        
        if interval:
            if interval < 1:  # Check if interval is less than 1 second
                interval = 1
            self.timer_interval = interval * 1000  # Convert to milliseconds
            self.set_timer_interval = self.timer_interval  # Store the set timer interval
        self.root.lift()  # Bring the main window to the top
        self.root.focus_force()  # Give focus to the main window
        self.root.attributes("-topmost", True)

    def start_pause_slideshow(self, event=None):
        if self.image_folder == "":
            messagebox.showinfo("You haven't picked a folder", "Please select an image folder first.")
        else:
            if self.timer is None:  # Check if timer is not running
                self.display_image()
                self.start_button.config(text="Pause")
                self.is_paused = False  # Set paused flag to False
                self.start_timer()
            else:
                if self.is_paused:  # Check if the slideshow is paused
                    self.start_button.config(text="Pause")
                    self.is_paused = False  # Set paused flag to False
                    self.start_timer()
                else:
                    self.pause_timer()
                    self.start_button.config(text="Start")
                    self.is_paused = True  # Set paused flag to True
    
    def pause_timer(self):
        if self.timer is not None:
            self.root.after_cancel(self.timer)
            self.timer = None

    def start_timer(self):
        if self.image_folder != "" and not self.is_paused:
            self.update_timer()
            self.timer = self.root.after(1000, self.start_timer)

    def update_timer(self):
        seconds_left = int(self.timer_interval / 1000)
        self.timer_label.config(text=f"{seconds_left}")
        self.timer_interval -= 1000
    
        if self.timer_interval < 0:
            self.timer_interval = self.set_timer_interval  # Use the stored set timer interval
            # Do not call next_image(); instead reset index and display the image if it is the time for a slide change
            if not self.random_next_image_var.get():
                self.current_image_index = (self.current_image_index + 1) % len(self.image_files)
            else:
                self.current_image_index = random.randint(0, len(self.image_files) - 1)
            self.display_image()
			
    def toggle_mirror_image(self):
        self.is_mirrored = not self.is_mirrored
        self.display_image()

    def toggle_greyscale(self):
        self.is_greyscale = not self.is_greyscale
        self.display_image()			
		
    def load_image(self, image_path):
        image = Image.open(image_path)
        
        # Check if the image has EXIF data
        if "exif" in image.info:
            exif_data = piexif.load(image.info["exif"])
            if piexif.ImageIFD.Orientation in exif_data["0th"]:
                orientation = exif_data["0th"][piexif.ImageIFD.Orientation]
                if orientation == 3:
                    image = image.rotate(180, expand=True)
                elif orientation == 6:
                    image = image.rotate(-90, expand=True)
                elif orientation == 8:
                    image = image.rotate(90, expand=True)
    
        if self.is_greyscale:
            image = image.convert("L")
    
        if self.is_mirrored:
            image = image.transpose(Image.FLIP_LEFT_RIGHT)
    
        aspect_ratio = image.width / image.height
        canvas_width = self.canvas.winfo_width()
        canvas_height = self.canvas.winfo_height()
        max_width = min(canvas_width, int(aspect_ratio * canvas_height))
        max_height = min(canvas_height, int(canvas_width / aspect_ratio))
        scale_factor = min(max_width / image.width, max_height / image.height)
        new_width = int(image.width * scale_factor)
        new_height = int(image.height * scale_factor)
    
        if new_width > 0 and new_height > 0:
            resized_image = image.resize((new_width, new_height), Image.BICUBIC)
            self.photo = ImageTk.PhotoImage(resized_image)
            self.canvas.delete("all")
            self.canvas.create_image(canvas_width // 2, canvas_height // 2, image=self.photo)

    def display_image(self):
        if self.image_folder != "" and self.image_files:
            if self.should_load_image():  # We should immediately load the image
                image_path = os.path.join(self.image_folder, self.image_files[self.current_image_index])
                threading.Thread(target=self.load_image, args=(image_path,)).start()
            else:  # Handling rapid browsing or long press by showing only image name
                image_name = self.image_files[self.current_image_index]
                self.show_image_name(image_name)
    
    def show_image_name(self, name):
        self.canvas.delete("all")
        self.canvas.create_text(
            self.canvas.winfo_width() // 2,
            self.canvas.winfo_height() // 2,
            text=name,
            fill="white"
        )
    
    def update_image_size(self, event=None):
        current_width = self.root.winfo_width()
        current_height = self.root.winfo_height()
    
        if (current_width, current_height) != self.window_size:
            self.window_size = (current_width, current_height)
            self.canvas.config(width=current_width, height=current_height)
            self.buffer_forsize()
			
    def buffer_forsize(self, event=None):
        if self.resize_timer:
            self.root.after_cancel(self.resize_timer)
        self.resize_timer = self.root.after(500, self.display_image)
		
    def update_switch_timestamps(self):
        current_time = time.time()
        self.switch_timestamps.append(current_time)
        # Clean up old timestamps
        threshold_time = 1
        self.switch_timestamps = [t for t in self.switch_timestamps if current_time - t <= threshold_time]
        
        rapid_browsing = len(self.switch_timestamps) > 6  # Adjust this threshold as needed
        if rapid_browsing:
            # Schedule the delayed display of the current image
            self.display_current_image_with_delay()
            self.switch_timestamps.clear()  # Clear timestamps to reset rapid browsing detection
        return rapid_browsing
		
    def queue_image_loading(self):
        if self.image_loading_queue.full():
            # Clear the queue if it"s full
            with self.image_loading_queue.mutex:
                self.image_loading_queue.queue.clear()
        self.image_loading_queue.put(self.current_image_index)
        self.process_image_loading_queue()

    def process_image_loading_queue(self):
        if not self.image_loading_queue.empty():
            # Only process the last item in the queue
            while self.image_loading_queue.qsize() > 1:
                self.image_loading_queue.get()
            last_index = self.image_loading_queue.get()
            self.root.after_cancel(self.timer) if self.timer else None
            self.current_image_index = last_index
            threading.Thread(target=self.display_image).start()
            self.timer_interval = self.set_timer_interval	
		
    def next_image(self, event=None):
        self.manage_button_press()
        if self.image_folder != "" and self.image_files:
            if self.should_load_image():
                if self.random_next_image_var.get():
                    # Skip random selection if navigating through images too rapidly or holding the button too long
                    self.current_image_index = random.randint(0, len(self.image_files) - 1)
                else:
                    self.current_image_index = (self.current_image_index + 1) % len(self.image_files)
                self.display_image()

    
    def previous_image(self, event=None):
        self.manage_button_press()  # Indicate start of button press
        if self.image_folder != "" and self.image_files:  # Ensure we have images to handle
            if self.should_load_image():
                if self.random_next_image_var.get():
                    # Skip random selection if navigating through images too rapidly or holding the button too long
                    self.current_image_index = random.randint(0, len(self.image_files) - 1)
                else:
                    self.current_image_index = (self.current_image_index - 1) % len(self.image_files)
                self.display_image()

            
    def display_current_image_with_delay(self):
        # Cancel any previous image display attempts
        if hasattr(self, "delayed_display_image_timer"):
            self.root.after_cancel(self.delayed_display_image_timer)
    
        # Schedule a new display attempt for the current image after the delay
        self.delayed_display_image_timer = self.root.after(300, self.display_current_image)

    def display_current_image(self):
        # Call the original method to load and display the current image
        self.display_image()

    def should_load_image(self):
        threshold_rapid_presses = 6  # after how many rapid presses to display the image name
        threshold_time = 0.5  # how long to consider presses as "rapid" in seconds
        current_time = time.time()
        self.switch_timestamps.append(current_time)
        self.switch_timestamps = [t for t in self.switch_timestamps if current_time - t <= threshold_time]
    
        # Reset timer interval
        self.timer_interval = self.set_timer_interval
    
        # Check if rapid or long pressing is occurring
        if len(self.switch_timestamps) > threshold_rapid_presses or self.is_button_press_in_progress:
            # Schedule the delayed display of the current image
            self.display_current_image_with_delay()
            return False
        return True

the next and previous button is broken, can you make it so it loads next and previous images, but only show the image name in text when it's too much on the queue, pressed too long or too rapid. i want to still browse by long press, and rapid press. but only if it's too fast or too much images to be processed it just shows the image name temporarily while i can keep browsing pressing next or previous