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

/**
 * BitHackUtils provides static functions that implement various bit twiddling hacks.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Calculate ASCII lengths of decimal numbers.
 *

 *
 * @author Rupert Smith
 */
public class BitHackUtils
{
    /** The powers of ten below 2^31-1. */
    private static final long[] POWERS_OF_TEN =
        { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };

    /** The powers of ten below 2^63-1. */
    private static final long[] POWERS_OF_TEN_LONG =
        {
            1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000L, 100000000000L,
            1000000000000L, 10000000000000L, 100000000000000L, 1000000000000000L, 10000000000000000L,
            100000000000000000L, 1000000000000000000L
        };

    /** Holds a table of log base 2 up to 255. */
    private static final int[] LOG_TABLE_256 = new int[256];

    /** Branch values for the v3 log2 method. */
    private static final int[] LOG2_V3_BRANCH_VALUES = new int[] { 0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000 };

    /** Shift values for the v3 log2 method. */
    private static final int[] LOG2_V3_SHIFT_VALUES = new int[] { 1, 2, 4, 8, 16 };

    /** Unsigned value of 10^19, which is the smallest unsigned value with 20 digits. */
    private static final long TEN_POW_19 = 0x8AC7230489E80000L;

    static
    {
        LOG_TABLE_256[0] = LOG_TABLE_256[1] = 0;

        for (int i = 2; i < 256; i++)
        {
            LOG_TABLE_256[i] = 1 + LOG_TABLE_256[i / 2];
        }

        LOG_TABLE_256[0] = -1;
    }

    /**
     * Calcalates the log base 2 of an integer. This code is tuned to uniformly distributed output values, longer
     * numbers are slightly favoured.
     *
     * @param  value The value to calculate for.
     *
     * @return Log base 2 of the input value.
     */
    public static int intLogBase2(int value)
    {
        int temp1;
        int temp2 = value >> 16;

        if (temp2 > 0)
        {
            temp1 = temp2 >> 8;

            return (temp1 > 0) ? (24 + LOG_TABLE_256[temp1]) : (16 + LOG_TABLE_256[temp2]);
        }
        else
        {
            temp1 = value >> 8;

            return (temp1 > 0) ? (8 + LOG_TABLE_256[temp1]) : LOG_TABLE_256[value];
        }
    }

    /**
     * Calcalates the log base 2 of an integer. This code is tuned to uniformly distributed input values, longer numbers
     * are favoured.
     *
     * @param  value The value to calculate for.
     *
     * @return Log base 2 of the input value.
     */
    public static int intLogBase2v2(int value)
    {
        int temp;

        if ((temp = value >> 24) > 0)
        {
            return 24 + LOG_TABLE_256[temp];
        }
        else if ((temp = value >> 16) > 0)
        {
            return 16 + LOG_TABLE_256[temp];
        }
        else if ((temp = value >> 8) > 0)
        {
            return 8 + LOG_TABLE_256[temp];
        }
        else
        {
            return LOG_TABLE_256[value];
        }
    }

    /**
     * Calcalates the log base 2 of an integer in O(log(N)) steps; shorter numbers are favoured.
     *
     * @param  value The value to calculate for.
     *
     * @return Log base 2 of the input value.
     */
    public static int intLogBase2v3(int value)
    {
        int result = 0;

        if ((value & LOG2_V3_BRANCH_VALUES[4]) > 0)
        {
            value >>= LOG2_V3_SHIFT_VALUES[4];
            result |= LOG2_V3_SHIFT_VALUES[4];
        }

        if ((value & LOG2_V3_BRANCH_VALUES[3]) > 0)
        {
            value >>= LOG2_V3_SHIFT_VALUES[3];
            result |= LOG2_V3_SHIFT_VALUES[3];
        }

        if ((value & LOG2_V3_BRANCH_VALUES[2]) > 0)
        {
            value >>= LOG2_V3_SHIFT_VALUES[2];
            result |= LOG2_V3_SHIFT_VALUES[2];
        }

        if ((value & LOG2_V3_BRANCH_VALUES[1]) > 0)
        {
            value >>= LOG2_V3_SHIFT_VALUES[1];
            result |= LOG2_V3_SHIFT_VALUES[1];
        }

        if ((value & LOG2_V3_BRANCH_VALUES[0]) > 0)
        {
            value >>= LOG2_V3_SHIFT_VALUES[0];
            result |= LOG2_V3_SHIFT_VALUES[0];
        }

        return result;
    }

    /**
     * Calcalates the log base 10 of an integer.
     *
     * @param  value The value to calculate for.
     *
     * @return Log base 10 of the input value.
     */
    public static int intLogBase10(int value)
    {
        int temp = ((intLogBase2v3(value) + 1) * 1233) >> 12;

        return temp - ((value < POWERS_OF_TEN[temp]) ? 1 : 0);
    }

    /**
     * Calcalates the log base 10 of an integer. This produces results faster for longer numbers.
     *
     * @param  value The value to calculate for.
     *
     * @return Log base 10 of the input value.
     */
    public static int intLogBase10v2(int value)
    {
        return (value >= 1000000000)
            ? 9
            : ((value >= 100000000)
                ? 8
                : ((value >= 10000000)
                    ? 7
                    : ((value >= 1000000)
                        ? 6
                        : ((value >= 100000)
                            ? 5
                            : ((value >= 10000)
                                ? 4 : ((value >= 1000) ? 3 : ((value >= 100) ? 2 : ((value >= 10) ? 1 : 0))))))));
    }

    /**
     * Calcalates the log base 10 of an integer. This produces results faster for shorter numbers.
     *
     * @param  value The value to calculate for.
     *
     * @return Log base 10 of the input value.
     */
    public static int intLogBase10v3(int value)
    {
        return (value < 10)
            ? 0
            : ((value < 100)
                ? 1
                : ((value < 1000)
                    ? 2
                    : ((value < 10000)
                        ? 3
                        : ((value < 100000)
                            ? 4
                            : ((value < 1000000)
                                ? 5
                                : ((value < 10000000)
                                    ? 6 : ((value < 100000000) ? 7 : ((value < 1000000000) ? 8 : 9))))))));

    }

    /**
     * Calcalates the log base 10 of an integer. This method favours shorter numbers.
     *
     * @param  value The value to calculate for.
     *
     * @return Log base 10 of the input value.
     */
    public static int intLogBase10(long value)
    {
        return (value >= 1000000000000000000L)
            ? 18
            : ((value >= 100000000000000000L)
                ? 17
                : ((value >= 10000000000000000L)
                    ? 16
                    : ((value >= 1000000000000000L)
                        ? 15
                        : ((value >= 100000000000000L)
                            ? 14
                            : ((value >= 10000000000000L)
                                ? 13
                                : ((value >= 1000000000000L)
                                    ? 12
                                    : ((value >= 100000000000L)
                                        ? 11
                                        : ((value >= 10000000000L)
                                            ? 10
                                            : ((value >= 1000000000L)
                                                ? 9
                                                : ((value >= 100000000L)
                                                    ? 8
                                                    : ((value >= 10000000L)
                                                        ? 7
                                                        : ((value >= 1000000L)
                                                            ? 6
                                                            : ((value >= 100000L)
                                                                ? 5
                                                                : ((value >= 10000L)
                                                                    ? 4
                                                                    : ((value >= 1000L)
                                                                        ? 3
                                                                        : ((value >= 100L)
                                                                            ? 2
                                                                            : ((value >= 10L) ? 1 : 0)))))))))))))))));
    }

    /**
     * Calcalates the log base 10 of an integer. This method favours longer numbers, or evenly distributed input.
     *
     * @param  value The value to calculate for.
     *
     * @return Log base 10 of the input value.
     */
    public static int intLogBase10v2(long value)
    {
        return (value < 10)
            ? 0
            : ((value < 100)
                ? 1
                : ((value < 1000)
                    ? 2
                    : ((value < 10000)
                        ? 3
                        : ((value < 100000)
                            ? 4
                            : ((value < 1000000)
                                ? 5
                                : ((value < 10000000)
                                    ? 6
                                    : ((value < 100000000)
                                        ? 7
                                        : ((value < 1000000000L)
                                            ? 8
                                            : ((value < 10000000000L)
                                                ? 9
                                                : ((value < 100000000000L)
                                                    ? 10
                                                    : ((value < 1000000000000L)
                                                        ? 11
                                                        : ((value < 10000000000000L)
                                                            ? 12
                                                            : ((value < 100000000000000L)
                                                                ? 13
                                                                : ((value < 1000000000000000L)
                                                                    ? 14
                                                                    : ((value < 10000000000000000L)
                                                                        ? 15
                                                                        : ((value < 100000000000000000L)
                                                                            ? 16
                                                                            : ((value < 1000000000000000000L)
                                                                                ? 17 : 18)))))))))))))))));
    }

