package org.seqcode.data.readdb;
import java.io.*;
import java.util.*;
import java.nio.IntBuffer;
/**
* index information for a set of hits
*/
public class Header implements Closeable {
private int numHits;
/* indexPositions and indexPointers are paired arrays.
indexPositions contains values from the hits file;
the corresponding entry in indexPointers is the offset (in sizeof(int) units)
of the first position in the hits file that contains that value.
indexPositions may not contain duplicate values.
*/
private int[] indexPositions, indexPointers;
public int getNumHits() {return numHits;}
/* returns the first element in the file of hits
that should be read when looking for a hit at a given position.
Note that the value returned is a lower bound on the index of that
position in the list of hits.
*/
public int getFirstIndex(int position) {
if (indexPointers.length == 0) {
return 1;
}
int p = Arrays.binarySearch(indexPositions, position);
// System.err.println("First maps " + position + " to " + p);
if (p >= 0) {
// System.err.println("Returning " + indexPointers[p]);
return indexPointers[p];
} else {
p = (p+1)*-1 - 1;
if (p < 0) { p = 0;}
// System.err.println("Returning " + indexPointers[p]);
return indexPointers[p];
}
}
/* returns the last element in the file of hits that should
be read when looking for a hit at a given position.
This is an upper bound on the index of that position in the list of hits.
*/
public int getLastIndex(int position) {
if (indexPointers.length == 0) {
return 1;
}
int p = Arrays.binarySearch(indexPositions, position);
// System.err.println("Last maps " + position + " to " + p);
if (p >= 0) {
p++;
} else {
p = (p+1)*-1;
}
if (p < indexPointers.length) {
// System.err.println("Returning " + indexPointers[p]);
return indexPointers[p];
} else {
// System.err.println("Returning " + numHits);
return numHits;
}
}
/* empty constructor for use in saving/restoring from file
*/
public Header() {}
/**
* Creates a header file to index to provided set of hits.
* The hits must be sorted.
*/
public Header(IntBuffer hits) {
init(hits, 16*1024);
}
public Header(IntBuffer hits, int pagesize) {
init(hits, pagesize);
}
private void init(IntBuffer hits, int pagesize) {
indexPositions = new int[0];
indexPointers = new int[0];
numHits = hits.limit();
int hitstoskip = pagesize / 4;
ArrayList<Integer> positions = new ArrayList<Integer>();
ArrayList<Integer> pointers = new ArrayList<Integer>();
int lastposition = -10;
int lastpointer = -10 * hitstoskip;
for (int i = 0; i < numHits; i++) {
if (i > lastpointer + hitstoskip &&
lastposition != hits.get(i)) {
positions.add(hits.get(i));
pointers.add(i);
lastpointer = i;
}
lastposition = hits.get(i);
}
indexPositions = new int[positions.size()];
indexPointers = new int[positions.size()];
for (int i = 0; i < indexPositions.length; i++) {
indexPositions[i] = positions.get(i);
indexPointers[i] = pointers.get(i);
}
}
public void writeIndexFile(String fname) throws IOException {
OutputStream stream = new FileOutputStream(fname);
byte[] buffer = new byte[8192];
int[] nh = new int[1];
nh[0] = numHits;
Bits.sendInts(nh, stream, buffer);
Bits.sendInts(indexPositions, stream, buffer);
Bits.sendInts(indexPointers, stream, buffer);
stream.close();
}
public static Header readIndexFile(String fname) throws IOException {
File f = new File(fname);
long size = f.length();
InputStream stream = new FileInputStream(fname);
Header h = new Header();
byte[] buffer = new byte[8192];
int[] nh = Bits.readInts(1, stream, buffer);
h.numHits = nh[0];
size -= 4;
h.indexPositions = Bits.readInts((int)size/8, stream, buffer);
h.indexPointers = Bits.readInts((int)size/8, stream, buffer);
stream.close();
return h;
}
public void printIndex() {
for (int i = 0; i < indexPositions.length; i++) {
System.err.println(String.format("%d : %d -> %d",i,indexPointers[i],indexPositions[i]));
}
}
public void close() {}
}