/*
 * Copyright The Sett Ltd, 2005 to 2014.
 *
 * Licensed 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.
 */
package com.thesett.common.util.maps;

import java.util.Iterator;

import com.thesett.common.util.Countable;
import com.thesett.common.util.Sizeable;

/**
 * CircularArrayMap is a map, that is keyed by integers. It places some approximate expectations of the life-cycle of
 * keys used in the map, in order to provide a fast and reasonably compact data structure. The expectations are:
 *
 *

 *
The integer keys will be generated sequentially and inserted into the map roughly in the order that they are
 * generated. This means that new keys are added as a compact block of sequential keys.

 *
The integer keys will be removed from the map roughly in the same order that they were inserted. This means that
 * as keys are removed from the map, the removals will not create blocks of keys that are very sparse.

 *

 *
 *
These expectations on the keys may be met by a process that works over a set of data in an approximately forward
 * only style. For example a process that takes data records and processes them though some sort of pipe-line, where
 * temporary values must be calculated and stored against the records at each stage of the pipe-line, but that can be
 * discarded later in the pipe-line, might be able to use this data structure efficiently.
 *
 *

CRC Card

 *
ResponsibilitiesCollaborations
 *
Look up a value by a key.
 *
Store a value against a key.
 *

 *
 * @author Rupert Smith
 */
public class CircularArrayMap<V> implements Dictionary<Integer, V>, Countable, Iterable<V>, Sizeable
{
    /** Default initial size of the array. */
    public static final int DEFAULT_INITIAL_SIZE = 16;

    /** Holds the low mark designating the highest table entry no longer used. */
    private int lowMark;

    /** Holds the start offset of the first entry in the array. */
    private int start;

    /** Holds the end offset of the last entry in the array. */
    private int end;

    /** Holds the current length of the allocated array. */
    private int length;

    /** Holds the mapped data. */
    private Object[] data;

    /** Holds a count of the number of elements in the map. */
    private int count;

    /**
     * Holds an offset, used to adjust the indexing when the element zero of the array does not align with index zero.
     */
    private int offset;

    /** Creates an array with the default initial size. */
    public CircularArrayMap()
    {
        this(DEFAULT_INITIAL_SIZE);
    }

    /**
     * Creates an array with the specified initial size.
     *
     * @param initialSize The initial size of the array.
     */
    public CircularArrayMap(int initialSize)
    {
        data = new Object[initialSize];
        length = data.length;
        lowMark = -1;
        start = 0;
        end = 0;
        count = 0;
        offset = 0;
    }

    /** {@inheritDoc} */
    public int size()
    {
        return count;
    }

    /** {@inheritDoc} */
    public boolean isEmpty()
    {
        return count == 0;
    }

    /**
     * {@inheritDoc}
     *
     * @throws ClassCastException If the key is not an Integer.
     */
    public boolean containsKey(Object objectKey)
    {
        int key = (Integer) objectKey;

        return keyInRange(key) && (data[offset(key)] != null);
    }

    /**
     * {@inheritDoc}
     *
     * @throws ClassCastException If the key is not an Integer.
     */
    public V get(Object objectKey)
    {
        int key = (Integer) objectKey;

        if (keyInRange(key))
        {
            return (V) data[offset(key)];
        }

        return null;
    }

    /** {@inheritDoc} */
    public V put(Integer key, V value)
    {
        if (keyTooLarge(key))
        {
            expand(key);
        }

        int offset = offset(key);
        V oldValue = (V) data[offset];
        data[offset] = value;

        // If the key is beyond the current end of the array, then move the end up.
        if (key >= end)
        {
            end = key + 1;
        }

        // Increment the count only if a new value was inserted.
        if (oldValue == null)
        {
            count++;
        }

        return oldValue;
    }

    /**
     * Clears entries up to and including the specified key, from the map. This is a simple garbage collection operation
     * to clear consumed data from the circular buffer.
     *
     * @param key The key to clear up to.
     */
    public void clearUpTo(int key)
    {
        if (((start <= key) && (key < (end - 1))))
        {
            // Loop from the start of the data, up to the key to clear up to, clearing all data encountered in-between.
            int newStart;

            for (newStart = start; (newStart <= end) && (newStart <= key); newStart++)
            {
                int offset = offset(newStart);

                if (data[offset] != null)
                {
                    data[offset] = null;
                    count--;
                }
            }

            // Continue on after the clear up to point, until the first non-null entry or end of array is encountered,
            // and make that the new start.
            for (; newStart <= end; newStart++)
            {
                if (data[offset(newStart)] != null)
                {
                    break;
                }
            }

            start = newStart;
        }
        else
        {
            // The key does not lie between the start and end markers, so clear the entire map up to the end
            int newStart;

            for (newStart = start; (newStart <= end); newStart++)
            {
                int offset = offset(newStart);

                if (data[offset] != null)
                {
                    data[offset] = null;
                    count--;
                }
            }

            start = newStart;

            offset = -start;
        }
    }

    /**
     * Sets the low mark to the specified value, provided it is higher than the current low mark.
     *
     * @param key The new minimum low mark.
     */
    public void setLowMark(int key)
    {
        lowMark = (lowMark < key) ? key : lowMark;
    }

    /** Clears entries up to and including the current low mark. */
    public void clearUpToLowMark()
    {
        if (lowMark >= 0)
        {
            clearUpTo(lowMark);
        }
    }

    /** {@inheritDoc} */
    public V remove(Object objectKey)
    {
        int key = (Integer) objectKey;

        if (keyInRange(key))
        {
            // Check if the key is the first element in the list, and walk forward to find the next non-empty element
            // in order to advance the start to.
            if (key == start)
            {
                int newStart = start + 1;

                while ((data[offset(newStart)] == null) && (newStart <= end))
                {
                    newStart++;
                }

                start = newStart;
            }

            int offset = offset(key);
            V result = (V) data[offset];
            data[offset] = null;

            // Decrement the count only if a value was removed.
            if (result != null)
            {
                count--;
            }

            return result;
        }

        return null;
    }

    /** {@inheritDoc} */
    public void clear()
    {
        data = new Object[data.length];
        length = data.length;
        lowMark = -1;
        start = 0;
        end = 0;
        count = 0;
        offset = 0;
    }

    /** {@inheritDoc} */
    public Iterator<V> iterator()
    {
        return new Iterator<V>()
            {
                /** Holds the current offset into the data. */
                int current = start;

                /** {@inheritDoc} */
                public boolean hasNext()
                {
                    return current < end;
                }

                /** {@inheritDoc} */
                public V next()
                {
                    return (V) data[current++];
                }

                /** {@inheritDoc} */
                public void remove()
                {
                    throw new UnsupportedOperationException("'remove' not supported on this iterator.");
                }
            };
    }

    /** {@inheritDoc} */
    public long sizeof()
    {
        return length;
    }

    /** {@inheritDoc} */
    public String toString()
    {
        return "CircularArrayMap: [ start = " + start + ", end = " + end + ", length = " + length + ", count = " +
            count + ", lowMark = " + lowMark + " ]";
    }

