/*
 * WBI Indicator Explorer
 *
 * Copyright 2015 Sebastian Nogara <[email protected]>
 *
 * This file is part of WBI.
 *
 * 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/>.
 */

package client.ui.components;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.SpanElement;
import com.google.gwt.dom.client.Style;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HasText;
import com.google.gwt.user.client.ui.Widget;

/**
 * Button with enhanced look and feel.
 */
public class MaterialButton extends Composite
    implements HasText, HasClickHandlers, ClickHandler {

    /**
     * {@link MaterialButton} element class.
     */
    public static enum Class {
        /**
         * Class added to animate the {@code MaterialButton}.
         */
        ANIMATE("animate"),

        /**
         * Class added to select the {@code MaterialButton}.
         */
        SELECTED("selected");

        /**
         * Class name.
         */
        private String name;

        /**
         * Initialize {@code Class}.
         *
         * @param name Class name.
         */
        private Class(String name) {
            this.name = name;
        }

        /**
         * Get class name.
         *
         * @return Class name.
         */
        public String getName() {
            return name;
        }
    }

    public interface MaterialButtonUiBinder
        extends UiBinder<Widget, MaterialButton> {}
    private static MaterialButtonUiBinder uiBinder =
        GWT.create(MaterialButtonUiBinder.class);

    /**
     * Main {@code Widget}.
     */
    @UiField
    public Anchor anchor;

    /**
     * Button text.
     */
    @UiField
    public SpanElement label;

    /**
     * Ink for ripple animation.
     */
    @UiField
    public SpanElement ink;

    /**
     * Whether animations are enabled by default.
     */
    private static final boolean DEFAULT_ANIMATION_ENABLED = false;

    /**
     * Whether animations are enabled.
     */
    private boolean animationEnabled;

    /**
     * Initialize {@code MaterialButton}.
     */
    public MaterialButton() {
        initWidget(uiBinder.createAndBindUi(this));
        anchor.addClickHandler(this);
    }

    /**
     * Initialize {@code MaterialButton}.
     *
     * @param text Button text.
     * @param animationEnabled Whether animations are enabled.
     */
    public MaterialButton(String text, boolean animationEnabled) {
        this();

        setText(text);
        setAnimationEnabled(animationEnabled);
    }

    /**
     * Initialize {@code MaterialButton}.
     *
     * @param text Button text.
     */
    public MaterialButton(String text) {
        this(text, DEFAULT_ANIMATION_ENABLED);
    }

    /**
     * Set whether animations are enabled.
     *
     * @param animationEnabled Whether animations are enabled.
     */
    public void setAnimationEnabled(boolean animationEnabled) {
        this.animationEnabled = animationEnabled;
    }

    @Override
    public void onClick(ClickEvent event) {
        if (animationEnabled) {
            ink.removeClassName(Class.ANIMATE.getName());

            Style style = ink.getStyle();
            int size = anchor.getOffsetWidth();

            style.setWidth(size, Style.Unit.PX);
            style.setHeight(size, Style.Unit.PX);
            style.setMarginLeft(-size / 2, Style.Unit.PX);
            style.setMarginTop(-size / 2, Style.Unit.PX);

            style.setLeft(event.getX(), Style.Unit.PX);
            style.setTop(event.getY(), Style.Unit.PX);

            ink.addClassName(Class.ANIMATE.getName());
        }
    }

    @Override
    public HandlerRegistration addClickHandler(ClickHandler handler) {
        return anchor.addClickHandler(handler);
    }

    @Override
    public void setText(String text) {
        label.setInnerText(text);
    }

    @Override
    public String getText() {
        return label.getInnerText();
    }

    /**
     * Toggle the specified class.
     *
     * @param cls {@link Class} to toggle.
     * @param toggle Whether to add or remove the class.
     */
    private void toggleClass(Class cls, boolean toggle) {
        Element anchorElement = anchor.getElement();
        if (toggle) {
            anchorElement.addClassName(cls.getName());
        } else {
            anchorElement.removeClassName(cls.getName());
        }
    }

    /**
     * Set whether the button is selected.
     *
     * @param selected Whether the button is selected.
     */
    public void setSelected(boolean selected) {
        toggleClass(Class.SELECTED, selected);
    }
}