/*
 * 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;

/**
 * Operators in first order logic, connect terms into compound units composed of many terms under the semantics of the
 * operator. Some operators are implicit in the language, such as the standard logic operators of 'and', 'or', 'implies'
 * and so on. Others may be invented and given a particular semantics specified in the language of first order logic
 * itself. An operator is a functor; it has a name, a number of arguments and forms a compound of terms. On top of the
 * behaviour of functors, operators also have precedences and associativities, that define in what order they bind to
 * neighbouring terms in the a textual form of the language. The precedences and associativity are not part of the logic
 * as such, they are hints to a parser.
 *
 *
An OpSymbol is a functor, that additionally provides information to a parser as to its parsing priority and
 * associativity. An operator is a restricted case of a functor, in that it can take a minimum of one and a maximum of
 * two arguments.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Combine associativity and priority with a named composite.
 *
 Provide the textual representnation of a symbol.
 *
 Report a symbols fixity.
 *
 Provide priority comparison of the symbol with other symbols.
 *
 Allow a symbol to act as a template to instantiate copies from.
 *

 *
 * @author Rupert Smith
 */
public class OpSymbol extends Functor implements Comparable, Cloneable
{
    /** Defines the possible operator associativities. */
    public enum Associativity
    {
        /** Non-associative post-fix. */
        XF,

        /** Left associative post-fix. */
        YF,

        /** Non-associative pre-fix. */
        FX,

        /** Right associative pre-fix. */
        FY,

        /** Non-associative in-fix. */
        XFX,

        /** Right associative in-fix. */
        XFY,

        /** Left associative in-fix. */
        YFX
    }

    /** Defines the possible operator fixities. */
    public enum Fixity
    {
        /** Pre-fix. */
        Pre,

        /** Post-fix. */
        Post,

        /** In-fix. */
        In
    }

    /** Holds the raw text name of this operator. */
    protected String textName;

    /** Holds the associativity of this operator. */
    protected Associativity associativity;

    /** Holds the priority of this operator. */
    protected int priority;

    /**
     * Creates a new operator with the specified name and arguments.
     *
     * @param textName      The name of the operator.
     * @param arguments     The arguments the operator is applied to.
     * @param associativity Specifies the associativity of the operator.
     * @param priority      The operators priority.
     */
    public OpSymbol(String textName, Term[] arguments, Associativity associativity, int priority)
    {
        super(-1, arguments);

        // Check that there is at least one and at most two arguments.
        if ((arguments == null) || (arguments.length < 1) || (arguments.length > 2))
        {
            throw new IllegalArgumentException("An operator has minimum 1 and maximum 2 arguments.");
        }

        this.textName = textName;
        this.priority = priority;
        this.associativity = associativity;
    }

    /**
     * Creates a new operator with the specified name but no arguments.
     *
     * @param name          The interned name of the operator.
     * @param textName      The text name of the operator.
     * @param associativity Specifies the associativity of the operator.
     * @param priority      The operators priority.
     */
    public OpSymbol(int name, String textName, Associativity associativity, int priority)
    {
        super(name, null);

        this.textName = textName;
        this.priority = priority;
        this.associativity = associativity;
    }

    /**
     * Sets the arguments of this operator. It can be convenient to be able to set the outside of the constructor, for
     * example, when parsing may want to create the operator first and fill in its arguments later.
     *
     * @param arguments The arguments the operator is applied to.
     */
    public void setArguments(Term[] arguments)
    {
        // Check that there is at least one and at most two arguments.
        if ((arguments == null) || (arguments.length < 1) || (arguments.length > 2))
        {
            throw new IllegalArgumentException("An operator has minimum 1 and maximum 2 arguments.");
        }

        this.arguments = arguments;
        this.arity = arguments.length;
    }

    /**
     * Provides the symbols associativity.
     *
     * @return The symbols associativity.
     */
    public Associativity getAssociativity()
    {
        return associativity;
    }

    /**
     * Provides the symbols priority.
     *
     * @return The symbols priority.
     */
    public int getPriority()
    {
        return priority;
    }

    /**
     * Provides the symbols textual representation.
     *
     * @return The symbols textual representation.
     */
    public String getTextName()
    {
        return textName;
    }

    /**
     * Provides the symbols fixity, derived from its associativity.
     *
     * @return The symbols fixity.
     */
    public Fixity getFixity()
    {
        switch (associativity)
        {
        case FX:
        case FY:
            return Fixity.Pre;

        case XF:
        case YF:
            return Fixity.Post;

        case XFX:
        case XFY:
        case YFX:
            return Fixity.In;

        default:
            throw new IllegalStateException("Unknown associativity.");
        }
    }

    /**
     * Reports whether this operator is an prefix operator.
     *
     * @return <tt>true <tt>if this operator is an prefix operator.
     */
    public boolean isPrefix()
    {
        return ((associativity == Associativity.FX) || (associativity == Associativity.FY));
    }

    /**
     * Reports whether this operator is an postfix operator.
     *
     * @return <tt>true <tt>if this operator is an postfix operator.
     */
    public boolean isPostfix()
    {
        return ((associativity == Associativity.XF) || (associativity == Associativity.YF));
    }

    /**
     * Reports whether this operator is an infix operator.
     *
     * @return <tt>true <tt>if this operator is an infix operator.
     */
    public boolean isInfix()
    {
        return ((associativity == Associativity.XFY) || (associativity == Associativity.YFX) ||
            (associativity == Associativity.XFX));
    }

    /**
     * Reports whether this operatis is right associative.
     *
     * @return <tt>true</tt> if this operatis is right associative.
     */
    public boolean isRightAssociative()
    {
        return ((associativity == Associativity.FY) || (associativity == Associativity.XFY));
    }

    /**
     * Reports whether this operatis is left associative.
     *
     * @return <tt>true</tt> if this operatis is left associative.
     */
    public boolean isLeftAssociative()
    {
        return ((associativity == Associativity.YF) || (associativity == Associativity.YFX));
    }

    /**
     * Compares this object with the specified object for order, providing a negative integer, zero, or a positive
     * integer as this symbols priority is less than, equal to, or greater than the comparator. If this symbol is 'less'
     * than another that means that it has a lower priority value, which means that it binds more tightly.
     *
     * @param  o The object to be compared with.
     *
     * @return A negative integer, zero, or a positive integer as this symbols priority is less than, equal to, or
     *         greater than the comparator.
     */
    public int compareTo(Object o)
    {
        OpSymbol opSymbol = (OpSymbol) o;

        return (priority < opSymbol.priority) ? -1 : ((priority > opSymbol.priority) ? 1 : 0);
    }

    /**
     * Provides a copied clone of the symbol. The available symbols that a parser recognizes may be set up in a symbol
     * table. When an instance of a symbol is encountered it may be desireable to copy the symbol from the table. Using
     * this method an OpSymbol may act both as a template for symbols and as an individual instance of a symbols
     * occurance.
     *
     * @return A shallow copy of the symbol.
     */
    public OpSymbol copySymbol()
    {
        try
        {
            return (OpSymbol) clone();
        }
        catch (CloneNotSupportedException e)
        {
            throw new IllegalStateException(
                "Got a CloneNotSupportedException but clone is defined on OpSymbol and should not fail.", e);
        }
    }

    /**
     * Outputs the operator name, associativity, priority, arity and arguments as a string, used mainly for debugging
     * purposes.
     *
     * @return The operator as a string.
     */
    public String toString()
    {
        return "OpSymbol: [ name = " + textName + ", arity = " + arity + ", priority = " + priority +
            ", associativity = " + associativity + ", arguments = " + toStringArguments() + " ]";
    }

    /**
     * Creates a shallow clone of this operator symbol.
     *
     * @return A shallow clone of this object.
     *
     * @throws CloneNotSupportedException If cloning fails.
     */
    protected Object clone() throws CloneNotSupportedException
    {
        // Create a new state and copy the existing board position into it
        OpSymbol newSymbol = (OpSymbol) super.clone();

        return newSymbol;
    }
}


/*
 * 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.swing.workflow;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.JButton;
import javax.swing.JPanel;

/**
 * WorkFlowButtonsPanel is a panel of buttons consisting of back, next, finish and cancel buttons.
 *
 *
An ActionListener can register itself with the button panel and it will be sent all of the back, next, finish and
 * cancel events that the button panel generates.
 *
 *
WorkFlowButtonsPanel works in conjunction with work flows. A work flow controller can be registered with the
 * button panel in which case the controller will be sent all the action events that originate from the buttons. The
 * button panel will also listen for changes to the underlying state of the work flow and current work screen and enable
 * or disable its buttons accordingly.
 *
 *
The rules for enabling and disabling buttons are as follows:
 *
 *
If the current screen state changes its back or next available or finished state or if the current screen changes
 * then the back, next and finished buttons will be enabled according to the {@link WorkFlowScreenState#isNextAvailable},
 * {@link WorkFlowScreenState#isPrevAvailable} and {@link WorkFlowScreenState#isFinished} properties of the current
 * screen. This holds true unless the current screen is int the NOT_INITIALIZED state in which case back, next and
 * finish buttons will all be disabled.
 *
 *
If the entire work flow moves in to the NOT_INITIALIZED state then all buttons will be disabled. If it moves into
 * the ready state the cancel button will be enabled but not the finish button. If it moves into the NOT_SAVED state
 * then both the cancel and finish buttons will be enabled.
 *
 *

CRC Card

 *
ResponsibilitiesCollaborations
 *
Build user interface
 *
Register listeners for button events
 *
Enable or diable buttons according to the state of the work flow
 *
Enable or diable buttons according to the state of curent work flow screen
 *

 *
 * @author Rupert Smith
 */