    /**
     * Expands the size of the storage to whichever is the larger of 1.5 times the old size, or an array large enough to
     * hold the proposed key that caused the expansion, copying the old data into a new array.
     *
     * @param key The key that was too large and caused expansion.
     */
    private void expand(int key)
    {
        // Set the new size to whichever is the larger of 1.5 times the old size, or an array large enough to hold
        // the proposed key that caused the expansion.
        int newFactorSize = ((length * 3) / 2) + 1;
        int newSpaceSize = spaceRequired(key);

        int newSize = (newSpaceSize > newFactorSize) ? newSpaceSize : newFactorSize;

        Object[] oldData = data;
        data = new Object[newSize];

        // The valid data in the old array runs from offset(start) to offset(end) when offset(start) < offset(end), and
        // from offset(start) to length - 1 and 0 to offset(end) when offset(start) >= offset(end).
        int offsetStart = offset(start);
        int offsetEnd = offset(end);

        if (offsetStart < offsetEnd)
        {
            System.arraycopy(oldData, offsetStart, data, 0, end - start);
        }
        else
        {
            System.arraycopy(oldData, offsetStart, data, 0, length - offsetStart);
            System.arraycopy(oldData, 0, data, length - offsetStart, offsetEnd);
        }

        offset = -start;
        length = newSize;
    }

    /**
     * Computes the offset within the storage array for a given key.
     *
     * @param  key The key to compute an offset for.
     *
     * @return The offset of the key in the storage array.
     */
    private int offset(int key)
    {
        return (key + offset) % length;
    }

    /**
     * Checks if the key can possibly refer to a value in the map, because it lies between the start and end markers.
     *
     * @param  key The key to check.
     *
     * @return <tt>true</tt> if the key can possibly refer to a value in the map.
     */
    private boolean keyInRange(int key)
    {
        return ((start <= key) && (key < end));
    }

    /**
     * Checks if the key is large enough to be beyond the end of the array.
     *
     * @param  key The key to check.
     *
     * @return <tt>true</tt> if the key is large enough to be beyond the end of the array.
     */
    private boolean keyTooLarge(int key)
    {
        return (key - start) > (length - 1);
    }

    /**
     * Calculates the size of array required to store the specified key.
     *
     * @param  key The key to check.
     *
     * @return The size of array required to store the specified key.
     */
    private int spaceRequired(int key)
    {
        return key - start + 1;
    }
}


/*
 * Licensed 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.
 */
package org.hobsoft.microbrowser.selenium;

import org.openqa.selenium.WebElement;

import static com.google.common.base.Preconditions.checkArgument;

/**
 * Radio form control wrapper for a Selenium {@code WebElement}.
 */
class SeleniumRadioControl extends SeleniumCheckboxControl
{
	// ----------------------------------------------------------------------------------------------------------------
	// constructors
	// ----------------------------------------------------------------------------------------------------------------

	SeleniumRadioControl(WebElement element)
	{
		super(element);
	}

	// ----------------------------------------------------------------------------------------------------------------
	// Control methods
	// ----------------------------------------------------------------------------------------------------------------

	@Override
	public void setValue(String value)
	{
		checkArgument(!UNCHECKED_VALUE.equals(value), "Cannot uncheck radio control");

		super.setValue(value);
	}

	// ----------------------------------------------------------------------------------------------------------------
	// CheckableControl methods
	// ----------------------------------------------------------------------------------------------------------------

	@Override
	public boolean isUncheckable()
	{
		return false;
	}
}


/*
 * Copyright The Sett Ltd, 2005 to 2014.
 *
 * Licensed 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.
 */
package com.thesett.text.impl.model;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import com.thesett.common.util.doublemaps.HashMapXY;
import com.thesett.text.api.TextGridEvent;
import com.thesett.text.api.TextGridListener;
import com.thesett.text.api.TextTableEvent;
import com.thesett.text.api.TextTableListener;
import com.thesett.text.api.model.TextGridModel;
import com.thesett.text.api.model.TextTableModel;

/**
 *

CRC Card

 *
 Responsibilities  Collaborations
 *

 *

 *
 * @author Rupert Smith
 */
public class TextGridImpl implements TextGridModel
{
    /** Maximum occupied column of this child grid. */
    protected int maxColumn;

    /** Maximum occupied row of this child grid. */
    protected int maxRow;

    /** Holds the grid data. */
    HashMapXY<Character> data = new HashMapXY<Character>(100);

    /** Holds a set of listeners for updates to this model. */
    Collection<TextGridListener> listeners = new HashSet<TextGridListener>();

    /** {@inheritDoc} */
    public int getWidth()
    {
        return maxColumn + 1;
    }

    /** {@inheritDoc} */
    public int getHeight()
    {
        return maxRow + 1;
    }

    /** {@inheritDoc} */
    public void insert(char character, int c, int r)
    {
        internalInsert(character, c, r);
        updateListeners();
    }

    /** {@inheritDoc} */
    public void insert(String string, int c, int r)
    {
        for (char character : string.toCharArray())
        {
            internalInsert(character, c++, r);
        }

        updateListeners();
    }

    /** {@inheritDoc} */
    public char getCharAt(int c, int r)
    {
        Character character = data.get((long) c, (long) r);

        if (character == null)
        {
            return ' ';
        }
        else
        {
            return character;
        }
    }

    /** {@inheritDoc} */
    public TextGridModel createInnerGrid(int c, int r, int w, int h)
    {
        return new NestedTextGridImpl(c, r, w, h, this);
    }

    /** {@inheritDoc} */
    public TextTableModel createTable(int c, int r, int w, int h)
    {
        // Supply a text table, with this grid set up to listen for updates to the table, and to be re-rendered as the
        // table changes.
        TextTableModel textTable = new TextTableImpl();

        textTable.addTextTableListener(new TableListener());

        return textTable;
    }

    /** {@inheritDoc} */
    public void addTextGridListener(TextGridListener listener)
    {
        listeners.add(listener);
    }

    /** {@inheritDoc} */
    public void removeTextGridListener(TextGridListener listener)
    {
        listeners.remove(listener);
    }

    /** Notifies all interested listeners of an update to this model. */
    protected void updateListeners()
    {
        TextGridEvent event = new TextGridEvent(this);

        for (TextGridListener listener : listeners)
        {
            listener.changedUpdate(event);
        }
    }

    /**
     * Inserts a single character into the grid at the specified location. This is a private insert method, that does
     * not notify model listeners, so that the public insert methods can do that as a separate step.
     *
     * @param character The character to insert.
     * @param c         The column position.
     * @param r         The row position.
     */
    private void internalInsert(char character, int c, int r)
    {
        maxColumn = (c > maxColumn) ? c : maxColumn;
        maxRow = (r > maxRow) ? r : maxRow;

        data.put((long) c, (long) r, character);
    }

    /**
     * Re-renders a table into this grid, when the table changes.
     */
    private class TableListener implements TextTableListener
    {
        /** {@inheritDoc} */
        public void changedUpdate(TextTableEvent event)
        {
            TextTableGridRenderer renderer = new TextTableGridRenderer(event.getModel(), TextGridImpl.this);
            renderer.renderTable();
        }
    }
}


/*
 * Copyright The Sett Ltd, 2005 to 2014.
 *
 * Licensed 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.
 */
package com.thesett.aima.logic.fol.isoprologparser;

import com.thesett.aima.logic.fol.Clause;
import com.thesett.aima.logic.fol.Sentence;
import com.thesett.aima.logic.fol.SentenceImpl;
import com.thesett.aima.logic.fol.VariableAndFunctorInterner;
import com.thesett.common.parsing.SourceCodeException;

