package org.wicketstuff.openlayers3.examples;

import java.util.Arrays;

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.model.Model;
import org.apache.wicket.util.string.Strings;
import org.wicketstuff.annotation.mount.MountPath;
import org.wicketstuff.openlayers3.DefaultOpenLayersMap;
import org.wicketstuff.openlayers3.OpenLayersMap;
import org.wicketstuff.openlayers3.api.Map;
import org.wicketstuff.openlayers3.api.View;
import org.wicketstuff.openlayers3.api.coordinate.LongLat;
import org.wicketstuff.openlayers3.api.format.GeoJsonFormat;
import org.wicketstuff.openlayers3.api.layer.Layer;
import org.wicketstuff.openlayers3.api.layer.Tile;
import org.wicketstuff.openlayers3.api.layer.Vector;
import org.wicketstuff.openlayers3.api.overlay.Overlay;
import org.wicketstuff.openlayers3.api.proj.Projection;
import org.wicketstuff.openlayers3.api.source.tile.Osm;
import org.wicketstuff.openlayers3.api.source.vector.VectorSource;
import org.wicketstuff.openlayers3.api.source.vector.loader.DefaultGeoJsonLoader;
import org.wicketstuff.openlayers3.api.style.Icon;
import org.wicketstuff.openlayers3.api.style.Style;
import org.wicketstuff.openlayers3.api.util.Color;
import org.wicketstuff.openlayers3.api.util.CorsPolicy;
import org.wicketstuff.openlayers3.behavior.ClickFeatureHandler;
import org.wicketstuff.openlayers3.component.MarkerPopover;
import org.wicketstuff.openlayers3.component.PopoverPanel;
import org.wicketstuff.openlayers3.examples.base.BasePage;

import com.google.gson.JsonArray;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;

/**
 * Provides a page demonstrating WFS (Web Feature Service) data.
 */
@MountPath("/wfs")
public class WfsPage extends BasePage {

    /**
     * Popover for providing detail on markers.
     */
    private PopoverPanel popoverPanel;

    /**
     * Map instance.
     */
    private OpenLayersMap map;

    /**
     * Marker over Miles' office.
     */
    private MarkerPopover markerPopover;

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

        // create our popover panel
        add(popoverPanel = new PopoverPanel("popover"));

        // location of Miles' office
        LongLat longLat = new LongLat(-72.638429, 42.313229, "EPSG:4326").transform(View.DEFAULT_PROJECTION);

        // add a marker that will update the content of the popover, move the popover and then make it visible when
        // the marker is clicked
        add(markerPopover = new MarkerPopover("marker",
                Model.of(new Color("#8b0000")),
                popoverPanel,
                Model.of("Miles' Office"),
                Model.of("<p>This is where Miles' labors away on his code</p>"),
                Model.of(longLat)));

        // style for map features
        Style style = new Style(new Icon("http://api.tiles.mapbox.com/mapbox.js/v2.0.1/images/marker-icon.png")
                .crossOrigin(CorsPolicy.ANONYMOUS));

        // create and add our marker
        map = new DefaultOpenLayersMap("map",

                // create the model for our map
                Model.of(new Map(

                        // list of layers
                        Arrays.<Layer>asList(

                                // a new tile layer with the map of the world
                                new Tile("Streets",

                                        // a new web map service tile layer
                                        new Osm()),

                                // add our vector layer with the data
                                new Vector(new VectorSource(new GeoJsonFormat(),
                                        new DefaultGeoJsonLoader(
                                                "http://mhc-macris.net:8080/geoserver/ows?service=WFS"
                                                        + "&version=1.0.0&request=GetFeature&typeName=MHC:in_pts"
                                                        + "&outputFormat=json",
                                                "EPSG:3857"),
                                        new Projection("EPSG:3857", "degress", "nue")), style)),

                        // list of overlays
                        Arrays.<Overlay>asList(

                                // overlay with the popover
                                popoverPanel.getPopover(),

                                // overlay with our marker and popover
                                new Overlay(markerPopover,

                                        // position of the overlay
                                        longLat,

                                        // position of the overlay relative to the point
                                        Overlay.Positioning.BottomCenter)),

                        // view for this map
                        new View(

                                // center the map on Miles' office
                                longLat,

                                // zoom level for the view
                                16))));

        // add a handler for feature clicks
        map.add(new ClickFeatureHandler("EPSG:4326") {

            @Override
            public void handleClick(AjaxRequestTarget target, String featureId, LongLat longLat,
                                    JsonObject properties) {

                // get the coordinates for the feature
                JsonArray coordinates = properties.get("geometry").getAsJsonArray();
                Double longitude = coordinates.get(0).getAsDouble();
                Double latitude = coordinates.get(1).getAsDouble();
                LongLat coordinate = new LongLat(longitude, latitude, "EPSG:4326").transform(View.DEFAULT_PROJECTION);

                // parse out the name of the feature
                String name =parseField(properties, "HISTORIC_N");
                if(name.isEmpty()) {
                    name = parseField(properties, "USE_TYPE");
                }

                // parse out the address for the feature
                StringBuilder address = new StringBuilder();
                address.append(parseField(properties, "ADDRESS"));
                address.append("</br>");
                address.append(parseField(properties, "TOWN_NAME"));

                // parse out constructed year
                String constructed = parseField(properties, "CONSTRUCTI");

                // assemble our description
                StringBuffer description = new StringBuffer();
                description.append("<p>" + "c. ");
                description.append(constructed + "</p>");
                description.append("<p>" + address.toString() + "</p>");

                // update and display the popover with facility data
                popoverPanel.getTitleModel().setObject(name);
                popoverPanel.getContentModel().setObject(description.toString());
                popoverPanel.setPosition(coordinate);
                popoverPanel.show(target);
            }

            @Override
            public void handleClickMiss(AjaxRequestTarget target, LongLat longLat) {

                popoverPanel.hide(target);
            }
        });

        add(map);
    }

    /**
     * Parses out a field of data from a JSON object.
     *
     * @param properties JSON object with the properties
     * @param field Field to parse
     * @return String with the parsed data
     */
    private String parseField(JsonObject properties, String field) {

        String value = "";

        if (!(properties.get(field) instanceof JsonNull) && properties.get(field) != null) {
            value = Strings.escapeMarkup(properties.get(field).getAsString()).toString();
        }

        return value;
    }
}
