/*
* Copyright 1998-2015 University Corporation for Atmospheric Research/Unidata
*
* Portions of this software were developed by the Unidata Program at the
* University Corporation for Atmospheric Research.
*
* Access and use of this software shall impose the following obligations
* and understandings on the user. The user is granted the right, without
* any fee or cost, to use, copy, modify, alter, enhance and distribute
* this software, and any derivative works thereof, and its supporting
* documentation for any purpose whatsoever, provided that this entire
* notice appears in all copies of the software, derivative works and
* supporting documentation. Further, UCAR requests that the user credit
* UCAR/Unidata in any publications that result from the use of this
* software or in any product that includes this software. The names UCAR
* and/or Unidata, however, may not be used in any advertising or publicity
* to endorse or promote any products or commercial entity unless specific
* written permission is obtained from UCAR/Unidata. The user also
* understands that UCAR/Unidata is not obligated to provide the user with
* any support, consulting, training or assistance of any kind with regard
* to the use, operation and performance of this software nor to provide
* the user with any updates, revisions, new versions or "bug fixes."
*
* THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package ucar.nc2.ft.cover.impl;
import com.google.protobuf.ByteString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import thredds.inventory.MFile;
import ucar.ma2.Array;
import ucar.ma2.DataType;
import ucar.nc2.Attribute;
import ucar.nc2.constants.CDM;
import ucar.nc2.dataset.CoordinateAxis;
import ucar.nc2.dataset.CoordinateTransform;
import ucar.nc2.dataset.TransformType;
import ucar.nc2.ft.cover.Coverage;
import ucar.nc2.ft.cover.CoverageCS;
import ucar.nc2.ft.cover.CoverageDataset;
import ucar.nc2.ft.cover.collection.CoverageProto;
import ucar.nc2.stream.NcStream;
import ucar.unidata.io.RandomAccessFile;
import ucar.unidata.util.Parameter;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.DoubleBuffer;
import java.util.List;
/**
* Describe
*
* @author caron
* @since 3/7/2015
*/
public class CoverageIndexWriter {
static public final int version = 1;
static private final Logger logger = LoggerFactory.getLogger(CoverageIndexWriter.class);
public static final String MAGIC_START = "CoverageGridv01Index"; // was Grib1CollectionIndex
// indexFile is in the cache
public boolean writeIndex(String name, File idxFile, List<MFile> files, CoverageDataset cds) throws IOException {
boolean deleteOnClose = false;
if (idxFile.exists()) {
RandomAccessFile.eject(idxFile.getPath());
if (!idxFile.delete())
logger.warn(" gc1 cant delete index file {}", idxFile.getPath());
}
logger.debug(" createIndex for {}", idxFile.getPath());
try (RandomAccessFile raf = new RandomAccessFile(idxFile.getPath(), "rw")) {
raf.order(RandomAccessFile.BIG_ENDIAN);
//// header message
raf.write(MAGIC_START.getBytes(CDM.utf8Charset));
raf.writeInt(version);
CoverageProto.GridCollection.Builder indexBuilder = CoverageProto.GridCollection.newBuilder();
indexBuilder.setName(name);
indexBuilder.setTopDir("faike");
/* directory and mfile list
File directory = new File(dcm.getRoot());
List<GcMFile> gcmfiles = GcMFile.makeFiles(directory, files, allFileSet);
for (MFile gcmfile : files) {
CoverageProto.MFile.Builder b = CoverageProto.MFile.newBuilder();
b.setFilename(gcmfile.getName());
b.setLastModified(gcmfile.getLastModified());
b.setLength(gcmfile.getLength());
//b.setIndex(gcmfile.index); // LOOK ??
indexBuilder.addMfiles(b.build());
} */
for (CoverageDataset.CoverageSet cset : cds.getCoverageSets())
indexBuilder.addCsets( writeCoverageSet( cset));
//for (Attribute att : cds.getAttributes())
// indexBuilder.addAtts(writeAttribute(att));
CoverageProto.GridCollection index = indexBuilder.build();
byte[] b = index.toByteArray();
NcStream.writeVInt(raf, b.length); // message size
raf.write(b); // message - all in one gulp
logger.debug(" write GribCollectionIndex= {} bytes", b.length);
logger.debug(" file size = %d bytes", raf.length());
return true;
} finally {
// remove it on failure
if (deleteOnClose && !idxFile.delete())
logger.error(" gc1 cant deleteOnClose index file {}", idxFile.getPath());
}
}
protected CoverageProto.CoverageSet writeCoverageSet(CoverageDataset.CoverageSet cset) throws IOException {
CoverageProto.CoverageSet.Builder b = CoverageProto.CoverageSet.newBuilder();
b.setName("fake");
b.setCs( writeCoverageCS( cset.getCoverageCS()));
for (Coverage coverage : cset.getCoverages())
b.addCoverages(writeCoverage(coverage));
return b.build();
}
protected CoverageProto.CoverageCS writeCoverageCS(CoverageCS coverCS) throws IOException {
CoverageProto.CoverageCS.Builder b = CoverageProto.CoverageCS.newBuilder();
b.setName(coverCS.getName());
for (CoordinateAxis axis : coverCS.getCoordinateAxes())
b.addCoords(writeCoordinateAxis(axis));
for (CoordinateTransform transform : coverCS.getCoordinateTransforms())
b.addTransforms(writeCoordinateTransform(transform));
return b.build();
}
protected CoverageProto.Coverage writeCoordinateAxis(CoordinateAxis axis) throws IOException {
CoverageProto.Coverage.Builder b = CoverageProto.Coverage.newBuilder();
b.setName(axis.getShortName());
b.setDataType(axis.getDataType().ordinal());
for (Attribute att : axis.getAttributes())
b.addAtts(writeAttribute(att));
b.setAxisType(axis.getAxisType().ordinal());
return b.build();
}
protected CoverageProto.CoordTransform writeCoordinateTransform(CoordinateTransform t) throws IOException {
CoverageProto.CoordTransform.Builder b = CoverageProto.CoordTransform.newBuilder();
b.setName(t.getName());
b.setType(t.getTransformType() == TransformType.Projection ? CoverageProto.CoordTransform.Type.HORIZ : CoverageProto.CoordTransform.Type.VERT);
for (Parameter att : t.getParameters())
b.addAtts(writeParameter(att));
return b.build();
}
protected CoverageProto.Coverage writeCoverage(Coverage cover) throws IOException {
CoverageProto.Coverage.Builder b = CoverageProto.Coverage.newBuilder();
b.setName(cover.getShortName());
b.setDataType(cover.getDataType().ordinal());
for (Attribute att : cover.getAttributes())
b.addAtts(writeAttribute(att));
return b.build();
}
protected CoverageProto.Attribute.Builder writeAttribute(Attribute att) throws IOException {
CoverageProto.Attribute.Builder b = CoverageProto.Attribute.newBuilder();
b.setName(att.getShortName());
b.setDataType(att.getDataType().ordinal());
b.setLen(att.getLength());
if (att.isUnsigned())
b.setUnsigned(true);
if (att.getLength() > 0) {
if (att.isString()) {
for (int i = 0; i < att.getLength(); i++)
b.addSdata(att.getStringValue(i));
} else {
Array data = att.getValues();
ByteBuffer bb = data.getDataAsByteBuffer();
b.setData(ByteString.copyFrom(bb.array()));
}
}
return b;
}
protected CoverageProto.Attribute.Builder writeParameter(Parameter att) throws IOException {
CoverageProto.Attribute.Builder b = CoverageProto.Attribute.newBuilder();
b.setName(att.getName());
DataType dtype = att.isString() ? DataType.STRING : DataType.DOUBLE;
b.setDataType(dtype.ordinal());
b.setLen(att.getLength());
if (att.isString()) {
b.addSdata(att.getStringValue());
} else {
b.setData(ByteString.copyFrom(getDataAsByteArray(att)));
}
return b;
}
private byte[] getDataAsByteArray(Parameter p) {
ByteBuffer bb = ByteBuffer.allocate(8*p.getLength());
DoubleBuffer ib = bb.asDoubleBuffer();
for (double dval : p.getNumericValues())
ib.put( dval);
return bb.array();
}
}