/**
 * Parses first order logic Horn clauses from strings using Prolog syntax. The sentence should be a clause terminated by
 * a full stop.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Parse a string as a logical term relative to a variable and functor interner.
 *      {@link Clause}, {@link VariableAndFunctorInterner}.
 *

 *
 * @author Rupert Smith
 */
public class SentenceParser extends BasePrologParser<Clause>
{
    /**
     * Creates a clause parser over an interner.
     *
     * @param interner The interner to use to intern all functor and variable names.
     */
    public SentenceParser(VariableAndFunctorInterner interner)
    {
        super(interner);
    }

    /**
     * Parses the next sentence from the current token source.
     *
     * @return The fully parsed syntax tree for the next sentence, or null if no more sentences are available, for
     *         example, because an end of file has been reached.
     *
     * @throws SourceCodeException If the source being parsed does not match the grammar.
     */
    public Sentence<Clause> parse() throws SourceCodeException
    {
        if (parser.peekAndConsumeEof())
        {
            return null;
        }
        else
        {
            return new SentenceImpl<Clause>(parser.sentence());
        }
    }
}


/*
 * Copyright The Sett Ltd, 2005 to 2014.
 *
 * Licensed 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.
 */
package com.thesett.aima.logic.fol.prolog.builtins;

import java.util.Queue;

import com.thesett.aima.logic.fol.Functor;

/**
 * Cut implements the prolog '!' operator, that prevents back-tracking within a functor. '!' is true; that is it does
 * not ever fail. All choice points between the cut and the parent goal are removed. The effect is to commit to use both
 * the current clause and the substitutions found at the point of the cut.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Implement the cut operator.
 *

 *
 * @author Rupert Smith
 */
public class Cut extends BaseBuiltIn
{
    /** Used for providing user readable execution traces. */
    /* private static final Logger trace = Logger.getLogger("TRACE.Prolog." + Cut.class.getSimpleName()); */

    /** Flag used as a quick check to see if trace is enabled. */
    private static final boolean TRACE = false; //log.isLoggable(Level.FINE)

    /**
     * Creates a cut built-in to implement the specified functor.
     *
     * @param functor The functor to implement as a built-in.
     */
    public Cut(Functor functor)
    {
        super(functor);
    }

    /** {@inheritDoc} */
    public boolean proofStep(ResolutionState state)
    {
        if (TRACE)
        {
            /*trace.fine(state.getTraceIndenter().generateTraceIndent() + "Cutting choice points...");*/
        }

        Queue<ResolutionState> choicePointStates = parentChoicePointState.getChoicePoints();

        if (choicePointStates != null)
        {
            for (ResolutionState choicePointState : choicePointStates)
            {
                choicePointState.cut();
            }
        }

        state.getGoalStack().poll();

        return true;
    }
}


/*
 * Copyright The Sett Ltd, 2005 to 2014.
 *
 * Licensed 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.
 */
package com.thesett.aima.search.util.uninformed;

import java.util.Comparator;

import com.thesett.aima.search.SearchNode;

/**
 * UniformCostComparator is a Comparator that compare the path costs for two search nodes.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Order search nodes by their path cost.
 *

 *
 * @author Rupert Smith
 */
public final class UniformCostComparator implements Comparator<SearchNode>
{
    /**
     * Compares two search nodes by their path cost.
     *
     * @param  object1 The first search node to compare.
     * @param  object2 The second search node to compare.
     *
     * @return 1 if the first node has a higher path cost than the second, -1 if it has a lower path cost and 0 if they
     *         have the same path cost.
     */
    public int compare(SearchNode object1, SearchNode object2)
    {
        float cost1 = object1.getPathCost();
        float cost2 = object2.getPathCost();

        return (cost1 > cost2) ? 1 : ((cost1 < cost2) ? -1 : 0);
    }
}


/*
 * Copyright The Sett Ltd, 2005 to 2014.
 *
 * Licensed 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.
 */
package com.thesett.aima.logic.fol;

/**
 * IntegerType is the base type for all integer numeric literals.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Indicate that a term is an integer.
 *
 Indicate that a term is not a real number.
 *

 *
 * @author Rupert Smith
 */
public abstract class IntegerType extends NumericType
{
    /**
     * Determines whether a number is an integer.
     *
     * @return <tt>true</tt> if a number is an integer, <tt>false</tt> otherwise.
     */
    public boolean isInteger()
    {
        return true;
    }

    /** {@inheritDoc} */
    public void accept(TermVisitor visitor)
    {
        if (visitor instanceof IntegerTypeVisitor)
        {
            ((IntegerTypeVisitor) visitor).visit(this);
        }
        else
        {
            super.accept(visitor);
        }
    }
}


/*
 * Copyright The Sett Ltd, 2005 to 2014.
 *
 * Licensed 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.
 */
package com.thesett.aima.logic.fol.isoprologparser;

import java.util.Arrays;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;

import com.thesett.aima.logic.fol.Functor;
import com.thesett.aima.logic.fol.OpSymbol;
import com.thesett.aima.logic.fol.Term;
import com.thesett.common.parsing.SourceCodeException;
import com.thesett.common.util.Queue;
import com.thesett.common.util.StackQueue;

