/*
* Copyright (c) 2012 The Broad Institute
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package htsjdk.variant.bcf2;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.EnumSet;
/**
* BCF2 types and associated information
*
* @author depristo
* @since 05/12
*/
public enum BCF2Type {
// the actual values themselves
MISSING(0, 0, 0x00) {
@Override public int read(final InputStream in) throws IOException {
throw new IllegalArgumentException("Cannot read MISSING type");
}
@Override public void write(final int value, final OutputStream out) throws IOException {
throw new IllegalArgumentException("Cannot write MISSING type");
}
},
INT8 (1, 1, 0xFFFFFF80, -127, 127) {
@Override
public int read(final InputStream in) throws IOException {
return BCF2Utils.readByte(in);
}
@Override
public void write(final int value, final OutputStream out) throws IOException {
out.write(0xFF & value); // TODO -- do we need this operation?
}
},
INT16(2, 2, 0xFFFF8000, -32767, 32767) {
@Override
public int read(final InputStream in) throws IOException {
final int b2 = BCF2Utils.readByte(in) & 0xFF;
final int b1 = BCF2Utils.readByte(in) & 0xFF;
return (short)((b1 << 8) | b2);
}
@Override
public void write(final int value, final OutputStream out) throws IOException {
// TODO -- optimization -- should we put this in a local buffer?
out.write((0x00FF & value));
out.write((0xFF00 & value) >> 8);
}
},
INT32(3, 4, 0x80000000, -2147483647, 2147483647) {
@Override
public int read(final InputStream in) throws IOException {
final int b4 = BCF2Utils.readByte(in) & 0xFF;
final int b3 = BCF2Utils.readByte(in) & 0xFF;
final int b2 = BCF2Utils.readByte(in) & 0xFF;
final int b1 = BCF2Utils.readByte(in) & 0xFF;
return (int)(b1 << 24 | b2 << 16 | b3 << 8 | b4);
}
@Override
public void write(final int value, final OutputStream out) throws IOException {
out.write((0x000000FF & value));
out.write((0x0000FF00 & value) >> 8);
out.write((0x00FF0000 & value) >> 16);
out.write((0xFF000000 & value) >> 24);
}
},
FLOAT(5, 4, 0x7F800001) {
@Override
public int read(final InputStream in) throws IOException {
return INT32.read(in);
}
@Override
public void write(final int value, final OutputStream out) throws IOException {
INT32.write(value, out);
}
},
CHAR (7, 1, 0x00000000) {
@Override
public int read(final InputStream in) throws IOException {
return INT8.read(in);
}
@Override
public void write(final int value, final OutputStream out) throws IOException {
INT8.write(value, out);
}
};
private final int id;
private final Object missingJavaValue;
private final int missingBytes;
private final int sizeInBytes;
private final long minValue, maxValue;
BCF2Type(final int id, final int sizeInBytes, final int missingBytes) {
this(id, sizeInBytes, missingBytes, 0, 0);
}
BCF2Type(final int id, final int sizeInBytes, final int missingBytes, final long minValue, final long maxValue) {
this.id = id;
this.sizeInBytes = sizeInBytes;
this.missingJavaValue = null;
this.missingBytes = missingBytes;
this.minValue = minValue;
this.maxValue = maxValue;
}
/**
* How many bytes are used to represent this type on disk?
* @return
*/
public int getSizeInBytes() {
return sizeInBytes;
}
/**
* The ID according to the BCF2 specification
* @return
*/
public int getID() { return id; }
/**
* Can we encode value v in this type, according to its declared range.
*
* Only makes sense for integer values
*
* @param v
* @return
*/
public final boolean withinRange(final long v) { return v >= minValue && v <= maxValue; }
/**
* Return the java object (aka null) that is used to represent a missing value for this
* type in Java
*
* @return
*/
public Object getMissingJavaValue() { return missingJavaValue; }
/**
* The bytes (encoded as an int) that are used to represent a missing value
* for this type in BCF2
*
* @return
*/
public int getMissingBytes() { return missingBytes; }
/**
* An enum set of the types that might represent Integer values
*/
private final static EnumSet<BCF2Type> INTEGERS = EnumSet.of(INT8, INT16, INT32);
/**
* @return true if this BCF2Type corresponds to the magic "MISSING" type (0x00)
*/
public boolean isMissingType() {
return this == MISSING;
}
public boolean isIntegerType() {
return INTEGERS.contains(this);
}
/**
* Read a value from in stream of this BCF2 type as an int [32 bit] collection of bits
*
* For intX and char values this is just the int / byte value of the underlying data represented as a 32 bit int
* For a char the result must be converted to a char by (char)(byte)(0x0F & value)
* For doubles it's necessary to convert subsequently this value to a double via Double.bitsToDouble()
*
* @param in
* @return
* @throws IOException
*/
public int read(final InputStream in) throws IOException {
throw new IllegalArgumentException("Not implemented");
}
public void write(final int value, final OutputStream out) throws IOException {
throw new IllegalArgumentException("Not implemented");
}
}