package org.basex.gui.view.tree; import org.basex.data.Data; import org.basex.util.list.IntList; import org.basex.util.list.ObjList; /** * This class determines nodes per level and caches them. * * @author BaseX Team 2005-12, BSD License * @author Wolfgang Miller */ final class TreeNodeCache implements TreeConstants { /** Document depth. */ private final int maxLevel; /** All nodes document nodes per level. */ private final IntList[] nodes; /** * This constructor invokes methods to cache all document nodes. * @param data data reference * @param atts show attributes */ TreeNodeCache(final Data data, final boolean atts) { final ObjList<IntList> alil = new ObjList<IntList>(); if(USE_CHILDITERATOR) { IntList parList = new IntList(1); parList.add(0); alil.add(parList); int l = 0; while(true) { parList = getNextNodeLine(parList, data); if(parList.size() == 0) break; alil.add(parList); ++l; } maxLevel = l + 1; } else { final int ts = data.meta.size; final IntList roots = data.resources.docs(); alil.add(new IntList()); for(int i = 0, is = roots.size(); i < is; ++i) { final int root = roots.get(i); alil.get(0).add(root); final int sh = i + 1 == roots.size() ? ts : roots.get(i + 1); for(int p = root + 1; p < sh; ++p) { final int k = data.kind(p); if(!atts && k == Data.ATTR || ONLY_ELEMENT_NODES & k != Data.ELEM) continue; int lv = 0; final int par = data.parent(p, k); while(par != alil.get(lv).get(alil.get(lv).size() - 1)) ++lv; for(int j = alil.size(); j <= lv + 1; ++j) alil.add(new IntList()); alil.get(lv + 1).add(p); } } maxLevel = alil.size(); } nodes = alil.toArray(new IntList[alil.size()]); } /** * Saves node line in parentList. * @param par array with nodes of the line before * @param data the data reference * @return IntList filled with nodes of the current line */ private static IntList getNextNodeLine(final IntList par, final Data data) { final int l = par.size(); final IntList line = new IntList(); for(int i = 0; i < l; ++i) { final int p = par.get(i); final ChildIterator iter = new ChildIterator(data, p); while(iter.more()) { final int pre = iter.next(); if(data.kind(pre) == Data.ELEM || !ONLY_ELEMENT_NODES) line.add(pre); } } return line; } /** * Returns the lowest index value. * @param lv level * @param lp left pre * @param rp right pre * @return index */ private int getMinIndex(final int lv, final int lp, final int rp) { final int l = 0; final int r = nodes[lv].size() - 1; int min = searchPreIndex(lv, lp, rp, l, r); if(min == -1) return min; final int[] n = nodes[lv].toArray(); while(min-- > 0 && n[min] > lp); return min + 1; } /** * Generates subtree borders. * @param d data reference * @param pre pre value * @return borders array */ TreeBorder[] subtree(final Data d, final int pre) { final TreeBorder[] bo = new TreeBorder[maxLevel]; if(pre == 0 && d.meta.ndocs == 1) { for(int i = 0; i < maxLevel; ++i) bo[i] = new TreeBorder(i, 0, nodes[i].size()); return bo; } final int[] rlp = findPre(pre); final int rl = rlp[0]; final int ri = rlp[1]; // level pair bo[rl] = new TreeBorder(rl, ri, 1); final int np = pre + d.size(pre, d.kind(pre)); int h = 1; for(int i = rl + 1; i < maxLevel; ++i) { final int min = getMinIndex(i, pre, np); if(min == -1) break; int c = 0; for(int j = min; j < nodes[i].size(); ++j) if(nodes[i].get(j) < np) ++c; else break; bo[i] = new TreeBorder(i, min, c); ++h; } final TreeBorder[] bon = new TreeBorder[h]; System.arraycopy(bo, rl, bon, 0, h); return bon; } /** * Finds pre value in cached nodes and returns level and index position. * @param pre pre value * @return level and position pair */ private int[] findPre(final int pre) { int pos = -1; int l; for(l = 0; l < maxLevel; ++l) { pos = searchPreArrayPos(l, 0, nodes[l].size() - 1, pre); if(pos > -1) break; } return pos > -1 ? new int[] { l, pos} : null; } /** * Determines the index position of given pre value. * @param lv level to be searched * @param l left array border * @param r right array border * @param pre pre value * @return the determined index position */ int searchPreArrayPos(final int lv, final int l, final int r, final int pre) { return searchPreIndex(lv, pre, pre, l, r); } /** * Returns pre by given index. * @param bo border * @param ix index * @return pre int getPrePerIndex(final TreeBorder bo, final int ix) { return * nodes[bo.level].get(bo.start + ix); } */ /** * Searches for pre value or pre range. * @param lv level * @param lb left TreeBorder * @param rb right TreeBorder * @param l left array TreeBorder * @param r right array TreeBorder * @return result index */ int searchPreIndex(final int lv, final int lb, final int rb, final int l, final int r) { int index = -1; int ll = l; int rr = r; while(rr >= ll && index == -1) { final int m = ll + (rr - ll) / 2; if(nodes[lv].get(m) < lb) { ll = m + 1; } else if(nodes[lv].get(m) > rb) { rr = m - 1; } else { index = m; } } return index; } /** * Returns pre value at given level and index. * @param lv level * @param i index * @return pre value */ int getPrePerLevelAndIndex(final int lv, final int i) { return nodes[lv].get(i); } }