/**
 * DynamicOperatorParser is a 'deferred decision parser' that can be used to parse Prolog with dynamically defined
 * operators. Prolog operators are dynamic; they can be redefined at run-time with altered fixities, associativities and
 * priorities. This means that the grammar of prolog is not fixed and parser generator tools have a hard time coping
 * with it. A solution is to parse sequences of adjacent terms into a flat array, and then to pass this array to this
 * parser to attempt to correctly parse the sequence of terms using the currently defined operators.
 *
 *
This parser maintains the {@link OperatorTable} in an ISO Prolog compliant manner. That is, it does not permit
 * the ',' operator to be redefined, it does not allow an infix and postfix operator with the same name to be
 * simultaneosly defined, priority must be between 0 and 1200 inclusive, setting a priority of 0 on an operator removes
 * it from the table. It is the responsibility of the caller to ensure that operators have valid names.
 *
 *
The grammar to parse looks like:
 *
 *

 * T := t
 * T := op T
 * T := T op
 * T := T op T
 *

 *
 * Where t is a term already fully parsed, for example, a functor, an atom, a variable, an operator as an atom. 'op' is
 * an operator, which can be pre, post, or infix by its position in the different rules.
 *
 *
This grammar can be parsed using a simple Shift-Reduce, or LR parser. The translation of the grammar into a
 * parsing table looks like:
 *
 *
Augment the grammar with a start state and number the rules:
 *
 *

 * 0. S := T
 * 1. T := t
 * 2. T := op T
 * 3. T := T op
 * 4. T := T op T
 *

 *
 *
Expand the rules into item sets by shifting a '.' down the rules:
 *
 *
Item Set 0
 *
 *

 *   S := . T
 * + T := . t
 * + T := . op T
 * + T := . T op
 * + T := . T op T
 *

 *
 *
Item Set 1
 *
 *

 *   T := t .
 *

 *
 *
Item Set 2
 *
 *

 *   T := op . T
 * + T := . t
 * + T := . op T
 * + T := . T op
 * + T := . T op T
 *

 *
 *
Item Set 3
 *
 *

 *   S := T .
 *   T := T . op
 *   T := T . op T
 *

 *
 *
Item Set 4
 *
 *

 *   T := op T .
 *   T := T . op
 *   T := T . op T
 *

 *
 *
Item Set 5
 *
 *

 *   T := T op .
 *   T := T op . T
 * + T := . t
 * + T := . op T
 * + T := . T op
 * + T := . T op T
 *

 *
 *
Item Set 6
 *
 *

 *   T := T op T .
 *   T := T . op
 *   T := T . op T
 *

 *
 *
Which yields the transition table between these states of:
 *
 *

Transition Table

 *
    t  op  T
 *
 0  1   2  3
 *
 1
 *
 2  1   2  4
 *
 3      5
 *
 4      5
 *
 5  1   2  6
 *
 6      5
 *

 *
 *
Which results in an LR parser table of:
 *
 *

LR Parser Table

 *
  Action            Goto
 *
    t     op      $     T
 *
 0 s1     s2            3
 *
 1 r1     r1     r1
 *
 2 s1     s2            4
 *
 3        s5     acc
 *
 4 r2     s5/r2  r2
 *
 5 s1/r3  s2/r3  r3     6
 *
 6 r4     s5/r4  r4
 *

 *
 *
From which it can be seen that there are 4 shift-reduce conflicts. It is these conflicts that make this grammar
 * difficult to parse with generator tools. This DynamicOperatorParser uses the operator precedence, fixity and
 * associativity values to decide which way to resolve the conflicts. The 's1/r2' conflict when encountering 't' in
 * state 5 is always shifted as non-operator terms have priority 0 in Prolog. The remaining conflicts are all
 * operator/operator conflicts, and are therefore a matter of deciding which operator takes precedence; the one most
 * recently seen, in which case reduce; the one which is encountered as the next symbol, in which case shift. The
 * operators priority values are compared and the one with the lower value wins. If the priorities are equal, then the
 * associativity of the next operator is used to decide, if it binds left then reduce, binds right then shift, if it is
 * non-associative then the choice is ambigious so an error is reported.
 *
 *
The parser is further complicated by the fact that operators can be overloaded in Prolog. This means that each
 * {@link CandidateOpSymbol} encountered can map onto multiple {@link OpSymbol} definitions and a choice as to which one
 * is used must be made in the context of the position in which is encountered. Consider the following sequences of
 * symbols when and operator/operator conflict is encountered:
 *
 *

 * alpha OpA beta OpB ...
 *

 *
 *
Where alpha and beta are sequences of symbols, possibly empty. Now consider for the empty or non-empty values of
 * alpha and beta, what fixities of operator are possible for OpA and OpB. Note that OpA and OpB must be prefix,
 * postfix, or infix and cannot be an constant atom, because operators as constant atoms must be bracketed in ISO
 * Prolog, and will therefore have already been resolved from a {@link CandidateOpSymbol} to an {@link OpSymbol}.
 *
 *

Possibly Fixity Combinations

 *
 alpha = not_empty, beta = not_empty  (OpA = in, OpB = post) or (OpA = in, OpB = in)
 *
 alpha = empty, beta = not_empty  (OpA = pre, OpB = post) or (OpA = in, OpB = in)
 *
 alpha = not_empty, beta = empty  (OpA = post, OpB = in) or (OpA = post, OpB = post) or (OpA = in, OpB = pre)
 *
 alpha = empty, beta = empty      (OpA = pre, OpB = pre)
 *

 *
 *
ISO Prolog does not permit a postfix and infix operator with the same name to be defined simultaneously, which
 * reduces the above table to only one possible operator combination in each case.
 *
 *
The evaluation of the fixity combinations, and operator precedence to decide conflicts can be seen in the
 * {@link ResolveAction#apply()} method.
 *
 *
Error reporting is added to the LR parser by filling the blank transitions in the parse tables with error actions
 * with custom error messages specific to the empty transition.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Add new operators to the table following ISO Prolog rules.
 *
 Find all candidate operators matching a given name.
 *
 Parse sequences of terms and candidate operators using ISO Prolog rules.
 *      {@link Term}, {@link CandidateOpSymbol}, {@link OpSymbol}.
 *

 *
 * @author Rupert Smith
 */
public class DynamicOperatorParser implements OperatorTable
{
    /** Used for debugging purposes. */
    /* private static final Logger log = Logger.getLogger(DynamicOperatorParser.class.getName()); */

    /** Encodes the possible symbols that this parser accepts. */
    private enum Symbol
    {
        /** A term which is not a {@link CandidateOpSymbol}. It may be a previously resolved {@link OpSymbol} though. */
        Term,

        /** A symbol which is a {@link CandidateOpSymbol} to be resovled onto an {@link OpSymbol}. */
        Op,

        /** A final symbol to complete the sequence. */
        Final
    }

    /** Defines the action to shift to state 1. */
    private final ShiftAction s1 = new ShiftAction(1);

    /** Defines the action to shift to state 2. */
    private final ShiftAction s2 = new ShiftAction(2);

    /** Defines the action to shift to state 5. */
    private final ShiftAction s5 = new ShiftAction(5);

    /** Defines the action to resolve using rule 1. */
    private final ReduceAction r1 = new ReduceAction(1);

    /** Defines the action to resolve using rule 2. */
    private final ReduceAction r2 = new ReduceAction(2);

    /** Defines the action to resolve using rule 3. */
    private final ReduceAction r3 = new ReduceAction(3);

    /** Defines the action to resolve using rule 4. */
    private final ReduceAction r4 = new ReduceAction(4);

    /** Defines an error message when the final symbol is encountered in the start state. */
    private final ErrorAction e1 = new ErrorAction("Term sequence cannot be empty.");

    /** Defines an error message when nothing is specified to apply an operator to. */
    private final ErrorAction e2 = new ErrorAction("Something expected after operator.");

    /** Defines an error message when two adjacement terms no seperated by an operator are encounterd. */
    private final ErrorAction e3 = new ErrorAction("Cannot have two adjacent non-operator terms.");

    /**
     * Holds the LR parser action table, that describes which action to perform when encountering a given symbol in a
     * given state. The first index to the two dimensional array is the state number, the second is the {@link Symbol}s
     * ordinal value. Note that there are three operator/operator shift/reduce conflicts in this table.
     */
    private final Action[][] actionTable =
        new Action[][]
        {
            { s1, s2, e1 },
            { r1, r1, r1 },
            { s1, s2, e2 },
            { e3, s5, new Accept() },
            { r2, new ResolveAction(s5, r2), r2 },
            { s1, new ResolveAction(s2, r3), r3 },
            { r4, new ResolveAction(s5, r4), r4 }
        };

    /** Holds the LR parser goto table, that describes the state to transition to after resolving a rule. */
    private final Integer[] gotoTable = new Integer[] { 3, null, 4, null, null, 6, null };

    /** Holds the rules to apply when resolving. */
    private final Action[] rules = { null, new Rule1(), new Rule2(), new Rule3(), new Rule4() };

    /** Holds the parser state stack. */
    private final Queue<Integer> stack = new StackQueue<Integer>();

    /** Holds the parsers current state. */
    private int state;

    /** Holds the parsers current position within the input sequence of terms. */
    private int position;

    /** Holds the output stack onto which terms are placed pending their consumption by rule reductions. */
    private final Queue<Term> outputStack = new StackQueue<Term>();

    /** Holds the current next term on the input sequence. */
    private Term nextTerm;

    /** Holds the table of defined operators by name and fixity. */
    private final Map<String, EnumMap<OpSymbol.Fixity, OpSymbol>> operators =
        new HashMap<String, EnumMap<OpSymbol.Fixity, OpSymbol>>();

