package com.revolsys.swing.table.geometry;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.swing.JComponent;
import javax.swing.undo.UndoableEdit;
import com.revolsys.datatype.DataTypes;
import com.revolsys.geometry.model.Geometry;
import com.revolsys.geometry.model.GeometryFactory;
import com.revolsys.geometry.model.Point;
import com.revolsys.geometry.model.Polygonal;
import com.revolsys.geometry.model.vertex.Vertex;
import com.revolsys.swing.field.NumberTextField;
import com.revolsys.swing.map.form.GeometryCoordinatesPanel;
import com.revolsys.swing.map.form.LayerRecordForm;
import com.revolsys.swing.map.layer.record.AbstractRecordLayer;
import com.revolsys.swing.map.layer.record.LayerRecord;
import com.revolsys.swing.table.AbstractTableModel;
import com.revolsys.swing.table.TablePanel;
import com.revolsys.swing.undo.UndoManager;
import com.revolsys.util.MathUtil;
import com.revolsys.util.Property;
public class GeometryCoordinatesTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
public static int[] getEventRowObject(final TablePanel panel) {
final GeometryCoordinatesTableModel model = panel.getTableModel();
final int row = TablePanel.getEventRow();
final int[] object = model.getVertexIndex(row);
return object;
}
public static Map<int[], Vertex> getIndexOfVertices(final Geometry geometry) {
final Map<int[], Vertex> pointIndexes = new LinkedHashMap<>();
if (geometry == null || geometry.isEmpty()) {
} else {
for (final Vertex vertex : geometry.vertices()) {
final int[] vertexId = vertex.getVertexId();
final Vertex clone = vertex.clone();
pointIndexes.put(vertexId, clone);
}
}
return pointIndexes;
}
private int axisCount;
private List<String> axisNames = Arrays.asList("#", "X", "Y", "Z", "M");
private int columnCount = 0;
private Reference<LayerRecordForm> form;
private Geometry geometry;
private final GeometryCoordinatesPanel geometryCoordinatesPanel;
private GeometryFactory geometryFactory;
private int numIndexItems;
private int segmentIndexColumn;
private int vertexIndexColumn;
private Map<int[], Vertex> vertexIndexMap = Collections.emptyMap();
private List<int[]> vertexIndices = Collections.emptyList();
public GeometryCoordinatesTableModel() {
this(null);
}
public GeometryCoordinatesTableModel(final GeometryCoordinatesPanel geometryCoordinatesPanel) {
this.geometryCoordinatesPanel = geometryCoordinatesPanel;
}
public int getAxisCount() {
return this.axisCount;
}
@Override
public Class<?> getColumnClass(final int columnIndex) {
if (columnIndex < this.numIndexItems) {
return Integer.class;
} else {
return Double.class;
}
}
@Override
public int getColumnCount() {
return this.columnCount;
}
@Override
public String getColumnName(final int column) {
return this.axisNames.get(column);
}
public double getCoordinate(final int rowIndex, final int columnIndex) {
if (rowIndex < getRowCount()) {
final int axisIndex = columnIndex - this.numIndexItems;
if (axisIndex > -1) {
final Point point = getVertex(rowIndex);
if (point != null) {
final double coordinate = point.getCoordinate(axisIndex);
return coordinate;
}
}
}
return Double.NaN;
}
@Override
public JComponent getEditorField(final int rowIndex, final int columnIndex, final Object value) {
if (columnIndex < this.numIndexItems) {
return null;
} else {
final int axisIndex = columnIndex - this.numIndexItems;
final int scale;
if (this.geometryFactory.isFloating()) {
scale = 7;
} else {
scale = (int)Math.ceil(Math.log10(this.geometryFactory.getScale(axisIndex)));
}
final NumberTextField field = new NumberTextField(DataTypes.DOUBLE, 20, scale);
field.setFieldValue(value);
field.setUndoManager(getForm().getUndoManager());
return field;
}
}
public LayerRecordForm getForm() {
return this.form.get();
}
public Geometry getGeometry() {
return this.geometry;
}
public int getNumIndexItems() {
return this.numIndexItems;
}
@Override
public int getRowCount() {
return this.vertexIndices.size();
}
public int getSegmentIndexColumn() {
return this.segmentIndexColumn;
}
@Override
public Object getValueAt(final int rowIndex, final int columnIndex) {
if (rowIndex < getRowCount()) {
final int[] vertexIndex = getVertexIndex(rowIndex);
if (columnIndex < vertexIndex.length) {
return vertexIndex[columnIndex];
} else if (columnIndex == this.segmentIndexColumn) {
return vertexIndex[vertexIndex.length - 1] + " \u2193";
} else {
final int axisIndex = columnIndex - this.numIndexItems;
final Point point = getVertex(rowIndex);
if (point == null) {
return "-";
} else {
final double coordinate = point.getCoordinate(axisIndex);
if (Double.isNaN(coordinate)) {
return "NaN";
} else if (Double.isInfinite(coordinate)) {
if (coordinate < 0) {
return "-Infinity";
} else {
return "Infinity";
}
} else {
return coordinate;
}
}
}
} else {
return "-";
}
}
private Vertex getVertex(final int rowIndex) {
final int[] vertexIndex = getVertexIndex(rowIndex);
if (vertexIndex == null) {
return null;
} else {
return this.vertexIndexMap.get(vertexIndex);
}
}
public int[] getVertexIndex(final int rowIndex) {
if (rowIndex >= 0 && rowIndex < getRowCount()) {
return this.vertexIndices.get(rowIndex);
} else {
return new int[0];
}
}
public int getVertexIndexColumn() {
return this.vertexIndexColumn;
}
@Override
public boolean isCellEditable(final int rowIndex, final int columnIndex) {
if (rowIndex < getRowCount()) {
if (columnIndex >= this.numIndexItems) {
return true;
}
}
return false;
}
public void setForm(final LayerRecordForm form) {
this.form = new WeakReference<>(form);
}
public void setGeometry(final Geometry geometry) {
final LayerRecordForm form = this.geometryCoordinatesPanel.getForm();
final LayerRecord record = form.getRecord();
final Geometry oldGeometry = record.getGeometry();
if (oldGeometry != geometry) {
final AbstractRecordLayer layer = record.getLayer();
final String geometryFieldName = record.getGeometryFieldName();
final UndoableEdit setGeometryUndo = layer.newSetFieldUndo(record, geometryFieldName,
oldGeometry, geometry);
final UndoManager undoManager = form.getUndoManager();
undoManager.addEdit(setGeometryUndo);
}
if (this.geometry != geometry) {
this.geometry = geometry;
if (geometry == null) {
this.geometryFactory = GeometryFactory.DEFAULT_3D;
this.vertexIndexMap = Collections.emptyMap();
this.vertexIndices = Collections.emptyList();
} else {
this.geometryFactory = geometry.getGeometryFactory();
this.vertexIndexMap = getIndexOfVertices(geometry);
this.vertexIndices = new ArrayList<>(this.vertexIndexMap.keySet());
}
this.axisCount = this.geometryFactory.getAxisCount();
this.axisNames = new ArrayList<>();
if (geometry.isGeometryCollection()) {
this.axisNames.add("P");
}
if (geometry instanceof Polygonal) {
this.axisNames.add("R");
}
this.vertexIndexColumn = this.axisNames.size();
this.axisNames.add("#");
this.segmentIndexColumn = this.axisNames.size();
this.axisNames.add("S #");
this.numIndexItems = this.axisNames.size();
this.axisNames.add("X");
this.axisNames.add("Y");
if (this.axisCount > 2) {
this.axisNames.add("Z");
}
if (this.axisCount > 3) {
this.axisNames.add("M");
}
this.columnCount = this.axisNames.size();
fireTableStructureChanged();
}
}
@Override
public void setValueAt(final Object value, final int rowIndex, final int columnIndex) {
if (Property.hasValue(value)) {
if (rowIndex < getRowCount()) {
if (columnIndex >= this.numIndexItems) {
final int axisIndex = columnIndex - this.numIndexItems;
final Vertex vertex = getVertex(rowIndex);
if (vertex != null) {
final double[] coordinates = vertex.getCoordinates();
coordinates[axisIndex] = MathUtil.toDouble(value.toString());
final Point newPoint = this.geometryFactory.point(coordinates);
if (!newPoint.equalsExact(vertex)) {
final int[] vertexId = vertex.getVertexId();
final Geometry newGeometry = this.geometry.moveVertex(newPoint, vertexId);
setGeometry(newGeometry);
}
}
}
}
}
}
public void setVertexIndexColumn(final int vertexIndexColumn) {
this.vertexIndexColumn = vertexIndexColumn;
}
}