package com.revolsys.geometry.cs;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import javax.measure.quantity.Length;
import javax.measure.unit.Unit;
import com.revolsys.datatype.DataType;
import com.revolsys.geometry.cs.projection.CoordinatesProjection;
import com.revolsys.geometry.cs.projection.ProjectionFactory;
import com.revolsys.geometry.model.BoundingBox;
import com.revolsys.geometry.model.GeometryFactory;
public class ProjectedCoordinateSystem implements CoordinateSystem {
private static final long serialVersionUID = 1902383026085071877L;
private Area area;
private final Authority authority;
private final List<Axis> axis = new ArrayList<>();
private CoordinatesProjection coordinatesProjection;
private boolean deprecated;
private final GeographicCoordinateSystem geographicCoordinateSystem;
private int id;
private BoundingBox areaBoundingBox;
private final LinearUnit linearUnit;
private final String name;
private final Map<String, Object> normalizedParameters = new TreeMap<>();
private final Map<String, Object> parameters = new LinkedHashMap<>();
private final Projection projection;
public ProjectedCoordinateSystem(final int id, final String name,
final GeographicCoordinateSystem geographicCoordinateSystem, final Area area,
final Projection projection, final Map<String, Object> parameters, final LinearUnit linearUnit,
final List<Axis> axis, final Authority authority, final boolean deprecated) {
this.id = id;
this.name = name;
this.area = area;
this.geographicCoordinateSystem = geographicCoordinateSystem;
this.projection = projection;
setParameters(parameters);
this.linearUnit = linearUnit;
if (axis != null && !axis.isEmpty()) {
this.axis.add(axis.get(0));
this.axis.add(axis.get(1));
}
this.authority = authority;
this.deprecated = deprecated;
}
public ProjectedCoordinateSystem(final int id, final String name,
final GeographicCoordinateSystem geographicCoordinateSystem, final Projection projection,
final Map<String, Object> parameters, final LinearUnit linearUnit, final List<Axis> axis,
final Authority authority) {
this.id = id;
this.name = name;
this.geographicCoordinateSystem = geographicCoordinateSystem;
this.projection = projection;
setParameters(parameters);
this.linearUnit = linearUnit;
if (axis != null && !axis.isEmpty()) {
this.axis.add(axis.get(0));
this.axis.add(axis.get(1));
}
this.authority = authority;
}
@Override
public ProjectedCoordinateSystem clone() {
try {
return (ProjectedCoordinateSystem)super.clone();
} catch (final Exception e) {
return null;
}
}
@Override
public boolean equals(final Object object) {
if (object == null) {
return false;
} else if (object == this) {
return true;
} else if (object instanceof ProjectedCoordinateSystem) {
final ProjectedCoordinateSystem cs = (ProjectedCoordinateSystem)object;
if (!this.geographicCoordinateSystem.equals(cs.geographicCoordinateSystem)) {
return false;
} else if (!this.projection.equals(cs.projection)) {
return false;
} else if (!this.normalizedParameters.equals(cs.normalizedParameters)) {
return false;
} else if (!this.linearUnit.equals(cs.linearUnit)) {
return false;
} else {
return true;
}
} else {
return false;
}
}
public boolean equalsExact(final Object object) {
if (object == null) {
return false;
} else if (object == this) {
return true;
} else if (object instanceof ProjectedCoordinateSystem) {
final ProjectedCoordinateSystem cs = (ProjectedCoordinateSystem)object;
if (!this.area.equals(cs.area)) {
return false;
} else if (!this.authority.equals(cs.authority)) {
return false;
} else if (!DataType.equal(this.axis, cs.axis)) {
return false;
} else if (!this.geographicCoordinateSystem.equals(cs.geographicCoordinateSystem)) {
return false;
} else if (this.id != cs.id) {
return false;
} else if (!DataType.equal(this.linearUnit, cs.linearUnit)) {
return false;
} else if (!DataType.equal(this.name, cs.name)) {
return false;
} else if (!DataType.equal(this.normalizedParameters, cs.normalizedParameters)) {
return false;
} else if (!DataType.equal(this.projection, cs.projection)) {
return false;
} else {
return true;
}
} else {
return false;
}
}
@Override
public Area getArea() {
return this.area;
}
@Override
public BoundingBox getAreaBoundingBox() {
if (this.areaBoundingBox == null) {
final GeometryFactory geographicGeometryFactory = this.geographicCoordinateSystem
.getGeometryFactory();
BoundingBox boundingBox;
if (this.area == null) {
boundingBox = geographicGeometryFactory.newBoundingBox(-180, -90, 180, 90);
} else {
final BoundingBox latLonBounds = this.area.getLatLonBounds();
boundingBox = latLonBounds.convert(geographicGeometryFactory);
}
final GeometryFactory geometryFactory = getGeometryFactory();
this.areaBoundingBox = boundingBox.convert(geometryFactory);
}
return this.areaBoundingBox;
}
@Override
public Authority getAuthority() {
return this.authority;
}
@Override
public List<Axis> getAxis() {
return this.axis;
}
@Override
public synchronized CoordinatesProjection getCoordinatesProjection() {
if (this.coordinatesProjection == null) {
this.coordinatesProjection = ProjectionFactory.newCoordinatesProjection(this);
}
return this.coordinatesProjection;
}
@Override
public int getCoordinateSystemId() {
return this.id;
}
@Override
public String getCoordinateSystemName() {
return this.name;
}
public double getDoubleParameter(final String key) {
final Number value = getParameter(key);
if (value == null) {
return Double.NaN;
} else {
return value.doubleValue();
}
}
public GeographicCoordinateSystem getGeographicCoordinateSystem() {
return this.geographicCoordinateSystem;
}
@Override
public Unit<Length> getLengthUnit() {
return this.linearUnit.getUnit();
}
public LinearUnit getLinearUnit() {
return this.linearUnit;
}
@SuppressWarnings("unchecked")
public <V> V getParameter(final String key) {
return (V)this.normalizedParameters.get(key);
}
public Map<String, Object> getParameters() {
return this.parameters;
}
public Projection getProjection() {
return this.projection;
}
@Override
@SuppressWarnings("unchecked")
public Unit<Length> getUnit() {
return this.linearUnit.getUnit();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
if (this.geographicCoordinateSystem != null) {
result = prime * result + this.geographicCoordinateSystem.hashCode();
}
if (this.projection != null) {
result = prime * result + this.projection.hashCode();
}
for (final Entry<String, Object> entry : this.normalizedParameters.entrySet()) {
final String key = entry.getKey();
result = prime * result + key.hashCode();
result = prime * result + entry.getValue().hashCode();
}
if (this.linearUnit != null) {
result = prime * result + this.linearUnit.hashCode();
}
return result;
}
@Override
public boolean isDeprecated() {
return this.deprecated;
}
public void setId(final int id) {
this.id = id;
}
public void setParameters(final Map<String, Object> parameters) {
for (final Entry<String, Object> param : parameters.entrySet()) {
final String name = param.getKey().intern();
final Object value = param.getValue();
this.parameters.put(name, value);
final String normalizedName = ProjectionParameterNames.getParameterName(name);
this.normalizedParameters.put(normalizedName, value);
}
}
@Override
public String toString() {
return this.name;
}
}