
from LUIObject import LUIObject
from LUILayouts import LUIHorizontalStretchedLayout
from LUILabel import LUILabel
from LUIInitialState import LUIInitialState

__all__ = ["LUIButton"]


class LUIButton(LUIObject):

    """ Simple button, containing three sprites and a label. """

    def __init__(self, text="Button", template="ButtonDefault", **kwargs):
        """ Constructs a new button. The template controls which sprites to use.
        If the template is "ButtonDefault" for example, the sprites
        "ButtonDefault_Left", "ButtonDefault" and "ButtonDefault_Right" will
        be used. The sprites used when the button is pressed should be named
        "ButtonDefaultFocus_Left" and so on then.

        If an explicit width is set on the button, the button will stick to
        that width, otherwise it will automatically resize to fit the label """
        LUIObject.__init__(self, x=0, y=0, solid=True)
        self._template = template
        self._layout = LUIHorizontalStretchedLayout(
            parent=self, prefix=self._template, width="100%")
        self._label = LUILabel(parent=self, text=text)
        self._label.z_offset = 1
        self._label.center_vertical = True
        self._label.margin = 0, 20, 0, 20
        self.margin.left = -1
        self._hovered = False
        self._pressed = False
        self._use_custom_texture = False
        self._custom_texture = None
        self._custom_uv = None
        self._custom_texture_hover = None
        self._custom_uv_hover = None
        self._custom_texture_pressed = None
        self._custom_uv_pressed = None
        LUIInitialState.init(self, kwargs)

    def _apply_stretch_sizes(self):
        """Ensure internal sprites stretch to the button size."""
        try:
            layout = getattr(self, '_layout', None)
            if layout is not None:
                if hasattr(layout, 'width'):
                    layout.width = "100%"
                if hasattr(layout, 'height'):
                    layout.height = "100%"
                inner = getattr(layout, '_layout', None)
                if inner is not None:
                    if hasattr(inner, 'width'):
                        inner.width = "100%"
                    if hasattr(inner, 'height'):
                        inner.height = "100%"
                for attr in ('_sprite_left', '_sprite_mid', '_sprite_right'):
                    spr = getattr(layout, attr, None)
                    if spr is not None:
                        if hasattr(spr, 'height'):
                            spr.height = "100%"
                        if attr == '_sprite_mid' and hasattr(spr, 'width'):
                            spr.width = "100%"
        except Exception:
            pass

    def _apply_custom_texture(self, state="normal"):
        """Apply custom texture based on state: normal/hover/pressed."""
        if not self._use_custom_texture:
            return

        tex = None
        uv = None
        if state == "pressed" and self._custom_texture_pressed is not None:
            tex = self._custom_texture_pressed
            uv = self._custom_uv_pressed
        elif state == "hover" and self._custom_texture_hover is not None:
            tex = self._custom_texture_hover
            uv = self._custom_uv_hover
        else:
            tex = self._custom_texture
            uv = self._custom_uv

        if tex is None:
            return

        layout = getattr(self, "_layout", None)
        if layout is None:
            return
        for attr in ("_sprite_left", "_sprite_mid", "_sprite_right"):
            spr = getattr(layout, attr, None)
            if spr is None:
                continue
            try:
                if hasattr(spr, "set_texture"):
                    spr.set_texture(tex, resize=False)
                if uv and hasattr(spr, "set_uv_range"):
                    u0, v0, u1, v1 = uv
                    spr.set_uv_range(u0, v0, u1, v1)
            except Exception:
                pass

        # Hide left/right caps for single-image mode
        try:
            if hasattr(layout, "_sprite_left") and layout._sprite_left is not None:
                layout._sprite_left.width = 0
            if hasattr(layout, "_sprite_right") and layout._sprite_right is not None:
                layout._sprite_right.width = 0
        except Exception:
            pass

        self._apply_stretch_sizes()

    def set_custom_textures(self, normal_tex, normal_uv=None, hover_tex=None, hover_uv=None, pressed_tex=None, pressed_uv=None):
        """Set custom textures for normal/hover/pressed states."""
        self._use_custom_texture = True
        self._custom_texture = normal_tex
        self._custom_uv = normal_uv
        self._custom_texture_hover = hover_tex
        self._custom_uv_hover = hover_uv
        self._custom_texture_pressed = pressed_tex
        self._custom_uv_pressed = pressed_uv
        if self._hovered:
            self._apply_custom_texture("hover")
        else:
            self._apply_custom_texture("normal")

    def set_custom_texture(self, texture, uv=None):
        """Use a single texture for the button background."""
        self.set_custom_textures(texture, uv, None, None, None, None)

    def clear_custom_texture(self):
        """Restore default template textures."""
        self._use_custom_texture = False
        self._custom_texture = None
        self._custom_uv = None
        self._custom_texture_hover = None
        self._custom_uv_hover = None
        self._custom_texture_pressed = None
        self._custom_uv_pressed = None
        try:
            self._layout.prefix = self._template
            self._apply_stretch_sizes()
        except Exception:
            pass

    @property
    def text(self):
        """ Returns the current label text of the button """
        return self._label.text

    @text.setter
    def text(self, text):
        """ Sets the label text of the button """
        self._label.text = text

    def on_mousedown(self, event):
        """ Internal on_mousedown handler. Do not override """
        self._pressed = True
        if self._use_custom_texture:
            self._apply_custom_texture("pressed")
        else:
            self._layout.prefix = self._template + "Focus"
            self._apply_stretch_sizes()
        self._label.margin.top = 1

    def on_mouseup(self, event):
        """ Internal on_mouseup handler. Do not override """
        self._pressed = False
        if self._use_custom_texture:
            if self._hovered:
                self._apply_custom_texture("hover")
            else:
                self._apply_custom_texture("normal")
        else:
            self._layout.prefix = self._template
            self._apply_stretch_sizes()
        self._label.margin.top = 0

    def on_mouseover(self, event):
        """ Internal mouseover handler """
        self._hovered = True
        if self._use_custom_texture and not self._pressed:
            self._apply_custom_texture("hover")

    def on_mouseout(self, event):
        """ Internal mouseout handler """
        self._hovered = False
        self._pressed = False
        if self._use_custom_texture:
            self._apply_custom_texture("normal")
