""" Button classes

Simple example:

.. UIExample:: 50

    b = ui.Button(text="Push me")


Example with interaction:

.. UIExample:: 200

    from flexx import app, event, ui

    class Example(ui.HFix):
    
        def init(self):
            with ui.VBox():
                self.b1 = ui.Button(text='apple')
                self.b2 = ui.Button(text='banana')
                self.b3 = ui.Button(text='pear')
                self.buttonlabel= ui.Label(text='...')
            with ui.VBox():
                self.r1 = ui.RadioButton(text='apple')
                self.r2 = ui.RadioButton(text='banana')
                self.r3 = ui.RadioButton(text='pear')
                self.radiolabel = ui.Label(text='...')
            with ui.VBox():
                self.c1 = ui.ToggleButton(text='apple')
                self.c2 = ui.ToggleButton(text='banana')
                self.c3 = ui.ToggleButton(text='pear')
                self.checklabel = ui.Label(text='...')
    
    
        @event.reaction('b1.mouse_click', 'b2.mouse_click','b3.mouse_click',  )
        def _button_clicked(self, *events):
            ev = events[-1]
            self.buttonlabel.set_text('Clicked on the ' + ev.source.text)
    
        @event.reaction('r1.checked', 'r2.checked','r3.checked')
        def _radio_changed(self, *events):
            # There will also be events for radio buttons being unchecked, but
            # Flexx ensures that the last event is for the one being checked
            ev = events[-1]
            self.radiolabel.set_text('Selected the ' + ev.source.text)
    
        @event.reaction('c1.checked', 'c2.checked','c3.checked',  )
        def _check_changed(self, *events):
            selected = [c.text for c in (self.c1, self.c2, self.c3) if c.checked]
            if selected:
                self.checklabel.set_text('Selected: ' + ', '.join(selected))
            else:
                self.checklabel.set_text('None selected')

"""

from ... import event
from .._widget import Widget


class BaseButton(Widget):
    """ Abstract button class.
    """

    CSS = """

    .flx-BaseButton {
        min-height: 16px;
        white-space: nowrap;
        padding: 0.2em 0.4em;
        border-radius: 3px;
        color: #333;
    }
    .flx-BaseButton, .flx-BaseButton > input {
        margin: 2px; /* room for outline */
    }
    .flx-BaseButton:focus, .flx-BaseButton > input:focus  {
        outline: none;
        box-shadow: 0px 0px 3px 1px rgba(0, 100, 200, 0.7);
    }
    
    .flx-Button, .flx-ToggleButton{
        background: #e8e8e8;
        border: 1px solid #ccc;
        transition: background 0.3s;
    }
    .flx-Button:hover, .flx-ToggleButton:hover {
        background: #e8eaff;
    }
    
    .flx-ToggleButton {
        text-align: left;
    }
    .flx-ToggleButton.flx-checked {
        background: #e8eaff;
    }
    .flx-ToggleButton::before {
        content: '\\2610\\00a0 ';
    }
    .flx-ToggleButton.flx-checked::before {
        content: '\\2611\\00a0 ';
    }
    
    .flx-RadioButton > input, .flx-CheckBox > input{
        margin-left: 0.3em;
        margin-right: 0.3em;
    }
    
    .flx-RadioButton > input, .flx-CheckBox > input {
        color: #333;
    }
    .flx-RadioButton:hover > input, .flx-CheckBox:hover > input {
        color: #036;
    }

    
    """

    text = event.StringProp('', settable=True, doc="""
        The text on the button.
        """)
    checked = event.BoolProp(False, settable=True, doc="""
        Whether the button is checked.
        """)
    disabled = event.BoolProp(False, settable=True, doc="""
        Whether the button is disabled.
        """)
    
    @event.emitter
    def mouse_click(self, e):
        """ Event emitted when the mouse is clicked.

        See mouse_down() for a description of the event object.
        """
        e.target.blur()
        return self._create_mouse_event(e)


class Button(BaseButton):
    """ A push button.
    """

    def _create_dom(self):
        global window
        node = window.document.createElement('button')
        # node = window.document.createElement('input')
        # node.setAttribute('type', 'button')
        self._addEventListener(node, 'click', self.mouse_click, 0)
        return node

    def _render_dom(self):
        return [self.text]
    
    @event.reaction('disabled')
    def __disabled_changed(self, *events):
        if events[-1].new_value:
            self.node.setAttribute("disabled", "disabled")
        else:
            self.node.removeAttribute("disabled")


class ToggleButton(BaseButton):
    """ A button that can be toggled. It behaves like a checkbox, while
    looking more like a regular button.
    """
    
    def _create_dom(self):
        global window
        node = window.document.createElement('button')
        self._addEventListener(node, 'click', self.mouse_click, 0)
        return node
    
    def _render_dom(self):
        return [self.text]
    
    @event.reaction('mouse_click')
    def __toggle_checked(self, *events):
        self.set_checked(not self.checked)

    @event.reaction('checked')
    def __check_changed(self, *events):
        if self.checked:
            self.node.classList.add('flx-checked')
        else:
            self.node.classList.remove('flx-checked')


class RadioButton(BaseButton):
    """ A radio button. Of any group of radio buttons that share the
    same parent, only one can be active.
    """
    
    def _create_dom(self):
        global window
        outernode = window.document.createElement('label')
        node = window.document.createElement('input')
        outernode.appendChild(node)
        
        node.setAttribute('type', 'radio')
        node.setAttribute('id', self.id)
        outernode.setAttribute('for', self.id)
        self._addEventListener(node, 'click', self._check_radio_click, 0)
        
        return outernode, node
    
    def _render_dom(self):
        return [self.node, self.text]
    
    @event.reaction('parent')
    def __update_group(self, *events):
        if self.parent:
            self.node.name = self.parent.id

    @event.reaction('checked')
    def __check_changed(self, *events):
        self.node.checked = self.checked
    
    def _check_radio_click(self, ev):
        """ This method is called on JS a click event. We *first* update
        the checked properties, and then emit the Flexx click event.
        That way, one can connect to the click event and have an
        up-to-date checked props (even on Py).
        """
        # Turn off any radio buttons in the same group
        if self.parent:
            for child in self.parent.children:
                if isinstance(child, RadioButton) and child is not self:
                    child.set_checked(child.node.checked)
        # Turn on this button (last)
        self.set_checked(self.node.checked)
        # Process actual click event
        self.mouse_click(ev)


class CheckBox(BaseButton):
    """ A checkbox button.
    """
   
    def _create_dom(self):
        global window
        outernode = window.document.createElement('label')
        node = window.document.createElement('input')
        outernode.appendChild(node)
        
        node.setAttribute('type', 'checkbox')
        node.setAttribute('id', self.id)
        outernode.setAttribute('for', self.id)
        self._addEventListener(node, 'click', self._check_changed_from_dom, 0)
        
        return outernode, node
    
    def _render_dom(self):
        return [self.node, self.text]
    
    @event.reaction('checked')
    def __check_changed(self, *events):
        self.node.checked = self.checked

    def _check_changed_from_dom(self, ev):
        self.set_checked(self.node.checked)
