package org.geoserver.kml.builder;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.geoserver.kml.KmlEncodingContext;
import org.geoserver.kml.decorator.KmlDecoratorFactory.KmlDecorator;
import org.geoserver.platform.ServiceException;
import org.geoserver.wms.MapLayerInfo;
import org.geoserver.wms.WMSMapContent;
import org.geotools.data.FeatureSource;
import org.geotools.data.Query;
import org.geotools.feature.FeatureCollection;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.map.Layer;
import org.geotools.referencing.CRS;
import org.geotools.util.logging.Logging;
import org.opengis.filter.Filter;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import de.micromata.opengis.kml.v_2_2_0.Document;
import de.micromata.opengis.kml.v_2_2_0.Kml;
import de.micromata.opengis.kml.v_2_2_0.LookAt;
public abstract class AbstractNetworkLinkBuilder {
static final Logger LOGGER = Logging.getLogger(AbstractNetworkLinkBuilder.class);
protected KmlEncodingContext context;
public AbstractNetworkLinkBuilder(KmlEncodingContext context) {
this.context = context;
}
public Kml buildKMLDocument() {
// prepare kml, document and folder
Kml kml = new Kml();
Document document = kml.createAndSetDocument();
Map formatOptions = context.getRequest().getFormatOptions();
String kmltitle = (String) formatOptions.get("kmltitle");
if(kmltitle == null) {
kmltitle = context.getMapContent().getTitle();
}
document.setName(kmltitle);
// get the callbacks for the document and let them loose
List<KmlDecorator> decorators = context.getDecoratorsForClass(Document.class);
for (KmlDecorator decorator : decorators) {
document = (Document) decorator.decorate(document, context);
if (document == null) {
throw new ServiceException("Coding error in decorator " + decorator
+ ", document objects cannot be set to null");
}
}
encodeDocumentContents(document);
return kml;
}
abstract void encodeDocumentContents(Document document);
/**
* @return the aggregated bounds for all the requested layers, taking into account whether the
* whole layer or filtered bounds is used for each layer
*/
protected ReferencedEnvelope computePerLayerQueryBounds(final WMSMapContent context,
final List<ReferencedEnvelope> target, final LookAt lookAt) {
// no need to compute queried bounds if request explicitly specified the view area
final boolean computeQueryBounds = lookAt == null;
ReferencedEnvelope aggregatedBounds;
try {
boolean longitudeFirst = true;
aggregatedBounds = new ReferencedEnvelope(CRS.decode("EPSG:4326", longitudeFirst));
} catch (Exception e) {
throw new RuntimeException(e);
}
aggregatedBounds.setToNull();
final List<Layer> mapLayers = context.layers();
final List<MapLayerInfo> layerInfos = context.getRequest().getLayers();
for (int i = 0; i < mapLayers.size(); i++) {
final Layer Layer = mapLayers.get(i);
final MapLayerInfo layerInfo = layerInfos.get(i);
ReferencedEnvelope layerLatLongBbox;
layerLatLongBbox = computeLayerBounds(Layer, layerInfo, computeQueryBounds);
try {
layerLatLongBbox = layerLatLongBbox.transform(
aggregatedBounds.getCoordinateReferenceSystem(), true);
} catch (Exception e) {
throw new RuntimeException(e);
}
target.add(layerLatLongBbox);
aggregatedBounds.expandToInclude(layerLatLongBbox);
}
return aggregatedBounds;
}
@SuppressWarnings("rawtypes")
protected ReferencedEnvelope computeLayerBounds(Layer layer, MapLayerInfo layerInfo,
boolean computeQueryBounds) {
final Query layerQuery = layer.getQuery();
// make sure if layer is going to be filtered, the resulting bounds are obtained instead of
// the whole bounds
final Filter filter = layerQuery.getFilter();
if (layerQuery.getFilter() == null || Filter.INCLUDE.equals(filter)) {
computeQueryBounds = false;
}
if (!computeQueryBounds && !layerQuery.isMaxFeaturesUnlimited()) {
computeQueryBounds = true;
}
ReferencedEnvelope layerLatLongBbox = null;
if (computeQueryBounds) {
FeatureSource featureSource = layer.getFeatureSource();
try {
CoordinateReferenceSystem targetCRS = CRS.decode("EPSG:4326");
FeatureCollection features = featureSource.getFeatures(layerQuery);
layerLatLongBbox = features.getBounds();
layerLatLongBbox = layerLatLongBbox.transform(targetCRS, true);
} catch (Exception e) {
LOGGER.info("Error computing bounds for " + featureSource.getName() + " with "
+ layerQuery);
}
}
if (layerLatLongBbox == null) {
try {
layerLatLongBbox = layerInfo.getLatLongBoundingBox();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return layerLatLongBbox;
}
}