package org.basex.gui.view.plot;
import static org.basex.util.Token.*;
import java.util.Arrays;
import org.basex.core.Context;
import org.basex.data.Data;
import org.basex.data.Nodes;
import org.basex.index.StatsType;
import org.basex.index.Names;
import org.basex.util.list.IntList;
import org.basex.util.list.TokenList;
/**
* An additional layer which prepares the data for the scatter plot.
*
* @author BaseX Team 2005-12, BSD License
* @author Lukas Kircher
*/
final class PlotData {
/** Database context. */
final Context context;
/** The x axis of the plot. */
final PlotAxis xAxis;
/** The y axis of the plot. */
final PlotAxis yAxis;
/** Items pre values. */
int[] pres;
/** Item token selected by user. */
byte[] item = EMPTY;
/**
* Default constructor.
* @param ctx database context
*/
PlotData(final Context ctx) {
xAxis = new PlotAxis(this);
yAxis = new PlotAxis(this);
pres = new int[0];
context = ctx;
}
/**
* Returns a string array with all top items
* and the keys of the specified set.
* @return key array
*/
TokenList getItems() {
final Data data = context.data();
final TokenList tl = new TokenList();
if(data.meta.pathindex) {
for(final byte[] k : data.paths.desc(EMPTY, true, true)) {
if(getCategories(k).size() > 1) tl.add(k);
}
}
return tl;
}
/**
* Returns a string array with suitable categories for the specified item.
* @param it top item
* @return key array
*/
TokenList getCategories(final byte[] it) {
final Data data = context.data();
final TokenList tl = new TokenList();
if(data.meta.pathindex) {
for(final byte[] k : data.paths.desc(it, true, false)) {
final Names nm = startsWith(k, '@') ? data.atnindex : data.tagindex;
if(nm.stat(nm.id(delete(k, '@'))).type != StatsType.NONE) tl.add(k);
}
}
return tl;
}
/**
* Called if the user changes the item level displayed in the plot. If a new
* item was selected the plot data is recalculated.
* @param newItem item selected by the user
* @return true if a new item was selected and the plot data has been
* recalculated
*/
boolean setItem(final String newItem) {
if(newItem == null) return false;
final byte[] b = token(newItem);
if(eq(b, item)) return false;
item = b;
refreshItems(context.current(), true);
return true;
}
/**
* Refreshes item list and coordinates if the selection has changed. So far
* only numerical data is considered for plotting.
* @param nodes nodes to be displayed
* @param sub determine descendant nodes of given context nodes
*/
void refreshItems(final Nodes nodes, final boolean sub) {
final Data data = context.data();
final IntList tmpPres = new IntList();
final int itmID = data.tagindex.id(item);
if(!sub) {
pres = nodes.list;
Arrays.sort(pres);
return;
}
final int[] contextPres = nodes.list;
for(int p : contextPres) {
final int nl = p + data.size(p, Data.ELEM);
while(p < nl) {
final int kind = data.kind(p);
if(kind == Data.ELEM) {
if(data.name(p) == itmID) tmpPres.add(p);
p += data.attSize(p, kind);
} else {
++p;
}
}
}
pres = tmpPres.toArray();
Arrays.sort(pres);
}
/**
* Returns the array position of a given pre value by performing a binary
* search on the sorted pre values array currently displayed in the plot.
* @param pre pre value to be looked up
* @return array index if found, -1 if not
*/
int findPre(final int pre) {
return Arrays.binarySearch(pres, pre);
}
}