/*
 * $Id: NodeTreeIterator.java 220 2007-07-16 10:32:15Z sugimotokenichi $
 * Copyright (C) 2005 SUGIMOTO Ken-ichi
 * 作成日： 2005/07/28
 */
package feat2.template;

import java.util.NoSuchElementException;

import feat2.template.impl.HTMLCompositeNodeImpl;
import feat2.template.impl.HTMLNodeImpl;


/**
 * HTMLツリーのイテレータ。
 * @author SUGIMOTO
 */
public class NodeTreeIterator implements NodeIterator {

    private HTMLNodeImpl start;
    private HTMLNodeImpl current;
    private HTMLNodeImpl next;
    private HTMLNodeImpl currentBak;
    private HTMLNodeImpl nextBak;

    /**
     * nodeから始まるイテレータを作る。
     * @param node nullのときは最初からhasNext()がfalseになる
     */
    public NodeTreeIterator(HTMLNode node) {
        start = nextBak = next = (HTMLNodeImpl)node;
    }

    public void remove() {
        if ( current == null ) {
            throw new IllegalStateException();
        }
        else {
            current.detach();
            current = null;
        }
    }

    public boolean hasNext() {
        return next != null;
    }

    public Object next() {
        return nextNode();
    }

    public HTMLNode nextNode() {
        if ( next == null ) {
            throw new NoSuchElementException();
        }
        else {
            current = next;
            next = null;

            if ( current instanceof HTMLCompositeNodeImpl ) {
                next = ((HTMLCompositeNodeImpl)current).firstChild;
            }

            // 子ノードがなければ次の兄弟ノードへ移る
            if ( next == null ) {
                // 開始ノードの子ノードがなかったときは終了
                if ( current == start )
                    return current;
                next = current.next;
            }

            // 次の兄弟ノードがなければ、親ノードの次のノードへ移る
            if ( next == null) {
                HTMLNodeImpl cur_ = current;
                while ( next == null ) {
                    cur_ = (HTMLNodeImpl)cur_.parent;

                    // 親ノードがないか、開始点に戻ったら終了
                    if ( cur_ == start || cur_ == null )
                        break;

                    next = cur_.next;
                }
            }
        }
        return current;
    }

    public void mark() {
        currentBak = current;
        nextBak = next;
    }

    public void reset() {
        current = currentBak;
        next = nextBak;
    }

    public boolean skip(Object o) {
        HTMLNodeImpl c = current;
        HTMLNodeImpl n = next;
        while(hasNext()) {
            if ( next() == o )
                return true;
        }
        current = c;
        next = n;
        return false;
    }

}
