package com.revolsys.elevation.gridded.esriascii;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.util.zip.GZIPOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import com.revolsys.datatype.DataTypes;
import com.revolsys.elevation.gridded.GriddedElevationModel;
import com.revolsys.elevation.gridded.GriddedElevationModelWriter;
import com.revolsys.elevation.gridded.compactbinary.CompactBinaryGriddedElevation;
import com.revolsys.geometry.cs.esri.EsriCoordinateSystems;
import com.revolsys.geometry.model.BoundingBox;
import com.revolsys.geometry.model.GeometryFactory;
import com.revolsys.io.AbstractWriter;
import com.revolsys.io.FileUtil;
import com.revolsys.spring.resource.Resource;
import com.revolsys.util.Exceptions;
import com.revolsys.util.number.Doubles;
import com.revolsys.util.number.Integers;
public class EsriAsciiGriddedElevationModelWriter extends AbstractWriter<GriddedElevationModel>
implements GriddedElevationModelWriter {
private Resource resource;
private Writer writer;
public EsriAsciiGriddedElevationModelWriter(final Resource resource) {
this.resource = resource;
}
@Override
public void close() {
super.close();
flush();
if (this.writer != null) {
FileUtil.closeSilent(this.writer);
this.writer = null;
}
this.resource = null;
}
@Override
public void flush() {
if (this.writer != null) {
try {
this.writer.flush();
} catch (final IOException e) {
}
}
}
protected void open(final GriddedElevationModel model) {
final GeometryFactory geometryFactory = model.getGeometryFactory();
if (this.writer == null) {
final String fileNameExtension = this.resource.getFileNameExtension();
final OutputStream bufferedOut = this.resource.newBufferedOutputStream();
if ("zip".equals(fileNameExtension)
|| CompactBinaryGriddedElevation.FILE_EXTENSION_ZIP.equals(fileNameExtension)) {
try {
final String fileName = this.resource.getBaseName();
final ZipOutputStream zipOut = new ZipOutputStream(bufferedOut);
final String prjString = EsriCoordinateSystems.toString(geometryFactory);
if (prjString.length() > 0) {
final ZipEntry prjEntry = new ZipEntry(FileUtil.getBaseName(fileName) + ".prj");
zipOut.putNextEntry(prjEntry);
zipOut.write(prjString.getBytes(StandardCharsets.UTF_8));
}
final ZipEntry fileEntry = new ZipEntry(fileName);
zipOut.putNextEntry(fileEntry);
this.writer = new OutputStreamWriter(zipOut, StandardCharsets.UTF_8);
} catch (final IOException e) {
throw Exceptions.wrap("Error creating: " + this.resource, e);
}
} else if ("gz".equals(fileNameExtension)) {
try {
String fileName = this.resource.getBaseName();
if (!fileName.endsWith("." + CompactBinaryGriddedElevation.FILE_EXTENSION)) {
fileName += "." + CompactBinaryGriddedElevation.FILE_EXTENSION;
}
final GZIPOutputStream zipOut = new GZIPOutputStream(bufferedOut);
this.writer = new OutputStreamWriter(zipOut, StandardCharsets.UTF_8);
} catch (final IOException e) {
throw Exceptions.wrap("Error creating: " + this.resource, e);
}
} else {
EsriCoordinateSystems.writePrjFile(this.resource, geometryFactory);
this.writer = this.resource.newWriter();
}
}
}
@Override
public void write(final GriddedElevationModel model) {
final String nodataValue = DataTypes.toString(model.getProperty("nodataValue", "-9999"));
if (this.resource == null) {
throw new IllegalStateException("Writer is closed");
} else {
open(model);
try {
final BoundingBox boundingBox = model.getBoundingBox();
final int width = model.getGridWidth();
final int height = model.getGridHeight();
final int cellSize = model.getGridCellSize();
this.writer.write("NCOLS ");
this.writer.write(Integers.toString(width));
this.writer.write('\n');
this.writer.write("NROWS ");
this.writer.write(Integers.toString(height));
this.writer.write('\n');
this.writer.write("XLLCORNER ");
this.writer.write(Doubles.toString(boundingBox.getMinX()));
this.writer.write('\n');
this.writer.write("YLLCORNER ");
this.writer.write(Doubles.toString(boundingBox.getMinY()));
this.writer.write('\n');
this.writer.write("CELLSIZE ");
this.writer.write(Integers.toString(cellSize));
this.writer.write('\n');
this.writer.write("NODATA_VALUE ");
this.writer.write(nodataValue);
this.writer.write('\n');
for (int gridY = height - 1; gridY >= 0; gridY--) {
for (int gridX = 0; gridX < width; gridX++) {
final double elevation = model.getElevation(gridX, gridY);
if (Double.isFinite(elevation)) {
final String elevationString = Doubles.toString(elevation);
this.writer.write(elevationString);
} else {
this.writer.write(nodataValue);
}
this.writer.write(' ');
}
this.writer.write('\n');
}
this.writer.write('\n');
} catch (final Throwable e) {
throw Exceptions.wrap("Unable to write to: " + this.resource, e);
} finally {
close();
}
}
}
}