"""Control actions triggered by the GUI."""

# atbswp: Record mouse and keyboard actions and reproduce them identically at will
#
# Copyright (C) 2019 Mairo Rufus <akoudanilo@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
import os
import platform
import py_compile
import shutil
import sys
import tempfile
import time
from datetime import date
from pathlib import Path
from threading import Thread

import pyautogui

from pynput import keyboard, mouse

import settings

import wx
import wx.adv


TMP_PATH = os.path.join(tempfile.gettempdir(),
                        "atbswp-" + date.today().strftime("%Y%m%d"))
HEADER = (
            f"#!/bin/env python3\n"
            f"# Created by atbswp (https://github.com/rmpr/atbswp)\n"
            f"# on {date.today().strftime('%d %b %Y ')}\n"
            f"import pyautogui\n"
            f"import time\n"
            f"pyautogui.FAILSAFE = False\n"
        )


class FileChooserCtrl:
    """Control class for both the open capture and save capture options.

    Keyword arguments:
    capture -- content of the temporary file
    parent -- the parent Frame
    """

    capture = str()

    def __init__(self, parent):
        """Set the parent frame."""
        self.parent = parent

    def load_content(self, path):
        """Load the temp file capture from disk."""
        # TODO: Better input control
        if not path or not os.path.isfile(path):
            return None
        with open(path, 'r') as f:
            return f.read()

    def load_file(self, event):
        """Load a capture manually chosen by the user."""
        title = "Choose a capture file:"
        dlg = wx.FileDialog(self.parent,
                            message=title,
                            defaultDir="~",
                            defaultFile="capture.py",
                            style=wx.DD_DEFAULT_STYLE)
        if dlg.ShowModal() == wx.ID_OK:
            self._capture = self.load_content(dlg.GetPath())
            with open(TMP_PATH, 'w') as f:
                f.write(self._capture)
        dlg.Destroy()

    def save_file(self, event):
        """Save the capture currently loaded."""
        with wx.FileDialog(self.parent, "Save capture file", wildcard="*",
                           style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) as fileDialog:

            if fileDialog.ShowModal() == wx.ID_CANCEL:
                return     # the user changed their mind

            # save the current contents in the file
            pathname = fileDialog.GetPath()
            try:
                shutil.copy(TMP_PATH, pathname)
            except IOError:
                wx.LogError(f"Cannot save current data in file {pathname}.")


