/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* $Id$ */
package org.apache.fop.layoutmgr;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* An iterator over {@link Position} instances, that is wrapped around
* another 'parent' {@link Iterator}. The parent can be either another
* {@code PositionIterator}, or an iterator over {@link KnuthElement}s,
* for example.
* The {@link #next()} method always returns a {@link Position}. The
* {@link #getPos(Object)} method can be overridden in subclasses
* to take care of obtaining the {@link LayoutManager} or {@link Position}
* from the object returned by the parent iterator's {@code next()} method.
*/
public class PositionIterator implements Iterator {
private Iterator parentIter;
private Object nextObj;
private LayoutManager childLM;
private boolean hasNext;
/**
* Construct position iterator.
* @param parentIter an iterator to use as parent
*/
public PositionIterator(Iterator parentIter) {
this.parentIter = parentIter;
lookAhead();
//checkNext();
}
/** @return layout manager of next child layout manager or null */
public LayoutManager getNextChildLM() {
// Move to next "segment" of iterator, ie: new childLM
if (childLM == null && nextObj != null) {
childLM = getLM(nextObj);
hasNext = true;
}
return childLM;
}
/**
* @param nextObj next object from which to obtain position
* @return layout manager
*/
protected LayoutManager getLM(Object nextObj) {
return getPos(nextObj).getLM();
}
/**
* Default implementation assumes that the passed
* {@code nextObj} is itself a {@link Position}, and just returns it.
* Subclasses for which this is not the case, must provide a
* suitable override this method.
* @param nextObj next object from which to obtain position
* @return position of next object.
*/
protected Position getPos(Object nextObj) {
if (nextObj instanceof Position) {
return (Position)nextObj;
}
throw new IllegalArgumentException(
"Cannot obtain Position from the given object.");
}
private void lookAhead() {
if (parentIter.hasNext()) {
hasNext = true;
nextObj = parentIter.next();
} else {
endIter();
}
}
/** @return true if not at end of sub-sequence with same child layout manager */
protected boolean checkNext() {
LayoutManager lm = getLM(nextObj);
if (childLM == null) {
childLM = lm;
} else if (childLM != lm && lm != null) {
// End of this sub-sequence with same child LM
hasNext = false;
childLM = null;
return false;
}
return true;
}
/** end (reset) iterator */
protected void endIter() {
hasNext = false;
nextObj = null;
childLM = null;
}
/** {@inheritDoc} */
public boolean hasNext() {
return (hasNext && checkNext());
}
/** {@inheritDoc} */
public Position next() throws NoSuchElementException {
if (hasNext) {
Position retPos = getPos(nextObj);
lookAhead();
return retPos;
} else {
throw new NoSuchElementException("PosIter");
}
}
/** @return peek at next object */
public Object peekNext() {
return nextObj;
}
/** {@inheritDoc} */
public void remove() throws UnsupportedOperationException {
throw new UnsupportedOperationException("PositionIterator doesn't support remove");
}
}