    /**
     * Calculates the number of ASCII characters that will be needed to represent a specifed signed 32-bit integer.
     *
     * @param  value The value to get the character count for.
     *
     * @return The number of ASCII character need to represent an signed 32-bit integer.
     */
    public static int getCharacterCountInt32(int value)
    {
        if (value >= 0)
        {
            return getCharacterCountUInt32(value);
        }
        else if (value == Integer.MIN_VALUE)
        {
            return getCharacterCountUInt32(Integer.MAX_VALUE) + 1;
        }
        else
        {
            return getCharacterCountUInt32(-value) + 1;
        }
    }

    /**
     * Calculates the number of ASCII characters that will be needed to represent a specified unsigned 32-bit integer.
     *
     * @param  value The value to get the character count for.
     *
     * @return The number of ASCII character need to represent an unsigned 32-bit integer.
     */
    public static int getCharacterCountUInt32(int value)
    {
        // A negative value indicates an unsigned number with a size > Integer.MAX_VALUE. Such numbers always
        // have the maximum size of 10.
        if (value < 0)
        {
            return 10;
        }
        else
        {
            return intLogBase10v3(value) + 1;
        }
    }

    /**
     * Calculates the number of ASCII characters that will be needed to represent a specifed signed 64-bit integer.
     *
     * @param  value The value to get the character count for.
     *
     * @return The number of ASCII character need to represent an signed 64-bit integer.
     */
    public static int getCharacterCountInt64(long value)
    {
        if (value >= 0)
        {
            return getCharacterCountUInt64(value);
        }
        else if (value == Long.MIN_VALUE)
        {
            return getCharacterCountUInt64(Long.MAX_VALUE) + 1;
        }
        else
        {
            return getCharacterCountUInt64(-value) + 1;
        }
    }

    /**
     * Calculates the number of ASCII characters that will be needed to represent a specified unsigned 64-bit integer.
     *
     * @param  value The value to get the character count for.
     *
     * @return The number of ASCII character need to represent an unsigned 64-bit integer.
     */
    public static int getCharacterCountUInt64(long value)
    {
        // A negative value indicates an unsigned number with a size > Long.MAX_VALUE. Such numbers have a maximum size
        // of 19 or 20.
        if (value < 0)
        {
            return (value < TEN_POW_19) ? 19 : 20;
        }
        else
        {
            return intLogBase10v2(value) + 1;
        }
    }

    /**
     * Calculates the number of ASCII characters that will be needed to represent a specified signed decimal number.
     *
     * @param  integerValue The integer component of the decimal number.
     * @param  scale        The scale component of the decimal number.
     *
     * @return The number of ASCII character need to represent a signed decimal number.
     */
    public static int getCharacterCountDecimal(long integerValue, int scale)
    {
        boolean isNeg = integerValue < 0;

        // Work out how many digits will be needed for the number, adding space for the minus sign, the decimal
        // point and leading zeros if needed.
        int totalDigits = BitHackUtils.getCharacterCountInt64(integerValue);
        int totalLength = totalDigits;

        if (isNeg)
        {
            totalDigits--; // Minus sign already accounted for.
        }

        if (scale > 0)
        {
            totalLength++; // For the decimal point.

            if (scale >= totalDigits)
            {
                // For the leading zeros (+ 1 for the zero before decimal point).
                totalLength += (scale - totalDigits) + 1;
            }
        }
        else
        {
            // Add a zero for each negative point in scale
            totalLength -= scale;
        }

        return totalLength;
    }