public class WorkFlowButtonsPanel extends JPanel implements PropertyChangeListener
{
    /** Used for logging. */
    /* private static final Logger log = Logger.getLogger(WorkFlowButtonsPanel.class.getName()); */

    /** Holds the Back button. */
    private final JButton backButton = new JButton("<| Back");

    /** Holds the Next button. */
    private final JButton nextButton = new JButton("Next |>");

    /** Holds the Finish button. */
    private final JButton finishButton = new JButton("Finish");

    /** Holds the Cancel button. */
    private final JButton cancelButton = new JButton("Cancel");

    /** Create a new work flow buttons panel. */
    public WorkFlowButtonsPanel()
    {
        initComponents();
    }

    /** Builds the user interface. */
    public void initComponents()
    {
        // Place the buttons in the panel
        add(backButton);
        add(nextButton);
        add(finishButton);
        add(cancelButton);
    }

    /**
     * Called when a property in the work flow state is changed.
     *
     * @param event The property change event.
     */
    public void propertyChange(PropertyChangeEvent event)
    {
        /*log.fine("void propertyChange(PropertyChangeEvent): called");*/

        /*log.fine("source class = " + event.getSource().getClass());*/
        /*log.fine("source object = " + event.getSource());*/
        /*log.fine("property name = " + event.getPropertyName());*/
        /*log.fine("new value = " + event.getNewValue());*/
        /*log.fine("old value = " + event.getOldValue());*/

        Object source = event.getSource();
        Object oldValue = event.getOldValue();
        String propertyName = event.getPropertyName();

        // Check if the event source is an individual screen state
        if (source instanceof WorkFlowScreenState)
        {
            WorkFlowScreenState wfsState = (WorkFlowScreenState) source;

            // Update the buttons to reflect the change in screen state
            updateButtonsForScreen(wfsState);
        }

        // Check if the event source is the whole work flow
        if (source instanceof WorkFlowState)
        {
            WorkFlowState wfState = (WorkFlowState) source;

            // Check if the event cause is a change in current screen
            if ("currentScreenState".equals(propertyName))
            {
                WorkFlowScreenState newScreenState = wfState.getCurrentScreenState();
                WorkFlowScreenState oldScreenState = (WorkFlowScreenState) oldValue;

                // De-register this as a listener for the old current screen state
                if (oldScreenState != null)
                {
                    oldScreenState.removePropertyChangeListener(this);
                }

                // Register this as a listener for the new current screen state
                if (newScreenState != null)
                {
                    newScreenState.addPropertyChangeListener(this);
                }

                // Update the buttons to reflect the current screen state
                updateButtonsForScreen(newScreenState);
            }

            // Check if the event cause is a change in the work flow state
            else if ("state".equals(propertyName))
            {
                // Update the buttons to reflect the change in state
                updateButtonsForWorkFlow(wfState);
            }
        }
    }

    /**
     * Updates the buttons enabled/disabled status to reflect the current screen state.
     *
     * @param state The new work flow screen state.
     */
    public void updateButtonsForScreen(WorkFlowScreenState state)
    {
        // Check if it is in the READY or NOT_SAVED state
        if (state.getState().equals(WorkFlowScreenState.READY) ||
                state.getState().equals(WorkFlowScreenState.NOT_SAVED))
        {
            backButton.setEnabled(state.isPrevAvailable());
            nextButton.setEnabled(state.isNextAvailable());
            finishButton.setEnabled(state.isFinished());
        }

        // Check if it is in the NOT_INITIALIZED state
        if (state.getState().equals(WorkFlowScreenState.NOT_INITIALIZED))
        {
            backButton.setEnabled(false);
            nextButton.setEnabled(false);
            finishButton.setEnabled(false);
        }
    }

    /**
     * Updates the buttons enabled/disabled status to reflect the current work flow state.
     *
     * @param state The new work flow state.
     */
    public void updateButtonsForWorkFlow(WorkFlowState state)
    {
        // Check if it is in the NOT_INITIALIZED state
        if (state.getState().equals(WorkFlowState.NOT_INITIALIZED))
        {
            backButton.setEnabled(false);
            nextButton.setEnabled(false);
            finishButton.setEnabled(false);
            cancelButton.setEnabled(false);
        }

        // Check if it is in the READY state
        if (state.getState().equals(WorkFlowState.READY))
        {
            finishButton.setEnabled(false);
            cancelButton.setEnabled(true);

            // Update buttons for the current screen state
            updateButtonsForScreen(state.getCurrentScreenState());
        }

        // Check if it is in the NOT_SAVED state
        if (state.getState().equals(WorkFlowState.NOT_SAVED))
        {
            finishButton.setEnabled(true);
            cancelButton.setEnabled(true);
        }
    }

    /**
     * Registers the work flow button panel with the specified work flow controller. This will cause the work flow
     * controller to receive button press events from the panel and register the button panel to receive state changes
     * from the underlying work flow model.
     *
     * @param controller The work flow controller to recieve work flow events from.
     */
    public void registerWorkFlowController(WorkFlowController controller)
    {
        // Set the work flow controller to listen for button events
        backButton.addActionListener(controller);
        nextButton.addActionListener(controller);
        finishButton.addActionListener(controller);
        cancelButton.addActionListener(controller);

        // Register this to listen for changes to the work flow state
        controller.getWorkFlowState().addPropertyChangeListener(this);

        // Register this to listen for changes to the state for the current screen if it is not null
        WorkFlowScreenState currentScreenState = controller.getWorkFlowState().getCurrentScreenState();

        if (currentScreenState != null)
        {
            currentScreenState.addPropertyChangeListener(this);
        }
    }
}


/*
 * 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.LinkedList;
import java.util.List;

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

/**
 * The DefaultBuiltIn implements an implicit default built-in operator that implements the normal processing pathway in
 * a Prolog program. That is, the head of the goal stack is unified against the head of the current clause chosen for
 * examination at this step of the proof, and if a match is found, the functors in the clause body are pushed onto the
 * goal stack (in reverse order, so that they are processed intuitively left-to-right when popped off again).
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Unify the current goal against the head of the current clause.
 *      {@link ResolutionState}, {@link PrologUnifier}
 *
 Create any new goals resulting from the RHS of the unified against clause.
 *      {@link ResolutionState}.
 *

 *
 * @author Rupert Smith
 */
public class DefaultBuiltIn extends BaseBuiltIn
{
    /** Used for providing user readable execution traces. */
    /* private static final Logger trace = Logger.getLogger("TRACE.Prolog." + DefaultBuiltIn.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 default built-in to implement the specified functor.
     *
     * @param functor The functor to implement as a built in.
     */
    public DefaultBuiltIn(Functor functor)
    {
        super(functor);
    }

