package org.basex.index;
import java.io.IOException;
import java.util.Arrays;
import org.basex.core.Text;
import org.basex.data.MetaData;
import org.basex.io.in.DataInput;
import org.basex.io.out.DataOutput;
import org.basex.util.Array;
import org.basex.util.TokenBuilder;
import org.basex.util.Util;
import org.basex.util.hash.TokenIntMap;
import org.basex.util.hash.TokenSet;
/**
* This class indexes and organizes the tags or attribute names,
* used in an XML document.
*
* @author BaseX Team 2005-12, BSD License
* @author Christian Gruen
* @author Lukas Kircher
*/
public final class Names extends TokenSet implements Index {
/** Statistical information. */
private Stats[] stats;
/** Meta data. */
private final MetaData meta;
/**
* Default constructor.
* @param md meta data
*/
public Names(final MetaData md) {
stats = new Stats[CAP];
meta = md;
}
/**
* Constructor, specifying an input file.
* @param in input stream
* @param md meta data
* @throws IOException I/O exception
*/
public Names(final DataInput in, final MetaData md) throws IOException {
super(in);
stats = new Stats[keys.length];
meta = md;
for(int s = 1; s < size; ++s) stats[s] = new Stats(in);
}
/**
* Initializes the statistics.
*/
public void init() {
for(int s = 1; s < size; ++s) stats[s] = new Stats();
}
/**
* Indexes a name and returns its unique id.
* @param n name to be added
* @param v value, added to statistics
* @param st statistics flag
* @return name id
*/
public int index(final byte[] n, final byte[] v, final boolean st) {
final int i = Math.abs(add(n));
if(st) {
if(stats[i] == null) stats[i] = new Stats();
final Stats stat = stats[i];
if(v != null) stat.add(v, meta);
stat.count++;
}
return i;
}
/**
* Adds a value to the statistics of the specified key.
* Evaluates the value for the specified key id.
* @param n name id
* @param v value, added to statistics
*/
public void index(final int n, final byte[] v) {
stats[n].add(v, meta);
}
@Override
public void write(final DataOutput out) throws IOException {
super.write(out);
for(int s = 1; s < size; ++s) {
if(stats[s] == null) stats[s] = new Stats();
stats[s].write(out);
}
}
/**
* Returns the statistics for the specified key id.
* @param id id
* @return statistics
*/
public Stats stat(final int id) {
return stats[id];
}
@Override
public byte[] info() {
final double[] tl = new double[size];
int len = 0;
tl[0] = 0;
for(int i = 1; i < size; ++i) {
if(len < keys[i].length) len = keys[i].length;
if(stats[i] == null) continue;
tl[i] = stats[i].count;
}
len += 2;
// print all entries in descending number of occurrences
final int[] ids = Array.createOrder(tl, false);
final TokenBuilder tb = new TokenBuilder();
tb.add(Text.LI_STRUCTURE + Text.HASH + Text.NL);
tb.add(Text.LI_ENTRIES + (size - 1) + Text.NL);
for(int i = 0; i < size - 1; ++i) {
final int s = ids[i];
if(stats[s] == null) continue;
final byte[] key = keys[s];
tb.add(" ");
tb.add(key);
for(int j = 0; j < len - key.length; ++j) tb.add(' ');
tb.add(stats[s] + Text.NL);
}
return tb.finish();
}
@Override
public TokenIntMap entries(final byte[] prefix) {
final TokenIntMap tim = new TokenIntMap();
for(int i = 1; i < size; ++i) {
tim.add(keys[i], stats[i].count);
}
return tim;
}
@Override
protected void rehash() {
super.rehash();
stats = Arrays.copyOf(stats, size << 1);
}
@Override
public void close() { }
// Unsupported methods ======================================================
@Override
public IndexIterator iter(final IndexToken token) {
throw Util.notexpected();
}
@Override
public int count(final IndexToken token) {
throw Util.notexpected();
}
}