/**
* Copyright 2004-2016 Riccardo Solmi. All rights reserved.
* This file is part of the Whole Platform.
*
* The Whole Platform 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 3 of the License, or
* (at your option) any later version.
*
* The Whole Platform 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 the Whole Platform. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whole.lang.iterators;
import java.util.NoSuchElementException;
import org.whole.lang.bindings.BindingManagerFactory;
import org.whole.lang.bindings.IBindingScope;
import org.whole.lang.model.IEntity;
import org.whole.lang.operations.ICloneContext;
/**
* iterator(nestedIterators[0](nestedIterators[1](...)))
*
* @author Riccardo Solmi
*/
public class ComposeIterator<E extends IEntity> extends AbstractLazyCloneableCompositeIterator<E> {
private IBindingScope lookaheadScope;
private IEntityIterator<E> iterator;
private IEntityIterator<? extends IEntity>[] nestedIterators;
private int laIndex = -1;
private E nextEntity = null;
protected ComposeIterator(IEntityIterator<E> iterator, IEntityIterator<? extends IEntity>... nestedIterators) {
this.iterator = iterator;
this.nestedIterators = nestedIterators;
laIndex = nestedIterators.length-1;
initLazyClone(false);
}
@Override
public IEntityIterator<E> clone(ICloneContext cc) {
ComposeIterator<E> iterator = (ComposeIterator<E>) super.clone(cc);
iterator.nestedIterators = iterator.nestedIterators.clone();
return iterator;
}
protected boolean lazyReset() {
return false;
}
public int childIteratorSize() {
return 1+nestedIterators.length;
}
protected IEntityIterator<?> childIterator(int index) {
return index == 0 ? iterator : nestedIterators[index-1];
}
@SuppressWarnings("unchecked")
protected void childIterator(int index, IEntityIterator<?> iterator) {
if (index == 0)
this.iterator = (IEntityIterator<E>) iterator;
else
nestedIterators[index-1] = (IEntityIterator<? extends E>) iterator;
}
protected final IEntityIterator<? extends IEntity> nestedIterator(int index) {
return getChildIterator(index+1);
//was return index == -1 ? iterator : nestedIterators[index];
}
protected boolean updateIterators(int startIndex) {
int updateIndex = startIndex;
do {
lookaheadScope().wClear();
for (int i=nestedIterators.length-1; i>updateIndex; i--)
lookaheadScope().wAddAll(nestedIterator(i).lookaheadScope());
while (nestedIterator(updateIndex).hasNext()) {
if (updateIndex == -1)
return true;
IEntity la = nestedIterator(updateIndex).next();
nestedIterator(--updateIndex).reset(la);
}
} while (updateIndex++ < startIndex);
return false;
}
protected boolean updateIterators() {
boolean result = false;
if (resetEntity != null) {
nestedIterator(laIndex).reset(resetEntity);
resetEntity = null;
}
getBindings().wEnterScope(lookaheadScope(), true);
for (int updateIndex = laIndex; updateIndex <= nestedIterators.length-1; updateIndex++)
if (updateIterators(updateIndex)) {
laIndex = -1;
result = true;
break;
}
getBindings().wExitScope();
return result;
}
public boolean hasNext() {
return lookahead() != null;
}
public E next() {
E result = lookahead();
if (result == null)
throw new NoSuchElementException();
//FIXME path prefix bindings are not bound
// for (String name : getChildIterator(0).lookaheadScope().wLocalNames()) {
// getBindings().wUnset(name);
// lookaheadScope().wUnset(name);
// }
// getBindings().wEnterScope(lookaheadScope(), true);
getChildIterator(0).next();
// getBindings().wExitScope(true);
getBindings().wAddAll(lookaheadScope());
laIndex = -1;
nextEntity = null;
return result;
}
@SuppressWarnings("unchecked")
public E lookahead() {
if (nextEntity != null)
return nextEntity;
if (!updateIterators())
return null;
//FIXME path prefix bindings are not bound
// getBindings().wEnterScope(lookaheadScope(), true);
nextEntity = ((IEntityIterator<E>) getChildIterator(0)).lookahead();
// getBindings().wExitScope();
lookaheadScope().wAddAll(getChildIterator(0).lookaheadScope());
return nextEntity;
}
@SuppressWarnings("unchecked")
public void set(E entity) {
((IEntityIterator<E>) getChildIterator(0)).set(entity);
}
@SuppressWarnings("unchecked")
public void add(E entity) {
((IEntityIterator<E>) getChildIterator(0)).add(entity);
}
public void remove() {
getChildIterator(0).remove();
}
public void reset(IEntity entity) {
super.reset(entity);
nextEntity = null;
laIndex = nestedIterators.length-1;
}
public IBindingScope lookaheadScope() {
if (lookaheadScope == null)
lookaheadScope = BindingManagerFactory.instance.createSimpleScope();
return lookaheadScope;
}
public void prune() {
}
@Override
public void toString(StringBuilder sb) {
for (int i=nestedIterators.length-1; i>=0; i--) {
sb.append(nestedIterators[i].toString());
sb.append("/");
}
sb.append(iterator.toString());
}
}