    /**
     * Parses a flat list of terms, which are literals, variables, functors, or operators into a tree in such a way that
     * the operators associativity and precendence is obeyed.
     *
     * @param  terms A flat list of terms possibly containing operators, to be parsed.
     *
     * @return The functor at the root of the sequence of terms parsed into an abstract syntax tree.
     *
     * @throws SourceCodeException If the list of terms does not form a valid syntactical construction under the current
     *                             set of defined operators.
     */
    public Term parseOperators(Term[] terms) throws SourceCodeException
    {
        // Initialize the parsers state.
        stack.offer(0);
        state = 0;
        position = 0;
        nextTerm = null;

        // Consume the terms from left to right.
        for (position = 0; position <= terms.length;)
        {
            Symbol nextSymbol;

            // Decide what the next symbol to parse is; candidate op, term or final.
            if (position < terms.length)
            {
                nextTerm = terms[position];

                if (nextTerm instanceof CandidateOpSymbol)
                {
                    nextSymbol = Symbol.Op;
                }
                else
                {
                    nextSymbol = Symbol.Term;
                }
            }
            else
            {
                nextSymbol = Symbol.Final;
            }

            // Look in the action table to find the action associated with the current symbol and state.
            Action action = actionTable[state][nextSymbol.ordinal()];

            // Apply the action.
            action.apply();
        }

        return (Functor) outputStack.poll();
    }

    /**
     * Sets the priority and associativity of a named operator in this table. This method may be used to remove
     * operators by some implementations, through a special setting of the priority value. A priority value of zero will
     * remove any existing operator matching the fixity of the one specified (that is pre, or post/infix). To be
     * accepted, the operator must have a priority between 0 and 1200 inclusive, and can only be a postfix operator when
     * an infix is not already defined with the same name, and similarly for infix operators when a postfix operator is
     * already defined.
     *
     * @param name          The interned name of the operator to set in the table.
     * @param textName      The text name of the operator to set in the table.
     * @param priority      The priority of the operator. Zero removes the operator.
     * @param associativity The associativity of the operator.
     */
    public void setOperator(int name, String textName, int priority, OpSymbol.Associativity associativity)
    {
        // Check that the name of the operator is valid.

        // Check that the priority of the operator is valid.
        if ((priority < 0) || (priority > 1200))
        {
            throw new IllegalArgumentException("Operator priority must be between 0 and 1200 inclusive.");
        }

        OpSymbol opSymbol = new OpSymbol(name, textName, associativity, priority);

        // Consult the defined operators to see if there are any already defined that match the name of the
        // new definition, otherwise a map of operators by fixity needs to be created.
        EnumMap<OpSymbol.Fixity, OpSymbol> operatorMap = operators.get(textName);

        // Check if the priority is non-zero in which case the operator is being added or redefined.
        if (priority > 0)
        {
            if (operatorMap == null)
            {
                operatorMap = new EnumMap<OpSymbol.Fixity, OpSymbol>(OpSymbol.Fixity.class);
                operators.put(textName, operatorMap);
            }

            // Check if the operators fixity to see if further rules regarding simultaneous definition of post and
            // infix operators need to be applied.
            if (opSymbol.isPostfix())
            {
                // Postfix, so check if an infix definition already exists, which is not allowed.
                if (operatorMap.containsKey(OpSymbol.Fixity.In))
                {
                    throw new IllegalArgumentException(
                        "Cannot define a postfix operator when an infix one with the same name already exists.");
                }
            }
            else if (opSymbol.isInfix())
            {
                // Infix, so check if a postfix definition already exists, which is not allowed.
                if (operatorMap.containsKey(OpSymbol.Fixity.Post))
                {
                    throw new IllegalArgumentException(
                        "Cannot define an infix operator when an postfix one with the same name already exists.");
                }
            }

            // Add the operator to the table replacing any previous definition of the same fixity.
            operatorMap.put(opSymbol.getFixity(), opSymbol);
        }
        else
        {
            // The priority is zero, in which case the operator is to be removed.
            if ((operatorMap != null) && opSymbol.isPrefix())
            {
                // Remove it from the prefix table, if it exists there.
                operatorMap.remove(OpSymbol.Fixity.Pre);
            }
            else if ((operatorMap != null) && (opSymbol.isPostfix() || opSymbol.isInfix()))
            {
                // Remove it from the postfix/infix table, if it exists there.
                operatorMap.remove(OpSymbol.Fixity.Post);
                operatorMap.remove(OpSymbol.Fixity.In);
            }
        }
    }

    /**
     * Checks the operator table for all possible operators matching a given name.
     *
     * @param  name The interned name of the operator to find.
     *
     * @return An array of matching operators, or <tt>null</tt> if none can be found.
     */
    public EnumMap<OpSymbol.Fixity, OpSymbol> getOperatorsMatchingNameByFixity(String name)
    {
        return operators.get(name);
    }

    /**
     * Prints the current state of this parser as a string, mainly for debugging purposes.
     *
     * @return The current state of this parser as a string.
     */
    public String toString()
    {
        return "DynamicOperatorsParser: [ state = " + state + ", nextTerm = " + nextTerm + " stack = " + stack +
            " outputStack = " + outputStack + " ]";
    }

    /**
     * Checks if a candidate operator symbol can have one of the specified fixities, and resolve it to an oeprator with
     * that fixity if so. If it cannot be resolved an exception is raised.
     *
     * @param  candidate The candidate operator symbol to resolve.
     * @param  fixities  The possible fixities to resolve the symbol to.
     *
     * @return The candidate operator resolved to an actual operator.
     *
     * @throws SourceCodeException If the candidate operator cannot be resolved.
     */
    protected static OpSymbol checkAndResolveToFixity(CandidateOpSymbol candidate, OpSymbol.Fixity... fixities)
        throws SourceCodeException
    {
        OpSymbol result = null;

        for (OpSymbol.Fixity fixity : fixities)
        {
            result = candidate.getPossibleOperators().get(fixity);

            if (result != null)
            {
                break;
            }
        }

        if (result == null)
        {
            throw new SourceCodeException("Operator " + candidate + " must be one of " + Arrays.toString(fixities) +
                ", but does not have the required form.", null, null, null, candidate.getSourceCodePosition());
        }

        return result;
    }

    /**
     * A base class for defining parsers actions and rule reductions from.
     */
    private abstract static class Action
    {
        /**
         * Applies a parser action; shift, reduce, resolve or accept.
         *
         * @throws SourceCodeException With an error location if the action cannot be performed because the input
         *                             sequence does not form a valid instance of the grammar.
         */
        public abstract void apply() throws SourceCodeException;
    }

    /**
     * Defines a shift action. Shift changes to a new state, places the new state on the stack, consumes one input
     * symbol and places the symbol on the output stack.
     */
    private class ShiftAction extends Action
    {
        /** Holds the state to shift to. */
        public int toState;

        /**
         * Creates a shift action to the specified state.
         *
         * @param toState The state to shift to.
         */
        private ShiftAction(int toState)
        {
            this.toState = toState;
        }

        /**
         * Performs a shift action. Changes to a new state, places the new state on the stack, consumes one input symbol
         * and places the symbol on the output stack.
         */
        public void apply()
        {
            state = toState;
            stack.offer(state);
            position++;
            outputStack.offer(nextTerm);
        }
    }

