package com.revolsys.gis.wms.capabilities;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Element;
import com.revolsys.collection.Parent;
import com.revolsys.geometry.model.BoundingBox;
import com.revolsys.geometry.model.GeometryFactory;
import com.revolsys.gis.wms.WmsClient;
import com.revolsys.raster.GeoreferencedImage;
import com.revolsys.record.io.format.xml.XmlUtil;
import com.revolsys.spring.resource.UrlResource;
import com.revolsys.webservice.WebServiceResource;
public class WmsLayerDefinition implements Parent<WmsLayerDefinition>, WebServiceResource {
private final String abstractDescription;
private Attribution attribution;
private final List<AuthorityUrl> authorityUrls = new ArrayList<>();
private final List<WmsBoundingBox> boundingBoxes = new ArrayList<>();
private final int cascaded;
private final List<FormatUrl> dataUrls = new ArrayList<>();
private final List<Dimension> dimensions = new ArrayList<>();
private final List<Extent> extents = new ArrayList<>();
private final List<FormatUrl> featureListUrls = new ArrayList<>();
private final int fixedHeight;
private final int fixedWidth;
private final List<WmsIdentifier> identifiers = new ArrayList<>();
private final List<String> keywords = new ArrayList<>();
private BoundingBox latLonBoundingBox;
private final List<WmsLayerDefinition> layers = new ArrayList<>();
private final String name;
private final boolean noSubsets;
private final boolean opaque;
private WebServiceResource parent;
private final boolean queryable;
private final List<MetadataUrl> metadataUrls = new ArrayList<>();
private final List<String> srs = new ArrayList<>();
private final List<Style> styles = new ArrayList<>();
private final String title;
private double maximumScale = 0;
private double minimumScale = Long.MAX_VALUE;
public WmsLayerDefinition(final Element layerElement) {
final String queryable = layerElement.getAttribute("queryable");
this.queryable = "1".equals(queryable);
final String opaque = layerElement.getAttribute("opaque");
this.opaque = "1".equals(opaque);
final String noSubsets = layerElement.getAttribute("noSubsets");
this.noSubsets = "1".equals(noSubsets);
this.cascaded = XmlUtil.getAttributeInt(layerElement, "cascaded", 0);
this.fixedWidth = XmlUtil.getAttributeInt(layerElement, "fixedWidth", 0);
this.fixedHeight = XmlUtil.getAttributeInt(layerElement, "fixedHeight", 0);
this.name = XmlUtil.getFirstElementText(layerElement, "Name");
this.title = XmlUtil.getFirstElementText(layerElement, "Title");
this.abstractDescription = XmlUtil.getFirstElementText(layerElement, "Abstract");
XmlUtil.forFirstElement(layerElement, "KeywordList", keywordsElement -> {
XmlUtil.forEachElement(keywordsElement, "Keyword", (keywordElement) -> {
final String keyword = keywordElement.getTextContent();
this.keywords.add(keyword);
});
});
XmlUtil.forEachElement(layerElement, "CRS", (srsElement) -> {
final String srs = srsElement.getTextContent();
this.srs.add(srs);
});
XmlUtil.forEachElement(layerElement, "SRS", (srsElement) -> {
final String srs = srsElement.getTextContent();
this.srs.add(srs);
});
XmlUtil.forFirstElement(layerElement, "LatLonBoundingBox", (boundingBoxElement) -> {
final double minX = XmlUtil.getAttributeDouble(boundingBoxElement, "minx", -180);
final double maxX = XmlUtil.getAttributeDouble(boundingBoxElement, "maxx", 180);
final double minY = XmlUtil.getAttributeDouble(boundingBoxElement, "miny", -90);
final double maxY = XmlUtil.getAttributeDouble(boundingBoxElement, "maxy", 90);
final GeometryFactory geometryFactory = GeometryFactory.floating(4326, 2);
this.latLonBoundingBox = geometryFactory.newBoundingBox(minX, minY, maxX, maxY);
});
XmlUtil.forFirstElement(layerElement, "EX_GeographicBoundingBox", (boundingBoxElement) -> {
final double minX = XmlUtil.getFirstElementDouble(boundingBoxElement, "westBoundLongitude",
-180);
final double maxX = XmlUtil.getFirstElementDouble(boundingBoxElement, "eastBoundLongitude",
180);
final double minY = XmlUtil.getFirstElementDouble(boundingBoxElement, "southBoundLatitude",
-90);
final double maxY = XmlUtil.getFirstElementDouble(boundingBoxElement, "northBoundLatitude",
90);
final GeometryFactory geometryFactory = GeometryFactory.floating(4326, 2);
this.latLonBoundingBox = geometryFactory.newBoundingBox(minX, minY, maxX, maxY);
});
XmlUtil.forEachElement(layerElement, "DataURL", (formatUrlElement) -> {
final FormatUrl formatUrl = new FormatUrl(formatUrlElement);
this.dataUrls.add(formatUrl);
});
XmlUtil.forEachElement(layerElement, "FeatureListURL", (formatUrlElement) -> {
final FormatUrl formatUrl = new FormatUrl(formatUrlElement);
this.featureListUrls.add(formatUrl);
});
XmlUtil.forEachElement(layerElement, "BoundingBox", (formatUrlElement) -> {
final WmsBoundingBox boundingBox = new WmsBoundingBox(formatUrlElement);
this.boundingBoxes.add(boundingBox);
});
XmlUtil.forEachElement(layerElement, "Dimension", (dimensionElement) -> {
final Dimension dimension = new Dimension(dimensionElement);
this.dimensions.add(dimension);
});
XmlUtil.forEachElement(layerElement, "Extent", (extentElement) -> {
final Extent extent = new Extent(extentElement);
this.extents.add(extent);
});
XmlUtil.forFirstElement(layerElement, "Attribution", (attributionElement) -> {
this.attribution = new Attribution(attributionElement);
});
XmlUtil.forEachElement(layerElement, "AuthorityUrl", (authorityUrlElement) -> {
final AuthorityUrl authorityUrl = new AuthorityUrl(authorityUrlElement);
this.authorityUrls.add(authorityUrl);
});
XmlUtil.forEachElement(layerElement, "Identifier", (identifierElement) -> {
final WmsIdentifier identifier = new WmsIdentifier(identifierElement);
this.identifiers.add(identifier);
});
XmlUtil.forEachElement(layerElement, "MetaDataURL", (metadataElement) -> {
final MetadataUrl metadataUrl = new MetadataUrl(metadataElement);
this.metadataUrls.add(metadataUrl);
});
XmlUtil.forEachElement(layerElement, "Style", (styleElement) -> {
final Style style = new Style(styleElement);
this.styles.add(style);
});
this.maximumScale = XmlUtil.getFirstElementDouble(layerElement, "MinScaleDenominator", 0);
this.minimumScale = XmlUtil.getFirstElementDouble(layerElement, "MaxScaleDenominator",
Long.MAX_VALUE);
XmlUtil.forFirstElement(layerElement, "ScaleHint", (scaleHintElement) -> {
this.maximumScale = XmlUtil.getAttributeDouble(scaleHintElement, "min", 0);
this.minimumScale = XmlUtil.getAttributeDouble(scaleHintElement, "max", Long.MAX_VALUE);
});
XmlUtil.forEachElement(layerElement, "Layer", (childLayerElement) -> {
final WmsLayerDefinition childLayer = new WmsLayerDefinition(childLayerElement);
this.layers.add(childLayer);
childLayer.parent = this;
});
}
public String getAbstractDescription() {
return this.abstractDescription;
}
public Attribution getAttribution() {
return this.attribution;
}
public List<AuthorityUrl> getAuthorityUrls() {
return this.authorityUrls;
}
public List<WmsBoundingBox> getBoundingBoxes() {
return this.boundingBoxes;
}
public int getCascaded() {
return this.cascaded;
}
@Override
public List<WmsLayerDefinition> getChildren() {
return this.layers;
}
public List<FormatUrl> getDataUrls() {
return this.dataUrls;
}
public GeometryFactory getDefaultGeometryFactory() {
if (this.srs.isEmpty()) {
if (this.parent instanceof WmsLayerDefinition) {
final WmsLayerDefinition parentLayer = (WmsLayerDefinition)this.parent;
return parentLayer.getDefaultGeometryFactory();
} else {
return GeometryFactory.floating(4326, 2);
}
} else {
return WmsClient.getGeometryFactory(this.srs.get(0));
}
}
public String getDefaultStyleName() {
if (this.styles.isEmpty()) {
if (this.parent instanceof WmsLayerDefinition) {
final WmsLayerDefinition parentLayer = (WmsLayerDefinition)this.parent;
return parentLayer.getDefaultStyleName();
} else {
return "default";
}
} else {
return this.styles.get(0).getName();
}
}
public List<Dimension> getDimensions() {
return this.dimensions;
}
public List<Extent> getExtents() {
return this.extents;
}
public List<FormatUrl> getFeatureListUrls() {
return this.featureListUrls;
}
public int getFixedHeight() {
return this.fixedHeight;
}
public int getFixedWidth() {
return this.fixedWidth;
}
@Override
public String getIconName() {
if (this.layers.isEmpty()) {
return "map";
} else {
return "folder:map";
}
}
public List<WmsIdentifier> getIdentifiers() {
return this.identifiers;
}
public List<String> getKeywords() {
return this.keywords;
}
public com.revolsys.geometry.model.BoundingBox getLatLonBoundingBox() {
if (this.latLonBoundingBox == null) {
if (this.parent instanceof WmsLayerDefinition) {
final WmsLayerDefinition parentLayer = (WmsLayerDefinition)this.parent;
return parentLayer.getLatLonBoundingBox();
} else {
return BoundingBox.empty();
}
}
return this.latLonBoundingBox;
}
public List<WmsLayerDefinition> getLayers() {
return this.layers;
}
public GeoreferencedImage getMapImage(final BoundingBox boundingBox, final int imageWidth,
final int imageHeight) {
final BoundingBox queryBoundingBox = boundingBox.intersection(getLatLonBoundingBox());
final String srs = "EPSG:" + queryBoundingBox.getCoordinateSystemId();
final WmsClient wmsClient = getWmsClient();
return wmsClient.getMapImage(this.name, getDefaultStyleName(), srs, queryBoundingBox,
"image/png", imageWidth, imageHeight);
}
public double getMaximumScale() {
return this.maximumScale;
}
public List<MetadataUrl> getMetadataUrls() {
return this.metadataUrls;
}
public double getMinimumScale() {
return this.minimumScale;
}
@Override
public String getName() {
return this.name;
}
@SuppressWarnings("unchecked")
@Override
public <R extends WebServiceResource> R getParent() {
return (R)this.parent;
}
@Override
public UrlResource getServiceUrl() {
throw new UnsupportedOperationException();
}
public List<String> getSrs() {
return this.srs;
}
public List<Style> getStyles() {
return this.styles;
}
public String getTitle() {
return this.title;
}
@Override
public WmsClient getWebService() {
if (this.parent instanceof WmsLayerDefinition) {
final WmsLayerDefinition parentLayer = (WmsLayerDefinition)this.parent;
return parentLayer.getWmsClient();
} else if (this.parent instanceof WmsClient) {
return (WmsClient)this.parent;
} else {
return null;
}
}
public WmsClient getWmsClient() {
return getWebService();
}
@Override
public boolean isAllowsChildren() {
return !this.layers.isEmpty();
}
public boolean isNoSubsets() {
return this.noSubsets;
}
public boolean isOpaque() {
return this.opaque;
}
public boolean isQueryable() {
return this.queryable;
}
public void setParent(final WebServiceResource parent) {
this.parent = parent;
}
@Override
public String toString() {
if (this.title != null) {
return this.title;
} else {
return this.name;
}
}
}