    /** {@inheritDoc} */
    public boolean proofStep(ResolutionState state)
    {
        Functor goalTerm = state.getGoalStack().peek().getFunctor();
        Functor matchTerm = state.getCurrentClause().getHead();

        // This is used to record variables bound on the domain side of the unificiation. This information seems
        // like is does not need to be kept because usually all of these bindings are in the stack frame.
        // However, this is not always the case as unification can capture a variable on the domain side.
        // These variables need to be unbound on backtracking too.
        List<Variable> domainVariables = new LinkedList<Variable>();

        // This is used to record variables bound on the query goal side of the unification. This information
        // must be kept so that the undo operation can unbind these variables before placing the goal back
        // onto the stack when backtracking.
        List<Variable> boundVariables = new LinkedList<Variable>();

        // Unify the current query goal with the possibly matching clause, creating variable bindings.
        boolean matched = state.getUnifier().unifyInternal(goalTerm, matchTerm, boundVariables, domainVariables);

        // Even if unification fails, any partial bindings created are remembered, to ensure that they are cleaned
        // up when this proof steps state is undone.
        for (Variable binding : boundVariables)
        {
            state.getVariableBindings().offer(binding);
        }

        for (Variable binding : domainVariables)
        {
            state.getVariableBindings().offer(binding);
        }

        // If the unification succeeded, establish a new state with the unified query removed from the goal stack, the
        // body of the unified with clause added to it for resolution, and the variable binding trail extended with
        // any additional bindings resulting from the unification.
        if (matched)
        {
            if (TRACE)
            {
                /*trace.fine(state.getTraceIndenter().generateTraceIndent() + "Unify " +
                    goalTerm.toString(state.getInterner(), true, true) + " against " +
                    matchTerm.toString(state.getInterner(), true, true) + ", ok.");*/
            }

            // Consume the successfully unified goal from the goal stack.
            state.getGoalStack().poll();

            // Add all functors on the body side of the unified clause onto the goal stack for resolution.
            Functor[] body = state.getCurrentClause().getBody();

            if ((body != null) && (body.length != 0))
            {
                // The new goals are placed onto the goal stack backwards. It is a stack, hence they get
                // explored first, depth first, but their insertion order is reversed for an intuitive
                // left-to-right evaluation order.
                for (int i = body.length - 1; i >= 0; i--)
                {
                    BuiltInFunctor newGoal = state.getBuiltInTransform().apply(body[i]);
                    newGoal.setParentChoicePointState(state.getLastChoicePoint());
                    state.getGoalStack().offer(newGoal);
                }
            }

            return true;
        }
        else
        {
            if (TRACE)
            {
                /*trace.fine(state.getTraceIndenter().generateTraceIndent() + "Failed to unify " +
                    goalTerm.toString(state.getInterner(), true, true) + " against " +
                    matchTerm.toString(state.getInterner(), true, true) + ".");*/
            }

            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.aima.attribute.impl;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import com.thesett.aima.state.BaseType;
import com.thesett.aima.state.OrdinalAttribute;
import com.thesett.aima.state.Type;
import com.thesett.common.error.NotImplementedException;

/**
 * EnumAttributes are used to encapsulate Java 1.5 enums as implementations of the {@link OrdinalAttribute} interface.
 * This means that there must be methods to state how many different values an enum can take on and to list all those
 * possible values as {@link OrdinalAttribute}s. The actual enums are stored as integer ordinals. A map of class level
 * enum information is maintained to provide information about how many and what values a given class of enums can take
 * on.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Provide factory to convert an enum into an OrdinalAttribute.
 *
 Provide count of how many values an enum can have.
 *
 Provide listing of all enum values.
 *

 *
 * @author Rupert Smith
 */
public class EnumAttribute implements OrdinalAttribute
{
    /** Used to hold all the different enum classes. */
    private static final Map<Class, EnumClassImpl> attributeClasses = new HashMap<Class, EnumClassImpl>();

    /** Holds the enum ordinal. */
    private final int ordinal;

    /** Holds a reference to the class of enum attribute that this one belongs to. */
    EnumClassImpl attributeClass;

    /**
     * Creates a new EnumAttribute object.
     *
     * @param value          The value of the enum attribute.
     * @param attributeClass The factory implementation for the class type of enum for this attribute.
     */
    private EnumAttribute(Enum value, EnumClassImpl attributeClass)
    {
        // Keep the ordinal represenation and the pointer to the attribute class information.
        this.ordinal = value.ordinal();
        this.attributeClass = attributeClass;
    }

    /**
     * Generates a factory for building enum attributes of the specified enum class.
     *
     * @param  cls The class type of enum to get an enum attribute factory for.
     *
     * @return The enum attribute factory for the enum class type specified.
     */
    public static EnumAttributeFactory getFactoryForClass(Class cls)
    {
        // Check that the requested class is actually an enum.
        if (!cls.isEnum())
        {
            throw new IllegalArgumentException("Can only create enum attribute factories for classes that are enums.");
        }

        return EnumClassImpl.getInstance(cls);
    }

    /**
     * Returns the attribute type of this attribute.
     *
     * @return The attribute type of this attribute.
     */
    public Type<EnumAttribute> getType()
    {
        return attributeClass;
    }

    /**
     * The ordinal value of the enum value of this attribute.
     *
     * @return The ordinal value of the enum value of this attribute.
     */
    public int ordinal()
    {
        return ordinal;
    }

    /**
     * The number of possible values that an instance of this enum attribute can take on.
     *
     * @return the number of possible values that an instance of this enum attribute can take on.
     */
    /*public int getNumPossibleValues()
    {
        // Fetch the number of possible values from the attribute class.
        return attributeClass.numValues;
    }*/

    /**
     * Gets the underlying value of this attribute as an Enum.
     *
     * @return An instance of the underlying enum.
     */
    public Enum getEnumValue()
    {
        return attributeClass.values[ordinal];
    }

    /**
     * Generates hashCodes unique to the value of the enum value.
     *
     * @return A hash code for the enum value of this attribute.
     */
    public int hashCode()
    {
        // Return a hash made from the enum ordinal.
        return Integer.valueOf(ordinal).hashCode();
    }

    /**
     * Tests if two enum attributes are equal. They are equal if they are of the same enum class and have the same enum
     * value.
     *
     * @param  o The object to compare to.
     *
     * @return True if the comparator is an enum attribute of the same class of enum as this one and has the same value,
     *         false otherwise.
     */
    public boolean equals(Object o)
    {
        EnumAttribute compareTo = (EnumAttribute) o;

        return compareTo.attributeClass.enumClass.equals(attributeClass.enumClass) && (compareTo.ordinal == ordinal);
    }

    /**
     * Defines the type interface for enum attributes.
     */
    public static interface EnumType extends Type<EnumAttribute>
    {
    }

    /**
     * Used to provide a factory for creating enum attributes of a given class.
     */
    public static interface EnumAttributeFactory
    {
        /**
         * Creates an enum attribute of the enum class that this is a factory for.
         *
         * @param  value The enum value that the attribute should have.
         *
         * @return An EnumAttribute with the specified enum value.
         */
        public EnumAttribute createEnumAttribute(Enum value);

        /** Drops an attribute class. The attribute class is explicitly deleted. */
        public void dropAttributeClass();
    }

    /**
     * Defines the class of enum attributes. Class = Type + Factory.
     */
    public static interface EnumClass extends EnumType, EnumAttributeFactory
    {
    }

    /**
     * Provides an implementation of the enum attribute factory.
     */
    private static class EnumClassImpl extends BaseType<EnumAttribute> implements EnumClass
    {
        /** The number of possible values this attribute can take on. */
        int numValues;

        /** Used to hold the class of the enum class that this is an attribute factory for. */
        Class enumClass;

        /** Used to hold a mapping from the ordinals to the underlying enums that they correspond to. */
        Enum[] values;

        /**
         * Builds a new factory for a given enum class.
         *
         * @param enumClass The class type of the enumeration.
         */
        private EnumClassImpl(Class enumClass)
        {
            // Keep a reference to the underlying enum class.
            this.enumClass = enumClass;

            // Count the number of possible values that this enum can have.
            numValues = enumClass.getEnumConstants().length;

            // Create a populated array of all those values.
            values = (Enum[]) enumClass.getEnumConstants();
        }

        /**
         * Gets an instance of this enum attribute factory implementation. This may be an existing object if one already
         * exists for this enum class or a new one will be created if not.
         *
         * @param  enumClass The class type of the enum to get a factory for.
         *
         * @return An enum factory implementation for the enum class.
         */
        public static EnumAttributeFactory getInstance(Class enumClass)
        {
            // Try to get the attribute class from the map of those that have already been created.
            EnumClassImpl attributeClass = attributeClasses.get(enumClass);

            // Check if this is a new class and create it if so.
            if (attributeClass == null)
            {
                attributeClass = new EnumClassImpl(enumClass);
                attributeClasses.put(enumClass, attributeClass);
            }

            return attributeClass;
        }

        /**
         * Gets a new default instance of the type. The types value will be set to its default uninitialized value.
         *
         * @return A new default instance of the type. Always <tt>false</tt>.
         */
        public EnumAttribute getDefaultInstance()
        {
            throw new NotImplementedException();
        }

        /**
         * Creates an enum attribute of the class that this is a factory for.
         *
         * @param  value The enum value to create a new enum attribute for.
         *
         * @return A new enum attribute with the specified value.
         */
        public EnumAttribute createEnumAttribute(Enum value)
        {
            return new EnumAttribute(value, this);
        }

        /** Drops an attribute class. The attribute class is explicitly deleted. */
        public void dropAttributeClass()
        {
            attributeClasses.remove(enumClass);
        }

        /**
         * Returns the name of this enum attribute class. This will be the name of the underlying enum Java Class.
         *
         * @return The name of this enum attribute class. This will be the name of the underlying enum Java Class.
         */
        public String getName()
        {
            return enumClass.getName();
        }

        /**
         * Gets the underlying Java class that implements the type.
         *
         * @return The underlying Java class that implements the type.
         */
        public Class<EnumAttribute> getBaseClass()
        {
            return EnumAttribute.class;
        }

        /** {@inheritDoc} */
        public String getBaseClassName()
        {
            return getBaseClass().getName();
        }

        /**
         * The number of possible values that an instance of this enum attribute can take on.
         *
         * @return the number of possible values that an instance of this enum attribute can take on.
         */
        public int getNumPossibleValues()
        {
            // Fetch the number of possible values from the attribute class.
            return numValues;
        }

        /**
         * Gets the set of all possible values that this enum attribute can have. This will be a set of enum attributes.
         *
         * @return A set of enum attributes for all possible values of this enum attribute.
         */
        public Set<EnumAttribute> getAllPossibleValuesSet()
        {
            // Turn the array of possible enum values into a set.
            Enum[] enumValues = (Enum[]) enumClass.getEnumConstants();

            Set<EnumAttribute> valueSet = new HashSet<EnumAttribute>();

            for (Enum enumValue : enumValues)
            {
                valueSet.add(createEnumAttribute(enumValue));
            }

            return valueSet;
        }

        /**
         * Generates an iterator over the set of all possible enum attribute values of this attribute.
         *
         * @return An iterator over the set of all possible enum attribute values of this attribute.
         */
        public Iterator<EnumAttribute> getAllPossibleValuesIterator()
        {
            return getAllPossibleValuesSet().iterator();
        }
    }

    /**
     * Gets the set of all possible values that this enum attribute can have. This will be a set of enum attributes.
     *
     * @return A set of enum attributes for all possible values of this enum attribute.
     */
    /*public Set<EnumAttribute> getAllPossibleValuesSet()
    {
        // Turn the array of possible enum values into a set.
        Enum[] enumValues = (Enum[]) attributeClass.enumClass.getEnumConstants();

        Set<EnumAttribute> valueSet = new HashSet<EnumAttribute>();

        for (int i = 0; i < enumValues.length; i++)
        {
            valueSet.add(attributeClass.createEnumAttribute(enumValues[i]));
        }

        return valueSet;
    }*/

    /**
     * Generates an iterator over the set of all possible enum attribute values of this attribute.
     *
     * @return An iterator over the set of all possible enum attribute values of this attribute.
     */
    /*public Iterator<EnumAttribute> getAllPossibleValuesIterator()
    {
        return getAllPossibleValuesSet().iterator();
    }*/
}


/*
 * 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.wam.debugger.uifactory;

import com.thesett.aima.logic.fol.wam.debugger.text.AttributeGrid;
import com.thesett.aima.logic.fol.wam.debugger.text.AttributeSet;

/**
 * Implements a color delta that modifies the background color of a row of a text grid.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Apply a background color change to a row of a text grid.

 *

 *
 * @author Rupert Smith
 */
public class RowBackgroundColorDelta<C> implements ColorDelta<C>
{
    /** The row to make color changes to. */
    private final int row;

    /** The text grid model to alter the background color of. */
    private final AttributeGrid grid;

    /**
     * Creates a color delta for a table row.
     *
     * @param row  The row to make color changes to.
     * @param grid The text grid model to alter the background color of.
     */
    public RowBackgroundColorDelta(int row, AttributeGrid grid)
    {
        this.row = row;
        this.grid = grid;
    }

    /**
     * {@inheritDoc}
     *
     *
Applies color changes to the background of a row.
     */
    public void changeColor(C color)
    {
        AttributeSet aset = new AttributeSet();
        aset.put(AttributeSet.BACKGROUND_COLOR, color);
        grid.insertRowAttribute(aset, row);
    }
}


/*
 * 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.wam.debugger.uifactory;

import com.thesett.common.util.ReflectionUtils;

/**
 * ComponentFactoryBuilder creates instances of the UI component factories.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Provide component factory implementations.

 *

 *
 * @author Rupert Smith
 */
public class ComponentFactoryBuilder
{
    /** The name of the Swing factory. */
    public static final String SWING_FACTORY =
        "com.thesett.aima.logic.fol.wam.debugger.uifactory.impl.SwingComponentFactory";

    /**
     * Creates an instance of the named component factory.
     *
     * @param  className The name of the component factory class to instantiate.
     *
     * @return An instance of the named component factory.
     */
    public static ComponentFactory createComponentFactory(String className)
    {
        return (ComponentFactory) ReflectionUtils.newInstance(ReflectionUtils.forName(className));
    }
}


/*
 * 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;

import com.thesett.aima.logic.fol.Term;
import com.thesett.aima.logic.fol.Variable;
import com.thesett.aima.logic.fol.VariableBindingContext;

/**
 * StackVariable is a {@link Variable} that has been assigned an offset within a stack frame in which it may hold its
 * binding.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Associate a name with an optional substitution.
 *
 Allow a variable to be marked as anonymous.
 *
 Provide a position relative to a stack frame where this variable can store its binding.
 *

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

    /** Used to hold the stack frame offset for this variable. */
    protected int position;

    /** Holds the binding context supplier used to designate where this variables bindings are stored. */
    VariableBindingContextSupplier contextSupplier;

    /**
     * Creates a new variable, the name does not have to be unique and the the variable can be free by supplying a null
     * substitution. The variables allocated position on the stack frame must be specified.
     *
     * @param name            The name of the variable.
     * @param substitution    The substitution to create the variable with, use <tt>null</tt> for a free variable.
     * @param anonymous       Set to <tt>true</tt> if the variable is to be anonymous.
     * @param position        The variables allocated position on the stack frame.
     * @param contextSupplier The supplier of the variable binding context for this variable.
     */
    public StackVariable(int name, Term substitution, boolean anonymous, int position,
        VariableBindingContextSupplier contextSupplier)
    {
        super(name, substitution, anonymous);

        this.position = position;
        this.contextSupplier = contextSupplier;
    }

    /**
     * Provides this variables binding context.
     *
     * @return This variables binding context, or <tt>null</tt> if none has been established.
     */
    public VariableBindingContext<Variable> getBindingContext()
    {
        return contextSupplier.getBindingContext();
    }

    /**
     * Provides the storage cell for the specified variable. Some types of variable may defer their storage onto a
     * storage cell other than themselves, other variable types may simply return themselves as their own storage cells.
     *
     * @param  variable The variable to get the storage cell for.
     *
     * @return The storage cell where the specified variable sets its bindings, or <tt>null</tt> if none has been
     *         established.
     */
    public Variable getStorageCell(Variable variable)
    {
        VariableBindingContext<Variable> context = getBindingContext();

        if (context == null)
        {
            return null;
        }
        else
        {
            return context.getStorageCell(this);
        }
    }

    /**
     * Provides this variables allocated stack frame position.
     *
     * @return The stack from position of this variable.
     */
    public int getPosition()
    {
        return position;
    }

    /**
     * Gets the actual value of a term, which is either the term itself, or in the case of variables, the value that is
     * currently assigned to the variable. When the variable is free, the variable term itself is returned.
     *
     * @return The term itself, or the assigned value of this variable.
     */
    public Term getValue()
    {
        Variable storageCell = getStorageCell(this);

        if (storageCell == null)
        {
            return this;
        }
        else
        {
            return storageCell.getValue();
        }
    }

    /**
     * Binds this variable to the specified value.
     *
     * @param term The value to bind this variable to.
     */
    public void setSubstitution(Term term)
    {
        Term termToBindTo = term;

        // When binding against a variable, always bind to its storage cell and not the variable itself.
        if (termToBindTo instanceof Variable)
        {
            Variable variableToBindTo = (Variable) term;
            termToBindTo = variableToBindTo.getStorageCell(variableToBindTo);
        }

        getStorageCell(this).setSubstitution(termToBindTo);
    }

    /** Frees all assigned variables in the term, leaving them unnassigned. */
    public void free()
    {
        getStorageCell(this).setSubstitution(null);
    }

    /**
     * Reports whether or not this variable is bound to a value.
     *
     * @return <tt>true</tt> if this variable has been assigned a value, <tt>false</tt> otherwise.
     */
    public boolean isBound()
    {
        VariableBindingContext<Variable> context = getBindingContext();

        // The variable can only be bound if it has a binding context and is bound in that context.
        return (context != null) && context.getStorageCell(this).isBound();
    }

    /**
     * Makes a clone of the term, converting its variables to refer directly to their storage cells.
     *
     * @return A copy of this term, with entirely independent variables to the term it was copied from.
     */
    public Variable queryConversion()
    {
        /*log.fine("public Variable queryConversion(): called");*/

        return getStorageCell(this);
    }

    /**
     * Creates a string representation of this variable, mostly used for debugging purposes.
     *
     * @return A string representation of this variable.
     */
    public String toString()
    {
        return "StackVariable: [ name = " + name + ", position = " + position + ", substitution = " +
            ((isBound()) ? "instantiated" : "null") + " ]";
    }

    /**
     * Pretty prints a term relative to the symbol namings provided by the specified interner.
     *
     * @param interner      The interner use to provide symbol names.
     * @param printBindings <tt>true</tt> if variable binding values should be printed, <tt>false</tt> if just the
     *                      variables name without any binding should be printed.
     *
     * @return A pretty printed string containing the term.
     */
    /*public String toString(VariableAndFunctorInterner interner, boolean printBindings)
    {
        return toString();
    }*/
}


/*
 * 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.wam.debugger.text;

import java.util.ArrayList;
import java.util.List;

import com.thesett.common.util.doublemaps.DoubleKeyedMap;
import com.thesett.common.util.doublemaps.HashMapXY;

/**
 * AttributeGridImpl maintains a grid of attribute sets.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Insert text attributes into grid cells. 	 {@link HashMapXY}

 *
 Insert text attributes into grid columns.

 *
 Insert text attributes into grid rows.

 *
 Provide cascaded text attributes for grid cells. 	 {@link HashMapXY}

 *

 *
 * @author Rupert Smith
 */
public class AttributeGridImpl implements AttributeGrid
{
    /** Holds the grid data. */
    DoubleKeyedMap<Long, Long, AttributeSet> cellAttributes = new HashMapXY<AttributeSet>(100);

    /** Holds the per column attributes. */
    List<AttributeSet> columnAttributes = new ArrayList<AttributeSet>();

    /** Holds the per line attributes. */
    List<AttributeSet> rowAttributes = new ArrayList<AttributeSet>();

    /** {@inheritDoc} */
    public void insertAttribute(AttributeSet attributes, int c, int r)
    {
        internalInsert(attributes, c, r);
    }

    /** {@inheritDoc} */
    public void insertColumnAttribute(AttributeSet attributes, int c)
    {
        setColumnAttribute(attributes, c);
    }

    /** {@inheritDoc} */
    public void insertRowAttribute(AttributeSet attributes, int r)
    {
        setRowAttribute(attributes, r);
    }

    /** {@inheritDoc} */
    public AttributeSet getAttributeAt(int c, int r)
    {
        AttributeSet attributeSet = cellAttributes.get((long) c, (long) r);
        attributeSet = (attributeSet == null) ? getColumnAttributeOrNull(c) : attributeSet;
        attributeSet = (attributeSet == null) ? getRowAttributeOrNull(r) : attributeSet;

        return attributeSet;
    }

    /** {@inheritDoc} */
    public AttributeSet getColumnAttribute(int c)
    {
        return getColumnAttributeOrNull(c);
    }

    /** {@inheritDoc} */
    public AttributeSet getRowAttribute(int r)
    {
        return getRowAttributeOrNull(r);
    }

    /**
     * Sets a column attribute, adding padding to the underlying array as necessary to ensure it is large enough to hold
     * the attribute at the requested position.
     *
     * @param attributes The attribute to set.
     * @param c          The column to set it on.
     */
    private void setColumnAttribute(AttributeSet attributes, int c)
    {
        if (c >= columnAttributes.size())
        {
            for (int i = columnAttributes.size(); i <= c; i++)
            {
                columnAttributes.add(null);
            }
        }

        columnAttributes.set(c, attributes);
    }

    /**
     * Sets a row attribute, adding padding to the underlying array as necessary to ensure it is large enough to hold
     * the attribute at the requested position.
     *
     * @param attributes The attribute to set.
     * @param r          The row to set it on.
     */
    private void setRowAttribute(AttributeSet attributes, int r)
    {
        if (r >= rowAttributes.size())
        {
            for (int i = rowAttributes.size(); i <= r; i++)
            {
                rowAttributes.add(null);
            }
        }

        rowAttributes.set(r, attributes);
    }

    /**
     * Gets a columns attribute if possible, without overflowing the underlying array.
     *
     * @param  c The column to get the attributes for.
     *
     * @return The column attributes or <tt>null</tt> if none are set.
     */
    private AttributeSet getColumnAttributeOrNull(int c)
    {
        if ((c >= 0) && (c < columnAttributes.size()))
        {
            return columnAttributes.get(c);
        }
        else
        {
            return null;
        }
    }

    /**
     * Gets a rows attribute if possible, without overflowing the underlying array.
     *
     * @param  r The row to get the attributes for.
     *
     * @return The row attributes or <tt>null</tt> if none are set.
     */
    private AttributeSet getRowAttributeOrNull(int r)
    {
        if ((r >= 0) && (r < rowAttributes.size()))
        {
            return rowAttributes.get(r);
        }
        else
        {
            return null;
        }
    }

    /**
     * Inserts a set of attributes 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 attributes The attribute set to insert.
     * @param c          The column position.
     * @param r          The row position.
     */
    private void internalInsert(AttributeSet attributes, int c, int r)
    {
        cellAttributes.put((long) c, (long) r, attributes);
    }
}


/*
 * 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.expressions;

import com.thesett.aima.logic.fol.NumericType;
import com.thesett.aima.logic.fol.Term;

/**
 * BinaryArithmeticOperator provides a base implementation for all one-place arithmetic operators on a numeric argument.
 * The {@link #getValue()} method invokes {@link #getValue()} on its argument to recursively evaluate it, as it may also
 * be an arithmetic operator or other {@link BuiltInExpressionOperator}. It checks that the resulting argument is fully
 * instantiated and numeric prior to calling the operators implementing {#evaluate} method to compute the result.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Ensure that the argument evaluates to a fully instantiated number.  {@link Term}, {@link NumericType}.
 *
 Evaluate the arithmetic operator.
 *

 *
 * @author Rupert Smith
 */
public abstract class UnaryArithmeticOperator extends BuiltInExpressionOperator
{
    /**
     * Creates a unary arithmetic operator on one argument.
     *
     * @param name      The interned name of the operator.
     * @param arguments The operators arguments. There must be exactly one.
     */
    protected UnaryArithmeticOperator(int name, Term[] arguments)
    {
        super(name, arguments);

        // Ensure that there are exactly two argument.
        if (arguments.length != 1)
        {
            throw new IllegalArgumentException("UnaryArithmeticOperators must take exactly one argument.");
        }
    }

    /**
     * Gets the actual value of a term, which is a numeric type equal in value to the arithmetic operator applied to its
     * argument. This method checks that the argument produces a value which is fully instantiated and numeric when its
     * {@link Term#getValue()} methods is invoked.
     *
     * @return A numeric type equal in value to the the arithmetic operator applied to its argument.
     */
    public NumericType getValue()
    {
        Term firstArgValue = arguments[0].getValue();

        // Check that the argument to operate on is a numeric values.
        if (!firstArgValue.isNumber())
        {
            throw new IllegalStateException(
                "instantiation_error, 'arithmetic/2' expects numeric arguments, but the first argument is non-numeric.");
        }

        return evaluate((NumericType) firstArgValue);
    }

    /**
     * Evaluates the arithmetic operator on its numeric argument.
     *
     * @param  firstNumber The first argument.
     *
     * @return The result of performing the arithmetic operator on its argument.
     */
    protected abstract NumericType evaluate(NumericType firstNumber);
}


/*
 * 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.wam.debugger.uifactory.impl;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;

import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;

import com.thesett.aima.logic.fol.wam.debugger.swing.DiscreetScrollBarUI;
import com.thesett.aima.logic.fol.wam.debugger.swing.FillViewportLayout;
import com.thesett.aima.logic.fol.wam.debugger.swing.GripComponentMouseMover;
import com.thesett.aima.logic.fol.wam.debugger.swing.JTextGrid;
import com.thesett.aima.logic.fol.wam.debugger.swing.MotionDelta;
import com.thesett.aima.logic.fol.wam.debugger.swing.ToolingColorScheme;
import com.thesett.aima.logic.fol.wam.debugger.text.EnhancedTextGrid;
import com.thesett.aima.logic.fol.wam.debugger.text.EnhancedTextGridImpl;
import com.thesett.aima.logic.fol.wam.debugger.uifactory.ColorFactory;
import com.thesett.aima.logic.fol.wam.debugger.uifactory.ColorScheme;
import com.thesett.aima.logic.fol.wam.debugger.uifactory.ComponentFactory;
import com.thesett.aima.logic.fol.wam.debugger.uifactory.KeyCombinationBuilder;
import com.thesett.aima.logic.fol.wam.debugger.uifactory.KeyShortcutMap;
import com.thesett.aima.logic.fol.wam.debugger.uifactory.MainWindow;

/**
 * SwingComponentFactory implements a UI component factory that produces Swing components.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Create the main window. 	 {@link ColorScheme}

 *
 Create a grip-able panel for adjusting screen layout. 	 {@link ColorScheme}

 *
 Create an editor panel. 	 {@link ColorScheme}

 *
 Create a black panel for filling in unused areas of the screen. 	 {@link ColorScheme}

 *

 *
 * @author Rupert Smith
 */
public class SwingComponentFactory implements ComponentFactory<JComponent, Color, KeyStroke>
{
    /** The default cursor appearance. */
    private static final Cursor DEFAULT_CURSOR = new Cursor(Cursor.DEFAULT_CURSOR);

    /** The cursor for vertical resizing controls mouse-over. */
    private static final Cursor VERTICAL_RESIZE_CURSOR = new Cursor(Cursor.W_RESIZE_CURSOR);

    /** The cursor for horizontal resizing controls mouse-over. */
    private static final Cursor HORIZONTAL_RESIZE_CURSOR = new Cursor(Cursor.N_RESIZE_CURSOR);

    /** The grip cursor appearance to use when moving components. */
    private static final Cursor GRIP_CURSOR = new Cursor(Cursor.MOVE_CURSOR);

    /** The color factory. */
    private final SwingColorFactory colorFactory = new SwingColorFactory();

    /** The color scheme to apply to user areas within components. */
    private ColorScheme<Color> colorScheme;

    /** The key combination builder. */
    private final SwingKeyCombinationBuilder keyCombinationBuilder = new SwingKeyCombinationBuilder();

    /** The keyboard short cut map to use across the components. */
    private KeyShortcutMap<KeyStroke> keyShortcutMap = new DefaultKeyShortcutMap<KeyStroke>(keyCombinationBuilder);

    private final ToolingColorScheme toolingColorScheme =
        new ToolingColorScheme()
        {
            public Color getToolingBackground()
            {
                return Color.DARK_GRAY;
            }

            public Color getToolingActiveBackground()
            {
                return Color.LIGHT_GRAY;
            }
        };

    /** Creates a component factory that produces Swing components. */
    public SwingComponentFactory()
    {
        colorScheme = new DefaultColorScheme(colorFactory);
    }

    /** {@inheritDoc} */
    public MainWindow<JComponent, KeyStroke> createMainWindow()
    {
        return new SwingMainWindow(this);
    }

    /** {@inheritDoc} */
    public EnhancedTextGrid createTextGrid()
    {
        return new EnhancedTextGridImpl();
    }

    /** {@inheritDoc} */
    public JComponent createTextGridPanel(EnhancedTextGrid model)
    {
        JTextGrid textPane = new JTextGrid();

        textPane.setBackground(colorScheme.getBackground());
        textPane.setForeground(colorScheme.getMainText());
        textPane.setAutoscrolls(true);

        Font font = new Font("DejaVu Sans Mono", Font.PLAIN, 12);
        textPane.setFont(font);
        textPane.setModel(model);
        textPane.initializeStandardMouseHandling();

        JScrollPane scrollPane =
            new JScrollPane(textPane, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        scrollPane.getVerticalScrollBar().setUI(new DiscreetScrollBarUI(toolingColorScheme));
        scrollPane.getHorizontalScrollBar().setUI(new DiscreetScrollBarUI(toolingColorScheme));
        scrollPane.setBorder(BorderFactory.createEmptyBorder());
        scrollPane.getViewport().setLayout(new FillViewportLayout());

        return scrollPane;
    }

    /** {@inheritDoc} */
    public JComponent createGripPanel(MotionDelta motionDelta, boolean vertical)
    {
        JPanel vbar = new JPanel();
        vbar.setBackground(toolingColorScheme.getToolingBackground());

        GripComponentMouseMover resizer =
            new GripComponentMouseMover(vbar, motionDelta, vertical ? VERTICAL_RESIZE_CURSOR : HORIZONTAL_RESIZE_CURSOR,
                GRIP_CURSOR);
        vbar.addMouseMotionListener(resizer);
        vbar.addMouseListener(resizer);

        return vbar;
    }

    /** {@inheritDoc} */
    public JComponent createBlankPanel()
    {
        JPanel vbar = new JPanel();
        vbar.setBackground(colorScheme.getBackground());
        vbar.setForeground(colorScheme.getDisabledText());

        return vbar;
    }

    /** {@inheritDoc} */
    public void setColorScheme(ColorScheme<Color> colorScheme)
    {
        this.colorScheme = colorScheme;
    }

    /** {@inheritDoc} */
    public ColorScheme<Color> getColorScheme()
    {
        return colorScheme;
    }

    /** {@inheritDoc} */
    public ColorFactory<Color> getColorFactory()
    {
        return colorFactory;
    }

    /** {@inheritDoc} */
    public KeyCombinationBuilder<KeyStroke> getKeyCombinationBuilder()
    {
        return keyCombinationBuilder;
    }

    /** {@inheritDoc} */
    public void setKeyShortcutMap(KeyShortcutMap<KeyStroke> shortcutMap)
    {
        this.keyShortcutMap = shortcutMap;
    }

    /** {@inheritDoc} */
    public KeyShortcutMap<KeyStroke> getKeyShortcutMap()
    {
        return keyShortcutMap;
    }
}


/*
 * 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.attribute.impl;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import com.thesett.aima.attribute.time.TimeOnly;
import com.thesett.aima.state.BaseType;
import com.thesett.aima.state.InfiniteValuesException;
import com.thesett.aima.state.RandomInstanceFactory;
import com.thesett.aima.state.Type;
import com.thesett.aima.state.TypeVisitor;

/**
 * Implements an integer range type. This allows a sequential range of ints to be defined as a named type.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Maintain a set of named int range types.
 *
 Provide all integers within the types range.
 *
 Provide a default value that lies in the range.
 *
 Check an integer value against the range type.
 *

 *
 * @author Rupert Smith
 */
public class TimeRangeType extends BaseType<TimeOnly> implements Type<TimeOnly>, RandomInstanceFactory<TimeOnly>,
    Serializable
{
    /** Holds all of the named time range types that have been defined. */
    private static final Map<String, TimeRangeType> INT_RANGE_TYPES = new HashMap<String, TimeRangeType>();

    /** Holds the minimum value an instance of this type can take. */
    private final TimeOnly minValue;

    /** Holds the maximum value an instance of this type can take. */
    private final TimeOnly maxValue;

    /** Used to hold the name of this time range type. */
    private final String typeName;

    /**
     * Creates an instance of an integer range type with the specified name and min and max values.
     *
     * @param name The name of the type.
     * @param min  The minimum value an instance of the type can take.
     * @param max  The maximum value an instance of the type can take.
     */
    private TimeRangeType(String name, TimeOnly min, TimeOnly max)
    {
        typeName = name;
        minValue = min;
        maxValue = max;
    }

    /**
     * Gets the named integer range type, if one exists.
     *
     * @param  name The name of the time range type to get.
     *
     * @return The named time range type, or <tt>null</tt> if none matching the name exists.
     */
    public static TimeRangeType getInstance(String name)
    {
        synchronized (INT_RANGE_TYPES)
        {
            return INT_RANGE_TYPES.get(name);
        }
    }

    /**
     * Creates a new time range type with the specified name, if it does not already exist.
     *
     * @param  name The name of the time range type to create.
     * @param  min  The minimum value that an instance of the type can take.
     * @param  max  The maximum value that an instance of teh type can take.
     *
     * @return A new time range type.
     *
     * @throws IllegalArgumentException If min is not less than or equal to max, or the named type already exists.
     */
    public static Type createInstance(String name, TimeOnly min, TimeOnly max)
    {
        // Ensure that min is less than or equal to max.
        if ((min != null) && (max != null) && (min.compareTo(max) > 0))
        {
            throw new IllegalArgumentException("'min' must be less than or equal to 'max'.");
        }

        synchronized (INT_RANGE_TYPES)
        {
            // Add the newly created type to the map of all types.
            TimeRangeType newType = new TimeRangeType(name, min, max);

            // Ensure that the named type does not already exist, unless it has an identical definition already, in which
            // case the old definition can be re-used and the new one discarded.
            TimeRangeType oldType = INT_RANGE_TYPES.get(name);

            if ((oldType != null) && !oldType.equals(newType))
            {
                throw new IllegalArgumentException("The type '" + name + "' already exists and cannot be redefined.");
            }
            else if ((oldType != null) && oldType.equals(newType))
            {
                return oldType;
            }
            else
            {
                INT_RANGE_TYPES.put(name, newType);

                return newType;
            }
        }
    }

    /**
     * {@inheritDoc}
     *
     *
The default value of an time range type is 'min'.
     */
    public TimeOnly getDefaultInstance()
    {
        return minValue;
    }

    /**
     * {@inheritDoc}
     *
     *
A random value of this type lies between 'min' and 'max'.
     */
    public TimeOnly createRandomInstance()
    {
        int start = minValue.getMilliseconds();
        int end = maxValue.getMilliseconds();

        return new TimeOnly((long) (start + random.nextInt(end - start)));
    }

    /** {@inheritDoc} */
    public String getName()
    {
        return typeName;
    }

    /** {@inheritDoc} */
    public Class<TimeOnly> getBaseClass()
    {
        return TimeOnly.class;
    }

    /** {@inheritDoc} */
    public String getBaseClassName()
    {
        return getBaseClass().getName();
    }

    /** {@inheritDoc} */
    public int getNumPossibleValues()
    {
        return -1;
    }

    /**
     * Checks an integer value against this type, to determine if it is a valid instance of the type.
     *
     * @param  value The value to check.
     *
     * @return <tt>true</tt> if the value lies in the types range, <tt>false</tt> if it does not.
     */
    public boolean isInstance(Comparable value)
    {
        return (value.compareTo(minValue) >= 0) && (value.compareTo(maxValue) <= 0);
    }

    /**
     * {@inheritDoc}
     *
     *
Beware that as this operation creates a fully expanded set of the integer range in memory, large ranges may
     * use a lot of memory. Consider using the {@link #getAllPossibleValuesIterator()} method instead, as it lazily
     * creates the values on demand.
     */
    public Set<TimeOnly> getAllPossibleValuesSet() throws InfiniteValuesException
    {
        throw new InfiniteValuesException("TimeRangeType has too many values to enumerate.", null);
    }

    /** {@inheritDoc} */
    public Iterator<TimeOnly> getAllPossibleValuesIterator() throws InfiniteValuesException
    {
        throw new InfiniteValuesException("TimeRangeType has too many values to enumerate.", null);
    }

    /** {@inheritDoc} */
    public void acceptVisitor(TypeVisitor visitor)
    {
        if (visitor instanceof TimeRangeTypeVisitor)
        {
            ((TimeRangeTypeVisitor) visitor).visit(this);
        }
        else
        {
            super.acceptVisitor(visitor);
        }
    }

    /**
     * Checks two time range types for equality, based on their name and time range.
     *
     * @param  o The object to compare to.
     *
     * @return <tt>true</tt> if the comparator is an time range type with the same name and range as this one.
     */
    public boolean equals(Object o)
    {
        if (this == o)
        {
            return true;
        }

        if (!(o instanceof TimeRangeType))
        {
            return false;
        }

        TimeRangeType that = (TimeRangeType) o;

        return (maxValue == that.maxValue) && (minValue == that.minValue) &&
            !((typeName != null) ? (!typeName.equals(that.typeName)) : (that.typeName != null));
    }

    /**
     * Provides a hashcode based on the name, and time range of this type.
     *
     * @return A hashcode based on the name, and time range of this type.
     */
    public int hashCode()
    {
        int result;
        result = (minValue != null) ? minValue.hashCode() : 0;
        result = (31 * result) + ((maxValue != null) ? maxValue.hashCode() : 0);
        result = (31 * result) + ((typeName != null) ? typeName.hashCode() : 0);

        return result;
    }
}


/*
 * 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.attribute.impl;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

import com.thesett.aima.state.BaseType;
import com.thesett.aima.state.InfiniteValuesException;
import com.thesett.aima.state.RandomInstanceFactory;
import com.thesett.aima.state.Type;
import com.thesett.aima.state.restriction.LengthRestriction;
import com.thesett.aima.state.restriction.RegexRestriction;
import com.thesett.aima.state.restriction.TypeRestriction;

/**
 * StringPatternType is a restricted type over strings, that allows a sub-class of string so to be specified that match
 * a regular expression or have a maximum length.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Maintain a set of named string pattern types.
 *
 Check a string value against the type.
 *

 *
 * @author Rupert Smith
 */
public class StringPatternType extends BaseType<String> implements Type<String>, RandomInstanceFactory<String>,
    Serializable
{
    /** Holds all of the named string pattern types that have been defined. */
    private static final Map<String, StringPatternType> STRING_PATTERN_TYPES = new HashMap<String, StringPatternType>();

    /** Caches the pattern in compiled form. */
    private Pattern compiledPattern;

    /**
     * Holds the regular expression pattern that instances of this type must match, or <tt>null</tt> if none is defined.
     */
    private final String pattern;

    /** Holds the maximum length instance of this type may have, or zero if no maximum length is defined. */
    private final int maxLength;

    /** Holds the name of this type. */
    private final String typeName;

    /**
     * Creates a patterned string type with the specified maximum length and matching regular expression.
     *
     * @param name      The name of the string pattern type to create.
     * @param maxLength The maximum length of instances of the type, may be zero or less for no maximum.
     * @param pattern   A regular expression that instances must match, or <tt>null</tt> for no pattern.
     */
    private StringPatternType(String name, int maxLength, String pattern)
    {
        this.typeName = name;
        this.maxLength = maxLength;
        this.pattern = pattern;

        // Compile the regular expression.
        if (pattern != null)
        {
            this.compiledPattern = Pattern.compile(pattern);
        }

        restrictions = new LinkedList<TypeRestriction>();

        if ((pattern != null) && !"".equals(pattern))
        {
            restrictions.add(new RegexRestriction(pattern));
        }

        if (maxLength > 0)
        {
            restrictions.add(new LengthRestriction(maxLength));
        }
    }

    /**
     * Gets the named string pattern type, if one exists.
     *
     * @param  name The name of the string pattern type to get.
     *
     * @return The named string pattern type, or <tt>null</tt> if none matching the name exists.
     */
    public static StringPatternType getInstance(String name)
    {
        synchronized (STRING_PATTERN_TYPES)
        {
            return STRING_PATTERN_TYPES.get(name);
        }
    }

    /**
     * Creates a new string pattern type with the specified name, if it does not already exist.
     *
     * @param  name      The name of the string pattern type to create.
     * @param  maxLength The maximum length of instances of the type, may be zero or less for no maximum.
     * @param  pattern   A regular expression that instances must match, or <tt>null</tt> for no pattern.
     *
     * @return A new string pattern type.
     *
     * @throws IllegalArgumentException If min is not less than or equal to max, or the named type already exists.
     */
    public static Type createInstance(String name, int maxLength, String pattern)
    {
        synchronized (STRING_PATTERN_TYPES)
        {
            StringPatternType newType = new StringPatternType(name, maxLength, pattern);

            // Ensure that the named type does not already exist.
            StringPatternType oldType = STRING_PATTERN_TYPES.get(name);

            if ((oldType != null) && !oldType.equals(newType))
            {
                throw new IllegalArgumentException("The type '" + name + "' already exists and cannot be redefined.");
            }
            else if ((oldType != null) && oldType.equals(newType))
            {
                return oldType;
            }
            else
            {
                // Add the newly created type to the map of all types.
                STRING_PATTERN_TYPES.put(name, newType);

                return newType;
            }
        }
    }

    /** {@inheritDoc} */
    public String getDefaultInstance()
    {
        return "";
    }

    /** {@inheritDoc} */
    public String createRandomInstance()
    {
        byte[] bytes = new byte[6];
        random.nextBytes(bytes);

        return new String(bytes);
    }

    /** {@inheritDoc} */
    public String getName()
    {
        return typeName;
    }

    /** {@inheritDoc} */
    public Class<String> getBaseClass()
    {
        return String.class;
    }

    /** {@inheritDoc} */
    public String getBaseClassName()
    {
        return getBaseClass().getName();
    }

    /** {@inheritDoc} */
    public int getNumPossibleValues()
    {
        return -1;
    }

    /** {@inheritDoc} */
    public Set<String> getAllPossibleValuesSet() throws InfiniteValuesException
    {
        throw new InfiniteValuesException(
            "The number of possible values of a string pattern type may be too many to enumerate.", null);
    }

    /** {@inheritDoc} */
    public Iterator<String> getAllPossibleValuesIterator() throws InfiniteValuesException
    {
        throw new InfiniteValuesException(
            "The number of possible values of a string pattern type may be too many to enumerate.", null);
    }

    /**
     * Checks a string value against this type to see if it is a valid instance of the type.
     *
     * @param  value The value to type check.
     *
     * @return <tt>true</tt> if the string is a valid instance of this type.
     */
    public boolean isInstance(CharSequence value)
    {
        // Check the value is under the maximum if one is set.
        // Check the value matches the pattern if one is set.
        return ((maxLength <= 0) || (value.length() <= maxLength)) && compiledPattern.matcher(value).matches();
    }

    /**
     * Checks two string pattern types for equality, based on their name, length and pattern.
     *
     * @param  o The object to compare to.
     *
     * @return <tt>true</tt> if the comparator is a string pattern type with the same name, length and pattern.
     */
    public boolean equals(Object o)
    {
        if (this == o)
        {
            return true;
        }

        if (!(o instanceof StringPatternType))
        {
            return false;
        }

        StringPatternType that = (StringPatternType) o;

        return (maxLength == that.maxLength) &&
            !((pattern != null) ? (!pattern.equals(that.pattern)) : (that.pattern != null)) &&
            !((typeName != null) ? (!typeName.equals(that.typeName)) : (that.typeName != null));
    }

    /**
     * Provides a hashcode based on the name, length and pattern of this type.
     *
     * @return A hashcode based on the name, length and pattern of this type.
     */
    public int hashCode()
    {
        int result;
        result = ((pattern != null) ? pattern.hashCode() : 0);
        result = (31 * result) + maxLength;
        result = (31 * result) + ((typeName != null) ? typeName.hashCode() : 0);

        return result;
    }
}


/*
 * 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.compiler;

import com.thesett.aima.logic.fol.Clause;
import com.thesett.aima.logic.fol.Functor;
import com.thesett.aima.logic.fol.Predicate;
import com.thesett.aima.logic.fol.Term;
import com.thesett.aima.logic.fol.TermVisitor;
import com.thesett.common.util.StackQueue;

/**
 * PositionalTermTraverserImpl provides contextual traversal of a term with additional information about the current
 * position of the traversal, as defined in {@link PositionalTermTraverser}; it provides a set of flags and properties
 * as a term tree is walked over, to indicate some positional properties of the current term within the tree.
 *
 *
A {@link StackableOperator} is used which is reversible, and this is used to visit each sub-term encountered
 * twice,
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Establish an initial positional context upon visiting a clause.
 *
 Report whether the current term is a functor at the top-level within a clause.
 *
 Report whether the current term is within a clause head or body.
 *
 Report whether a top-level functor in a clause body is the last one in the body.
 *

 *
 * @author Rupert Smith
 */
public class PositionalTermTraverserImpl extends BasicTraverser implements PositionalTermTraverser
{
    /** Flag used to indicate that a term context is being entered. */
    protected boolean enteringContext;

    /** Flag used to indicate that a term context is being left. */
    protected boolean leavingContext;

    /** Holds an optional visitor to notify on context changes. */
    protected TermVisitor contextChangeVisitor;

    /** Holds the context stack for the traversal. */
    protected StackQueue<PositionalContextOperator> contextStack = new StackQueue<PositionalContextOperator>();

    /** Inidicates that the initial context has been established at the start of a traversal. */
    private boolean initialContextCreated;

    /**
     * Creates a traverser that uses the normal intuitive left-to-right traversal orderings for clauses and functors.
     */
    public PositionalTermTraverserImpl()
    {
        clauseHeadFirst = true;
        leftToRightClauseBodies = true;
        leftToRightFunctorArgs = true;
    }

    /**
     * Creates a traverser that uses the defubes left-to-right traversal orderings for clauses and functors.
     *
     * @param clauseHeadFirst         <tt>true</tt> to use the normal ordering, <tt>false</tt> for the reverse.
     * @param leftToRightClauseBodies <tt>true</tt> to use the normal ordering, <tt>false</tt> for the reverse.
     * @param leftToRightFunctorArgs  <tt>true</tt> to use the normal ordering, <tt>false</tt> for the reverse.
     */
    public PositionalTermTraverserImpl(boolean clauseHeadFirst, boolean leftToRightClauseBodies,
        boolean leftToRightFunctorArgs)
    {
        this.clauseHeadFirst = clauseHeadFirst;
        this.leftToRightClauseBodies = leftToRightClauseBodies;
        this.leftToRightFunctorArgs = leftToRightFunctorArgs;
    }

    /** {@inheritDoc} Visits a predicate, to set up an initial context for clause traversals. */
    public void visit(Predicate predicate)
    {
        // Set up the initial context, if this is the top-level of the traversal.
        createInitialContext(predicate);
    }

    /** {@inheritDoc} Visits a clause, to set up an initial context for clause traversals. */
    public void visit(Clause clause)
    {
        // Set up the initial context, if this is the top-level of the traversal.
        createInitialContext(clause);
    }

    /** {@inheritDoc} */
    public void visit(Term term)
    {
    }

    /** {@inheritDoc} */
    public boolean isTopLevel()
    {
        PositionalTermTraverserImpl.PositionalContextOperator position = contextStack.peek();

        return (position != null) && position.isTopLevel();
    }

    /** {@inheritDoc} */
    public boolean isInHead()
    {
        PositionalTermTraverserImpl.PositionalContextOperator position = contextStack.peek();

        return (position != null) && position.isInHead();
    }

    /** {@inheritDoc} */
    public boolean isLastBodyFunctor()
    {
        PositionalTermTraverserImpl.PositionalContextOperator position = contextStack.peek();

        return (position != null) && position.isLastBodyFunctor();
    }

    /** {@inheritDoc} */
    public Term getTerm()
    {
        PositionalTermTraverserImpl.PositionalContextOperator position = contextStack.peek();

        return (position != null) ? position.getTerm() : null;
    }

    /** {@inheritDoc} */
    public int getPosition()
    {
        PositionalTermTraverserImpl.PositionalContextOperator position = contextStack.peek();

        return (position != null) ? position.getPosition() : -1;
    }

    /** {@inheritDoc} */
    public boolean isEnteringContext()
    {
        return enteringContext;
    }

    /** {@inheritDoc} */
    public boolean isLeavingContext()
    {
        return leavingContext;
    }

    /** {@inheritDoc} */
    public boolean isContextChange()
    {
        return enteringContext || leavingContext;
    }

    /** {@inheritDoc} */
    public PositionalContext getParentContext()
    {
        PositionalTermTraverserImpl.PositionalContextOperator position = contextStack.peek();

        return (position != null) ? position.getParentContext() : null;
    }

    /** {@inheritDoc} */
    public void setContextChangeVisitor(TermVisitor contextChangeVisitor)
    {
        this.contextChangeVisitor = contextChangeVisitor;
    }

    /**
     * Prints the position of this traverser, mainly for debugging purposes.
     *
     * @return The position of this traverser, mainly for debugging purposes.
     */
    public String toString()
    {
        return "BasicTraverser: [ topLevel = " + isTopLevel() + ", inHead = " + isInHead() + ", lastBodyfunctor = " +
            isLastBodyFunctor() + ", enteringContext = " + enteringContext + ", leavingContext = " + leavingContext +
            " ]";
    }

    /** {@inheritDoc} */
    protected StackableOperator createHeadOperator(Functor head, Clause clause)
    {
        return new PositionalContextOperator(head, -1, true, true, false, null, contextStack.peek());
    }

    /** {@inheritDoc} */
    protected StackableOperator createBodyOperator(Functor bodyFunctor, int pos, Functor[] body, Clause clause)
    {
        return new PositionalContextOperator(bodyFunctor, pos, true, false, pos == (body.length - 1), null,
            contextStack.peek());
    }

    /** {@inheritDoc} */
    protected StackableOperator createTermOperator(Term argument, int pos, Functor functor)
    {
        return new PositionalContextOperator(argument, pos, false, null, false, null, contextStack.peek());
    }

    /** {@inheritDoc} */
    protected StackableOperator createClauseOperator(Clause bodyClause, int pos, Clause[] body, Predicate predicate)
    {
        return new PositionalContextOperator(bodyClause, pos, false, false, false, null, contextStack.peek());
    }

    /**
     * Sets up the initial context once, at the start of a traversal.
     *
     * @param term The term to establish the initial positional traversal context for.
     */
    private void createInitialContext(Term term)
    {
        if (!initialContextCreated)
        {
            PositionalContextOperator initialContext =
                new PositionalContextOperator(term, -1, false, false, false, null, contextStack.peek());
            contextStack.offer(initialContext);
            term.setReversable(initialContext);
            initialContextCreated = true;
        }
    }

    /**
     * PositionalContextOperator is a {@link StackableOperator} that passes on state changes when the term it is
     * attached to is traversed into. Although it implements {@link StackableOperator} it does not undo state changes
     * when back-tracking over the term, as it is assumed that successive terms will overwrite state as they need to.
     *
     *

CRC Card

     *
 Responsibilities  Collaborations
     *
 Optionally set the top-level, in-head, or last functor flags on the traverser.
     *      {@link PositionalTermTraverserImpl}.
     *

     */
    private class PositionalContextOperator extends StackableOperator implements PositionalContext
    {
        /** Holds the term that this is the context operator for. */
        Term term;

        /** Holds the 'position' within the parent term. */
        Integer position;

        /** The state of the top-level flag to establish. */
        Boolean topLevel;

        /** The state of the in-head flag to establish. */
        Boolean inHead;

        /** The state of the last functor flag to establish. */
        Boolean lastBodyFunctor;

        /** The parent context if any. */
        PositionalContextOperator parent;

        /**
         * Creates a context establishing operation.
         *
         * @param term            The term that this is the context operator for.
         * @param position        The 'position' within the parent term.
         * @param topLevel        <tt>true</tt> to set flag, <tt>false</tt> to clear, <tt>null</tt> to leave alone.
         * @param inHead          <tt>true</tt> to set flag, <tt>false</tt> to clear, <tt>null</tt> to leave alone.
         * @param lastBodyFunctor <tt>true</tt> to set flag, <tt>false</tt> to clear, <tt>null</tt> to leave alone.
         * @param delegate        A stackable operator to chain onto this one.
         */
        private PositionalContextOperator(Term term, Integer position, Boolean topLevel, Boolean inHead,
            Boolean lastBodyFunctor, StackableOperator delegate, PositionalContextOperator parent)
        {
            super(delegate);

            this.term = term;
            this.position = position;
            this.topLevel = topLevel;
            this.inHead = inHead;
            this.lastBodyFunctor = lastBodyFunctor;
            this.parent = parent;
        }

        /** {@inheritDoc} */
        public void applyOperator()
        {
            PositionalContextOperator previousContext = contextStack.peek();

            if (previousContext == null)
            {
                previousContext = new PositionalContextOperator(null, -1, false, false, false, null, previousContext);
            }

            topLevel = (topLevel == null) ? previousContext.topLevel : topLevel;
            inHead = (inHead == null) ? previousContext.inHead : inHead;
            lastBodyFunctor = (lastBodyFunctor == null) ? previousContext.lastBodyFunctor : lastBodyFunctor;
            position = (position == null) ? previousContext.position : position;

            contextStack.offer(this);

            if (PositionalTermTraverserImpl.this.contextChangeVisitor != null)
            {
                PositionalTermTraverserImpl.this.enteringContext = true;
                term.accept(PositionalTermTraverserImpl.this.contextChangeVisitor);
                PositionalTermTraverserImpl.this.enteringContext = false;
            }

            super.applyOperator();
        }

        /** {@inheritDoc} */
        public void undoOperator()
        {
            super.undoOperator();

            if (PositionalTermTraverserImpl.this.contextChangeVisitor != null)
            {
                PositionalTermTraverserImpl.this.leavingContext = true;
                term.accept(PositionalTermTraverserImpl.this.contextChangeVisitor);
                PositionalTermTraverserImpl.this.leavingContext = false;
            }

            contextStack.poll();
        }

        /** {@inheritDoc} */
        public boolean isTopLevel()
        {
            return topLevel;
        }

        /** {@inheritDoc} */
        public boolean isInHead()
        {
            return inHead;
        }

        /** {@inheritDoc} */
        public boolean isLastBodyFunctor()
        {
            return lastBodyFunctor;
        }

        /** {@inheritDoc} */
        public Term getTerm()
        {
            return term;
        }

        /** {@inheritDoc} */
        public int getPosition()
        {
            return position;
        }

        /** {@inheritDoc} */
        public PositionalContext getParentContext()
        {
            return parent;
        }
    }
}