    /**
     * Defines a reduce action. Reduce consumes states from the state stack, and symbols from the output stack in number
     * equal to the number of symbols on the right hand side of the rule that is being reduced by. It then shifts to the
     * state given by the goto table from the state left on top of the state stack. In this implementation the
     * consumption of symbols and states from the stacks is delegated to a {@link Action} implementation.
     */
    private class ReduceAction extends Action
    {
        /** Holds the rule number to reduce by. */
        public int ruleNum;

        /**
         * Creates a reduce action to reduce by the specified rule.
         *
         * @param rule The rule number to reduce by.
         */
        private ReduceAction(int rule)
        {
            this.ruleNum = rule;
        }

        /**
         * Performs a reduce by the specified rule number.
         *
         * @throws SourceCodeException With an error location if the action cannot be performed because the input
         *                             sequence does not form a valid instance of the grammar.
         */
        public void apply() throws SourceCodeException
        {
            Action rule = rules[ruleNum];
            rule.apply();

            state = gotoTable[stack.peek()];
            stack.offer(state);
        }
    }

    /**
     * ResolveAction decides a shift-reduce conflict between a pair of {@link CandidateOpSymbol}s. The resolution
     * procedure is as described in the class level comment for {@link DynamicOperatorParser}.
     */
    private class ResolveAction extends Action
    {
        /** The shift action to perform if a shift resolution is chosen. */
        ShiftAction shift;

        /** The reduce action to perform if a reduce resolution is chosen. */
        ReduceAction reduce;

        /**
         * Creates a resolve action between the specified shift and reduce actions.
         *
         * @param shift  The shift action to perform if a shift resolution is chosen.
         * @param reduce The reduce action to perform if a reduce resolution is chosen.
         */
        private ResolveAction(ShiftAction shift, ReduceAction reduce)
        {
            this.shift = shift;
            this.reduce = reduce;
        }

        /**
         * Performs shift-reduce resolution between a pair of operators as describe in {@link DynamicOperatorParser}.
         *
         * @throws SourceCodeException With an error location if the action cannot be performed because the input
         *                             sequence does not form a valid instance of the grammar.
         */
        public void apply() throws SourceCodeException
        {
            // This cast should not fail, as resolve is only called when the next symbol is a candidate operator.
            CandidateOpSymbol nextCandidate = (CandidateOpSymbol) nextTerm;

            // Walk back down the output stack looking for the last symbol and checking out what other terms may
            // exist on the stack too. This evaluates the output stack, looking at the previously parsed sequence
            // of terms that led to this conflict as a sequence of the form 'alpha OpA beta OpB', where OpA is the
            // previously unresolved operator conflicting with the nextTerm, and alpha and beta are potentially
            // empty sequences of symbols. The following code works out what the previous operator is and whether
            // alpha and beta are empty. At the end of this lastCandidate cannot be null, as resolve is only called
            // when a previous candidate symbol has been encountered.
            boolean alpha = false;
            boolean beta = false;
            CandidateOpSymbol lastCandidate = null;
            int pos = 0;

            for (Term nextTerm : outputStack)
            {
                boolean isOpSymbol = (nextTerm instanceof CandidateOpSymbol);

                if ((pos == 0) && !isOpSymbol)
                {
                    beta = true;
                }
                else if ((pos == 0) && isOpSymbol)
                {
                    lastCandidate = (CandidateOpSymbol) nextTerm;
                }
                else if ((pos == 1) && beta)
                {
                    lastCandidate = (CandidateOpSymbol) nextTerm;
                }
                else if ((pos == 1) && !beta)
                {
                    alpha = true;

                    break;
                }
                else if (pos == 2)
                {
                    alpha = true;

                    break;
                }

                pos++;
            }

            if (lastCandidate == null)
            {
                throw new IllegalStateException("'lastCandidate' is null but this should not be the case as this resolve " +
                    "action is only called when a previous candidate symbol exists.");
            }

            // Based on the form of the symbol sequence preceding the next symbol, work out which combination
            // of operator fixities in uniquely possible, and resolve the candidate operators onto that combination.
            OpSymbol lastOp;
            OpSymbol nextOp;

            if (alpha && beta)
            {
                lastOp = checkAndResolveToFixity(lastCandidate, OpSymbol.Fixity.In);
                nextOp = checkAndResolveToFixity(nextCandidate, OpSymbol.Fixity.In, OpSymbol.Fixity.Post);
            }
            else if (!alpha && beta)
            {
                lastOp = checkAndResolveToFixity(lastCandidate, OpSymbol.Fixity.Pre);
                nextOp = checkAndResolveToFixity(nextCandidate, OpSymbol.Fixity.In, OpSymbol.Fixity.Post);
            }
            else if (alpha && !beta)
            {
                lastOp = checkAndResolveToFixity(lastCandidate, OpSymbol.Fixity.In, OpSymbol.Fixity.Post);

                if (lastOp.isPostfix())
                {
                    nextOp = checkAndResolveToFixity(nextCandidate, OpSymbol.Fixity.In, OpSymbol.Fixity.Post);
                }
                else
                {
                    nextOp = checkAndResolveToFixity(nextCandidate, OpSymbol.Fixity.Pre);
                }
            }
            else
            {
                lastOp = checkAndResolveToFixity(lastCandidate, OpSymbol.Fixity.Pre);
                nextOp = checkAndResolveToFixity(nextCandidate, OpSymbol.Fixity.Pre);
            }

            // Compare the priority and associativities of the conflicting operators to decide whether to shift
            // or reduce.
            int comparison = lastOp.compareTo(nextOp);

            if (comparison < 0)
            {
                reduce.apply();
            }
            else if (comparison > 0)
            {
                shift.apply();
            }
            else
            {
                if (nextOp.isLeftAssociative())
                {
                    reduce.apply();
                }
                else if (nextOp.isRightAssociative())
                {
                    shift.apply();
                }
                else
                {
                    throw new SourceCodeException("Ambiguous operator associativity. Expression requires brackets.",
                        null, null, null, nextOp.getSourceCodePosition());
                }
            }
        }
    }

    /**
     * An error handling action to be used when an unknown transition in the parser table is attempted. This action
     * creates a source code exception with the location of the error in it.
     */
    private class ErrorAction extends Action
    {
        /** Holds a custom error description. */
        private final String errorMessage;

        /**
         * Creates an error action with the specified error message.
         *
         * @param errorMessage The error message.
         */
        private ErrorAction(String errorMessage)
        {
            this.errorMessage = errorMessage;
        }

        /**
         * Applies a parser error action that will generate an exception with the location of the current parse term in
         * it.
         *
         * @throws SourceCodeException With an error location for the current parse term.
         */
        public void apply() throws SourceCodeException
        {
            throw new SourceCodeException(errorMessage, null, null, null, nextTerm.getSourceCodePosition());
        }
    }

    /**
     * Performs an accept action. This advances over the last symbol in the input sequence so that the parser
     * terminates.
     */
    private class Accept extends Action
    {
        /** Accepts the input sequence as valid. */
        public void apply()
        {
            // Advance one beyond the final position to indicate acceptance of the sentence as a valid instance of
            // the grammar.
            position++;
        }
    }

    /**
     * Implements a reduction by rule 1 of the grammar. This consumes a single state from the state stack.
     */
    private class Rule1 extends Action
    {
        /** Defines the number of symbols on the right hand side of this rule. */
        private static final int NUM_SYMBOLS_RHS = 1;

        /** Reduces by rule 1. */
        public void apply()
        {
            for (int i = 0; i < NUM_SYMBOLS_RHS; i++)
            {
                stack.poll();
            }
        }
    }

