package mil.nga.giat.geowave.core.store.adapter.statistics;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import org.apache.commons.lang3.ArrayUtils;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
import mil.nga.giat.geowave.core.index.ByteArrayId;
import mil.nga.giat.geowave.core.index.Mergeable;
import mil.nga.giat.geowave.core.index.StringUtils;
import mil.nga.giat.geowave.core.store.base.DataStoreEntryInfo;
public class RowRangeDataStatistics<T> extends
AbstractDataStatistics<T>
{
public final static ByteArrayId STATS_TYPE = new ByteArrayId(
"ROW_RANGE");
private byte[] min = new byte[] {
(byte) 0xff
};
private byte[] max = new byte[] {
(byte) 0x00
};
public RowRangeDataStatistics() {}
public RowRangeDataStatistics(
ByteArrayId statisticsId ) {
super(
statisticsId,
composeId(statisticsId));
}
public static ByteArrayId composeId(
ByteArrayId statisticsId ) {
return new ByteArrayId(
ArrayUtils.addAll(
ArrayUtils.addAll(
STATS_TYPE.getBytes(),
STATS_SEPARATOR.getBytes()),
statisticsId.getBytes()));
}
public boolean isSet() {
return ((min.length > 1) || (min[0] != (byte) 0xff));
}
public byte[] getMin() {
return min;
}
public byte[] getMax() {
return max;
}
@Override
public byte[] toBinary() {
final ByteBuffer buffer = super.binaryBuffer(min.length + max.length + 4);
buffer.putInt(min.length);
buffer.put(min);
buffer.put(max);
return buffer.array();
}
@Override
public void fromBinary(
final byte[] bytes ) {
final ByteBuffer buffer = super.binaryBuffer(bytes);
final int minLength = buffer.getInt();
min = new byte[minLength];
buffer.get(min);
max = new byte[buffer.capacity() - buffer.position()];
buffer.get(max);
}
@Override
public void entryIngested(
final DataStoreEntryInfo entryInfo,
final T entry ) {
for (final ByteArrayId ids : entryInfo.getRowIds()) {
final byte[] idBytes = ids.getBytes();
min = compare(
min,
idBytes,
cardinality(
min,
idBytes)) > 0 ? idBytes : min;
max = compare(
max,
idBytes,
cardinality(
max,
idBytes)) < 0 ? idBytes : max;
}
}
@Override
public void merge(
final Mergeable statistics ) {
if ((statistics != null) && (statistics instanceof RowRangeDataStatistics)) {
@SuppressWarnings("unchecked")
final RowRangeDataStatistics<T> stats = (RowRangeDataStatistics<T>) statistics;
if (stats.isSet()) {
min = compare(
min,
stats.min,
cardinality(
min,
stats.min)) > 0 ? stats.min : min;
max = compare(
max,
stats.max,
cardinality(
max,
stats.max)) < 0 ? stats.max : max;
}
}
}
private int compare(
final byte[] a,
final byte[] b,
final int cardinality ) {
final BigInteger one = toInteger(
a,
cardinality);
final BigInteger two = toInteger(
b,
cardinality);
return one.compareTo(two);
}
private BigInteger toInteger(
final byte[] data,
final int cardinality ) {
return new BigInteger(
expandBy(
data,
cardinality));
}
private byte[] expandBy(
final byte[] b,
int cardinality ) {
final byte[] newD = new byte[cardinality + 1];
System.arraycopy(
b,
0,
newD,
1,
b.length);
return newD;
}
private int cardinality(
final byte[] a,
final byte[] b ) {
return Math.max(
a.length,
b.length);
}
@Override
public String toString() {
final StringBuffer buffer = new StringBuffer();
buffer.append(
"rows[index=").append(
getStatisticsId());
if (isSet()) {
buffer.append(
", min=").append(
StringUtils.stringFromBinary(getMin()));
buffer.append(
", max=").append(
StringUtils.stringFromBinary(getMax()));
}
else {
buffer.append(", No Values");
}
buffer.append("]");
return buffer.toString();
}
public JSONObject toJSONObject()
throws JSONException {
JSONObject jo = new JSONObject();
jo.put(
"type",
STATS_TYPE.getString());
jo.put(
"statisticsID",
statisticsId.getString());
if (isSet()) {
jo.put(
"min",
StringUtils.stringFromBinary(getMin()));
jo.put(
"max",
StringUtils.stringFromBinary(getMax()));
}
else {
jo.put(
"values",
"not set");
}
return jo;
}
}