/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.xwiki.rendering.wikimodel.util;
import java.util.ArrayList;
import java.util.List;
/**
* This is an internal utility class used as a context to keep in memory the
* current state of parsed trees (list items).
*
* @version $Id: a65caf30ecb590902e0b74aa4117a8bfc683ee12 $
* @since 4.0M1
*/
public final class TreeBuilder<X extends TreeBuilder.IPos<X>>
{
/**
* This interface identifies position of elements in rows.
*
* @author MikhailKotelnikov
*/
public interface IPos<X extends IPos<X>>
{
/**
* @return <code>true</code> if the underlying data in both positions
* are the same
*/
boolean equalsData(X pos);
/**
* @return the position of the node
*/
int getPos();
}
public interface ITreeListener<X extends IPos<X>>
{
void onBeginRow(X n);
void onBeginTree(X n);
void onEndRow(X n);
void onEndTree(X n);
}
private static <X extends IPos<X>> void addTail(
ITreeListener<X> listener,
List<X> firstArray,
List<X> secondArray,
int secondPos,
boolean openTree)
{
X n = getNode(secondArray, secondPos);
if (n == null) {
return;
}
if (openTree) {
listener.onBeginTree(n);
}
listener.onBeginRow(n);
firstArray.add(n);
addTail(listener, firstArray, secondArray, secondPos + 1, true);
}
private static <X extends IPos<X>> void doAlign(
ITreeListener<X> listener,
List<X> firstArray,
List<X> secondArray,
boolean expand)
{
boolean newTree = true;
int f;
int s;
int firstLen = firstArray.size();
int secondLen = secondArray.size();
for (f = 0, s = 0; f < firstLen && s < secondLen; f++) {
X first = firstArray.get(f);
X second = secondArray.get(s);
int firstPos = first.getPos();
int secondPos = second.getPos();
if (firstPos >= secondPos) {
if (!first.equalsData(second)) {
break;
} else if (s == secondLen - 1) {
newTree = false;
break;
}
s++;
}
}
removeTail(listener, firstArray, f, newTree, expand);
if (expand) {
addTail(listener, firstArray, secondArray, s, newTree);
}
}
private static <X extends IPos<X>> X getNode(List<X> list, int pos)
{
return pos < 0 || pos >= list.size() ? null : list.get(pos);
}
private static <X extends IPos<X>> void removeTail(
ITreeListener<X> listener,
List<X> array,
int pos,
boolean closeTree,
boolean remove)
{
X node = getNode(array, pos);
if (node == null) {
return;
}
removeTail(listener, array, pos + 1, true, true);
listener.onEndRow(node);
if (closeTree) {
listener.onEndTree(node);
}
if (remove) {
array.remove(pos);
}
}
public List<X> fList = new ArrayList<X>();
private ITreeListener<X> fListener;
public TreeBuilder(ITreeListener<X> listener)
{
super();
fListener = listener;
}
public void align(List<X> row)
{
doAlign(fListener, fList, row, true);
}
public void align(X pos)
{
List<X> list = new ArrayList<X>();
if (pos != null) {
list.add(pos);
}
align(list);
}
public X get(int pos)
{
return pos >= 0 && pos < fList.size() ? fList.get(pos) : null;
}
public X getPeek()
{
return get(fList.size() - 1);
}
public void trim(List<X> row)
{
doAlign(fListener, fList, row, false);
}
public void trim(X pos)
{
List<X> list = new ArrayList<X>();
if (pos != null) {
list.add(pos);
}
trim(list);
}
}