    /**
     * Implements a reduction by rule 2 of the grammar. This consumes two states from the state stack, and expects the
     * top two symbols on the output stack to be a terminal follow by an operator candidate that resolves to a prefix
     * operator.
     */
    private class Rule2 extends Action
    {
        /** Defines the number of symbols on the right hand side of this rule. */
        private static final int NUM_SYMBOLS_RHS = 2;

        /**
         * Reduces by rule 2.
         *
         * @throws SourceCodeException With an error location if the action cannot be performed because the input
         *                             sequence does not form a valid instance of the grammar.
         */
        public void apply() throws SourceCodeException
        {
            // Consume from the state stack for the number of RHS symbols.
            for (int i = 0; i < NUM_SYMBOLS_RHS; i++)
            {
                stack.poll();
            }

            // Attempt to consume a term and an operator in prefix order from the output stack.
            Term t = outputStack.poll();
            CandidateOpSymbol candidate = (CandidateOpSymbol) outputStack.poll();

            OpSymbol op = checkAndResolveToFixity(candidate, OpSymbol.Fixity.Pre);

            // Clone the operator symbol from the operator table before adding the unique source code position and
            // argument for this symbol instance.
            op = op.copySymbol();
            op.setSourceCodePosition(candidate.getSourceCodePosition());
            op.setArguments(new Term[] { t });

            // Place the fully parsed, promoted operator back onto the output stack.
            outputStack.offer(op);
        }
    }

    /**
     * Implements a reduction by rule 3 of the grammar. This consumes two states from the state stack, and expects the
     * top two symbols on the output stack to be an operator candidate that resolves to a postfix operator followed by a
     * terminal.
     */
    private class Rule3 extends Action
    {
        /** Defines the number of symbols on the right hand side of this rule. */
        private static final int NUM_SYMBOLS_RHS = 2;

        /**
         * Reduces by rule 3.
         *
         * @throws SourceCodeException With an error location if the action cannot be performed because the input
         *                             sequence does not form a valid instance of the grammar.
         */
        public void apply() throws SourceCodeException
        {
            // Consume from the state stack for the number of RHS symbols.
            for (int i = 0; i < NUM_SYMBOLS_RHS; i++)
            {
                stack.poll();
            }

            // Attempt to consume an operator and a term in postfix order from the output stack.
            CandidateOpSymbol candidate = (CandidateOpSymbol) outputStack.poll();
            Term t = outputStack.poll();

            OpSymbol op = checkAndResolveToFixity(candidate, OpSymbol.Fixity.Post);

            // Clone the operator symbol from the operator table before adding the unique source code position and
            // argument for this symbol instance.
            op = op.copySymbol();
            op.setSourceCodePosition(candidate.getSourceCodePosition());
            op.setArguments(new Term[] { t });

            outputStack.offer(op);
        }
    }

    /**
     * Implements a reduction by rule 3 of the grammar. This consumes three states from the state stack, and expects the
     * top three symbols on the output stack to be a terminal followed by ann operator candidate that resolves to a
     * infix operator followed by a terminal.
     */
    private class Rule4 extends Action
    {
        /** Defines the number of symbols on the right hand side of this rule. */
        private static final int NUM_SYMBOLS_RHS = 3;

        /**
         * Reduces by rule 4.
         *
         * @throws SourceCodeException With an error location if the action cannot be performed because the input
         *                             sequence does not form a valid instance of the grammar.
         */
        public void apply() throws SourceCodeException
        {
            // Consume from the state stack for the number of RHS symbols.
            for (int i = 0; i < NUM_SYMBOLS_RHS; i++)
            {
                stack.poll();
            }

            // Attempt to consume a term, ann operator and a term in infix order from the output stack.
            Term t1 = outputStack.poll();
            CandidateOpSymbol candidate = (CandidateOpSymbol) outputStack.poll();
            Term t2 = outputStack.poll();

            OpSymbol op = checkAndResolveToFixity(candidate, OpSymbol.Fixity.In);

            // Clone the operator symbol from the operator table before adding the unique source code position and
            // argument for this symbol instance.
            // Note that the order of the arguments is swapped here, because they come off the stack backwards.
            op = op.copySymbol();
            op.setSourceCodePosition(candidate.getSourceCodePosition());
            op.setArguments(new Term[] { t2, t1 });

            outputStack.offer(op);
        }
    }
}


/*
 * Copyright The Sett Ltd, 2005 to 2014.
 *
 * Licensed 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.
 */
package com.thesett.aima.search;

import java.util.Iterator;
import java.util.Queue;

/**
 * SearchNode represents a node in a search tree over a state space and supplies utility functions needed for
 * implementing a search. A search node consists of a state and parent search node. SearchNode objects also keep track
 * of the depth of the current state, the previous operation to get to this state and the cost of the path to this
 * state.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Record parent, state, most recent operation, depth and total cost
 *
 Provide queue of all successor states  {@link Successor}
 *
 Provide utility method to generate new search node from a successor  {@link Successor}
 *
 Apply repeated state filtering  {@link RepeatedStateFilter}
 *

 *
 * @author Rupert Smith
 */
public class SearchNode<O, T extends Traversable<O>>
{
    /* Used for logging. */
    /* private static final Logger log = Logger.getLogger(SearchNode.class.getName()); */

    /** State at this node. */
    protected T state;

    /** Reference back to parent node. This will be null if this is the root node. */
    protected SearchNode<O, T> parent;

    /** Operation that was applied to the parent node. */
    protected Operator<O> appliedOp;

    /** Depth of this node. */
    protected int depth;

    /** Cost of getting to this node. */
    protected float pathCost;

    /** Holds a reference to the repeated state filtering strategy. */
    protected RepeatedStateFilter<O, T> repeatedStateFilter;

    /** Holds a flag that indicates that this node has had its successors expanded. */
    protected boolean expanded;

    /** Can be used to hold a count of unexamined successors. */
    public int unexaminedSuccessorCount;

    /**
     * Constructor takes a state and makes it a parentless (or root) search node. The intial depth and cost are set to
     * zero.
     *
     * @param startState Creates a search node out of a start state.
     */
    public SearchNode(T startState)
    {
        state = startState;
        parent = null;
        appliedOp = null;
        depth = 0;
        pathCost = 0;
    }

    /** No-argument constructor needed for newInstance(). */
    protected SearchNode()
    {
    }

    /**
     * Returns state of this node.
     *
     * @return The state covered by this search node.
     */
    public T getState()
    {
        return state;
    }

    /**
     * Returns parent of this node.
     *
     * @return The parent search node that led to this one.
     */
    public SearchNode<O, T> getParent()
    {
        return parent;
    }

    /**
     * Returns applied operation for this node.
     *
     * @return The traversal operation that was applied to the parent state to get to the state of this search node.
     */
    public Operator<O> getAppliedOp()
    {
        return appliedOp;
    }

    /**
     * Returns depth of this node.
     *
     * @return The search depth from the start node to this one.
     */
    public int getDepth()
    {
        return depth;
    }

    /**
     * Returns cost of getting to this node.
     *
     * @return The path cost from the start node to this one.
     */
    public float getPathCost()
    {
        return pathCost;
    }

    /**
     * Attaches the specified repeated state filtering strategy to the search node. This strategy is propagated into all
     * successor nodes generated from this one.
     *
     * @param filter The state filter to prune the search space of repeated states with.
     */
    public void setRepeatedStateFilter(RepeatedStateFilter<O, T> filter)
    {
        // Keep the reference to the repeated state filter
        repeatedStateFilter = filter;
    }