class RecordCtrl:
    """Control class for the record button.

    Keyword arguments:
    capture -- current recording
    mouse_sensibility -- granularity for mouse capture
    """

    def __init__(self):
        """Initialize a new record."""
        self._header = HEADER

        self._capture = [self._header]
        self._lastx, self._lasty = pyautogui.position()
        self.mouse_sensibility = 21
        if getattr(sys, 'frozen', False):
            self.path = sys._MEIPASS
        else:
            self.path = Path(__file__).parent.absolute()

    def write_mouse_action(self, engine="pyautogui", move="", parameters=""):
        """Append a new mouse move to capture.

        Keyword arguments:
        engine -- the replay library used (default pyautogui)
        move -- the mouse movement (mouseDown, mouseUp, scroll, moveTo)
        parameters -- the details of the movement
        """
        def isinteger(s):
            try:
                int(s)
                return True
            except:
                return False

        if move == "moveTo":
            coordinates = [int(s) for s in parameters.split(", ") if isinteger(s)]
            if coordinates[0] - self._lastx < self.mouse_sensibility \
               and coordinates[1] - self._lasty < self.mouse_sensibility:
                return
            else:
                self._lastx, self._lasty = coordinates
        self._capture.append(engine + "." + move + '(' + parameters + ')')

    def write_keyboard_action(self, engine="pyautogui", move="", key=""):
        """Append keyboard actions to the class variable capture.

        Keyword arguments:
        - engine: the module which will be used for the replay
        - move: keyDown | keyUp
        - key: The key pressed
        """
        suffix = "(" + repr(key) + ")"
        if move == "keyDown":
            # Corner case: Multiple successive keyDown
            if move + suffix in self._capture[-1]:
                move = 'press'
                self._capture[-1] = engine + "." + move + suffix
        self._capture.append(engine + "." + move + suffix)

    def on_move(self, x, y):
        """Triggered by a mouse move."""
        if not self.recording:
            return False
        b = time.perf_counter()
        timeout = int(b - self.last_time)
        if timeout > 0:
            self._capture.append(f"time.sleep({timeout})")
        self.last_time = b
        self.write_mouse_action(move="moveTo", parameters=f"{x}, {y}")

    def on_click(self, x, y, button, pressed):
        """Triggered by a mouse click."""
        if not self.recording:
            return False
        if pressed:
            if button == mouse.Button.left:
                self.write_mouse_action(move="mouseDown", parameters=f"{x}, {y}, 'left'")
            elif button == mouse.Button.right:
                self.write_mouse_action(move="mouseDown", parameters=f"{x}, {y}, 'right'")
            elif button == mouse.Button.middle:
                self.write_mouse_action(move="mouseDown", parameters=f"{x}, {y}, 'middle'")
            else:
                wx.LogError("Mouse Button not recognized")
        else:
            if button == mouse.Button.left:
                self.write_mouse_action(move="mouseUp", parameters=f"{x}, {y}, 'left'")
            elif button == mouse.Button.right:
                self.write_mouse_action(move="mouseUp", parameters=f"{x}, {y}, 'right'")
            elif button == mouse.Button.middle:
                self.write_mouse_action(move="mouseUp", parameters=f"{x}, {y}, 'middle'")
            else:
                wx.LogError("Mouse Button not recognized")

    def on_scroll(self, x, y, dx, dy):
        """Triggered by a mouse wheel scroll."""
        if not self.recording:
            return False
        self.write_mouse_action(move="scroll", parameters=f"{y}")

    def on_press(self, key):
        """Triggered by a key press."""
        if not self.recording:
            return False
        b = time.perf_counter()
        timeout = int(b - self.last_time)
        if timeout > 0:
            self._capture.append(f"time.sleep({timeout})")
        self.last_time = b

        try:
            # Ignore presses on Fn key
            if key.char:
                self.write_keyboard_action(move='keyDown', key=key.char)

        except AttributeError:
            if key == keyboard.Key.alt:
                if platform.system() == "Darwin":
                    self.write_keyboard_action(move="keyDown", key='option')
                else:
                    self.write_keyboard_action(move="keyDown", key='alt')
            elif key == keyboard.Key.alt_l:
                if platform.system() == "Darwin":
                    self.write_keyboard_action(move="keyDown", key='optionleft')
                else:
                    self.write_keyboard_action(move='keyDown', key='altleft')
            elif key == keyboard.Key.alt_r:
                if platform.system() == "Darwin":
                    self.write_keyboard_action(move='keyDown', key='optionright')
                else:
                    self.write_keyboard_action(move='keyDown', key='altright')
            elif key == keyboard.Key.alt_gr:
                self.write_keyboard_action(move='keyDown', key='altright')
            elif key == keyboard.Key.backspace:
                self.write_keyboard_action(move='keyDown', key='backspace')
            elif key == keyboard.Key.caps_lock:
                self.write_keyboard_action(move='keyDown', key='capslock')
            elif key == keyboard.Key.cmd:
                if platform.system() == "Darwin":
                    self.write_keyboard_action(move='keyDown', key='command')
                else:
                    self.write_keyboard_action(move='keyDown', key='winleft')
            elif key == keyboard.Key.cmd_r:
                if platform.system() == "Darwin":
                    self.write_keyboard_action(move='keyDown', key='cmdright')
                else:
                    self.write_keyboard_action(move='keyDown', key='winright')
            elif key == keyboard.Key.ctrl:
                self.write_keyboard_action(move='keyDown', key='ctrlleft')
            elif key == keyboard.Key.ctrl_r:
                self.write_keyboard_action(move='keyDown', key='ctrlright')
            elif key == keyboard.Key.delete:
                self.write_keyboard_action(move='keyDown', key='delete')
            elif key == keyboard.Key.down:
                self.write_keyboard_action(move='keyDown', key='down')
            elif key == keyboard.Key.end:
                self.write_keyboard_action(move='keyDown', key='end')
            elif key == keyboard.Key.enter:
                self.write_keyboard_action(move='keyDown', key='enter')
            elif key == keyboard.Key.esc:
                self.write_keyboard_action(move='keyDown', key='esc')
            elif key == keyboard.Key.f1:
                self.write_keyboard_action(move='keyDown', key='f1')
            elif key == keyboard.Key.f2:
                self.write_keyboard_action(move='keyDown', key='f2')
            elif key == keyboard.Key.f3:
                self.write_keyboard_action(move='keyDown', key='f3')
            elif key == keyboard.Key.f4:
                self.write_keyboard_action(move='keyDown', key='f4')
            elif key == keyboard.Key.f5:
                self.write_keyboard_action(move='keyDown', key='f5')
            elif key == keyboard.Key.f6:
                self.write_keyboard_action(move='keyDown', key='f6')
            elif key == keyboard.Key.f7:
                self.write_keyboard_action(move='keyDown', key='f7')
            elif key == keyboard.Key.f8:
                self.write_keyboard_action(move='keyDown', key='f8')
            elif key == keyboard.Key.f9:
                self.write_keyboard_action(move='keyDown', key='f9')
            elif key == keyboard.Key.f10:
                self.write_keyboard_action(move='keyDown', key='f10')
            elif key == keyboard.Key.f11:
                self.write_keyboard_action(move='keyDown', key='f11')
            elif key == keyboard.Key.f12:
                self.write_keyboard_action(move='keyDown', key='f12')
            elif key == keyboard.Key.home:
                self.write_keyboard_action(move='keyDown', key='home')
            elif key == keyboard.Key.left:
                self.write_keyboard_action(move='keyDown', key='left')
            elif key == keyboard.Key.page_down:
                self.write_keyboard_action(move='keyDown', key='pagedown')
            elif key == keyboard.Key.page_up:
                self.write_keyboard_action(move='keyDown', key='pageup')
            elif key == keyboard.Key.right:
                self.write_keyboard_action(move='keyDown', key='right')
            elif key == keyboard.Key.shift:
                self.write_keyboard_action(move='keyDown', key='shift_left')
            elif key == keyboard.Key.shift_r:
                self.write_keyboard_action(move='keyDown', key='shiftright')
            elif key == keyboard.Key.space:
                self.write_keyboard_action(move='keyDown', key='space')
            elif key == keyboard.Key.tab:
                self.write_keyboard_action(move='keyDown', key='tab')
            elif key == keyboard.Key.up:
                self.write_keyboard_action(move='keyDown', key='up')
            elif key == keyboard.Key.media_play_pause:
                self.write_keyboard_action(move='keyDown', key='playpause')
            elif key == keyboard.Key.insert:
                self.write_keyboard_action(move='keyDown', key='insert')
            elif key == keyboard.Key.menu:
                self._capture.append(f"### The menu key is not handled yet")
            elif key == keyboard.Key.num_lock:
                self.write_keyboard_action(move='keyDown', key='num_lock')
            elif key == keyboard.Key.pause:
                self.write_keyboard_action(move='keyDown', key='pause')
            elif key == keyboard.Key.print_screen:
                self.write_keyboard_action(move='keyDown', key='print_screen')
            elif key == keyboard.Key.scroll_lock:
                self.write_keyboard_action(move='keyDown', key='scroll_lock')
            else:
                self._capture.append(f"### {key} is not supported yet")

    def on_release(self, key):
        """Triggered by a key released."""
        if not self.recording:
            return False
        if key == keyboard.Key.alt:
            if platform.system() == "Darwin":
                self.write_keyboard_action(move='keyUp', key='option')
            else:
                self.write_keyboard_action(move='keyUp', key='alt')
        elif key == keyboard.Key.alt_l:
            if platform.system() == "Darwin":
                self.write_keyboard_action(move='keyUp', key='optionleft')
            else:
                self.write_keyboard_action(move='keyUp', key='altleft')
        elif key == keyboard.Key.alt_r:
            if platform.system() == "Darwin":
                self.write_keyboard_action(move='keyUp', key='optionright')
            else:
                self.write_keyboard_action(move='keyUp', key='altright')
        elif key == keyboard.Key.alt_gr:
            self.write_keyboard_action(move='keyUp', key='altright')
        elif key == keyboard.Key.backspace:
            self.write_keyboard_action(move='keyUp', key='backspace')
        elif key == keyboard.Key.caps_lock:
            self.write_keyboard_action(move='keyUp', key='capslock')
        elif key == keyboard.Key.cmd:
            if platform.system() == "Darwin":
                self.write_keyboard_action(move='keyUp', key='command')
            else:
                self.write_keyboard_action(move='keyUp', key='winleft')
        elif key == keyboard.Key.cmd_r:
            if platform.system() == "Darwin":
                self.write_keyboard_action(move='keyUp', key='cmdright')
            else:
                self.write_keyboard_action(move='keyUp', key='winright')
        elif key == keyboard.Key.ctrl:
            self.write_keyboard_action(move='keyUp', key='ctrlleft')
        elif key == keyboard.Key.ctrl_r:
            self.write_keyboard_action(move='keyUp', key='ctrlright')
        elif key == keyboard.Key.delete:
            self.write_keyboard_action(move='keyUp', key='delete')
        elif key == keyboard.Key.down:
            self.write_keyboard_action(move='keyUp', key='down')
        elif key == keyboard.Key.end:
            self.write_keyboard_action(move='keyUp', key='end')
        elif key == keyboard.Key.enter:
            self.write_keyboard_action(move='keyUp', key='enter')
        elif key == keyboard.Key.esc:
            self.write_keyboard_action(move='keyUp', key='esc')
        elif key == keyboard.Key.f1:
            self.write_keyboard_action(move='keyUp', key='f1')
        elif key == keyboard.Key.f2:
            self.write_keyboard_action(move='keyUp', key='f2')
        elif key == keyboard.Key.f3:
            self.write_keyboard_action(move='keyUp', key='f3')
        elif key == keyboard.Key.f4:
            self.write_keyboard_action(move='keyUp', key='f4')
        elif key == keyboard.Key.f5:
            self.write_keyboard_action(move='keyUp', key='f5')
        elif key == keyboard.Key.f6:
            self.write_keyboard_action(move='keyUp', key='f6')
        elif key == keyboard.Key.f7:
            self.write_keyboard_action(move='keyUp', key='f7')
        elif key == keyboard.Key.f8:
            self.write_keyboard_action(move='keyUp', key='f8')
        elif key == keyboard.Key.f9:
            self.write_keyboard_action(move='keyUp', key='f9')
        elif key == keyboard.Key.f10:
            self.write_keyboard_action(move='keyUp', key='f10')
        elif key == keyboard.Key.f11:
            self.write_keyboard_action(move='keyUp', key='f11')
        elif key == keyboard.Key.f12:
            self.write_keyboard_action(move='keyUp', key='f12')
        elif key == keyboard.Key.home:
            self.write_keyboard_action(move='keyUp', key='home')
        elif key == keyboard.Key.left:
            self.write_keyboard_action(move='keyUp', key='left')
        elif key == keyboard.Key.page_down:
            self.write_keyboard_action(move='keyUp', key='pagedown')
        elif key == keyboard.Key.page_up:
            self.write_keyboard_action(move='keyUp', key='pageup')
        elif key == keyboard.Key.right:
            self.write_keyboard_action(move='keyUp', key='right')
        elif key == keyboard.Key.shift:
            self.write_keyboard_action(move='keyUp', key='shift_left')
        elif key == keyboard.Key.shift_r:
            self.write_keyboard_action(move='keyUp', key='shiftright')
        elif key == keyboard.Key.space:
            self.write_keyboard_action(move='keyUp', key='space')
        elif key == keyboard.Key.tab:
            self.write_keyboard_action(move='keyUp', key='tab')
        elif key == keyboard.Key.up:
            self.write_keyboard_action(move='keyUp', key='up')
        elif key == keyboard.Key.media_play_pause:
            self.write_keyboard_action(move='keyUp', key='playpause')
        elif key == keyboard.Key.insert:
            self.write_keyboard_action(move='keyUp', key='insert')
        elif key == keyboard.Key.menu:
            self._capture.append(f"### The menu key is not handled yet")
        elif key == keyboard.Key.num_lock:
            self.write_keyboard_action(move='keyUp', key='num_lock')
        elif key == keyboard.Key.pause:
            self.write_keyboard_action(move='keyUp', key='pause')
        elif key == keyboard.Key.print_screen:
            self.write_keyboard_action(move='keyUp', key='print_screen')
        elif key == keyboard.Key.scroll_lock:
            self.write_keyboard_action(move='keyUp', key='scroll_lock')
        else:
            if len(str(key)) <= 3:
                self.write_keyboard_action(move='keyUp', key=key)

    def action(self, event):
        """Triggered when the recording button is clicked on the GUI."""
        listener_mouse = mouse.Listener(
            on_move=self.on_move,
            on_click=self.on_click,
            on_scroll=self.on_scroll)
        listener_keyboard = keyboard.Listener(
            on_press=self.on_press,
            on_release=self.on_release)

        if event.GetEventObject().GetValue():
            listener_keyboard.start()
            listener_mouse.start()
            self.last_time = time.perf_counter()
            self.recording = True
            recording_state = wx.Icon(os.path.join(self.path, "img", "icon-recording.png"))
        else:
            self.recording = False
            with open(TMP_PATH, 'w') as f:
                # Remove the recording trigger event
                self._capture.pop()
                # If it's the mouse remove the previous also
                if "mouseDown" in self._capture[-1]:
                    self._capture.pop()
                f.seek(0)
                f.write("\n".join(self._capture))
                f.truncate()
            self._capture = [self._header]
            recording_state = wx.Icon(os.path.join(self.path, "img", "icon.png"))
        event.GetEventObject().GetParent().taskbar.SetIcon(recording_state)


