
/**
 * 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.p08;

import com.vividsolutions.jts.geom.Geometry;
import fr.cenra.rhomeo.Rhomeo;
import fr.cenra.rhomeo.api.data.Site;
import fr.cenra.rhomeo.api.process.Indicator;
import fr.cenra.rhomeo.api.process.ProcessContext;
import fr.cenra.rhomeo.core.BeanUtils;
import fr.cenra.rhomeo.core.Session;
import fr.cenra.rhomeo.core.WorkflowStep;
import fr.cenra.rhomeo.core.data.county.CountyRepository;
import fr.cenra.rhomeo.core.data.reference.GeoReferential;
import fr.cenra.rhomeo.core.data.reference.GeoReferentials;
import fr.cenra.rhomeo.core.util.GeometryUtils;
import fr.cenra.rhomeo.protocol.p08.I12;
import java.awt.Color;
import java.util.List;
import java.util.Optional;
import java.util.logging.Level;
import java.util.stream.Collectors;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javax.annotation.PostConstruct;
import org.geotoolkit.data.FeatureStoreUtilities;
import org.geotoolkit.data.bean.BeanFeature;
import org.geotoolkit.display2d.GO2Utilities;
import org.geotoolkit.feature.Feature;
import org.geotoolkit.feature.FeatureBuilder;
import org.geotoolkit.gui.javafx.render2d.FXMapFrame;
import org.geotoolkit.map.FeatureMapLayer;
import org.geotoolkit.map.MapBuilder;
import org.geotoolkit.map.MapContext;
import org.geotoolkit.map.MapItem;
import org.geotoolkit.map.MapLayer;
import org.geotoolkit.style.MutableStyleFactory;
import org.opengis.feature.Property;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.expression.PropertyName;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

/**
 *
 * @author Johann Sorel (Geomatys)
 */
@Component
@Scope("prototype")
public class FXP08DatasetPane extends VBox {

    @Autowired
    private Session session;

    @Autowired
    private GeoReferentials geoRef;

    @Autowired
    @Qualifier(I12.NAME)
    private Indicator indicator;

    @FXML
    private Button next;

    @FXML
    private BorderPane tableSpace;

    @Autowired(required = false)
    private CountyRepository countyRepository;

    private FXGeoReferentialTable table;

    public FXP08DatasetPane() {
        Rhomeo.loadFXML(this);
    }

    @PostConstruct
    private void postConstruct() {
        table = new FXGeoReferentialTable(geoRef, session.getDataContext().getSite(),
                GeoReferentials.TYPE_ZONE_HYDRO,
                GeoReferentials.TYPE_TACHE_ARTIF,
                GeoReferentials.TYPE_TACHE_URBAINE);
        tableSpace.setCenter(table);
    }

    @FXML
    void nextStep(ActionEvent event) {

        //check there is at least one year of data available
        int nbAvailable = 0;
        final ObservableList<GeoReferential> items = table.getItems();
        for(GeoReferential ref : items){
            //we need zone hydro,tache artif and tache_urbaine
            if(ref.zoneHydroLocal().get()
               && ref.tacheArtifLocal().get()
               && ref.tacheUrbaineLocal().get()) nbAvailable++;
        }

        if (nbAvailable <= 0) {
            Rhomeo.showAlert(Alert.AlertType.WARNING, "Impossible de passer à l'étape suivante : Aucun réferentiel téléchargé.");
            return;
        }

        final ProcessContext ctx = new ProcessContext(session.getDataset(), session.getDataContext());
        ctx.getIndicators().add(indicator);
        session.setProcessContext(ctx);

        if (!session.requestWorkflowStep(WorkflowStep.PROCESS)) {
            Rhomeo.showAlert(Alert.AlertType.WARNING, "Impossible de passer à l'étape suivante. Veuillez vérifier votre lot de données.");
        }
    }

    @FXML
    private void showMap() throws Exception {
        final Site currentSite = session.getDataContext().getSite();
        // Should not be null when called here
        if (currentSite == null) {
            throw new IllegalArgumentException("Currently selected site was null here, but shouldn't be");
        }

        // If counties are available, we display them on the map.
        final MapContext context = MapBuilder.createContext();
        final MutableStyleFactory sf = GO2Utilities.STYLE_FACTORY;

        if (countyRepository != null) {
            try {
                context.layers().add(MapBuilder.createFeatureLayer(countyRepository.getFeatures(), sf.style(sf.lineSymbolizer())
                ));
            } catch (Exception e) {
                Rhomeo.LOGGER.log(Level.WARNING, "Cannot show county layer", e);
            }
        }

        final BeanFeature feature = new BeanFeature(currentSite, BeanUtils.createMapping(Site.class, null));
        final MapLayer layer = MapBuilder.createFeatureLayer(FeatureStoreUtilities.collection(feature), sf.style(sf.polygonSymbolizer(null, sf.fill(Color.red), null)));
        layer.setName("Site");
        context.layers().add(layer);
        context.setAreaOfInterest(layer.getBounds());

        Geometry buffer = GeometryUtils.computeBuffer(currentSite.getGeometry());
        final FeatureBuilder fb = new FeatureBuilder(feature.getType());
        for (final Property p : feature.getProperties()) {
            if (p.getValue() instanceof Geometry)
                fb.setPropertyValue(p.getName(), buffer);
            else
                fb.setPropertyValue(p.getName(), p.getValue());
        }
        final Feature bufferFeature = fb.buildFeature("buffer");
        final FeatureMapLayer bufferLayer = MapBuilder.createFeatureLayer(FeatureStoreUtilities.collection(bufferFeature));
        bufferLayer.setName("Buffer");
        context.layers().add(1, bufferLayer);

        final FilterFactory2 ff = GO2Utilities.FILTER_FACTORY;
        final PropertyName geomProp = ff.property("geom");

        MapItem zoneHydro = geoRef.getWFSLayers(Optional.of(ff.intersects(geomProp, ff.literal(buffer))), GeoReferentials.TYPE_ZONE_HYDRO);
        zoneHydro = zoneHydro.items().get(0);
        MapItem wfsLayers = geoRef.getWFSLayers(Optional.of(ff.bbox(null, ((MapLayer)zoneHydro).getBounds())), GeoReferentials.TYPE_TACHE_ARTIF, GeoReferentials.TYPE_TACHE_URBAINE, GeoReferentials.TYPE_RPG);
        wfsLayers.setName("BBox filtered");
        context.items().add(0, wfsLayers);

        final List<Geometry> geomCollection = ((FeatureMapLayer)zoneHydro).getCollection().stream()
                .map(feat -> feat.getDefaultGeometryProperty().getValue())
                .filter(geom -> geom instanceof Geometry)
                .map(geom -> (Geometry) geom)
                .collect(Collectors.toList());
        Geometry filterGeom = GO2Utilities.JTS_FACTORY.createGeometryCollection(geomCollection.toArray(new Geometry[geomCollection.size()])).union();
        wfsLayers = geoRef.getWFSLayers(Optional.of(ff.intersects(geomProp, ff.literal(filterGeom))), GeoReferentials.TYPE_TACHE_ARTIF, GeoReferentials.TYPE_TACHE_URBAINE, GeoReferentials.TYPE_RPG);
        wfsLayers.setName("Polygon filtered");
        context.items().add(1, wfsLayers);

        context.items().add(0, zoneHydro);

        FXMapFrame.show(context);
    }
}
