/*
 * Copyright (c) 2017 by Gerrit Grunwald
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.point85.tilesfx.skins;

import org.point85.tilesfx.Tile;
import org.point85.tilesfx.events.SwitchEvent;
import org.point85.tilesfx.fonts.Fonts;
import org.point85.tilesfx.tools.Helper;

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.beans.InvalidationListener;
import javafx.event.EventHandler;
import javafx.event.EventType;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.util.Duration;


/**
 * Created by hansolo on 19.12.16.
 */
public class SwitchTileSkin extends TileSkin {
    private static final SwitchEvent SWITCH_PRESSED  = new SwitchEvent(SwitchEvent.SWITCH_PRESSED);
    private static final SwitchEvent SWITCH_RELEASED = new SwitchEvent(SwitchEvent.SWITCH_RELEASED);
    private Text                     titleText;
    private Text                     text;
    private Label                    description;
    private Rectangle                switchBorder;
    private Rectangle                switchBackground;
    private Circle                   thumb;
    private Timeline                 timeline;
    private EventHandler<MouseEvent> mouseEventHandler;
    private InvalidationListener     selectedListener;


    // ******************** Constructors **************************************
    public SwitchTileSkin(final Tile TILE) {
        super(TILE);
    }


    // ******************** Initialization ************************************
    @SuppressWarnings("rawtypes")
	@Override protected void initGraphics() {
        super.initGraphics();

        mouseEventHandler = e -> {
            final EventType TYPE = e.getEventType();
            if (MouseEvent.MOUSE_PRESSED == TYPE) {
                tile.setActive(!tile.isActive());
                tile.fireEvent(SWITCH_PRESSED);
            } else if(MouseEvent.MOUSE_RELEASED == TYPE) {
                tile.fireEvent(SWITCH_RELEASED);
            }
        };
        selectedListener = o -> moveThumb();

        timeline = new Timeline();

        titleText = new Text();
        titleText.setFill(tile.getTitleColor());
        Helper.enableNode(titleText, !tile.getTitle().isEmpty());

        text = new Text(tile.getText());
        text.setFill(tile.getUnitColor());
        Helper.enableNode(text, tile.isTextVisible());

        description = new Label(tile.getDescription());
        description.setAlignment(tile.getDescriptionAlignment());
        description.setWrapText(true);
        description.setTextFill(tile.getTextColor());
        Helper.enableNode(description, !tile.getDescription().isEmpty());

        switchBorder = new Rectangle();

        switchBackground = new Rectangle();
        switchBackground.setMouseTransparent(true);
        switchBackground.setFill(tile.isActive() ? tile.getActiveColor() : tile.getBackgroundColor());

        thumb = new Circle();
        thumb.setMouseTransparent(true);
        thumb.setEffect(shadow);

        getPane().getChildren().addAll(titleText, text, description, switchBorder, switchBackground, thumb);
    }

    @Override protected void registerListeners() {
        super.registerListeners();
        switchBorder.addEventHandler(MouseEvent.MOUSE_PRESSED, mouseEventHandler);
        switchBorder.addEventHandler(MouseEvent.MOUSE_RELEASED, mouseEventHandler);
        tile.activeProperty().addListener(selectedListener);
    }


    // ******************** Methods *******************************************
    @Override protected void handleEvents(final String EVENT_TYPE) {
        super.handleEvents(EVENT_TYPE);

        if ("VISIBILITY".equals(EVENT_TYPE)) {
            Helper.enableNode(titleText, !tile.getTitle().isEmpty());
            Helper.enableNode(text, tile.isTextVisible());
            Helper.enableNode(description, !tile.getDescription().isEmpty());
        }
    }

    private void moveThumb() {
        KeyValue thumbLeftX                 = new KeyValue(thumb.centerXProperty(), switchBackground.getLayoutX() + size * 0.1);
        KeyValue thumbRightX                = new KeyValue(thumb.centerXProperty(), switchBackground.getLayoutX() + switchBackground.getWidth() - size * 0.1);
        KeyValue switchBackgroundLeftColor  = new KeyValue(switchBackground.fillProperty(), tile.getBackgroundColor());
        KeyValue switchBackgroundRightColor = new KeyValue(switchBackground.fillProperty(), tile.getActiveColor());
        if (tile.isActive()) {
            // move thumb from left to the right
            KeyFrame kf0 = new KeyFrame(Duration.ZERO, thumbLeftX, switchBackgroundLeftColor);
            KeyFrame kf1 = new KeyFrame(Duration.millis(200), thumbRightX, switchBackgroundRightColor);
            timeline.getKeyFrames().setAll(kf0, kf1);
        } else {
            // move thumb from right to the left
            KeyFrame kf0 = new KeyFrame(Duration.ZERO, thumbRightX, switchBackgroundRightColor);
            KeyFrame kf1 = new KeyFrame(Duration.millis(200), thumbLeftX, switchBackgroundLeftColor);
            timeline.getKeyFrames().setAll(kf0, kf1);
        }
        timeline.play();
    }

