/*
 *    Geotoolkit - An Open Source Java GIS Toolkit
 *    http://www.geotoolkit.org
 *
 *    (C) 2015, Geomatys
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License as published by the Free Software Foundation;
 *    version 2.1 of the License.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 */
package org.geotoolkit.gui.javafx.parameter;

import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.Node;
import javafx.scene.control.DatePicker;
import org.apache.sis.util.UnconvertibleObjectException;

/**
 * COPIED FROM GEOTOOLKIT 4.0.0-M0082. Aim is to simplify edition.
 *
 * @author Alexis Manin (Geomatys)
 */
public class FXDateEditor extends FXValueEditor {

    static final Class[] SUPPORTED_CLASSES = new Class[]{Date.class, LocalDate.class, LocalDateTime.class};

    private final SimpleObjectProperty dateProperty = new SimpleObjectProperty();
    private final DatePicker editor = new DatePicker();

    public FXDateEditor(final Spi spi) {
        super(spi);

        dateProperty.addListener((ObservableValue observable, Object oldValue, Object newValue) -> {
            if (editor.valueProperty().isBound())
                return; // Do not throw exception, because user has set editor property as a target for one of his own property.

            if (newValue == null)
                editor.valueProperty().set(null);
            else if (newValue instanceof LocalDateTime)
                editor.valueProperty().set(((LocalDateTime)newValue).toLocalDate());
            else if (newValue instanceof LocalDate)
                editor.valueProperty().set((LocalDate)newValue);
            else if (newValue instanceof Date) {
                editor.valueProperty().set(new Timestamp(((Date)newValue).getTime()).toLocalDateTime().toLocalDate());
            } else throw new UnconvertibleObjectException("Cannot convert from "+newValue.getClass() + " to "+LocalDate.class);
        });

        editor.valueProperty().addListener((ObservableValue<? extends LocalDate> observable, LocalDate oldValue, LocalDate newValue) -> {
            if (dateProperty.isBound())
                return; // Do not throw exception, because user has set exposed property as a target for one of his own property.

            if (newValue == null) {
                dateProperty.set(null);
            } else {
                Class valueClass = getValueClass();
                if (valueClass == null)
                    dateProperty.set(newValue); // TODO : throw an exception ? editor has not been configured, but user already started to work with it.
                else if (LocalDateTime.class.isAssignableFrom(valueClass))
                    dateProperty.set(newValue.atStartOfDay());
                else if (LocalDate.class.isAssignableFrom(valueClass))
                    dateProperty.set(newValue);
                else if (Date.class.isAssignableFrom(valueClass))
                    dateProperty.set(Timestamp.valueOf(newValue.atStartOfDay()));
            }
        });
    }

    @Override
    public Property valueProperty() {
        return dateProperty;
    }

    @Override
    public Node getComponent() {
        return editor;
    }

    /**
     * SPI
     */
    public static final class Spi extends FXValueEditorSpi {

        @Override
        public boolean canHandle(Class binding) {
            for (final Class c : SUPPORTED_CLASSES) {
                if (c.isAssignableFrom(binding))
                    return true;
            }
            return false;
        }

        @Override
        public FXValueEditor createEditor() {
            return new FXDateEditor(this);
        }
    }
}
