/*
 * AlternativeElement.java
 *
 * This program is free software: you can redistribute it and/or
 * modify it under the terms of the BSD license.
 *
 * This program 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
 * LICENSE.txt file for more details.
 *
 * Copyright (c) 2003-2015 Per Cederberg. All rights reserved.
 */

package net.percederberg.grammatica.parser.re;

import java.io.IOException;
import java.io.PrintWriter;

import net.percederberg.grammatica.parser.ReaderBuffer;

/**
 * A regular expression alternative element. This element matches the
 * longest alternative element.
 *
 * @author   Per Cederberg
 * @version  1.5
 */
class AlternativeElement extends Element {

    /**
     * The first alternative element.
     */
    private Element elem1;

    /**
     * The second alternative element.
     */
    private Element elem2;

    /**
     * Creates a new alternative element.
     *
     * @param first          the first alternative
     * @param second         the second alternative
     */
    public AlternativeElement(Element first, Element second) {
        elem1 = first;
        elem2 = second;
    }

    /**
     * Creates a copy of this element. The copy will be an instance
     * of the same class matching the same strings. Copies of elements
     * are necessary to allow elements to cache intermediate results
     * while matching strings without interfering with other threads.
     *
     * @return a copy of this element
     */
    public Object clone() {
        return new AlternativeElement(elem1, elem2);
    }

    /**
     * Returns the length of a matching string starting at the
     * specified position. The number of matches to skip can also be
     * specified, but numbers higher than zero (0) cause a failed
     * match for any element that doesn't attempt to combine other
     * elements.
     *
     * @param m              the matcher being used
     * @param buffer         the input character buffer to match
     * @param start          the starting position
     * @param skip           the number of matches to skip
     *
     * @return the length of the longest matching string, or
     *         -1 if no match was found
     *
     * @throws IOException if a I/O error occurred
     */
    public int match(Matcher m, ReaderBuffer buffer, int start, int skip)
        throws IOException {

        int  length = 0;
        int  length1 = -1;
        int  length2 = -1;
        int  skip1 = 0;
        int  skip2 = 0;

        while (length >= 0 && skip1 + skip2 <= skip) {
            length1 = elem1.match(m, buffer, start, skip1);
            length2 = elem2.match(m, buffer, start, skip2);
            if (length1 >= length2) {
                length = length1;
                skip1++;
            } else {
                length = length2;
                skip2++;
            }
        }
        return length;
    }

    /**
     * Prints this element to the specified output stream.
     *
     * @param output         the output stream to use
     * @param indent         the current indentation
     */
    public void printTo(PrintWriter output, String indent) {
        output.println(indent + "Alternative 1");
        elem1.printTo(output, indent + "  ");
        output.println(indent + "Alternative 2");
        elem2.printTo(output, indent + "  ");
    }

}