    /**
     * Counts the number of bits set in a word.
     *
     * @param  word The word to count the bits in.
     *
     * @return The number of bits set in the word.
     */
    public static int ones(int word)
    {
        int result;

        for (result = 0; word != 0; result++)
        {
            word &= word - 1; // Clear the least significant bit set.
        }

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

import java.awt.Color;

import com.thesett.aima.logic.fol.wam.debugger.uifactory.ColorFactory;
import com.thesett.aima.logic.fol.wam.debugger.uifactory.Fader;

/**
 * SwingColorFactory provides a color factory that produces colors that work with AWT and Swing.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Create colors from rgb components.

 *

 *
 * @author Rupert Smith
 */
public class SwingColorFactory implements ColorFactory<Color>
{
    /** {@inheritDoc} */
    public Color createColor(int red, int green, int blue)
    {
        return new Color(red, green, blue);
    }

    /** {@inheritDoc} */
    public Color createColor(int[] rgb)
    {
        return new Color(rgb[0], rgb[1], rgb[2]);
    }

    /** {@inheritDoc} */
    public Color createColor(float red, float green, float blue)
    {
        return new Color(red, green, blue);
    }

    /** {@inheritDoc} */
    public Fader<Color> createFader(Color startColor, Color endColor)
    {
        return new FaderImpl(startColor, endColor);
    }
}


/*
 * 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 cell in a text grid.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Apply a background color change to a cell in a text grid.

 *

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

    /** 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 col  The column to make color changes to.
     * @param row  The row to make color changes to.
     * @param grid The text grid model to alter the background color of.
     */
    public CellBackgroundColorDelta(int col, int row, AttributeGrid grid)
    {
        this.col = col;
        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.insertAttribute(aset, col, 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.prolog.builtins;

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

/**
 * FirstStepBuiltIn takes a query (a headless clause) in first order logic, and creates continuation steps for each
 * conjunctive component of the query, as a proof step on a functor. The first step of a proof is different from the
 * other steps, because it operates on a query clause and not on a functor.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Turn a query into a conjunctive set of subsequent proof states.
 *

 *
 * @author Rupert Smith
 */
public class FirstStepBuiltIn extends BaseBuiltIn
{
    /**
     * Creates a first step built-in to implement the first step of turning a query clause into a conjunction of goals
     * to be proved.
     */
    public FirstStepBuiltIn()
    {
        super(null);
    }

    /** {@inheritDoc} */
    public boolean proofStep(ResolutionState state)
    {
        Clause query = state.getCurrentClause();

        // The query goals are placed onto the goal stack backwards so that their insertion order is reversed for an
        // intuitive left-to-right evaluation order.
        for (int i = query.getBody().length - 1; i >= 0; i--)
        {
            BuiltInFunctor newGoal = state.getBuiltInTransform().apply(query.getBody()[i]);
            state.getGoalStack().offer(newGoal);
        }

        return true;
    }
}


/*
 * Copyright The Sett Ltd, 2005 to 2014.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.thesett.aima.logic.fol.wam.compiler;

import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.thesett.aima.attribute.impl.IdAttribute;
import com.thesett.aima.logic.fol.Clause;
import com.thesett.aima.logic.fol.Functor;
import com.thesett.aima.logic.fol.FunctorName;
import com.thesett.aima.logic.fol.LinkageException;
import com.thesett.aima.logic.fol.Sentence;
import com.thesett.aima.logic.fol.wam.machine.WAMMachine;
import com.thesett.common.util.Sizeable;
import com.thesett.common.util.SizeableLinkedList;
import com.thesett.common.util.SizeableList;

/**
 * A compiled term is a handle onto a compiled down to binary code term. Compiled terms are not Java code and may be
 * executed outside of the JVM, but the Java retains a handle on them and provides sufficient wrapping around them that
 * they can be made to look as if they are a transparent abstract syntax tree within the JVM. This requires an ability
 * to decompile a clause back into its abstract syntax tree.
 *
 *
Decompilation of functors requires access to a mapping from registers to variables, but the variable to register
 * assignment is created at compile time accross a whole clause. Each functor that forms part of the clause head or body
 * must therefore hold a link to its containing functor in order to access this mapping.
 *
 *

CRC Card

 *
 Responsibilities
 *
 Decompile/decode a binary term to restore its abstract syntax tree.
 *

 *
 * @author Rupert Smith
 * @todo   For each functor in the head and body, set this as the containing clause. A mapping from variables to
 *         registers is maintained in the clause, and the functors need to be able to access this mapping.
 */
public class WAMCompiledQuery extends Clause<Functor> implements Sentence<WAMCompiledQuery>, Sizeable,
    WAMOptimizeableListing
{
    /** Used for debugging. */
    /* private static final Logger log = Logger.getLogger(WAMCompiledQuery.class.getName()); */

    /** Defines the possible states of compiled code, unlinked, or linked into a machine. */
    public enum LinkStatus
    {
        /** The code is not yet linked into a binary machine. */
        Unlinked,

        /** The code is linked into a binary machine. */
        Linked
    }

    /** Holds the state of the byte code in this compiled functor, whether it has been linked or not. */
    protected LinkStatus status;

    /** Holds the register to variable id mapping for the functor. */
    protected Map<Byte, Integer> varNames;

    /**
     * Holds a listing of all the free non-anonymous variables in the query, used to decide which variables to report in
     * the query results.
     */
    protected Set<Integer> nonAnonymousFreeVariables;

    /** Holds the byte code instructions for the clause, when it is not linked or when it has been disassembled. */
    protected SizeableList<WAMInstruction> instructions = new SizeableLinkedList<WAMInstruction>();

    /** Holds the original unoptimized instruction listing. */
    protected SizeableList<WAMInstruction> unoptimizedInstructions;

    /** Holds the offset of the compiled code for the clause within the machine it is compiled to. */
    protected WAMCallPoint callPoint;

    /** Holds a reference to the byte code machine, that provides the symbol table for the code. */
    protected WAMMachine machine;

    /** Holds a reference to the functor interner, that maps functors onto names. */
    protected IdAttribute.IdAttributeFactory<FunctorName> functorInterner;

    /**
     * Creates an empty (invalid) compiled program sentence in WAM. The variables of the program sentence are not
     * recorded, since they only need to be tracked in order to display the results of queries.
     */
    public WAMCompiledQuery()
    {
        super(null, null);
    }

    /**
     * Creates an empty (invalid) compiled query sentence in WAM.
     *
     * @param varNames     A mapping from registers to variables for the compiled clause.
     * @param freeVarNames The set of variables in the clause that are free.
     */
    public WAMCompiledQuery(Map<Byte, Integer> varNames, Set<Integer> freeVarNames)
    {
        super(null, null);

        this.varNames = varNames;
        this.nonAnonymousFreeVariables = freeVarNames;
    }

    /**
     * Sets a compiled head functor to this clause.
     *
     * @param head         The head of this clause.
     * @param instructions A list of instructions to add to the head.
     */
    public void setHead(Functor head, SizeableList<WAMInstruction> instructions)
    {
        this.head = head;

        addInstructions(instructions);
    }

    /**
     * Adds a conjunctive body functor to this query clause.
     *
     * @param body         A conjunctive body functor to add to this clause.
     * @param instructions A list of instructions to add to the body.
     */
    public void addInstructions(Functor body, SizeableList<WAMInstruction> instructions)
    {
        int oldLength;

        if (this.body == null)
        {
            oldLength = 0;
            this.body = new Functor[1];
        }
        else
        {
            oldLength = this.body.length;
            this.body = Arrays.copyOf(this.body, oldLength + 1);
        }

        this.body[oldLength] = body;

        addInstructions(instructions);
    }

    /**
     * Adds some instructions sequentially, after any existing instructions, to the clause.
     *
     * @param instructions The instructions to add to the clause.
     */
    public void addInstructions(Collection<WAMInstruction> instructions)
    {
        this.instructions.addAll(instructions);
    }

    /**
     * Gets the wrapped sentence in the logical language over WAMCompiledClauses.
     *
     * @return The wrapped sentence in the logical language.
     */
    public WAMCompiledQuery getT()
    {
        return this;
    }

    /**
     * Provides the mapping from registers to variable names for this compiled clause.
     *
     * @return The mapping from registers to variable names for this compiled clause.
     */
    public Map<Byte, Integer> getVarNames()
    {
        return varNames;
    }

    /**
     * Provides the set of variables in the clause that are not anonymous or bound.
     *
     * @return The set of variables in the clause that are not anonymous or bound.
     */
    public Collection<Integer> getNonAnonymousFreeVariables()
    {
        return nonAnonymousFreeVariables;
    }

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

    /** {@inheritDoc} */
    public List<WAMInstruction> getInstructions()
    {
        return Collections.unmodifiableList(instructions);
    }

    /** {@inheritDoc} */
    public void setOptimizedInstructions(SizeableList<WAMInstruction> instructions)
    {
        unoptimizedInstructions = this.instructions;
        this.instructions = instructions;
    }

    /** {@inheritDoc} */
    public List<WAMInstruction> getUnoptimizedInstructions()
    {
        return unoptimizedInstructions;
    }

    /**
     * Provides the entry call point to this compiled query.
     *
     * @return The entry call point to this compiled query.
     */
    public WAMCallPoint getCallPoint()
    {
        return callPoint;
    }

    /**
     * Emmits the binary byte code for the clause into a machine, writing into the specified byte array. The state of
     * this clause is changed to 'Linked' to indicate that it has been linked into a binary machine.
     *
     * @param  buffer    The code buffer to write to.
     * @param  machine   The binary machine to resolve call-points against, and to record as being linked into.
     * @param  callPoint The call point within the machine, at which the code is to be stored.
     *
     * @throws LinkageException If required symbols to link to cannot be found in the binary machine.
     */
    public void emmitCode(ByteBuffer buffer, WAMMachine machine, WAMCallPoint callPoint) throws LinkageException
    {
        // Ensure that the size of the instruction listing does not exceed max int (highly unlikely).
        if (sizeof() > Integer.MAX_VALUE)
        {
            throw new IllegalStateException("The instruction listing size exceeds Integer.MAX_VALUE.");
        }

        // Used to keep track of the size of the emitted code, in bytes, as it is written.
        int length = 0;

        // Insert the compiled code into the byte code machine's code area.
        for (WAMInstruction instruction : instructions)
        {
            instruction.emmitCode(buffer, machine);
            length += instruction.sizeof();
        }

        // Keep record of the machine that the code is hosted in, and the call point of the functor within the machine.
        this.machine = machine;
        this.callPoint = callPoint;

        // Record the fact that the code is now linked into a machine.
        this.status = LinkStatus.Linked;
    }
}


/*
 * 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.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JPanel;

import com.thesett.common.util.FifoStack;
import com.thesett.common.util.LifoStack;
import com.thesett.common.util.Stack;

/**
 * WorkFlowController is a pure control component in the work flow mvc framework. Its main responsibility is to listen
 * for user inputs, typically generated by {@link WorkFlowButtonsPanel} and respond to these inputs accordingly. It also
 * provides some auxiliary methods than work flow implementation can use to manipulate the work flow, such as setting
 * the current screen.
 *
 *
WorkFlowController provides an ActionListener which responds to four action commands, "back", "next", "finish"
 * and "cancel".
 *
 *

CRC Card

 *
ResponsibilitiesCollaborations
 *
Listen for back, next, finish and cancel actions
 *
Update the current screen
 *
Translate actions into calls to implementation of this controller and the current screen  {@link WorkFlowScreenPanel}
 *

 *
 * @author Rupert Smith
 * @todo   WorkFlowController uses a JPanel to store the current screen in. Should this be changed to a
 *         java.awt.Container to make it more generic?
 * @todo   Need to consider what default behaviour this abtract controller can provide. Far example should it keep track
 *         of all pages in the work flow which are in the NOT_SAVED state and then call each of their saveWork or
 *         dicardWork methods when the finish/cancel buttons are pressed. If so in what order should they be called? Can
 *         a sensible ordering be given or should the ordering remain unspecified. An ordering as well as all the pages
 *         in the flow could be kept track of within the work flow state. Also when the next or back buttons are pressed
 *         the implementation of the controller can be notified and also the current page can be notified. Is it
 *         necessary to notify both or just one of them? In what order should they be notified?
 */
public abstract class WorkFlowController implements ActionListener
{
    /** Used for logging. */
    /* private static final Logger log = Logger.getLogger(WorkFlowController.class.getName()); */

    /** Constant defining forward commit ordering of the screens. */
    public static final String FORWARD_ORDERING = "Forward";

    /** Constant defining reverse commit ordering of the screens. */
    public static final String REVERSE_ORDERING = "Reverse";

    /** Holds the state of the work flow. */
    private final WorkFlowState state;

    /**
     * Holds the screens that have been accessed in the work flow in order of access. They are held in a stack so that
     * they may easily be accessed in the order that they were encountered in the work flow. By default a fifo stack is
     * used so that the saveWork or discardWork methods of the work screens will be called in the order that the user
     * encountered these screens. This may be changed by setting the commit order via the {@link #setCommitOrder}
     * method.
     */
    private Stack accessedScreens;

    /** Holds reference to the JPanel that the work flow controller displays the work flow pages in. */
    private final JPanel panel;

    /** Holds the current screen within the work flow. */
    private WorkFlowScreenPanel currentScreen;

    /**
     * Creates a new work flow controller. The specified panel is used to place the current screen in.
     *
     * @param panel The panel that the work flow is rendered in.
     */
    public WorkFlowController(JPanel panel)
    {
        state = new WorkFlowState();

        // Keep reference to the JPanel to place pages in
        this.panel = panel;

        // Create a fifo stack to hold the accessed screens in
        accessedScreens = new FifoStack();
    }

    /**
     * This method will be called when the work flow is to be displayed. If the state is NOT_INTIALIZED it should load
     * its data, and build its user interface components and set the state to READY. If the state is READY or NOT_SAVED
     * it should not do anything.
     */
    public abstract void initialize();

    /**
     * This method should be implemented to save the state of the work flow. It is called when a finish event is
     * triggered at the end of the work flow.
     */
    public abstract void saveWork();

    /**
     * This method should be implemented to discard the state of the work flow. It is called when a cancel event is
     * triggered.
     */
    public abstract void discardWork();

    /** This method should be implemented to return to the previous page in the work flow. */
    public abstract void prevPage();

    /**
     * Returns the underlying state of the work flow.
     *
     * @return The current work flow state.
     */
    public WorkFlowState getWorkFlowState()
    {
        return state;
    }

    /**
     * Listens for events from back, next, finish and cancel inputs. If the event is finish the {@link #saveWork} method
     * is triggered. If the event is cancel the {@link #discardWork} method is called. If the event is back or next then
     * the {@link #prevPage} or {@link #nextPage} methods are called.
     *
     * @param event The work flow action event.
     */
    public void actionPerformed(ActionEvent event)
    {
        /*log.fine("void actionPerformed(ActionEvent): called");*/
        /*log.fine("Action is " + event.getActionCommand());*/

        // Check which action event was performed
        String action = event.getActionCommand();

        // Check if the finish button was pressed
        if ("Finish".equals(action))
        {
            // Save the work in progress
            saveWorkFlow();
        }

        // Check if the cancel button was pressed
        if ("Cancel".equals(action))
        {
            // Discard the work in progress
            discardWorkFlow();
        }

        // Check if the next page button was pressed
        if ("Next |>".equals(action))
        {
            // Notify implementing class of transition to the next page
            nextPage();
        }

        // Check if the prev page button was pressed
        if ("<| Prev".equals(action))
        {
            // Notify implementing class of transition to the previous page
            prevPage();
        }
    }

    /**
     * Sets the order in which the saveWork or dicardWork methods of the individual screens encountered in a work flow
     * are called. On of the constants {@link #FORWARD_ORDERING} or {@link #REVERSE_ORDERING} should be passed as the
     * value to this method to specify which ordering to use.
     *
     * @param order The commit ordering to use.
     */
    public void setCommitOrder(String order)
    {
        // Check that the specified order matches one of the ordering constants
        if (!order.equals(FORWARD_ORDERING) && !order.equals(REVERSE_ORDERING))
        {
            return;
        }

        // Check that the new ordering is different from the existing one so that some work needs to be done to change
        // it

        if (order.equals(FORWARD_ORDERING) && (accessedScreens instanceof LifoStack))
        {
            // Copy the screens into a forward ordered stack
            accessedScreens = new FifoStack(accessedScreens);
        }
        else if (order.equals(REVERSE_ORDERING) && (accessedScreens instanceof LifoStack))
        {
            // Copy the screens into a reverse ordered stack
            accessedScreens = new LifoStack(accessedScreens);
        }
    }

    /** This method should be implemented to go to the next page in the work flow. */
    protected void nextPage()
    {
        /*log.fine("void nextPage(): called");*/

        // Call the next page method of the current page to get the next page
        WorkFlowScreenPanel nextPage = currentScreen.nextPage();

        // Set the next page as the current one
        setCurrentScreen(nextPage);
    }

    /**
     * Method called when the finish button is pressed. It works through all the screens in the order in which they were
     * accessed (or reverse order, depending on the order set by the {@link #setCommitOrder} method). Any screens that
     * are in the NOT_SAVED state will have their {@link WorkFlowScreenPanel#saveWork} method called. After this step is
     * complete the {@link #saveWork} for the work flow controller is called.
     */
    protected void saveWorkFlow()
    {
        /*log.fine("void saveWorkFlow(): called");*/

        // Cycle through all the accessed screens in the work flow
        while (!accessedScreens.isEmpty())
        {
            WorkFlowScreenPanel nextScreen = (WorkFlowScreenPanel) accessedScreens.pop();

            // Check if the screen has unsaved state and call its save work method if so
            if (nextScreen.getState().getState().equals(WorkFlowScreenState.NOT_SAVED))
            {
                nextScreen.saveWork();
            }
        }

        // Call the save work method for the entire work flow controller to finalize the work flow
        saveWork();
    }

    /**
     * Method called when the cancel button is pressed. It works through all the screens in the order in which they were
     * accessed (or reverse order, depending on the order set by the {@link #setCommitOrder} method). Any screens that
     * are in the NOT_SAVED state will have their {@link WorkFlowScreenPanel#discardWork} method called. After this step
     * is complete the {@link #discardWork} for the work flow controller is called.
     */
    protected void discardWorkFlow()
    {
        /*log.fine("void discardWorkFlow(): called");*/

        // Cycle through all the accessed screens in the work flow
        while (!accessedScreens.isEmpty())
        {
            WorkFlowScreenPanel nextScreen = (WorkFlowScreenPanel) accessedScreens.pop();

            // Check if the screen has unsaved state and call its discard work method if so
            if (nextScreen.getState().getState().equals(WorkFlowScreenState.NOT_SAVED))
            {
                nextScreen.discardWork();
            }
        }

        // Call the discard work method for the entire work flow controller to finalize the work flow
        discardWork();
    }

    /**
     * This is a helper method that controller implementations may find useful for moving to a new screen. It places the
     * screen into the panel that this controller was built with, replacing any existing screen, changes the underlying
     * state to reflect the change to a new current screen and calls the new screens initialize method.
     *
     * @param screen The new work flow screen to be displayed.
     */
    protected void setCurrentScreen(WorkFlowScreenPanel screen)
    {
        // Remove any existing screen from the panel
        panel.removeAll();

        // Place the new screen into the panel
        panel.add(screen);

        // Check if the screen is not already in the stack of accessed screens. It may be if this is the second time
        // the screen is visited foir example if the back button is used.
        if (!accessedScreens.contains(screen))
        {
            // Add the screen to the stack of accessed screens
            accessedScreens.push(screen);
        }

        // Update the work flow state to reflect the change to a new screen state
        state.setCurrentScreenState(screen.getState());

        // Keep track of the current screen in a local member variable
        currentScreen = screen;

        // Initialize the new screen
        screen.initialize();

        // Force the panel to redraw
        panel.validate();
    }
}


/*
 * Copyright The Sett Ltd, 2005 to 2014.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.thesett.common.util.logic;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

/**
 * UnaryPredicateConjunction is a chain of unary predicates that are applied in the sequence order in which they are
 * added to the chain, to produce a new unary predicate which is the conjunction of all of its components.
 *
 *

CRC Card

 *
Responsibilities
 *

 * Accept unary predicates to build up a predicate chain.
 *
Allow a predicate to be removed from the chain.
 *
Allow the whole chain to be cleared.
 *

 *
 * @author Rupert Smith
 */
public class UnaryPredicateConjunction<T> implements UnaryPredicate<T>
{
    /** Holds the predicate chain. */
    Collection<UnaryPredicate<T>> chain = new LinkedList<UnaryPredicate<T>>();

    /**
     * Adds a new predicate to the chain.
     *
     * @param predicate A new predicate to add to the chain.
     */
    public void addPredicate(UnaryPredicate<T> predicate)
    {
        chain.add(predicate);
    }

    /**
     * Removes a predicate from the chain.
     *
     * @param predicate The predicate to remove.
     */
    public void removePredicate(UnaryPredicate<T> predicate)
    {
        chain.remove(predicate);
    }

    /** Removes all predicates from the chain. */
    public void clear()
    {
        chain.clear();
    }

    /**
     * Evaluates a logical predicate.
     *
     * @param  t The object to test for predicate membership.
     *
     * @return <tt>true</tt> if the object is a member of the predicate, <tt>false</tt> otherwise.
     */
    public boolean evaluate(T t)
    {
        // Start by assuming that the candidate will be a member of the predicate.
        boolean passed = true;

        // Loop through all predicates and fail if any one of them does.
        for (UnaryPredicate<T> predicate : chain)
        {
            if (!predicate.evaluate(t))
            {
                passed = false;

                break;
            }
        }

        return passed;
    }
}


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

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

/**
 * ContextualProperties is an extension of {@link java.util.Properties} that automatically selects properties based on
 * an environment parameter (defined by the system property {@link #ENV_SYS_PROPERTY}), the name of a class, plus a
 * modifier (which can be used to name a method of a class) and a property key. It also supports the definition of
 * arrays of property values using indexes. The properties are searched in the following order until a match is found:
 *
 *

 *
environment + class name with package name + modifier + key
 *
environment + class name with package name + key
 *
environment + key
 *
class name with package name + modifier + key
 *
class name with package name + key
 *
key
 *

 *
 *
To create arrays of property values add index numbers onto the end of the property keys. An array of string values
 * will be created with the elements of the array set to the value of the property at the matching index. Ideally the
 * index values will be contiguous, starting at 0. This does not need to be the case however. If an array definition
 * begins at index n, and ends at index m, Then an array big enough to hold m + 1 elements will be created and populated
 * with values from n to m. Values before n and any missing values between n and m will be null in the array.
 *
 *
To give an example, suppose you have two different environments 'DEVELOPMENT' and 'PRODUCTION' and they each need
 * the same properties but set to different values for each environment and some properties the same in both, you could
 * create a properties file like:
 *
 *
# Project configuration properties file.

 *

 * # These properties are environment specific.

 * DEVELOPMENT.debug=true

 * PRODUCTION.debug=false

 *

 * # Always debug MyClass in all environments but not the myMethod method.

 * MyClass.debug=true

 * MyClass.myMethod.debug=false

 *

 * # Set up an array of my ten favourite animals. Leave elements 3 to 8 as null as I haven't decided on them yet.

 * animals.0=cat

 * animals.1=dog

 * animals.2=elephant

 * animals.9=lion

 *

 * # This is a default value that will be used when the environment is not known.

 * debug=false

 *
 *
 *
The most specific definition of a property is searched for first moving out to the most general. This allows
 * general property defaults to be set and then overiden for specific uses by some classes and modifiers.
 *
 *
A ContextualProperties object can be loaded in the same way as a java.utils.Properties. A recommended way to do
 * this that does not assume that the properties file is a file (it could be in a jar) is to load the properties from
 * the url for the resource lookup up on the classpath:
 *
 *
Properties configProperties = new ContextualProperties();

 * configProperties.load(this.getClass().getClassLoader().getResourceAsStream("config.properties"));

 *
 *
 *
EnvironmentProperties will load the 'DEVELOPMENT.debug' property or 'PROUCTION.debug' property based on the
 * setting of the system environment property. If a matching property for the environment cannot be found then the
 * simple property name without the environment pre-pended onto it will be used instead. This 'use of default
 * environments' behaviour is turned on initially but it can be disabled by calling the {@link #useDefaultEnvironments}
 * method.
 *
 *
When a property matching a key cannot be found then the property accessor methods will always return null. If a
 * default value for a property exists but the 'use of default environments' behavious prevents it being used then the
 * accessor methods will return null.
 *
 *

CRC Card

 *
ResponsibilitiesCollaborations
 *
Automatically select properties dependant on environment, class name and modifier as well as property key.
 *
Convert indexed properties into arrays.
 *

 *
 * @author Rupert Smith
 */
public class ContextualProperties extends ParsedProperties
{
    /** The name of the system property that is used to define the environment. */
    public static final String ENV_SYS_PROPERTY = "environment";

    /**
     *
Holds the iteration count down order.
     *
     *
If e = 4, b = 2, m = 1 then the iteration order or i is 7,6,4 and then if using environment defaults 3,2,0
     * where the accessor key is: (i & e != 0 ? environment : "") + (i & b != 0 ? base : "") + (1 + m != 0 ? modifier :
     * "") + key
     *
     *
In other words the presence or otherwise of the three least significant bits when counting down from 7
     * specifies which of the environment, base and modifier are to be included in the key where the environment, base
     * and modifier stand for the bits in positions 2, 1 and 0. The numbers 5 and 1 are missed out of the count because
     * they stand for the case where the modifier is used without the base which is not done.
     */
    private static final int[] ORDER = new int[] { 7, 6, 4, 3, 2, 0 };

    /**
     * Defines the point in the iteration count order below which the 'use environment defaults' feature is being used.
     */
    private static final int ENVIRONMENT_DEFAULTS_CUTOFF = 4;

    /** Defines the bit representation for the environment in the key ordering. See {@link #ORDER}. */
    private static final int E = 4;

    /** Defines the bit representation for the base in the key ordering. See {@link #ORDER}. */
    private static final int B = 2;

    /** Defines the bit representation for the modifier in the key ordering. See {@link #ORDER}. */
    private static final int M = 1;

    /** Used to hold the value of the environment system property. */
    private final String environment;

    /** Used to indicate that the 'use of defaults' behaviour should be used. */
    private boolean useDefaults = true;

    /** Used to hold all the array properties. This is a mapping from property names to ArrayLists of Strings. */
    protected Map arrayProperties = new HashMap();

    /** Default constructor that builds a ContextualProperties that uses environment defaults. */
    public ContextualProperties()
    {
        super();

        // Keep the value of the system environment property.
        environment = System.getProperty(ENV_SYS_PROPERTY);
    }

    /**
     * Creates a ContextualProperties that uses environment defaults and is initialized with the specified properties.
     *
     * @param props The properties to initialize this with.
     */
    public ContextualProperties(Properties props)
    {
        super(props);

        // Keep the value of the system environment property.
        environment = System.getProperty(ENV_SYS_PROPERTY);

        // Extract any array properties as arrays.
        createArrayProperties();
    }

    /**
     * Parses an input stream as properties.
     *
     * @param     inStream The input stream to read the properties from.
     *
     * @exception IOException If there is an IO error during reading from the input stream.
     */
    public void load(InputStream inStream) throws IOException
    {
        super.load(inStream);

        // Extract any array properties as arrays.
        createArrayProperties();
    }

    /**
     * Tells this environment aware properties object whether it should use default environment properties without a
     * pre-pended environment when a property for the current environment cannot be found.
     *
     * @param flag True to use defaults, false to not use defaults.
     */
    public void useDefaultEnvironments(boolean flag)
    {
        useDefaults = flag;
    }

    /**
     * Looks up a property value relative to the environment, callers class and method. The default environment will be
     * checked for a matching property if defaults are being used. In order to work out the callers class and method
     * this method throws an exception and then searches one level up its stack frames.
     *
     * @param  key The property key.
     *
     * @return The value of this property searching from the most specific definition (environment, class, method, key)
     *         to the most general (key only), unless use of default environments is turned off in which case the most
     *         general proeprty searched is (environment, key).
     */
    public String getProperty(String key)
    {
        // Try to get the callers class name and method name by examing the stack.
        String className = null;
        String methodName = null;

        // Java 1.4 onwards only.
        /*try
        {
            throw new Exception();
        }
        catch (Exception e)
        {
            StackTraceElement[] stack = e.getStackTrace();

            // Check that the stack trace contains at least two elements, one for this method and one for the caller.
            if (stack.length >= 2)
            {
                className = stack[1].getClassName();
                methodName = stack[1].getMethodName();
            }
        }*/

        // Java 1.5 onwards only.
        StackTraceElement[] stack = Thread.currentThread().getStackTrace();

        // Check that the stack trace contains at least two elements, one for this method and one for the caller.
        if (stack.length >= 2)
        {
            className = stack[1].getClassName();
            methodName = stack[1].getMethodName();
        }

        // Java 1.3 and before? Not sure, some horrible thing that parses the text spat out by printStackTrace?

        return getProperty(className, methodName, key);
    }

    /**
     * Looks up a property value relative to the environment, base class and modifier. The default environment will be
     * checked for a matching property if defaults are being used.
     *
     * @param  base     An object of the class to retrieve properties relative to.
     * @param  modifier The modifier (which may stand for a method of the class).
     * @param  key      The property key.
     *
     * @return The value of this property searching from the most specific definition (environment, class, modifier,
     *         key) to the most general (key only), unless use of default environments is turned off in which case the
     *         most general property searched is (environment, key).
     */
    public String getProperty(Object base, String modifier, String key)
    {
        return getProperty(base.getClass().getName(), modifier, key);
    }

    /**
     * Looks up a property value relative to the environment, base class and modifier. The default environment will be
     * checked for a matching property if defaults are being used.
     *
     * @param  base     The name of the class to retrieve properties relative to.
     * @param  modifier The modifier (which may stand for a method of the class).
     * @param  key      The property key.
     *
     * @return The value of this property searching from the most specific definition (environment, class, modifier,
     *         key) to the most general (key only), unless use of default environments is turned off in which case the
     *         most general property searched is (environment, key).
     */
    public String getProperty(String base, String modifier, String key)
    {
        String result = null;

        // Loop over the key orderings, from the most specific to the most general, until a matching value is found.
        for (Iterator i = getKeyIterator(base, modifier, key); i.hasNext();)
        {
            String nextKey = (String) i.next();

            result = super.getProperty(nextKey);

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

        return result;
    }

    /**
     * Looks up an array property value relative to the environment, callers class and method. The default environment
     * will be checked for a matching array property if defaults are being used. In order to work out the callers class
     * and method this method throws an exception and then searches one level up its stack frames.
     *
     * @param  key The property key.
     *
     * @return The array value of this indexed property searching from the most specific definition (environment, class,
     *         method, key) to the most general (key only), unless use of default environments is turned off in which
     *         case the most general proeprty searched is (environment, key).
     */
    public String[] getProperties(String key)
    {
        // Try to get the callers class name and method name by throwing an exception an searching the stack frames.
        String className = null;
        String methodName = null;

        /* Java 1.4 onwards only.
           try {
             throw new Exception();
           } catch (Exception e) {
             StackTraceElement[] stack = e.getStackTrace();
             // Check that the stack trace contains at least two elements, one for this method and one for the caller.
             if (stack.length >= 2) {
               className = stack[1].getClassName();
               methodName = stack[1].getMethodName();
             }
           }*/
        return getProperties(className, methodName, key);
    }

    /**
     * Looks up an array property value relative to the environment, base class and modifier. The default environment
     * will be checked for a matching array property if defaults are being used.
     *
     * @param  base     An object of the class to retrieve properties relative to.
     * @param  modifier The modifier (which may stand for a method of the class).
     * @param  key      The property key.
     *
     * @return The array value of this indexed property searching from the most specific definition (environment, class,
     *         modifier, key) to the most general (key only), unless use of default environments is turned off in which
     *         case the most general proeprty searched is (environment, key).
     */
    public String[] getProperties(Object base, String modifier, String key)
    {
        return getProperties(base.getClass().getName(), modifier, key);
    }

    /**
     * Looks up an array property value relative to the environment, base class and modifier. The default environment
     * will be checked for a matching array property if defaults are being used.
     *
     * @param  base     The name of the class to retrieve properties relative to.
     * @param  modifier The modifier (which may stand for a method of the class).
     * @param  key      The property key.
     *
     * @return The array value of this indexed property searching from the most specific definition (environment, class,
     *         modifier, key) to the most general (key only), unless use of default environments is turned off in which
     *         case the most general property searched is (environment, key).
     */
    public String[] getProperties(String base, String modifier, String key)
    {
        String[] result = null;

        // Loop over the key orderings, from the most specific to the most general, until a matching value is found.
        for (Iterator i = getKeyIterator(base, modifier, key); i.hasNext();)
        {
            String nextKey = (String) i.next();
            Collection arrayList = (ArrayList) arrayProperties.get(nextKey);

            if (arrayList != null)
            {
                result = (String[]) arrayList.toArray(new String[] {});

                break;
            }
        }

        return result;
    }

    /**
     * For a given environment, base, modifier and key and setting of the use of default environments feature this
     * generates an iterator that walks over the order in which to try and access properties.
     *
     *
See the {@link #ORDER} constant for an explanation of how the key ordering is generated.
     *
     * @param  base     The name of the class to retrieve properties relative to.
     * @param  modifier The modifier (which may stand for a method of the class).
     * @param  key      The property key.
     *
     * @return An Iterator over String keys defining the order in which properties should be accessed.
     */
    protected Iterator getKeyIterator(final String base, final String modifier, final String key)
    {
        return new Iterator()
            {
                // The key ordering count always begins at the start of the ORDER array.
                private int i;

                public boolean hasNext()
                {
                    return (useDefaults ? ((i < ORDER.length) && (ORDER[i] > ENVIRONMENT_DEFAULTS_CUTOFF))
                                        : (i < ORDER.length));
                }

                public Object next()
                {
                    // Check that there is a next element and return null if not.
                    if (!hasNext())
                    {
                        return null;
                    }

                    // Get the next ordering count.
                    int o = ORDER[i];

                    // Do bit matching on the count to choose which elements to include in the key.
                    String result =
                        (((o & E) != 0) ? (environment + ".") : "") + (((o & B) != 0) ? (base + ".") : "") +
                        (((o & M) != 0) ? (modifier + ".") : "") + key;

                    // Increment the iterator to get the next key on the next call.
                    i++;

                    return result;
                }

                public void remove()
                {
                    // This method is not supported.
                    throw new UnsupportedOperationException("remove() is not supported on this key order iterator as " +
                        "the ordering cannot be changed");
                }
            };
    }

    /**
     * Scans all the properties in the parent Properties object and creates arrays for any array property definitions.
     *
     *
Array properties are defined with indexes. For example:
     *
     *
property.1=one

     * property.2=two

     * property.3=three

     *
     *
     *
Note that these properties will be stored as the 'empty string' or "" property array.
     *
     *
.1=one

     * 2=two

     *
     */
    protected void createArrayProperties()
    {
        // Scan through all defined properties.
        for (Object o : keySet())
        {
            String key = (String) o;
            String value = super.getProperty(key);

            // Split the property key into everything before the last '.' and after it.
            int lastDotIndex = key.lastIndexOf('.');
            String keyEnding = key.substring(lastDotIndex + 1, key.length());
            String keyStart = key.substring(0, (lastDotIndex == -1) ? 0 : lastDotIndex);

            // Check if the property key ends in an integer, in which case it is an array property.
            int index = 0;

            try
            {
                index = Integer.parseInt(keyEnding);
            }
            catch (NumberFormatException e)
            {
                // The ending is not an integer so its not an array.
                // Exception can be ignored as it means this property is not an array.
                e = null;

                continue;
            }

            // Check if an array property already exists for this base name and create one if not.
            ArrayList propArray = (ArrayList) arrayProperties.get(keyStart);

            if (propArray == null)
            {
                propArray = new ArrayList();
                arrayProperties.put(keyStart, propArray);
            }

            // Add the new property value to the array property for the index.
            propArray.set(index, value);
        }
    }
}


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

import java.util.List;

import org.jpc.salt.TermBuilder;

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

public class LojixTermBuilder extends TermBuilder<Term>
{
    /** The interner used to look up and construct all names. */
    private final VariableAndFunctorInterner interner;

    /**
     * Creates a term builder with the specified interner to look up and construct interned names with.
     *
     * @param interner The interner used to look up and construct all names.
     */
    public LojixTermBuilder(VariableAndFunctorInterner interner)
    {
        this.interner = interner;
    }

    /** {@inheritDoc} */
    public Term build()
    {
        Term result;

        if (!isCompound())
        {
            result = getFunctor();
        }
        else
        {
            if (getFunctor().isAtom())
            {
                List<Term> args = getArgs();
                int arity = args.size();
                Functor functor = (Functor) getFunctor();
                int name = interner.internFunctorName(interner.getFunctorName(functor.getName()), arity);
                result = new Functor(name, args.toArray(new Term[arity]));
            }
            else
            {
                throw new IllegalStateException("Invalid functor type.");
            }
        }

        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.common.throttle;

/**
 * Provides a base implementation of the non-waiting throttle checking method, using the system nano timer.
 *
 *

CRC Card

 *
ResponsibilitiesCollaborations
 *
Check against a throttle speed without waiting.
 *

 *
 * @author Rupert Smith
 */
public abstract class BaseThrottle implements Throttle
{
    /** Holds the length of a single cycle in nano seconds. */
    protected long cycleTimeNanos;

    /** Holds the time of the last succesfull call to the check method. */
    private long lastCheckTimeNanos;

    /** Flag used to detect the first call to the {@link #checkThrottle()} method. */
    boolean firstCheckCall = true;

    /**
     * Flag used to detect the first call to the {@link #throttle()} method. Zero or negative start time cannot be
     * relied on to detect this as System.nanoTime can return zero or negative values.
     */
    boolean firstCall = true;

    /**
     * Specifies the throttling rate in operations per second. This must be called with with a value, the inverse of
     * which is a measurement in nano seconds, such that the number of nano seconds do not overflow a long integer. The
     * value must also be larger than zero.
     *
     * @param hertz The throttling rate in cycles per second.
     */
    public void setRate(float hertz)
    {
        // Check that the argument is above zero.
        if (hertz <= 0.0f)
        {
            throw new IllegalArgumentException("The throttle rate must be above zero.");
        }

        // Calculate the cycle time.
        cycleTimeNanos = (long) (1000000000f / hertz);

        // Reset the first pass flag.
        firstCall = false;
        firstCheckCall = false;
    }

    /**
     * This method can only be called at the rate set by the {@link #setRate} method, if it is called faster than this
     * it will inject short pauses to restrict the call rate to that rate.
     *
     * @throws InterruptedException If interrupted whilst performing a blocking wait on the throttle.
     */
    public void throttle() throws InterruptedException
    {
        // Don't introduce any pause on the first call.
        if (!firstCall)
        {
            // Check if there is any time left in the cycle since the last throttle call to this method and introduce a
            // short pause to fill that time if there is.
            long remainingTimeNanos = timeToThrottleNanos();

            while (remainingTimeNanos > 0)
            {
                long milliPause = remainingTimeNanos / 1000000;
                int nanoPause = (int) (remainingTimeNanos % 1000000);

                Thread.sleep(milliPause, nanoPause);

                remainingTimeNanos = timeToThrottleNanos();
            }
        }
        else
        {
            firstCall = false;
        }
    }

    /**
     * Checks but does not enforce the throttle rate. When this method is called, it checks if a length of time greater
     * than that equal to the inverse of the throttling rate has passed since it was last called and returned <tt>
     * true</tt>
     *
     * @return <tt>true</tt> if a length of time greater than that equal to the inverse of the throttling rate has
     *         passed since this method was last called and returned <tt>true</tt>, <tt>false</tt> otherwise. The very
     *         first time this method is called on a throttle, it returns <tt>true</tt> as the base case to the above
     *         self-referential definition.
     */
    public boolean checkThrottle()
    {
        return timeToThrottleNanos() <= 0;
    }

    /**
     * Checks but does not enforce the throttle rate. When this method is called, it checks if a length of time greater
     * than that equal to the inverse of the throttling rate has passed since it was last called and returned <tt>
     * true</tt>. If the length of time still to elapse to the next throttle allow point is zero or less, this method
     * will return a negative value, if there is still time to pass until the throttle allow point, this method will
     * return a positive value indicating the amount of time still to pass. A thread can wait for that period of time
     * before rechecking the throttle condition.
     *
     * @return The length of time since or still to elaps to the next throttle allow point. A negative value indicates
     *         that the throttle time has passed and a positive time indicates that there is still time to pass before
     *         it is reached. The units are in nanoseconds.
     */
    public long timeToThrottleNanos()
    {
        long now = System.nanoTime();
        long remainingNanos = (cycleTimeNanos + lastCheckTimeNanos) - now;

        if ((remainingNanos <= 0))
        {
            firstCheckCall = false;
            lastCheckTimeNanos = now;

            return remainingNanos;
        }
        else if (firstCheckCall)
        {
            firstCheckCall = false;
            lastCheckTimeNanos = now;

            return 0;
        }
        else
        {
            return remainingNanos;
        }
    }
}


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

import java.util.HashMap;
import java.util.Map;

import com.thesett.aima.state.ComponentType;
import com.thesett.aima.state.State;

/**
 * MapBackedState provides an implementation of the {@link State} interface that is backed by a hash map.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Get properties as attributes by name.
 *
 Set properties from attribute by name.
 *

 *
 * @author Rupert Smith
 */
public class MapBackedState implements State
{
    /** Holds the property values. */
    private final Map<String, Object> properties = new HashMap<String, Object>();

    /** Holds the state type mapping. */
    private final DynaComponent componentType = new DynaComponent("MapBackedState");

    /** {@inheritDoc} */
    public Object getProperty(String property)
    {
        return properties.get(property);
    }

    /** {@inheritDoc} */
    public void setProperty(String name, Object value)
    {
        // Set the type of the new property in the state type mapping.
        componentType.addPropertyType(name, TypeHelper.getTypeFromObject(value));

        // Add the new property to the property map.
        properties.put(name, value);
    }

    /** {@inheritDoc} */
    public boolean hasProperty(String property)
    {
        return properties.containsKey(property);
    }

    /**
     * Gets the Component of this state.
     *
     * @return The Component of this state.
     */
    public ComponentType getComponentType()
    {
        return componentType;
    }
}


/*
 * 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.DoubleLiteral;
import com.thesett.aima.logic.fol.IntLiteral;
import com.thesett.aima.logic.fol.NumericType;
import com.thesett.aima.logic.fol.Term;

/**
 * UMinus implements the unary minus operator '-' in Prolog.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Negate a number.
 *

 *
 * @author Rupert Smith
 */
public class UMinus extends UnaryArithmeticOperator
{
    /**
     * Creates a new '-' expression operator.
     *
     * @param name      The interned name of the operator.
     * @param arguments The arguments, of which there must be two.
     */
    public UMinus(int name, Term[] arguments)
    {
        super(name, arguments);
    }

    /**
     * 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 NumericType evaluate(NumericType firstNumber)
    {
        // If the argument is a real number, then use real number arithmetic, otherwise use integer arithmetic.
        if (firstNumber.isInteger())
        {
            return new IntLiteral(-firstNumber.intValue());
        }
        else
        {
            return new DoubleLiteral(-firstNumber.doubleValue());
        }
    }
}


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

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import com.thesett.common.util.PropertiesHelper;

/**
 * PropertyReaderBase is a property file reader that uses a variety of methods to locate and load property files. The
 * {@link #findProperties} method attempts to load the properties from a file referenced by the system property with the
 * same name as the properties resource name, from a resource on the classpath with the same name as the properties
 * resource name or from a properties file name relative to the current working directory. It tries these methods
 * sequentially one after the other until one succeeds.
 *
 *
This class is intended to be extended by class representations of properties files so it contains a reference to
 * a {@link java.util.Properties} object. Extending classes must implement an abstract method to specify the name of the
 * properties resource file that contains the properties that the implementing class stands for. Normally, extending
 * classes will define constants for easy access to the properties that they are representing.
 *
 *
This class is a singleton.
 *
 *

CRC Card

 *
ResponsibilitiesCollaborations
 *
Search for properties resources in file or URL defined in system properties  {@link com.thesett.common.util.PropertiesHelper}
 *
Search for properties resources in file in classpath  {@link com.thesett.common.util.PropertiesHelper}
 *
Search for properties resources in file in current working directory  {@link com.thesett.common.util.PropertiesHelper}
 *
Specify the name of the resource to get properties from
 *

 *
 * @author Rupert Smith
 */
public abstract class PropertyReaderBase
{
    /** Used for logging. */
    /* private static final Logger log = Logger.getLogger(PropertyReaderBase.class.getName()); */

    /** Holds a reference to the read properties. */
    protected Properties properties;

    /** Default constructor. Loads the properties. This is a private constructor as this class is abstract. */
    protected PropertyReaderBase()
    {
        /*log.fine("protected PropertyReaderBase(): called");*/

        // Load the properties.
        // Don't load the properties until the sub-class explicitly triggers the find as the sub-class will
        // probably need to set up the resource name in its constructor first.
        // findProperties();
    }

    /**
     * Returns the read properties from the properties file.
     *
     * @return The properties for the specified resource name.
     */
    public Properties getProperties()
    {
        return properties;
    }

    /**
     * This should return the name of the resource, file or system property to use to locate the properties file to be
     * read.
     *
     * @return The resource name of the properties file.
     */
    protected abstract String getPropertiesResourceName();

    /**
     * This methods attempts to load the properties from a file or URL referenced by the system property with the same
     * name as the properties resource name, from a resource on the classpath with the same name as the properties
     * resource name or from a properties file name relative to the current working directory. It tries these methods
     * sequentially one after the other until one succeeds.
     */
    protected void findProperties()
    {
        /*log.fine("findProperties: called");*/

        // Try to load the properties from a file referenced by the system property matching
        // the properties file name.
        properties = getPropertiesUsingSystemProperty();

        if (properties != null)
        {
            /*log.fine("loaded properties using the system property");*/

            // The properties were succesfully located and loaded
            return;
        }

        /*log.fine("failed to get properties from the system properties");*/

        // Try to load the properties from a resource on the classpath using the current
        // class loader
        properties = getPropertiesUsingClasspath();

        if (properties != null)
        {
            /*log.fine("loaded properties from the class path");*/

            // The properties were succesfully located and loaded
            return;
        }

        /*log.fine("failed to get properties from the classpath");*/

        // Try to load the properties from a file relative to the current working directory
        properties = getPropertiesUsingCWD();

        if (properties != null)
        {
            /*log.fine("loaded properties from the current working directory");*/

            // The properties were succesfully located and loaded
            return;
        }

        /*log.fine("failed to get properties from the current working directory");*/
    }

    /**
     * Tries to load the properties from the file or URL named by the system property with name mathching the properties
     * resource name.
     *
     * @return The properties found under the file name or URL or null if none can be found there.
     */
    protected Properties getPropertiesUsingSystemProperty()
    {
        /*log.fine("getPropertiesUsingSystemProperty: called");*/

        // Get the path to the file from the system properties
        /*log.fine("getPropertiesResourceName() = " + getPropertiesResourceName());*/

        String path = System.getProperty(getPropertiesResourceName());

        /*log.fine("properties resource name = " + getPropertiesResourceName());*/
        /*log.fine("path = " + path);*/

        // Use PropertiesHelper to try to load the properties from the path
        try
        {
            return PropertiesHelper.getProperties(path);
        }
        catch (IOException e)
        {
            /*log.fine("Could not load properties from path " + path);*/

            // Failure of this method is noted, so exception is ignored.
            e = null;
        }

        return null;
    }

    /**
     * Tries to load the properties from the classpath using the classloader for this class.
     *
     * @return The properties loaded from the resource name under the classpath or null if none can be found there.
     */
    protected Properties getPropertiesUsingClasspath()
    {
        /*log.fine("getPropertiesUsingClasspath: called");*/

        // Try to open the properties resource name as an input stream from the classpath
        InputStream is = this.getClass().getClassLoader().getResourceAsStream(getPropertiesResourceName());

        // Use PropertiesHelper to try to load the properties from the input stream if one was succesfully created
        if (is != null)
        {
            try
            {
                return PropertiesHelper.getProperties(is);
            }
            catch (IOException e)
            {
                /*log.fine("Could not load properties from classpath");*/

                // Failure of this method is noted, so exception is ignored.
                e = null;
            }
        }

        return null;
    }

    /**
     * Tries to load the properties as a file or URL matching the properties resource name. File names will be taken
     * relative to the current working directory.
     *
     * @return The properties found from the resource name as a file in the current working directory or null if none
     *         can be found there.
     */
    protected Properties getPropertiesUsingCWD()
    {
        /*log.fine("getPropertiesUsingCWD: called");*/

        // Use PropertiesHelper to try to load the properties from a file or URl
        try
        {
            return PropertiesHelper.getProperties(getPropertiesResourceName());
        }
        catch (IOException e)
        {
            /*log.fine("Could not load properties from file or URL " + getPropertiesResourceName());*/

            // Failure of this method is noted, so exception is ignored.
            e = null;
        }

        return null;
    }
}


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

import com.thesett.aima.logic.fol.BasePositionalVisitor;
import com.thesett.aima.logic.fol.Clause;
import com.thesett.aima.logic.fol.Functor;
import com.thesett.aima.logic.fol.PositionalTermVisitor;
import com.thesett.aima.logic.fol.Term;
import com.thesett.aima.logic.fol.VariableAndFunctorInterner;
import com.thesett.aima.logic.fol.compiler.PositionalTermTraverser;
import com.thesett.aima.logic.fol.wam.builtins.BuiltInFunctor;
import com.thesett.aima.logic.fol.wam.builtins.BuiltInTransform;
import com.thesett.common.util.doublemaps.SymbolTable;

/**
 * BuiltInTransformVisitor should be used with a depth first positional walk over a term to compile. On leaving each
 * term, that is in a post-fix order, if the term is a functor, the built-in transformation function is applied to it.
 * If the built-in applies a transformation to a functor, it is substituted within its parent for the built-in.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Substitute built-ins into a term to compile.

 *

 *
 * @author Rupert Smith
 */
class BuiltInTransformVisitor extends BasePositionalVisitor implements PositionalTermVisitor
{
    /** Used for debugging. */
    /* private static final Logger log = Logger.getLogger(BuiltInTransformVisitor.class.getName()); */

    /** Holds the built in transformation function. */
    private final BuiltInTransform builtInTransform;

    /**
     * Creates the visitor with the supplied interner, symbol table and traverser.
     *
     * @param interner         The name interner.
     * @param symbolTable      The compiler symbol table.
     * @param traverser        The positional context traverser.
     * @param builtInTransform The built-in transformation function.
     */
    BuiltInTransformVisitor(VariableAndFunctorInterner interner, SymbolTable<Integer, String, Object> symbolTable,
        PositionalTermTraverser traverser, BuiltInTransform builtInTransform)
    {
        super(interner, symbolTable, traverser);

        this.builtInTransform = builtInTransform;
    }

    /** {@inheritDoc} */
    public void setPositionalTraverser(PositionalTermTraverser traverser)
    {
        this.traverser = traverser;
    }

    /**
     * Applies the built-in transform during a post-fix visit of a term.
     *
     * @param functor The functor to visit.
     */
    protected void leaveFunctor(Functor functor)
    {
        int pos = traverser.getPosition();

        if (!traverser.isInHead() && (pos >= 0))
        {
            Functor transformed = builtInTransform.apply(functor);

            if (functor != transformed)
            {
                /*log.fine("Transformed: " + functor + " to " + transformed.getClass());*/

                BuiltInFunctor builtInFunctor = (BuiltInFunctor) transformed;

                Term parentTerm = traverser.getParentContext().getTerm();

                if (parentTerm instanceof Clause)
                {
                    Clause parentClause = (Clause) parentTerm;

                    parentClause.getBody()[pos] = builtInFunctor;

                }
                else if (parentTerm instanceof Functor)
                {
                    Functor parentFunctor = (Functor) parentTerm;

                    parentFunctor.getArguments()[pos] = builtInFunctor;
                }
            }
        }
    }
}