    @Override public void dispose() {
        switchBorder.removeEventHandler(MouseEvent.MOUSE_PRESSED, mouseEventHandler);
        switchBorder.removeEventHandler(MouseEvent.MOUSE_RELEASED, mouseEventHandler);
        tile.activeProperty().removeListener(selectedListener);
        super.dispose();
    }


    // ******************** Resizing ******************************************
    @Override protected void resizeStaticText() {
        double maxWidth = width - size * 0.1;
        double fontSize = size * textSize.factor;

        titleText.setFont(Fonts.latoRegular(fontSize));
        if (titleText.getLayoutBounds().getWidth() > maxWidth) { Helper.adjustTextSize(titleText, maxWidth, fontSize); }
        switch(tile.getTitleAlignment()) {
            default    :
            case LEFT  : titleText.relocate(size * 0.05, size * 0.05); break;
            case CENTER: titleText.relocate((width - titleText.getLayoutBounds().getWidth()) * 0.5, size * 0.05); break;
            case RIGHT : titleText.relocate(width - (size * 0.05) - titleText.getLayoutBounds().getWidth(), size * 0.05); break;
        }

        fontSize = size * textSize.factor;
        text.setText(tile.getText());
        text.setFont(Fonts.latoRegular(fontSize));
        if (text.getLayoutBounds().getWidth() > maxWidth) { Helper.adjustTextSize(text, maxWidth, fontSize); }
        switch(tile.getTextAlignment()) {
            default    :
            case LEFT  : text.setX(size * 0.05); break;
            case CENTER: text.setX((width - text.getLayoutBounds().getWidth()) * 0.5); break;
            case RIGHT : text.setX(width - (size * 0.05) - text.getLayoutBounds().getWidth()); break;
        }
        text.setY(height - size * 0.05);

        fontSize = size * 0.1;
        description.setFont(Fonts.latoRegular(fontSize));
    }

    @Override protected void resize() {
        super.resize();

        description.setPrefSize(contentBounds.getWidth(), size * 0.43);
        description.relocate(contentBounds.getX(), height * 0.42);

        switchBorder.setWidth(size * 0.445);
        switchBorder.setHeight(size * 0.22);
        switchBorder.setArcWidth(size * 0.22);
        switchBorder.setArcHeight(size * 0.22);
        switchBorder.relocate((width - switchBorder.getWidth()) * 0.5, tile.getDescription().isEmpty() ? (height - switchBorder.getHeight()) * 0.5 : height - size * 0.40);

        switchBackground.setWidth(size * 0.425);
        switchBackground.setHeight(size * 0.2);
        switchBackground.setArcWidth(size * 0.2);
        switchBackground.setArcHeight(size * 0.2);
        switchBackground.relocate((width - switchBackground.getWidth()) * 0.5, tile.getDescription().isEmpty() ? (height - switchBackground.getHeight()) * 0.5 : height - size * 0.39);

        thumb.setRadius(size * 0.09);
        thumb.setCenterX(tile.isActive() ? width * 0.6125 : width * 0.3875);
        thumb.setCenterX(tile.isActive() ? switchBackground.getLayoutX() + switchBackground.getWidth() - size * 0.1 : switchBackground.getLayoutX() + size * 0.1);
        thumb.setCenterY(tile.getDescription().isEmpty() ? height * 0.5 : height - size * 0.29);
    }

    @Override protected void redraw() {
        super.redraw();
        titleText.setText(tile.getTitle());
        text.setText(tile.getText());
        description.setText(tile.getDescription());
        description.setAlignment(tile.getDescriptionAlignment());

        resizeStaticText();

        titleText.setFill(tile.getTitleColor());
        text.setFill(tile.getTextColor());
        description.setTextFill(tile.getDescriptionColor());
        switchBorder.setFill(tile.getForegroundColor());
        thumb.setFill(tile.getForegroundColor());
    }
}