/* -*-             c-basic-offset: 4; indent-tabs-mode: nil; -*-  //------100-columns-wide------>|*/
// for license please see accompanying LICENSE.txt file (available also at http://www.xmlpull.org/)

package org.xmlpull.v1.wrapper;

import java.io.IOException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

/**
 * Handy functions that combines XMLPULL API into higher level functionality.
 *
 * @author <a href="http://www.extreme.indiana.edu/~aslom/">Aleksander Slominski</a>
 */
public class XmlPullWrapper {
    protected XmlPullParser pp;

    public XmlPullWrapper(XmlPullParser parser) {
        pp = parser;
    }

    public XmlPullParser getPullParser() { return pp; }

    /**
     * This method bypasses all child subtrees until it reached END_TAG for current tree.
     * Parser must be on START_TAG of one of child subtrees.
     */
    public void jumpToEndOfTree()
        throws XmlPullParserException, IOException
    {
        pp.require(pp.START_TAG, null, null);
        while(true) {
            int eventType = pp.next();
            if (eventType == pp.START_TAG) {
                skipSubTree();
                pp.require(pp.END_TAG, null, null);
                pp.next(); //skip end tag
            } else if(eventType == pp.END_TAG) {
                break;
            }
        }
    }

    /**
     * This method bypasses all child subtrees until it finds a child subtree with start tag
     * that matches the tag name (if not null) and namespsce (if not null)
     * passed in. Parser must be positioned on START_TAG.
     * <p>If succesfulpositions parser on such START_TAG and return true
     * otherwise this method returns false and parser is positioned on END_TAG
     * signaling last element in curren subtree.
     */
    public boolean jumpToSubTree(final String tagNamespace, final String tagName)
        throws XmlPullParserException, IOException
    {
        if(tagNamespace == null && tagName == null) {
            throw new IllegalArgumentException(
                "namespace and name argument can not be both null:"+pp.getPositionDescription());
        }
        pp.require(pp.START_TAG, null, null);
        while(true) {
            int eventType = pp.next();

            if (eventType == pp.START_TAG)
            {
                String name = pp.getName();
                String namespace = pp.getNamespace();
                boolean matches = (tagNamespace != null && tagNamespace.equals(namespace))
                    ||(tagName != null && tagName.equals(name));
                if(matches) {
                    return true;
                }
                skipSubTree();
                pp.require(pp.END_TAG, name, namespace);
                pp.next(); //skip end tag
            } else if(eventType == pp.END_TAG) {
                return false;
            }
        }
    }

    /**
     * This method bypasses all events until it finds a start tag that has
     * passed in namesapce (if not null) and namespace (if not null).
     *
     * @return true if such START_TAG was found or false otherwise (and parser is on END_DOCUMENT).
     */
    public boolean jumpToStartTag(final String tagNamespace, final String tagName)
        throws XmlPullParserException, IOException
    {
        if(tagNamespace == null && tagName == null) {
            throw new IllegalArgumentException(
                "namespace and name argument can not be both null:"+pp.getPositionDescription());
        }
        while(true) {
            int eventType = pp.next();
            if(eventType == pp.START_TAG)
            {
                String name = pp.getName();
                String namespace = pp.getNamespace();
                boolean matches = (tagNamespace != null && tagNamespace.equals(namespace))
                    ||(tagName != null && tagName.equals(name));
                if(matches) {
                    return true;
                }
            } else if(eventType == pp.END_DOCUMENT) {
                return false;
            }

        }
    }

    /**
     * This method bypasses all events until it finds an end tag that has
     * passed in namesapce (if not null) and namespace (if not null).
     *
     * @return true if such END_TAG was found or false otherwise (and parser is on END_DOCUMENT).
     */
    public boolean jumpToEndTag(final String tagNamespace, final String tagName)
        throws XmlPullParserException, IOException
    {
        if(tagNamespace == null && tagName == null) {
            throw new IllegalArgumentException(
                "namespace and name argument can not be both null:"+pp.getPositionDescription());
        }
        while(true) {
            int eventType = pp.next();
            if(eventType == pp.END_TAG)
            {
                String name = pp.getName();
                String namespace = pp.getNamespace();
                boolean matches = (tagNamespace != null && tagNamespace.equals(namespace))
                    ||(tagName != null && tagName.equals(name));
                if(matches) {
                    return true;
                }
            } else if(eventType == pp.END_DOCUMENT) {
                return false;
            }

        }
    }

}

