package com.revolsys.record.io.format.mapguide;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.revolsys.collection.Parent;
import com.revolsys.collection.map.LinkedHashMapEx;
import com.revolsys.collection.map.MapEx;
import com.revolsys.collection.map.Maps;
import com.revolsys.datatype.DataType;
import com.revolsys.datatype.DataTypes;
import com.revolsys.geometry.cs.CoordinateSystem;
import com.revolsys.geometry.cs.esri.EsriCoordinateSystems;
import com.revolsys.geometry.model.GeometryFactory;
import com.revolsys.io.PathName;
import com.revolsys.record.schema.RecordDefinitionImpl;
import com.revolsys.spring.resource.Resource;
import com.revolsys.util.Property;
import com.revolsys.webservice.WebServiceResource;
public class FeatureSource extends ResourceDocument implements Parent<FeatureLayer> {
public static String getString(final MapEx map, final String name) {
final Object value = getValue(map, name);
return DataTypes.toString(value);
}
@SuppressWarnings("unchecked")
private static <V> V getValue(final MapEx map, final String name) {
Object value = map.getValue(name);
if (value instanceof List<?>) {
final List<?> list = (List<?>)value;
value = list.get(0);
}
return (V)value;
}
private final Map<String, Integer> coordinateSystemIdBySrsName = Maps
.<String, Integer> buildHash()//
// .add("UTM83-09", 26909) //
// .add("UTM83-10", 26910) //
// .add("UTM83-11", 26911) //
// .add("UTM83-12", 26912) //
// .add("WORLD-MERCATOR", 3857) //
.getMap();
private List<FeatureLayer> layers = new ArrayList<>();
private Map<String, FeatureLayer> layerByName = new HashMap<>();
public FeatureSource(final MapEx properties) {
setProperties(properties);
}
@SuppressWarnings("unchecked")
@Override
public <R extends WebServiceResource> R getChild(final String name) {
refreshIfNeeded();
if (name == null) {
return null;
} else {
return (R)this.layerByName.get(name.toLowerCase());
}
}
@Override
public List<FeatureLayer> getChildren() {
refreshIfNeeded();
return this.layers;
}
@Override
public String getIconName() {
return "folder:table";
}
private FeatureLayer newLayer(final String name, final MapEx element, final MapEx complexType) {
if (!"true".equals(getString(complexType, "@abstract"))) {
final PathName pathName = getPathName();
final PathName layerPathName = pathName.newChild(name);
final RecordDefinitionImpl recordDefinition = new RecordDefinitionImpl(layerPathName);
GeometryFactory geometryFactory = GeometryFactory.DEFAULT_3D;
final MapEx complexContent = getValue(complexType, "xs:complexContent");
final MapEx extension = getValue(complexContent, "xs:extension");
if ("gml:AbstractFeatureType".equals(getString(extension, "@base"))) {
final MapEx sequence = getValue(extension, "xs:sequence");
final List<MapEx> elements = sequence.getValue("xs:element");
for (final MapEx fieldElement : elements) {
final String fieldName = getString(fieldElement, "@name");
final boolean required = !"0".equals(getString(fieldElement, "@minOccurs"));
DataType dataType = DataTypes.STRING;
final MapEx simpleFieldType = getValue(fieldElement, "xs:simpleType");
if (simpleFieldType == null) {
final String fieldType = getString(fieldElement, "@type");
if ("gml:AbstractGeometryType".equals(fieldType)) {
final String geometryTypes = getString(fieldElement, "@fdo:geometryTypes");
for (final String geometryType : geometryTypes.split(" ")) {
final DataType geometryDataType = DataTypes.getDataType(geometryType);
if (geometryDataType != DataTypes.OBJECT) {
if (dataType == DataTypes.STRING) {
dataType = geometryDataType;
} else if (dataType == DataTypes.GEOMETRY) {
} else if (geometryDataType == DataTypes.GEOMETRY) {
dataType = DataTypes.GEOMETRY;
} else if (geometryDataType == DataTypes.GEOMETRY_COLLECTION) {
dataType = DataTypes.GEOMETRY;
} else if (dataType.equals(DataTypes.POINT)) {
if (geometryDataType.equals(DataTypes.POINT)) {
} else if (geometryDataType.equals(DataTypes.MULTI_POINT)) {
dataType = DataTypes.MULTI_POINT;
} else {
dataType = DataTypes.GEOMETRY;
}
} else if (dataType.equals(DataTypes.MULTI_POINT)) {
if (geometryDataType.equals(DataTypes.POINT)) {
} else if (geometryDataType.equals(DataTypes.MULTI_POINT)) {
} else {
dataType = DataTypes.GEOMETRY;
}
} else if (dataType.equals(DataTypes.LINE_STRING)) {
if (geometryDataType.equals(DataTypes.LINE_STRING)) {
} else if (geometryDataType.equals(DataTypes.MULTI_LINE_STRING)) {
dataType = DataTypes.MULTI_LINE_STRING;
} else {
dataType = DataTypes.GEOMETRY;
}
} else if (dataType.equals(DataTypes.MULTI_LINE_STRING)) {
if (geometryDataType.equals(DataTypes.LINE_STRING)) {
} else if (geometryDataType.equals(DataTypes.MULTI_LINE_STRING)) {
} else {
dataType = DataTypes.GEOMETRY;
}
} else if (dataType.equals(DataTypes.POLYGON)) {
if (geometryDataType.equals(DataTypes.POLYGON)) {
} else if (geometryDataType.equals(DataTypes.MULTI_POLYGON)) {
dataType = DataTypes.MULTI_POLYGON;
} else {
dataType = DataTypes.GEOMETRY;
}
} else if (dataType.equals(DataTypes.MULTI_POLYGON)) {
if (geometryDataType.equals(DataTypes.POLYGON)) {
} else if (geometryDataType.equals(DataTypes.MULTI_POLYGON)) {
} else {
dataType = DataTypes.GEOMETRY;
}
}
}
}
if (dataType == DataTypes.STRING) {
dataType = DataTypes.GEOMETRY;
}
int axisCount = 2;
if ("true".equals(getString(fieldElement, "@fdo:hasMeasure"))) {
axisCount = 4;
} else if ("true".equals(getString(fieldElement, "@fdo:hasElevation"))) {
axisCount = 3;
}
final String srsName = getString(fieldElement, "@fdo:srsName");
if (Property.hasValue(srsName)) {
final Integer coordinateSystemId = Maps.getInteger(this.coordinateSystemIdBySrsName,
srsName);
if (coordinateSystemId == null) {
try {
final Map<String, Object> csParameters = Collections.singletonMap("CSCODE",
srsName);
final MapGuideWebService webService = getWebService();
final Resource wktResource = webService
.getResource("CS.CONVERTCOORDINATESYSTEMCODETOWKT", null, csParameters);
final String wkt = wktResource.contentsAsString();
final CoordinateSystem coordinateSystem = EsriCoordinateSystems
.getCoordinateSystem(wkt);
geometryFactory = GeometryFactory.floating(coordinateSystem, axisCount);
} catch (final Throwable e) {
}
} else {
geometryFactory = GeometryFactory.floating(coordinateSystemId, axisCount);
}
}
}
} else {
final MapEx restriction = getValue(simpleFieldType, "xs:restriction");
if (restriction != null) {
final String fieldBase = getString(restriction, "@base");
dataType = DataTypes.getDataType(fieldBase.replace("xs:", ""));
}
}
if (dataType != null) {
recordDefinition.addField(fieldName, dataType, required);
}
}
recordDefinition.setGeometryFactory(geometryFactory);
final FeatureLayer layer = new FeatureLayer(this, recordDefinition);
return layer;
}
}
return null;
}
@Override
protected void refreshDo() {
final MapEx properties = new LinkedHashMapEx();
final String resourceId = getResourceId();
properties.put("RESOURCEID", resourceId);
final MapGuideWebService webService = getWebService();
final MapEx schemaResource = webService.getJsonResponse("DESCRIBEFEATURESCHEMA", properties);
final MapEx schema = schemaResource.getValue("xs:schema");
if (schema != null) {
final Map<String, String> prefixByUri = new HashMap<>();
for (final String name : schema.keySet()) {
if (name.startsWith("@xmlns:")) {
final String namespaceUri = getString(schema, name);
final String prefix = name.substring(7);
prefixByUri.put(namespaceUri, prefix);
}
}
final String targetNamespace = getString(schema, "@targetNamespace");
final String prefix = prefixByUri.get(targetNamespace);
final Map<String, MapEx> complexTypeDefinitions = new HashMap<>();
for (final MapEx complexType : schema.getValue("xs:complexType",
Collections.<MapEx> emptyList())) {
String name = getString(complexType, "@name");
if (prefix != null) {
name = prefix + ":" + name;
}
complexTypeDefinitions.put(name, complexType);
}
final List<FeatureLayer> layers = new ArrayList<>();
final Map<String, FeatureLayer> layerByName = new HashMap<>();
for (final MapEx element : schema.getValue("xs:element", Collections.<MapEx> emptyList())) {
final String name = getString(element, "@name");
final String type = getString(element, "@type");
final MapEx complexType = complexTypeDefinitions.get(type);
final FeatureLayer layer = newLayer(name, element, complexType);
if (layer != null) {
layers.add(layer);
layerByName.put(name.toLowerCase(), layer);
}
this.layers = layers;
this.layerByName = layerByName;
}
}
}
}