/**
 * Copyright © CENRA (2016)
 *
 * remi.clement@espaces-naturels.fr
 * 
 * This software is a multi-platform and portable application based on 
 * the scientifical toolbox to monitor wetlands. With this toolbox it’s 
 * possible to calculate indicators «RhoMéO» to monitor quality, 
 * fonctionalities and urban and agricultural pressures of wetlands. 
 * Indicators are calculated using naturalist data entered and/or imported,
 * and geographic data downloaded from a geographic server.
 * 
 * This software is governed by the CeCILL license under French law and
 * abiding by the rules of distribution of free software.  You can  use, 
 * modify and/ or redistribute the software under the terms of the CeCILL
 * license as circulated by CEA, CNRS and INRIA at the following URL
 * "http://www.cecill.info". 
 * 
 * As a counterpart to the access to the source code and  rights to copy,
 * modify and redistribute granted by the license, users are provided only
 * with a limited warranty  and the software's author,  the holder of the
 * economic rights,  and the successive licensors  have only  limited
 * liability. 
 * 
 * In this respect, the user's attention is drawn to the risks associated
 * with loading,  using,  modifying and/or developing or reproducing the
 * software by the user in light of its specific status of free software,
 * that may mean  that it is complicated to manipulate,  and  that  also
 * therefore means  that it is reserved for developers  and  experienced
 * professionals having in-depth computer knowledge. Users are therefore
 * encouraged to load and test the software's suitability as regards their
 * requirements in conditions enabling the security of their systems and/or 
 * data to be ensured and,  more generally, to use and operate it in the 
 * same conditions as regards security. 
 * 
 * The fact that you are presently reading this means that you have had
 * knowledge of the CeCILL license and that you accept its terms.
*/
package fr.cenra.rhomeo.fx;

import fr.cenra.rhomeo.api.result.IndicatorValuesByYearItem;
import java.util.HashMap;
import javafx.beans.binding.Bindings;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.ScatterChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TablePosition;
import javafx.scene.control.TableView;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import org.springframework.stereotype.Component;
import fr.cenra.rhomeo.api.ui.DashboardMenuItem;
import java.util.Map;
import java.util.Optional;

/**
 *
 * @author Alexis Manin (Geomatys)
 */
@Component
public class GraphDashboardItem implements DashboardMenuItem {

    private static final String GRAPH_TITLE = "Évolution des valeurs indicatrices";

    @Override
    public Optional<MenuItem> createItem(final TableView<IndicatorValuesByYearItem> target) {
        final MenuItem graphItem = new MenuItem("Graphique d'évolution");
        graphItem.setOnAction(evt -> displayGraph(target));
        graphItem.visibleProperty().bind(Bindings.size(target.getSelectionModel().getSelectedIndices()).greaterThan(1));
        return Optional.of(graphItem);
    }


    /**
     * Display the evolution graph in a modal window.
     */
    private static void displayGraph(final TableView<IndicatorValuesByYearItem> source) {
        if (source.getScene() == null || source.getScene().getWindow() == null)
            return;
        final Stage chartStage = new Stage(StageStyle.UTILITY);
        chartStage.initModality(Modality.WINDOW_MODAL);
        chartStage.initOwner(source.getScene().getWindow());
        chartStage.setTitle(GRAPH_TITLE);
        chartStage.setScene(new Scene(createChart(source)));

        chartStage.show();
    }

    /**
     * Create a point chart to display selected indicator values from dashboard.
     * @return A chart to display selected values.
     */
    private static XYChart<Number, Number> createChart(final TableView<IndicatorValuesByYearItem> source) {
        final Map<String, XYChart.Series<Number, Number>> series = new HashMap<>();
        final ObservableList<TablePosition> selectedCells = source.getSelectionModel().getSelectedCells();
        Double cellData;
        int year;
        IndicatorSiteColumn col;
        int minYear = Integer.MAX_VALUE;
        int maxYear = Integer.MIN_VALUE;
        double minValue = Double.MAX_VALUE;
        double maxValue = Double.MIN_VALUE;
        for (final TablePosition pos : selectedCells) {
            if (pos.getTableColumn() instanceof IndicatorSiteColumn) {
                col = (IndicatorSiteColumn) pos.getTableColumn();
                cellData = col.getCellData(pos.getRow());
                if (cellData != null && Double.isFinite(cellData)) {
                    year = source.getItems().get(pos.getRow()).getYear();
                    minYear = StrictMath.min(year, minYear);
                    maxYear = StrictMath.max(year, maxYear);
                    minValue = StrictMath.min(cellData, minValue);
                    maxValue = StrictMath.max(cellData, maxValue);

                    series.computeIfAbsent(col.getIndicator().getTitle(), (title) -> {
                        final XYChart.Series<Number, Number> s = new XYChart.Series<>();
                        s.setName(title);
                        return s;
                    }).getData().add(new XYChart.Data<>(year, cellData));
                }
            }
        }

        final XYChart<Number, Number> chart = new ScatterChart<>(
                new NumberAxis("Année", minYear - 1, maxYear + 1, 5),
                new NumberAxis("Valeur", minValue - 0.5, maxValue + 0.5, 0.5)
        );

        chart.setTitle(GRAPH_TITLE);
        chart.getData().addAll(series.values());
        chart.getData().sort((o1, o2) -> o1.getName().compareTo(o2.getName()));
        chart.setPadding(new Insets(10));
        return chart;
    }
}
