package com.revolsys.record.property;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import com.revolsys.collection.map.Maps;
import com.revolsys.datatype.DataType;
import com.revolsys.geometry.graph.Edge;
import com.revolsys.geometry.model.Geometry;
import com.revolsys.geometry.model.LineString;
import com.revolsys.geometry.model.Point;
import com.revolsys.geometry.model.vertex.Vertex;
import com.revolsys.record.Record;
import com.revolsys.record.Records;
import com.revolsys.record.schema.RecordDefinition;
public class DirectionalFields extends AbstractRecordDefinitionProperty {
public static final String PROPERTY_NAME = DirectionalFields.class.getName() + ".propertyName";
public static boolean canMergeRecords(final Point point, final Record record1,
final Record record2) {
final Set<String> excludes = Collections.emptySet();
final DirectionalFields property = getProperty(record1);
return property.canMerge(point, record1, record2, excludes);
}
public static boolean canMergeRecords(final Point point, final Record record1,
final Record record2, final Set<String> equalExcludeFieldNames) {
final DirectionalFields property = getProperty(record1);
return property.canMerge(point, record1, record2, equalExcludeFieldNames);
}
public static void edgeSplitFieldValues(final LineString line, final Point point,
final List<Edge<Record>> edges) {
if (!edges.isEmpty()) {
final Edge<Record> firstEdge = edges.get(0);
final Record record = firstEdge.getObject();
final DirectionalFields property = getProperty(record);
property.setEdgeSplitFieldNames(line, point, edges);
}
}
public static boolean equalsRecords(final Record record1, final Record record2) {
final Set<String> excludes = Collections.emptySet();
return equalsRecords(record1, record2, excludes);
}
public static boolean equalsRecords(final Record record1, final Record record2,
final Collection<String> equalExcludeFieldNames) {
final DirectionalFields property = getProperty(record1);
return property.equals(record1, record2, equalExcludeFieldNames);
}
public static Set<String> getCantMergeFieldNamesRecords(final Point point, final Record record1,
final Record record2, final Set<String> equalExcludeFieldNames) {
final DirectionalFields property = getProperty(record1);
return property.getCantMergeFieldNames(point, record1, record2, equalExcludeFieldNames);
}
public static DirectionalFields getProperty(final Record record) {
final RecordDefinition recordDefinition = record.getRecordDefinition();
return getProperty(recordDefinition);
}
public static DirectionalFields getProperty(final RecordDefinition recordDefinition) {
DirectionalFields property = recordDefinition.getProperty(PROPERTY_NAME);
if (property == null) {
property = new DirectionalFields();
property.setRecordDefinition(recordDefinition);
}
return property;
}
public static Record getReverseRecord(final Record record) {
final DirectionalFields property = getProperty(record);
final Record reverse = property.getReverse(record);
return reverse;
}
public static boolean hasProperty(final Record record) {
final RecordDefinition recordDefinition = record.getRecordDefinition();
return recordDefinition.getProperty(PROPERTY_NAME) != null;
}
public static Record merge(final Point point, final Record record1, final Record record2) {
final DirectionalFields property = getProperty(record1);
return property.getMergedRecord(point, record1, record2);
}
public static Record merge(final Record record1, final Record record2) {
final DirectionalFields property = getProperty(record1);
return property.getMergedRecord(record1, record2);
}
public static Record mergeLongest(final Point point, final Record record1, final Record record2) {
final DirectionalFields property = getProperty(record1);
return property.getMergedRecordReverseLongest(point, record1, record2);
}
public static Record mergeLongest(final Record record1, final Record record2) {
final DirectionalFields property = getProperty(record1);
return property.getMergedRecordReverseLongest(record1, record2);
}
public static void reverse(final Record record) {
final DirectionalFields property = getProperty(record);
property.reverseFieldValuesAndGeometry(record);
}
private final Map<String, Map<Object, Object>> directionalFieldValues = new HashMap<>();
private final List<List<String>> endAndSideFieldNamePairs = new ArrayList<>();
private final Map<String, String> endFieldNamePairs = new HashMap<>();
private final Set<String> fromFieldNames = new HashSet<>();
private final Map<String, String> reverseFieldNameMap = new HashMap<>();
private final Map<String, String> sideFieldNamePairs = new HashMap<>();
private final Set<String> sideFieldNames = new HashSet<>();
private final Set<String> toFieldNames = new HashSet<>();
public DirectionalFields() {
}
public void addDirectionalFieldValues(final String fieldName,
final Map<? extends Object, ? extends Object> values) {
final Map<Object, Object> newValues = new LinkedHashMap<>();
for (final Entry<? extends Object, ? extends Object> entry : values.entrySet()) {
final Object value1 = entry.getKey();
final Object value2 = entry.getValue();
addValue(newValues, value1, value2);
addValue(newValues, value2, value1);
}
this.directionalFieldValues.put(fieldName, newValues);
}
public void addEndAndSideFieldNamePairs(final String startLeftFieldName,
final String startRightFieldName, final String endLeftFieldName,
final String endRightFieldName) {
this.endAndSideFieldNamePairs.add(
Arrays.asList(startLeftFieldName, startRightFieldName, endLeftFieldName, endRightFieldName));
addEndFieldNamePairInternal(startLeftFieldName, endLeftFieldName);
addEndFieldNamePairInternal(startRightFieldName, endRightFieldName);
addFieldNamePair(this.reverseFieldNameMap, startLeftFieldName, endRightFieldName);
addFieldNamePair(this.reverseFieldNameMap, endLeftFieldName, startRightFieldName);
}
public void addEndFieldNamePair(final String startFieldName, final String endFieldName) {
addEndFieldNamePairInternal(startFieldName, endFieldName);
addFieldNamePair(this.reverseFieldNameMap, startFieldName, endFieldName);
}
private void addEndFieldNamePairInternal(final String startFieldName, final String endFieldName) {
addFieldNamePair(this.endFieldNamePairs, startFieldName, endFieldName);
this.fromFieldNames.add(startFieldName);
this.toFieldNames.add(endFieldName);
}
/**
* Add a mapping from the fromFieldName to the toFieldName and an
* inverse mapping to the namePairs map.
*
* @param namePairs The name pair mapping.
* @param fromFieldName The from attribute name.
* @param toFieldName The to attribute name.
*/
private void addFieldNamePair(final Map<String, String> namePairs, final String fromFieldName,
final String toFieldName) {
final String fromPair = namePairs.get(fromFieldName);
if (fromPair == null) {
final String toPair = namePairs.get(toFieldName);
if (toPair == null) {
namePairs.put(fromFieldName, toFieldName);
namePairs.put(toFieldName, fromFieldName);
} else if (toPair.equals(fromFieldName)) {
throw new IllegalArgumentException(
"Cannot override mapping " + toFieldName + "=" + toPair + " to " + fromFieldName);
}
} else if (fromPair.equals(toFieldName)) {
throw new IllegalArgumentException(
"Cannot override mapping " + fromFieldName + "=" + fromPair + " to " + toFieldName);
}
}
public void addSideFieldNamePair(final String leftFieldName, final String rightFieldName) {
addFieldNamePair(this.sideFieldNamePairs, leftFieldName, rightFieldName);
this.sideFieldNames.add(leftFieldName);
this.sideFieldNames.add(rightFieldName);
addFieldNamePair(this.reverseFieldNameMap, leftFieldName, rightFieldName);
}
protected void addValue(final Map<Object, Object> map, final Object key, final Object value) {
final Object oldValue = map.get(key);
if (oldValue != null && !oldValue.equals(value)) {
throw new IllegalArgumentException(
"Cannot override mapping " + key + "=" + oldValue + " with " + value);
}
map.put(key, value);
}
public boolean canMerge(final Point point, final Record record1, final Record record2,
final Collection<String> equalExcludeFieldNames) {
final boolean[] forwardsIndicators = getForwardsIndicators(point, record1, record2);
if (forwardsIndicators != null) {
final RecordDefinition recordDefinition = getRecordDefinition();
final EqualIgnoreFieldNames equalIgnore = EqualIgnoreFieldNames.getProperty(recordDefinition);
for (final String fieldName : recordDefinition.getFieldNames()) {
if (!record1.isFieldExcluded(equalExcludeFieldNames, fieldName)
&& !equalIgnore.isFieldIgnored(fieldName)) {
if (!canMerge(fieldName, point, record1, record2, equalExcludeFieldNames,
forwardsIndicators)) {
return false;
}
}
}
return true;
} else {
return false;
}
}
public boolean canMerge(final String fieldName, final Point point, final Record record1,
final Record record2, final Collection<String> equalExcludeFieldNames,
final boolean[] forwardsIndicators) {
final RecordDefinition recordDefinition = getRecordDefinition();
if (fieldName.equals(recordDefinition.getGeometryFieldName())) {
final LineString line1 = record1.getGeometry();
final LineString line2 = record2.getGeometry();
return !line1.equals(line2);
}
if (forwardsIndicators == null) {
return false;
} else {
final boolean line1Forwards = forwardsIndicators[0];
final boolean line2Forwards = forwardsIndicators[1];
if (hasDirectionalFieldValues(fieldName)) {
if (line1Forwards != line2Forwards) {
final Object value1 = record1.getValue(fieldName);
final Object value2 = getDirectionalFieldValue(record2, fieldName);
if (DataType.equal(value1, value2, equalExcludeFieldNames)) {
return true;
} else {
return false;
}
}
} else if (isFromField(fieldName)) {
return canMergeFromField(fieldName, record1, line1Forwards, record2, line2Forwards,
equalExcludeFieldNames);
} else if (isToField(fieldName)) {
return canMergeToField(fieldName, record1, line1Forwards, record2, line2Forwards,
equalExcludeFieldNames);
} else if (isSideField(fieldName)) {
if (line1Forwards != line2Forwards) {
final String oppositeFieldName = getSideFieldName(fieldName);
if (oppositeFieldName == null) { // only check the pair once
return true;
} else {
return equals(record1, fieldName, record2, oppositeFieldName, equalExcludeFieldNames);
}
}
}
return equals(record1, fieldName, record2, fieldName, equalExcludeFieldNames);
}
}
protected boolean canMergeFromField(final String startFieldName, final Record record1,
final boolean line1Forwards, final Record record2, final boolean line2Forwards,
final Collection<String> equalExcludeFieldNames) {
final String endFieldName = this.endFieldNamePairs.get(startFieldName);
if (line1Forwards) {
if (line2Forwards) {
// -->*--> true true
return isNull(record1, endFieldName, record2, startFieldName, equalExcludeFieldNames);
} else {
// -->*<-- true false
return true;
}
} else {
if (line2Forwards) {
// <--*--> false true
return isNull(record1, startFieldName, record2, startFieldName, equalExcludeFieldNames);
} else {
// <--*<-- false false
return isNull(record1, startFieldName, record2, endFieldName, equalExcludeFieldNames);
}
}
}
protected boolean canMergeToField(final String endFieldName, final Record record1,
final boolean line1Forwards, final Record record2, final boolean line2Forwards,
final Collection<String> equalExcludeFieldNames) {
final String startFieldName = this.endFieldNamePairs.get(endFieldName);
if (line1Forwards) {
if (line2Forwards) {
// -->*--> true true
return isNull(record1, endFieldName, record2, startFieldName, equalExcludeFieldNames);
} else {
// -->*<-- true false
return isNull(record1, endFieldName, record2, endFieldName, equalExcludeFieldNames);
}
} else {
if (line2Forwards) {
// <--*--> false true
return true;
} else {
// <--*<-- false false
return isNull(record1, startFieldName, record2, endFieldName, equalExcludeFieldNames);
}
}
}
public void clearFromFields(final Map<String, Object> record) {
for (final String fieldName : this.fromFieldNames) {
record.put(fieldName, null);
}
}
public void clearToFields(final Map<String, Object> record) {
for (final String fieldName : this.toFieldNames) {
record.put(fieldName, null);
}
}
public boolean equals(final Record record1, final Record record2,
final Collection<String> equalExcludeFieldNames) {
final RecordDefinition recordDefinition = getRecordDefinition();
final EqualIgnoreFieldNames equalIgnore = EqualIgnoreFieldNames.getProperty(recordDefinition);
for (final String fieldName : recordDefinition.getFieldNames()) {
if (!equalExcludeFieldNames.contains(fieldName) && !equalIgnore.isFieldIgnored(fieldName)) {
if (!equals(fieldName, record1, record2, equalExcludeFieldNames)) {
return false;
}
}
}
return true;
}
protected boolean equals(final Record record1, final String name1, final Record record2,
final String name2, final Collection<String> equalExcludeFieldNames) {
final Object value1 = record1.getValue(name1);
final Object value2 = record2.getValue(name2);
if (DataType.equal(value1, value2, equalExcludeFieldNames)) {
return true;
} else {
return false;
}
}
protected boolean equals(final String fieldName, final Record record1, final Record record2,
final Collection<String> equalExcludeFieldNames) {
final LineString line1 = record1.getGeometry();
final LineString line2 = record2.getGeometry();
final RecordDefinition recordDefinition = getRecordDefinition();
if (fieldName.equals(recordDefinition.getGeometryFieldName())) {
return line1.equals(line2);
}
boolean reverseEquals;
if (line1.equalsVertex(2, 0, line2, 0)) {
if (line1.isClosed()) {
// TODO handle loops
throw new IllegalArgumentException("Cannot handle loops");
}
reverseEquals = false;
} else {
reverseEquals = true;
}
if (reverseEquals) {
return equalsReverse(fieldName, record1, record2, equalExcludeFieldNames);
} else {
return equals(record1, fieldName, record2, fieldName, equalExcludeFieldNames);
}
}
private boolean equalsReverse(final String fieldName, final Record record1, final Record record2,
final Collection<String> equalExcludeFieldNames) {
if (hasDirectionalFieldValues(fieldName)) {
final Object value1 = record1.getValue(fieldName);
final Object value2 = getDirectionalFieldValue(record2, fieldName);
if (DataType.equal(value1, value2, equalExcludeFieldNames)) {
return true;
} else {
return false;
}
} else {
final String reverseFieldName = getReverseFieldName(fieldName);
if (reverseFieldName == null) {
return equals(record1, fieldName, record2, fieldName, equalExcludeFieldNames);
} else {
return equals(record1, fieldName, record2, reverseFieldName, equalExcludeFieldNames);
}
}
}
public Set<String> getCantMergeFieldNames(final Point point, final Record record1,
final Record record2, final Collection<String> equalExcludeFieldNames) {
final RecordDefinition recordDefinition = getRecordDefinition();
final boolean[] forwardsIndicators = getForwardsIndicators(point, record1, record2);
if (forwardsIndicators != null) {
final Set<String> fieldNames = new LinkedHashSet<>();
final EqualIgnoreFieldNames equalIgnore = EqualIgnoreFieldNames.getProperty(recordDefinition);
for (final String fieldName : recordDefinition.getFieldNames()) {
if (!equalExcludeFieldNames.contains(fieldName) && !equalIgnore.isFieldIgnored(fieldName)) {
if (!canMerge(fieldName, point, record1, record2, equalExcludeFieldNames,
forwardsIndicators)) {
fieldNames.add(fieldName);
}
}
}
return fieldNames;
} else {
final String geometryFieldName = recordDefinition.getGeometryFieldName();
return Collections.singleton(geometryFieldName);
}
}
protected Object getDirectionalFieldValue(final Map<String, ? extends Object> record,
final String fieldName) {
final Object value = record.get(fieldName);
final Map<Object, Object> valueMap = this.directionalFieldValues.get(fieldName);
if (valueMap != null) {
if (valueMap.containsKey(value)) {
final Object directionalValue = valueMap.get(value);
return directionalValue;
}
}
return value;
}
public Map<String, Map<Object, Object>> getDirectionalFieldValues() {
return this.directionalFieldValues;
}
public List<List<String>> getEndAndSideFieldNamePairs() {
return this.endAndSideFieldNamePairs;
}
public Map<String, String> getEndFieldNamePairs() {
return this.endFieldNamePairs;
}
protected boolean[] getForwardsIndicators(final Point point, final Record record1,
final Record record2) {
final LineString line1 = record1.getGeometry();
final LineString line2 = record2.getGeometry();
final boolean[] forwards = new boolean[2];
final int vertexCount1 = line1.getVertexCount();
final int vertexCount2 = line2.getVertexCount();
final int lastPointIndex1 = vertexCount1 - 1;
if (line1.equalsVertex(2, 0, line2, 0) && line1.equalsVertex(2, 0, point)) {
// <--*--> false true
forwards[0] = false;
forwards[1] = true;
} else if (line1.equalsVertex(2, vertexCount1 - 1, line2, vertexCount2 - 1)
&& line1.equalsVertex(2, lastPointIndex1, point)) {
// -->*<-- true false
forwards[0] = true;
forwards[1] = false;
} else if (line1.equalsVertex(2, vertexCount1 - 1, line2, 0)
&& line1.equalsVertex(2, lastPointIndex1, point)) {
// -->*--> true true
forwards[0] = true;
forwards[1] = true;
} else if (line1.equalsVertex(2, 0, line2, vertexCount2 - 1)
&& line1.equalsVertex(2, 0, point)) {
// <--*<-- false false
forwards[0] = false;
forwards[1] = false;
} else {
return null;
}
return forwards;
}
public Set<String> getFromFieldNames() {
return this.fromFieldNames;
}
public Map<String, Object> getMergedMap(final Point point, final Record record1, Record record2) {
final LineString line1 = record1.getGeometry();
LineString line2 = record2.getGeometry();
Record fromRecord;
Record toRecord;
LineString newLine;
final Vertex line1From = line1.getVertex(0);
final Vertex line2From = line2.getVertex(0);
if (line1From.equals(2, line2From) && line1From.equals(2, point)) {
record2 = getReverse(record2);
line2 = record2.getGeometry();
fromRecord = record2;
toRecord = record1;
newLine = line1.merge(point, line2);
} else {
final Vertex line1To = line1.getVertex(-1);
final Vertex line2To = line2.getVertex(-1);
if (line1To.equals(2, line2To) && line1To.equals(2, point)) {
record2 = getReverse(record2);
line2 = record2.getGeometry();
fromRecord = record1;
toRecord = record2;
newLine = line1.merge(point, line2);
} else if (line1To.equals(2, line2From) && line1To.equals(2, point)) {
fromRecord = record1;
toRecord = record2;
newLine = line1.merge(point, line2);
} else if (line1From.equals(2, line2To) && line1From.equals(2, point)) {
fromRecord = record2;
toRecord = record1;
newLine = line2.merge(point, line1);
} else {
throw new IllegalArgumentException("Lines for records don't touch");
}
}
final Map<String, Object> newValues = new LinkedHashMap<>(record1);
setFromFieldValues(fromRecord, toRecord, newValues);
setToFieldValues(toRecord, fromRecord, newValues);
final RecordDefinition recordDefinition = record1.getRecordDefinition();
final String geometryFieldName = recordDefinition.getGeometryFieldName();
newValues.put(geometryFieldName, newLine);
return newValues;
}
/**
* Get a new record that is the result of merging the two records. The
* attributes will be taken from the record with the longest length. If one
* line needs to be reversed then the second record will be reversed.
*
* @param record1
* @param record2
* @return
*/
public Record getMergedRecord(final Point point, final Record record1, Record record2) {
final LineString line1 = record1.getGeometry();
LineString line2 = record2.getGeometry();
Record fromRecord;
Record toRecord;
final boolean line1Longer = line1.getLength() > line2.getLength();
LineString newLine;
final int lastPoint1 = line1.getVertexCount() - 1;
final int lastPoint2 = line2.getVertexCount() - 1;
if (line1.equalsVertex(2, 0, line2, 0) && line1.equalsVertex(2, 0, point)) {
record2 = getReverse(record2);
line2 = record2.getGeometry();
fromRecord = record2;
toRecord = record1;
newLine = line1.merge(point, line2);
} else if (line1.equalsVertex(2, lastPoint1, line2, lastPoint2)
&& line1.equalsVertex(2, lastPoint1, point)) {
record2 = getReverse(record2);
line2 = record2.getGeometry();
fromRecord = record1;
toRecord = record2;
newLine = line1.merge(point, line2);
} else if (line1.equalsVertex(2, lastPoint1, line2, 0)
&& line1.equalsVertex(2, lastPoint1, point)) {
fromRecord = record1;
toRecord = record2;
newLine = line1.merge(point, line2);
} else if (line1.equalsVertex(2, 0, line2, lastPoint2) && line1.equalsVertex(2, 0, point)) {
fromRecord = record2;
toRecord = record1;
newLine = line2.merge(point, line1);
} else {
throw new IllegalArgumentException("Lines for records don't touch");
}
Record newRecord;
if (line1Longer) {
newRecord = Records.copy(record1, newLine);
} else {
newRecord = Records.copy(record2, newLine);
}
setFromFieldValues(fromRecord, toRecord, newRecord);
setToFieldValues(toRecord, fromRecord, newRecord);
LengthFieldName.setRecordLength(newRecord);
return newRecord;
}
/**
* Get a new record that is the result of merging the two records. The
* attributes will be taken from the record with the longest length. If one
* line needs to be reversed then the second record will be reversed.
*
* @param record1
* @param record2
* @return
*/
public Record getMergedRecord(final Record record1, Record record2) {
final LineString line1 = record1.getGeometry();
final int vertexCount1 = line1.getVertexCount();
LineString line2 = record2.getGeometry();
final int vertexCount2 = line2.getVertexCount();
Record fromRecord;
Record toRecord;
final boolean line1Longer = line1.getLength() > line2.getLength();
LineString newLine;
if (line1.equalsVertex(2, 0, line2, 0)) {
record2 = getReverse(record2);
line2 = record2.getGeometry();
fromRecord = record2;
toRecord = record1;
newLine = line1.merge(line2);
} else if (line1.equalsVertex(2, vertexCount1 - 1, line2, vertexCount2 - 1)) {
record2 = getReverse(record2);
line2 = record2.getGeometry();
fromRecord = record1;
toRecord = record2;
newLine = line1.merge(line2);
} else if (line1.equalsVertex(2, vertexCount1 - 1, line2, 0)) {
fromRecord = record1;
toRecord = record2;
newLine = line1.merge(line2);
} else if (line1.equalsVertex(2, 0, line2, vertexCount2 - 1)) {
fromRecord = record2;
toRecord = record1;
newLine = line2.merge(line1);
} else {
throw new IllegalArgumentException("Lines for records don't touch");
}
Record newRecord;
if (line1Longer) {
newRecord = Records.copy(record1, newLine);
} else {
newRecord = Records.copy(record2, newLine);
}
setFromFieldValues(fromRecord, toRecord, newRecord);
setToFieldValues(toRecord, fromRecord, newRecord);
LengthFieldName.setRecordLength(newRecord);
return newRecord;
}
public Record getMergedRecordReverseLongest(final Point point, final Record record1,
final Record record2) {
final LineString line1 = record1.getGeometry();
final LineString line2 = record2.getGeometry();
if (line1.getLength() >= line2.getLength()) {
return getMergedRecord(point, record1, record2);
} else {
return getMergedRecord(point, record2, record1);
}
}
/**
* Get a new record that is the result of merging the two records. The
* attributes will be taken from the record with the longest length. If one
* line needs to be reversed then the longest will be reversed.
*
* @param record1
* @param record2
* @return
*/
public Record getMergedRecordReverseLongest(final Record record1, final Record record2) {
final LineString line1 = record1.getGeometry();
final LineString line2 = record2.getGeometry();
if (line1.getLength() >= line2.getLength()) {
return getMergedRecord(record1, record2);
} else {
return getMergedRecord(record2, record1);
}
}
@Override
public String getPropertyName() {
return PROPERTY_NAME;
}
public Record getReverse(final Record record) {
final Record reverse = record.clone();
reverseFieldValuesAndGeometry(reverse);
return reverse;
}
public String getReverseFieldName(final String fieldName) {
return this.reverseFieldNameMap.get(fieldName);
}
public Map<String, Object> getReverseFieldValues(final Map<String, Object> record) {
final Map<String, Object> reverse = new LinkedHashMap<>(record);
for (final Entry<String, String> pair : this.reverseFieldNameMap.entrySet()) {
final String fromFieldName = pair.getKey();
final String toFieldName = pair.getValue();
final Object toValue = record.get(toFieldName);
reverse.put(fromFieldName, toValue);
}
for (final String fieldName : this.directionalFieldValues.keySet()) {
final Object value = getDirectionalFieldValue(record, fieldName);
reverse.put(fieldName, value);
}
return reverse;
}
public Map<String, Object> getReverseFieldValuesAndGeometry(final Map<String, Object> record) {
final Map<String, Object> reverse = getReverseFieldValues(record);
final String geometryFieldName = getRecordDefinition().getGeometryFieldName();
if (geometryFieldName != null) {
final Geometry geometry = getReverseLine(record);
reverse.put(geometryFieldName, geometry);
}
return reverse;
}
public Map<String, Object> getReverseGeometry(final Map<String, Object> record) {
final Map<String, Object> reverse = new LinkedHashMap<>(record);
final String geometryFieldName = getRecordDefinition().getGeometryFieldName();
if (geometryFieldName != null) {
final Geometry geometry = getReverseLine(record);
reverse.put(geometryFieldName, geometry);
}
return reverse;
}
protected Geometry getReverseLine(final Map<String, Object> record) {
final String geometryFieldName = getRecordDefinition().getGeometryFieldName();
final LineString line = (LineString)record.get(geometryFieldName);
if (line == null) {
return null;
} else {
final LineString reverseLine = line.reverse();
return reverseLine;
}
}
protected String getSideFieldName(final String fieldName) {
return this.sideFieldNamePairs.get(fieldName);
}
public Map<String, String> getSideFieldNamePairs() {
return this.sideFieldNamePairs;
}
public Set<String> getToFieldNames() {
return this.toFieldNames;
}
public boolean hasDirectionalFields() {
return !this.directionalFieldValues.isEmpty() || !this.reverseFieldNameMap.isEmpty();
}
public boolean hasDirectionalFieldValues(final String fieldName) {
return this.directionalFieldValues.containsKey(fieldName);
}
public boolean isFromField(final String fieldName) {
return this.fromFieldNames.contains(fieldName);
}
protected boolean isNull(final Record record1, final String name1, final Record record2,
final String name2, final Collection<String> equalExcludeFieldNames) {
final Object value1 = record1.getValue(name1);
final Object value2 = record2.getValue(name2);
if (value1 == null && value2 == null) {
return true;
} else {
return false;
}
}
public boolean isSideField(final String fieldName) {
return this.sideFieldNames.contains(fieldName);
}
public boolean isToField(final String fieldName) {
return this.toFieldNames.contains(fieldName);
}
public Map<String, Object> newSplitValues(final Record oldRecord, final LineString oldLine,
final Point splitPoint, final LineString newLine) {
final Map<String, Object> newValues = Maps.newLinkedHash(oldRecord);
final String geometryFieldName = oldRecord.getGeometryFieldName();
newValues.put(geometryFieldName, newLine);
setSplitFieldValues(oldLine, splitPoint, newValues, newLine);
return newValues;
}
public void reverseFieldValues(final Map<String, Object> record) {
final Map<String, Object> reverseFieldValues = getReverseFieldValues(record);
record.putAll(reverseFieldValues);
}
public void reverseFieldValuesAndGeometry(final Map<String, Object> record) {
final Map<String, Object> reverseFieldValues = getReverseFieldValuesAndGeometry(record);
record.putAll(reverseFieldValues);
}
public void reverseGeometry(final Map<String, Object> record) {
final Map<String, Object> reverseFieldValues = getReverseGeometry(record);
record.putAll(reverseFieldValues);
}
public void setDirectionalFieldValues(
final Map<String, Map<Object, Object>> directionalFieldValuesValues) {
for (final Entry<String, Map<Object, Object>> entry : directionalFieldValuesValues.entrySet()) {
final String fieldName = entry.getKey();
final Map<Object, Object> values = entry.getValue();
addDirectionalFieldValues(fieldName, values);
}
}
public void setEdgeSplitFieldNames(final LineString line, final Point point,
final List<Edge<Record>> edges) {
for (final Edge<Record> edge : edges) {
final Record record = edge.getObject();
setSplitFieldValues(record, line, point);
}
}
public void setEndAndSideFieldNamePairs(final List<List<String>> endAndSideFieldNamePairs) {
for (final List<String> endAndSideFieldNamePair : endAndSideFieldNamePairs) {
final String startLeftFieldName = endAndSideFieldNamePair.get(0);
final String startRightFieldName = endAndSideFieldNamePair.get(1);
final String endLeftFieldName = endAndSideFieldNamePair.get(2);
final String endRightFieldName = endAndSideFieldNamePair.get(3);
addEndAndSideFieldNamePairs(startLeftFieldName, startRightFieldName, endLeftFieldName,
endRightFieldName);
}
}
public void setEndFieldNamePairs(final Map<String, String> fieldNamePairs) {
this.endFieldNamePairs.clear();
this.toFieldNames.clear();
this.fromFieldNames.clear();
for (final Entry<String, String> pair : fieldNamePairs.entrySet()) {
final String from = pair.getKey();
final String to = pair.getValue();
addEndFieldNamePair(from, to);
}
}
public void setFromFieldValues(final Record source1, final Record source2,
final Map<String, Object> newRecord) {
for (final String fieldName : this.fromFieldNames) {
Object value = source1.getValue(fieldName);
if (value == null) {
value = source2.getValue(fieldName);
}
newRecord.put(fieldName, value);
}
}
public void setSideFieldNamePairs(final Map<String, String> fieldNamePairs) {
this.sideFieldNamePairs.clear();
for (final Entry<String, String> pair : fieldNamePairs.entrySet()) {
final String from = pair.getKey();
final String to = pair.getValue();
addSideFieldNamePair(from, to);
}
}
public void setSplitFieldValues(final LineString oldLine, final Point splitPoint,
final Map<String, Object> newRecord, final LineString newLine) {
final boolean firstPoint = newLine.equalsVertex(2, 0, splitPoint);
final boolean toPoint = newLine.equalsVertex(2, -1, splitPoint);
if (firstPoint) {
if (!toPoint) {
clearFromFields(newRecord);
}
} else if (toPoint) {
clearToFields(newRecord);
}
}
public void setSplitFieldValues(final Record newRecord, final LineString oldLine,
final Point splitPoint) {
final LineString newLine = newRecord.getGeometry();
if (newLine != null) {
setSplitFieldValues(oldLine, splitPoint, newRecord, newLine);
}
}
public void setToFieldValues(final Record toRecord, final Record fromRecord,
final Map<String, Object> newValues) {
for (final String fieldName : this.toFieldNames) {
Object value = toRecord.getValue(fieldName);
if (value == null) {
value = fromRecord.getValue(fieldName);
}
newValues.put(fieldName, value);
}
}
@Override
public String toString() {
return "DirectionalFields";
}
}