class PlayCtrl:
    """Control class for the play button."""

    global TMP_PATH

    def play(self, capture, toggle_button):
        """Play the loaded capture."""
        toggle_button.Value = True
        exec(capture)
        toggle_button.Value = False

    def action(self, event):
        """Replay a `count` number of time."""
        toggle_button = event.GetEventObject()
        count = settings.CONFIG.getint('DEFAULT', 'Repeat Count')
        infinite = settings.CONFIG.getboolean('DEFAULT', 'Infinite Playback')
        if toggle_button.Value:
            if TMP_PATH is None or not os.path.isfile(TMP_PATH):
                wx.LogError("No capture loaded")
                toggle_button.Value = False
                return
            with open(TMP_PATH, 'r') as f:
                capture = f.read()
            if capture == HEADER:
                wx.LogError("Empty capture")
                toggle_button.Value = False
                return
            if count == 1 and not infinite:
                self.play_thread = Thread()
                self.play_thread.daemon = True
                self.play_thread = Thread(target=self.play,
                                          args=(capture, toggle_button,))
                self.play_thread.start()
            else:
                i = 1
                while i <= count or infinite:
                    self.play_thread = Thread()
                    self.play_thread = Thread(target=self.play,
                                              args=(capture, toggle_button,))
                    self.play_thread.start()
                    self.play_thread.join()
                    i += 1
        else:
            if getattr(sys, 'frozen', False):
                path = os.path.join(Path(__file__).parent.absolute(), 'atbswp')
            else:
                path = os.path.join(Path(__file__).parent.absolute(), 'atbswp.py')
            settings.save_config()
            os.execl(path)


