

package org.treetank.service.xml.xpath.axis;

import org.treetank.api.INodeReadTrx;
import org.treetank.axis.AbsAxis;
import org.treetank.service.xml.xpath.XPathError;
import org.treetank.service.xml.xpath.XPathError.ErrorType;

/**
 * <h1>UnionAxis</h1>
 * <p>
 * Returns an union of two operands. This axis takes two node sequences as operands and returns a sequence
 * containing all the items that occur in either of the operands. A union of two sequences may lead to a
 * sequence containing duplicates. These duplicates can be removed by wrapping the UnionAxis with a
 * DupFilterAxis. The resulting sequence may also be out of document order.
 * </p>
 */
public class UnionAxis extends AbsAxis {

    /** First operand sequence. */
    private final AbsAxis mOp1;

    /** Second operand sequence. */
    private final AbsAxis mOp2;

    /**
     * Constructor. Initializes the internal state.
     * 
     * @param rtx
     *            Exclusive (immutable) trx to iterate with.
     * @param mOperand1
     *            First operand
     * @param mOperand2
     *            Second operand
     */
    public UnionAxis(final INodeReadTrx rtx, final AbsAxis mOperand1, final AbsAxis mOperand2) {

        super(rtx);
        mOp1 = mOperand1;
        mOp2 = mOperand2;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void reset(final long mNodeKey) {

        super.reset(mNodeKey);

        if (mOp1 != null) {
            mOp1.reset(mNodeKey);
        }
        if (mOp2 != null) {
            mOp2.reset(mNodeKey);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean hasNext() {

        // first return all values of the first operand
        while (mOp1.hasNext()) {
            mOp1.next();

            if (getNode().getDataKey() < 0) { // only nodes are
                // allowed
                throw new XPathError(ErrorType.XPTY0004);
            }
            return true;
        }

        // then all values of the second operand.
        while (mOp2.hasNext()) {
            mOp2.next();

            if (getNode().getDataKey() < 0) { // only nodes are
                // allowed
                throw new XPathError(ErrorType.XPTY0004);
            }
            return true;
        }

        return false;
    }

}
