package org.geotoolkit.metadata.dimap;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Date;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import org.opengis.util.FactoryException;
import org.apache.sis.referencing.CommonCRS;
import org.apache.sis.util.logging.Logging;
import org.geotoolkit.coverage.GridSampleDimension;
import org.geotoolkit.image.io.metadata.SpatialMetadata;
import org.geotoolkit.image.io.metadata.SpatialMetadataFormat;
import org.geotoolkit.image.io.plugin.TiffImageReader;
import org.geotoolkit.internal.image.io.DimensionAccessor;
import org.geotoolkit.nio.IOUtilities;
import org.geotoolkit.metadata.geotiff.GeoTiffExtension;
import org.geotoolkit.util.DomUtilities;
import org.geotoolkit.util.dom.LazyLoadElement;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
/**
* Geotiff extension with partial support of DIMAP_v1.1 metadata format.
*
* @author Quentin Boileau (Geomatys)
*/
public class DimapExtension extends GeoTiffExtension {
private static final Logger LOGGER = Logging.getLogger("org.geotoolkit.metadata.dimap");
@Override
public boolean isPresent(Object input) {
try {
return searchMetadataFile(input) != null;
} catch (IOException e) {
LOGGER.log(Level.FINE, "Error searching dimap metadata file : "+e.getMessage(), e);
}
return false;
}
@Override
public SpatialMetadata fillSpatialMetaData(TiffImageReader reader, SpatialMetadata metadata) throws IOException {
final Path metadataFile = searchMetadataFile(reader.getInput());
if (metadataFile == null)
throw new IOException("Dimap metadata file not found.");
final Document doc;
try {
doc = DomUtilities.read(metadataFile);
} catch (ParserConfigurationException | SAXException ex) {
throw new IOException(ex);
}
final Element dimapNode = doc.getDocumentElement();
//add new format to SpatialMetadata
final SpatialMetadata dimapMetadata = new SpatialMetadata(DimapMetadataFormat.INSTANCE, reader, metadata);
dimapMetadata.mergeTree(DimapMetadataFormat.NATIVE_FORMAT, new LazyLoadElement(metadataFile));
boolean geotkFormat = false;
final String[] formatNames = dimapMetadata.getMetadataFormatNames();
for (int i = 0; i < formatNames.length; i++) {
String formatName = formatNames[i];
if (formatName.equals(SpatialMetadataFormat.GEOTK_FORMAT_NAME)) {
geotkFormat = true;
}
}
//ensure GEOTK format before override parts of metadata
if (!geotkFormat) {
return dimapMetadata;
}
try {
//temporal
final Date prodDate = DimapAccessor.getImagingDate(dimapNode);
if (prodDate != null) {
GeoTiffExtension.setOrCreateSliceDimension(dimapMetadata, CommonCRS.Temporal.JAVA.crs(), prodDate.getTime());
}
} catch (FactoryException e) {
throw new IOException(e.getMessage(), e);
}
// add GridSampleDimensions definition to SpatialMetadata
addSampleDimensions(dimapMetadata, dimapNode);
return dimapMetadata;
}
/**
* Add sample dimensions extracted from Dimap native metadata in SpatialMetadata.
* @param dimapMeta geotk spacial metadata
* @param dimapNode native Dimap metadata
*/
private void addSampleDimensions(SpatialMetadata dimapMeta, Element dimapNode) {
final DimensionAccessor dimAccessor = new DimensionAccessor(dimapMeta);
dimAccessor.selectParent();
dimAccessor.removeChildren();
final GridSampleDimension[] gridSampleDimensions = DimapAccessor.readSampleDimensions(dimapNode);
for (final GridSampleDimension sampleDimension : gridSampleDimensions) {
dimAccessor.selectChild(dimAccessor.appendChild()); //new child
dimAccessor.setDimension(sampleDimension, Locale.ENGLISH);
dimAccessor.selectParent();
}
}
private void writeDimapMetadata(SpatialMetadata metadata) {
if (metadata instanceof SpatialMetadata) {
final SpatialMetadata md = (SpatialMetadata) metadata;
final int index = Arrays.binarySearch(md.getMetadataFormatNames(), DimapMetadataFormat.NATIVE_FORMAT);
if(index >= 0){
//found some dimap metadatas, write them
final Node node = md.getAsTree(DimapMetadataFormat.NATIVE_FORMAT);
//TODO
final Object output = null;
try {
DomUtilities.write((Document) node, output);
} catch (TransformerException| IOException ex) {
LOGGER.log(Level.WARNING, ex.getMessage(), ex);
}
}
}
}
/**
* Search DIMAP metadata file.
* E.g. : For an input geotiff named "myimage.tif"
* DIMAP metadata file should be in the same directory and
* can be named "metadata.dim" or "myimage.dim" or "myimage.DIM".
*
* @param input reader image input
* @return File to metadata or null if not found.
* @throws MalformedURLException
*/
private Path searchMetadataFile(final Object input) throws IOException {
if (IOUtilities.canProcessAsPath(input)) {
final Path inputPath = IOUtilities.toPath(input);
final Path parent = inputPath.toAbsolutePath().getParent();
// filename.dim
final String pattern1 = IOUtilities.changeExtension(inputPath, "dim").getFileName().toString();
final String pattern2 = "metadata.dim";
// Quick search for "filename.dim"
final Path candidate1 = parent.resolve(pattern1);
if (Files.isRegularFile(candidate1)) return candidate1;
// Quick search for "metadata.dim"
final Path candidate2 = parent.resolve(pattern2);
if (Files.isRegularFile(candidate2)) return candidate2;
// Full directory scan.
// Search file with name matching patterns IGNORING case
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(parent)) {
for (Path candidate : dirStream) {
if (pattern1.equalsIgnoreCase(candidate.getFileName().toString())) {
return candidate;
} else if (pattern2.equalsIgnoreCase(candidate.getFileName().toString())) {
return candidate;
}
}
}
}
return null;
}
}