class CompileCtrl:
    """Produce an executable Python bytecode file."""

    @staticmethod
    def compile(event):
        """Return a compiled version of the capture currently loaded.

        For now it only returns a bytecode file.
        #TODO: Return a proper executable for the platform currently
        used **Without breaking the current workflow** which works both
        in development mode and in production
        """
        try:
            bytecode_path = py_compile.compile(TMP_PATH)
        except:
            wx.LogError("No capture loaded")
            return
        default_file = "capture.pyc"
        with wx.FileDialog(parent=event.GetEventObject().Parent, message="Save capture executable",
                           defaultDir=os.path.expanduser("~"), defaultFile=default_file, wildcard="*",
                           style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) as fileDialog:

            if fileDialog.ShowModal() == wx.ID_CANCEL:
                return     # the user changed their mind
            pathname = fileDialog.GetPath()
            try:
                shutil.copy(bytecode_path, pathname)
            except IOError:
                wx.LogError(f"Cannot save current data in file {pathname}.")


class SettingsCtrl:
    """Control class for the settings."""

    def __init__(self, main_dialog):
        """Copy the reference of the main Window."""
        self.main_dialog = main_dialog

    @staticmethod
    def playback_speed(event):
        """Replay the capture 2 times faster."""
        # TODO: To implement
        pass

    @staticmethod
    def infinite_playback(event):
        """Toggle infinite playback."""
        current_value = settings.CONFIG.getboolean('DEFAULT', 'Infinite Playback')
        settings.CONFIG['DEFAULT']['Infinite Playback'] = str(not current_value)

    @staticmethod
    def repeat_count(event):
        """Set the repeat count."""
        current_value = settings.CONFIG.getint('DEFAULT', 'Repeat Count')
        dialog = SliderDialog(None, title="Choose a repeat count", size=(500, 50), default_value=current_value)
        dialog.ShowModal()
        new_value = dialog.value
        dialog.Destroy()
        settings.CONFIG['DEFAULT']['Repeat Count'] = str(new_value)

    @staticmethod
    def recording_hotkey(event):
        """Set the recording hotkey."""
        current_value = settings.CONFIG.getint('DEFAULT', 'Recording Hotkey')
        dialog = SliderDialog(None, title="Choose a function key: F2-12", size=(500, 50),
                              default_value=current_value-339, min_value=2, max_value=12)
        dialog.ShowModal()
        new_value = dialog.value + 339
        if new_value == settings.CONFIG.getint('DEFAULT', 'Playback Hotkey'):
            dlg = wx.MessageDialog(None, "Recording hotkey should be different from Playback one", "Error", wx.OK | wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
        dialog.Destroy()
        settings.CONFIG['DEFAULT']['Recording Hotkey'] = str(new_value)

    @staticmethod
    def playback_hotkey(event):
        """Set the playback hotkey."""
        current_value = settings.CONFIG.getint('DEFAULT', 'Playback Hotkey')
        dialog = SliderDialog(None, title="Choose a function key: F2-12", size=(500, 50),
                              default_value=current_value-339, min_value=2, max_value=12)
        dialog.ShowModal()
        new_value = dialog.value + 339
        if new_value == settings.CONFIG.getint('DEFAULT', 'Recording Hotkey'):
            dlg = wx.MessageDialog(None, "Playback hotkey should be different from Recording one", "Error", wx.OK | wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
        dialog.Destroy()
        settings.CONFIG['DEFAULT']['Playback Hotkey'] = str(new_value)

    def always_on_top(self, event):
        """Toggle the always on top setting."""
        current_value = settings.CONFIG['DEFAULT']['Always On Top']
        style = self.main_dialog.GetWindowStyle()
        self.main_dialog.SetWindowStyle(style ^ wx.STAY_ON_TOP)
        settings.CONFIG['DEFAULT']['Always On Top'] = str(not current_value)

    def language(self, event):
        """Manage the language among the one available."""
        menu = event.EventObject
        item = menu.FindItemById(event.Id)
        settings.CONFIG['DEFAULT']['Language'] = item.Name
        dialog = wx.MessageDialog(None,
                                  message="Restart the program to apply modifications",
                                  pos=wx.DefaultPosition)
        dialog.ShowModal()


class HelpCtrl:
    """Control class for the About menu."""

    @staticmethod
    def action(event):
        """Open the browser on the quick demo of atbswp"""
        url = "https://youtu.be/L0jjSgX5FYk"
        wx.LaunchDefaultBrowser(url, flags=0)


class SliderDialog(wx.Dialog):
    """Wrap a slider in a dialog and get the value"""

    def __init__(self, *args, **kwargs):
        """Initialize the widget with the custom attributes."""
        self._current_value = kwargs.pop("default_value", 1)
        self.min_value = kwargs.pop("min_value", 1)
        self.max_value = kwargs.pop("max_value", 999)
        super(SliderDialog, self).__init__(*args, **kwargs)
        self._value = 1
        self.init_ui()
        self.Bind(wx.EVT_CLOSE, self.on_close)

    def init_ui(self):
        """Initialize the UI elements"""
        pnl = wx.Panel(self)
        sizer = wx.BoxSizer(orient=wx.HORIZONTAL)
        self.slider = wx.Slider(parent=pnl, id=wx.ID_ANY, value=self._current_value,
                                minValue=self.min_value, maxValue=self.max_value,
                                name="Choose a number", size=self.GetSize(),
                                style=wx.SL_VALUE_LABEL | wx.SL_AUTOTICKS)
        sizer.Add(self.slider)
        pnl.SetSizer(sizer)
        sizer.Fit(self)

    def on_close(self, event):
        """Triggered when the widget is closed."""
        self._value = self.slider.Value
        event.Skip()

    @property
    def value(self):
        """Getter."""
        return self._value

    @value.setter
    def value(self, value):
        """Setter."""
        self._value = value