    /**
     * Reports the repeated state filter in use if there is one.
     *
     * @return The state filter to prune the search space of repeated states with.
     */
    public RepeatedStateFilter<O, T> getRepeatedStateFilter()
    {
        return repeatedStateFilter;
    }

    /**
     * Cheks if this node has already had its successor expanded.
     *
     * @return <tt>true</tt> if this node has had its successors expanded, <tt>false</tt> otherwise.
     */
    public boolean isExpanded()
    {
        return expanded;
    }

    /**
     * Expands a node into its successors. The successors are added to the specified collection which is returned as the
     * result of this function. The reason that the collection is passed as an argument is that there are many different
     * styles of buffer (fifo, lifo, etc) that search functions can use to implement different kinds of search and it is
     * more efficient to expand directly into the buffer than to have to copy the results into it after this method is
     * called, which would be the case if this method returned a collection.
     *
     *
If a repeated state filter has been attached to the search nodes then this method applies it here to all the
     * potential successor states. Only those that pass the filter are expanded into the collection.
     *
     * @param  expandInto The collection to place the successors in.
     * @param  reverse    When set, indicates that the expansion should be done backwards.
     *
     * @return The number of successor expanded.
     *
     * @throws SearchNotExhaustiveException If the successor nodes cannot be created. This may happen when using a
     *                                      custom node implementation that is not publicly accessible or that causes
     *                                      other class loading/creation errors.
     */
    public int expandSuccessors(Queue<SearchNode<O, T>> expandInto, boolean reverse) throws SearchNotExhaustiveException
    {
        // Used to keep count of the number of successors.
        int numSuccessors = 0;

        for (Iterator<Successor<O>> successors = getState().successors(reverse); successors.hasNext();)
        {
            numSuccessors++;

            // Get the next successor state
            Successor<O> next = successors.next();

            // Check if a repeated state filter is to be applied
            if (repeatedStateFilter != null)
            {
                // Filter the successor state and check if it should be accepted
                if (repeatedStateFilter.evaluate((T) next.getState(), this))
                {
                    // Add the filtered state to the successors
                    expandInto.offer(makeNode(next));
                }
            }

            // No repeated state filter is to be applied so add the successor state
            else
            {
                expandInto.offer(makeNode(next));
            }
        }

        // Successors have been expanded.
        expanded = true;

        return numSuccessors;
    }

    /**
     * Makes a new node of the same type as this one from a Successor state.
     *
     * @param  successor The successor state to turn into a search node.
     *
     * @return A search node covering the successor state.
     *
     * @throws SearchNotExhaustiveException If the successor nodes cannot be created. This may happen when using a
     *                                      custom node implementation that is not publicly accessible or that causes
     *                                      other class loading/creation errors.
     */
    public SearchNode<O, T> makeNode(Successor successor) throws SearchNotExhaustiveException
    {
        SearchNode newNode;

        try
        {
            // Create a new instance of this class
            newNode = getClass().newInstance();

            // Set the state, operation, parent, depth and cost for the new search node
            newNode.state = successor.getState();
            newNode.parent = this;
            newNode.appliedOp = successor.getOperator();
            newNode.depth = depth + 1;
            newNode.pathCost = pathCost + successor.getCost();

            // Check if there is a repeated state filter and copy the reference to it into the new node if so
            if (repeatedStateFilter != null)
            {
                newNode.setRepeatedStateFilter(repeatedStateFilter);
            }

            return newNode;
        }
        catch (InstantiationException e)
        {
            // In practice this should never happen but may if the nodes if some class loader error were to occur whilst
            // using a custom node implementation. Rethrow this as a RuntimeException.
            throw new IllegalStateException("InstantiationException during creation of new search node.", e);
        }
        catch (IllegalAccessException e)
        {
            // In practice this should never happen but may if the nodes to use are not public whilst using a custom node
            // implementation. Rethrow this as a RuntimeException.
            throw new IllegalStateException("IllegalAccessException during creation of new search node.", e);
        }
    }
}


/*
 * Copyright The Sett Ltd, 2005 to 2014.
 *
 * Licensed 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.
 */
package com.thesett.common.io;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.rmi.RemoteException;

/**
 * This is a client proxy to a distributed output stream. It extends the {@link java.io.OutputStream} class and is
 * therefore an OutputStream itself and can be used in any situation in which an OutputStream may be used. This client
 * is serializable and built from a distributed output stream. It provides a convenient way to return an output stream
 * accross an RMI call. It also hides the RemoteExceptions that may result from using RMI and returns these as
 * IOExceptions instead.
 *
 *

CRC Card

 *
ResponsibilitiesCollaborations
 *
Provide proxy wrapper to distributed output stream
 *  {@link DistributedOutputStream}
 *

 *
 * @author Rupert Smith
 */
public class ClientOutputStream extends OutputStream implements Serializable
{
    /** The sink end of the distributed output stream. */
    DistributedOutputStream sink;

    /**
     * Builds a client output stream proxy from a distributed output stream.
     *
     * @param dest The distributed output stream to wrap and send all data to.
     */
    public ClientOutputStream(DistributedOutputStream dest)
    {
        super();
        sink = dest;
    }

    /**
     * Flushes any buffered output to be written to this output stream.
     *
     * @throws IOException If an IOException occurs in the wrapped sink stream or a remote exception occurs.
     */
    public void flush() throws IOException
    {
        try
        {
            sink.flush();
        }
        catch (RemoteException e)
        {
            throw new IOException("There was a Remote Exception.", e);
        }
    }

    /**
     * Closes this output stream and releases any system resources associated with the stream.
     *
     * @throws IOException If an IOException occurs in the wrapped sink stream or a remote exception occurs.
     */
    public void close() throws IOException
    {
        try
        {
            sink.close();
        }
        catch (RemoteException e)
        {
            throw new IOException("There was a Remote Exception.", e);
        }
    }

    /**
     * Writes the specified byte b to this output stream.
     *
     * @param  b The byte to write.
     *
     * @throws IOException If an IOException occurs in the wrapped sink stream or a remote exception occurs.
     */
    public void write(int b) throws IOException
    {
        try
        {
            sink.write(b);
        }
        catch (RemoteException e)
        {
            throw new IOException("There was a Remote Exception.", e);
        }
    }

    /**
     * Writes all bytes from the specified byte array b to this output stream.
     *
     * @param  b The bytes to write.
     *
     * @throws IOException If an IOException occurs in the wrapped sink stream or a remote exception occurs.
     */
    public void write(byte[] b) throws IOException
    {
        try
        {
            sink.write(b);
        }
        catch (RemoteException e)
        {
            throw new IOException("There was a Remote Exception.", e);
        }
    }

    /**
     * Writes bytes from the specified byte array b, starting from index specified by off, and
     * continuing for len bytes, to this output stream.
     *
     * @param  b   The data.
     * @param  off The start offset in the data.
     * @param  len The number of bytes to write.
     *
     * @throws IOException If an IOException occurs in the wrapped sink stream or a remote exception occurs.
     */
    public void write(byte[] b, int off, int len) throws IOException
    {
        try
        {
            sink.write(b, off, len);
        }
        catch (RemoteException e)
        {
            throw new IOException("There was a Remote Exception.", e);
        }
    }
}