package com.revolsys.swing.map.layer.elevation.gridded;
import java.beans.PropertyChangeEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Predicate;
import javax.swing.JFileChooser;
import com.revolsys.collection.map.MapEx;
import com.revolsys.collection.map.Maps;
import com.revolsys.elevation.gridded.GriddedElevationModel;
import com.revolsys.elevation.gridded.GriddedElevationModelWriterFactory;
import com.revolsys.geometry.model.BoundingBox;
import com.revolsys.geometry.model.GeometryFactory;
import com.revolsys.geometry.model.Point;
import com.revolsys.io.FileUtil;
import com.revolsys.io.IoFactory;
import com.revolsys.io.file.FileNameExtensionFilter;
import com.revolsys.io.map.MapObjectFactoryRegistry;
import com.revolsys.logging.Logs;
import com.revolsys.raster.GeoreferencedImageReadFactory;
import com.revolsys.spring.resource.Resource;
import com.revolsys.swing.Icons;
import com.revolsys.swing.SwingUtil;
import com.revolsys.swing.component.BasePanel;
import com.revolsys.swing.component.TabbedValuePanel;
import com.revolsys.swing.component.ValueField;
import com.revolsys.swing.layout.GroupLayouts;
import com.revolsys.swing.map.layer.AbstractLayer;
import com.revolsys.swing.map.layer.Project;
import com.revolsys.swing.menu.MenuFactory;
import com.revolsys.swing.menu.Menus;
import com.revolsys.swing.parallel.Invoke;
import com.revolsys.util.PreferencesUtil;
import com.revolsys.util.Property;
public class GriddedElevationModelLayer extends AbstractLayer {
public static final String J_TYPE = "griddedElevationModelLayer";
static {
final MenuFactory menu = MenuFactory.getMenu(GriddedElevationModelLayer.class);
menu.addGroup(0, "table");
menu.addGroup(2, "edit");
final Predicate<GriddedElevationModelLayer> notReadOnly = ((Predicate<GriddedElevationModelLayer>)GriddedElevationModelLayer::isReadOnly)
.negate();
final Predicate<GriddedElevationModelLayer> editable = GriddedElevationModelLayer::isEditable;
Menus.<GriddedElevationModelLayer> addCheckboxMenuItem(menu, "edit", "Editable", "pencil",
notReadOnly, GriddedElevationModelLayer::toggleEditable, editable, true);
Menus.<GriddedElevationModelLayer> addMenuItem(menu, "edit", "Save As...", "disk",
GriddedElevationModelLayer::saveAs, true);
Menus.<GriddedElevationModelLayer> addMenuItem(menu, "refresh", "Reload from File",
"page:refresh", GriddedElevationModelLayer::revertDo, true);
menu.deleteMenuItem("refresh", "Refresh");
}
public static void mapObjectFactoryInit() {
MapObjectFactoryRegistry.newFactory(J_TYPE, "Gridded Elevation Model Layer",
GriddedElevationModelLayer::new);
}
public static void saveAs(final String title, final Consumer<File> exportAction) {
Invoke.later(() -> {
final JFileChooser fileChooser = SwingUtil.newFileChooser("Save As",
"com.revolsys.swing.map.layer.elevation.gridded.save", "directory");
final String defaultFileExtension = PreferencesUtil.getUserString(
"com.revolsys.swing.map.layer.elevation.gridded.save", "fileExtension", "demcb");
final List<FileNameExtensionFilter> fileFilters = new ArrayList<>();
for (final GriddedElevationModelWriterFactory factory : IoFactory
.factories(GriddedElevationModelWriterFactory.class)) {
factory.addFileFilters(fileFilters);
}
IoFactory.sortFilters(fileFilters);
fileChooser.setAcceptAllFileFilterUsed(false);
fileChooser.setSelectedFile(new File(fileChooser.getCurrentDirectory(), title));
for (final FileNameExtensionFilter fileFilter : fileFilters) {
fileChooser.addChoosableFileFilter(fileFilter);
if (Arrays.asList(fileFilter.getExtensions()).contains(defaultFileExtension)) {
fileChooser.setFileFilter(fileFilter);
}
}
fileChooser.setMultiSelectionEnabled(false);
final int returnVal = fileChooser.showSaveDialog(SwingUtil.getActiveWindow());
if (returnVal == JFileChooser.APPROVE_OPTION) {
final FileNameExtensionFilter fileFilter = (FileNameExtensionFilter)fileChooser
.getFileFilter();
File file = fileChooser.getSelectedFile();
if (file != null) {
final String fileExtension = FileUtil.getFileNameExtension(file);
final String expectedExtension = fileFilter.getExtensions().get(0);
if (!fileExtension.equals(expectedExtension)) {
file = FileUtil.getFileWithExtension(file, expectedExtension);
}
final File targetFile = file;
PreferencesUtil.setUserString("com.revolsys.swing.map.layer.elevation.gridded.save",
"fileExtension", expectedExtension);
PreferencesUtil.setUserString("com.revolsys.swing.map.layer.elevation.gridded.save",
"directory", file.getParent());
final String description = "Save " + title + " as " + targetFile.getAbsolutePath();
Invoke.background(description, () -> {
exportAction.accept(targetFile);
});
}
}
});
}
private GriddedElevationModel elevationModel;
private int opacity = 255;
private Resource resource;
private String url;
public GriddedElevationModelLayer(final Map<String, ? extends Object> properties) {
super(J_TYPE);
setProperties(properties);
setSelectSupported(false);
setQuerySupported(false);
setReadOnly(true);
final GriddedElevationModelLayerRenderer renderer = new GriddedElevationModelLayerRenderer(
this);
setRenderer(renderer);
final int opacity = Maps.getInteger(properties, "opacity", 255);
setOpacity(opacity);
setIcon(Icons.getIcon("picture"));
}
@Override
public BoundingBox getBoundingBox() {
final GriddedElevationModel elevationModel = getElevationModel();
if (elevationModel == null) {
return BoundingBox.empty();
} else {
return elevationModel.getBoundingBox();
}
}
@Override
public BoundingBox getBoundingBox(final boolean visibleLayersOnly) {
if (isExists() && (isVisible() || !visibleLayersOnly)) {
return getBoundingBox();
} else {
return getGeometryFactory().newBoundingBoxEmpty();
}
}
public double getElevation(final Point point) {
return getElevationModel().getElevation(point);
}
public GriddedElevationModel getElevationModel() {
return this.elevationModel;
}
@Override
public GeometryFactory getGeometryFactory() {
if (this.elevationModel == null) {
return getBoundingBox().getGeometryFactory();
} else {
return this.elevationModel.getGeometryFactory();
}
}
public int getOpacity() {
return this.opacity;
}
@Override
protected boolean initializeDo() {
final String url = getProperty("url");
if (Property.hasValue(url)) {
this.url = url;
this.resource = Resource.getResource(url);
revertDo();
return this.elevationModel != null;
} else {
Logs.error(this, "Layer definition does not contain a 'url' property");
return false;
}
}
@Override
public boolean isVisible() {
return super.isVisible() || isEditable();
}
@Override
public TabbedValuePanel newPropertiesPanel() {
final TabbedValuePanel propertiesPanel = super.newPropertiesPanel();
return propertiesPanel;
}
@Override
protected ValueField newPropertiesTabGeneralPanelSource(final BasePanel parent) {
final ValueField panel = super.newPropertiesTabGeneralPanelSource(parent);
if (this.url.startsWith("file:")) {
final String fileName = this.url.replaceFirst("file:(//)?", "");
SwingUtil.addLabelledReadOnlyTextField(panel, "File", fileName);
} else {
SwingUtil.addLabelledReadOnlyTextField(panel, "URL", this.url);
}
final String fileNameExtension = FileUtil.getFileNameExtension(this.url);
if (Property.hasValue(fileNameExtension)) {
SwingUtil.addLabelledReadOnlyTextField(panel, "File Extension", fileNameExtension);
final GeoreferencedImageReadFactory factory = IoFactory
.factoryByFileExtension(GeoreferencedImageReadFactory.class, fileNameExtension);
if (factory != null) {
SwingUtil.addLabelledReadOnlyTextField(panel, "File Type", factory.getName());
}
}
GroupLayouts.makeColumns(panel, 2, true);
return panel;
}
@Override
public void propertyChange(final PropertyChangeEvent event) {
super.propertyChange(event);
final String propertyName = event.getPropertyName();
if ("hasChanges".equals(propertyName)) {
final GriddedElevationModel image = getElevationModel();
if (event.getSource() == image) {
image.writeGriddedElevationModel();
}
}
}
protected void revertDo() {
if (this.resource != null) {
GriddedElevationModel elevationModel = null;
final Resource resource = Resource.getResource(this.url);
if (resource.exists()) {
try {
elevationModel = GriddedElevationModel.newGriddedElevationModel(resource);
if (elevationModel == null) {
Logs.error(GriddedElevationModelLayer.class,
"Cannot load elevation model: " + this.url);
}
} catch (final RuntimeException e) {
Logs.error(GriddedElevationModelLayer.class, "Unable to elevation model: " + this.url, e);
}
} else {
Logs.error(GriddedElevationModelLayer.class, "Elevation model does not exist: " + this.url);
}
setElevationModel(elevationModel);
} else {
if (this.elevationModel != null) {
this.elevationModel.cancelChanges();
}
}
firePropertyChange("hasChanges", true, false);
firePropertyChange("refresh", false, true);
}
public void saveAs() {
saveAs(this.resource.getBaseName(), (file) -> {
this.elevationModel.writeGriddedElevationModel(file);
});
}
protected void saveImageChanges() {
if (this.elevationModel != null) {
this.elevationModel.writeGriddedElevationModel();
}
}
@Override
public void setBoundingBox(final BoundingBox boundingBox) {
if (this.elevationModel != null) {
System.out.println(boundingBox);
this.elevationModel.setBoundingBox(boundingBox);
}
}
public void setElevationModel(final GriddedElevationModel elevationModel) {
final GriddedElevationModel old = this.elevationModel;
Property.removeListener(this.elevationModel, this);
this.elevationModel = elevationModel;
if (elevationModel == null) {
setExists(false);
} else {
setExists(true);
Property.addListener(elevationModel, this);
}
firePropertyChange("elevationModel", old, this.elevationModel);
}
public void setOpacity(int opacity) {
final int oldValue = this.opacity;
if (opacity < 0) {
opacity = 0;
} else if (opacity > 255) {
opacity = 255;
}
this.opacity = opacity;
firePropertyChange("opacity", oldValue, opacity);
}
@Override
public MapEx toMap() {
final MapEx map = super.toMap();
map.remove("querySupported");
map.remove("selectSupported");
map.remove("editable");
map.remove("readOnly");
map.remove("showOriginalImage");
map.remove("imageSettings");
addToMap(map, "url", this.url);
addToMap(map, "opacity", this.opacity, 1);
return map;
}
@Override
public void zoomToLayer() {
final Project project = getProject();
final GeometryFactory geometryFactory = project.getGeometryFactory();
final BoundingBox layerBoundingBox = getBoundingBox();
final BoundingBox boundingBox = layerBoundingBox.convert(geometryFactory)//
.expandPercent(0.1)//
.clipToCoordinateSystem();
project.setViewBoundingBox(boundingBox);
}
}