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

import java.io.Serializable;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.thesett.common.error.NotImplementedException;

/**
 * A HashArray is an implementation of the {@link IndexedMap} interface that preserves the ordering of its elements in
 * the same order in which they are inserted into the map. It differs from a {@link java.util.TreeMap} which orders its
 * elements according to a comparison function.
 *
 *
The data structure is build on top of an array into which the elements are inserted in arrival order and a
 * HashMap which is used to quickly convert keys into into indexes into the array. In this way it can provide a very
 * efficient keyed array with roughly constant access time provided the hashing is good.
 *
 *
Note that a HashArray does not implement the {@link java.util.SortedMap} interface as this is only to be
 * implemented by data structures that guarantee an ordering based on the ordering of the keys. This data structure is
 * not ordered by its keys but by the order in which elements are inserted.
 *
 *

CRC Card

 *
ResponsibilitiesCollaborations
 *
Manage keys and values as a map
 *
Get elements by index
 *
Insert elements by index
 *
Remove elements by index
 *

 *
 * @author Rupert Smith
 * @todo   A LinkedHashSet was used to track the insertion order of the keys. This was probably done as a quick hack to
 *         get this working. Would be better to store the keys in the data array itself. Better to drop the data array
 *         altogether and use a key list instead. LinkedList or ArrayList implementation for the key ordering list to be
 *         chosen using a constructor.
 * @todo   Add a constructor that allows the backing map to be passed as an argument so that map types other than hash
 *         maps can be supported. Rename this class to MapArray once this has been done. When combined with a TreeMap
 *         this data structure can provide both insertion ordering and value based ordering simultaneously.
 */
public class HashArray<K, V> implements IndexedMap<K, V>, Serializable
{
    /** The HashMap that holds the key to index mapping. */
    private final Map<K, Integer> keyToIndex;

    /** A linked list hash set that is used to keep track of the insertion order of the keys. */
    private final Set<K> keySet;

    /** The array that holds the data. */
    private final List<V> data;

    /** The array that holds the keys in insertion order. */
    private List<K> keys;

    /** Creates a new empty hash array. */
    public HashArray()
    {
        this.keyToIndex = new HashMap<K, Integer>();
        this.keySet = new LinkedHashSet<K>();
        this.data = new ArrayList<V>();
    }

    /**
     * Creates a new empty hash array with the specified starting size.
     *
     * @param size The initial size of the hash array to create.
     */
    public HashArray(int size)
    {
        this.keyToIndex = new HashMap<K, Integer>(size);
        this.keySet = new LinkedHashSet<K>(size);
        this.data = new ArrayList<V>(size);
    }

    /**
     * Builds a hash array from a map of keys to indexes and a collection of data elements that are stored in a
     * collection at the desired indexes referenced by the map.
     *
     * @param keyToIndex The key to index map.
     * @param data       The data collection at the correct indexes.
     */
    public HashArray(Map keyToIndex, Collection data)
    {
        this.keyToIndex = new HashMap<K, Integer>(keyToIndex);
        this.keySet = new LinkedHashSet<K>(keyToIndex.keySet());
        this.data = new ArrayList<V>(data);
    }

    /** Clears the whole data structure. */
    public void clear()
    {
        keyToIndex.clear();
        keySet.clear();
        data.clear();
    }

    /**
     * Returns true if this map contains a mapping for the specified key.
     *
     * @param  key The key to check in the map for.
     *
     * @return True if this map contains the key, false otherwise.
     */
    public boolean containsKey(Object key)
    {
        return keyToIndex.containsKey(key);
    }

    /**
     * Returns true if this map maps one or more keys to the specified value.
     *
     * @param  value The value to check if this array contains.
     *
     * @return True if this map maps one or more keys to the specified value.
     */
    public boolean containsValue(Object value)
    {
        return data.contains(value);
    }

    /**
     * Returns a set view of the mappings contained in this map.
     *
     * @return A set view of the mappings contained in this map.
     */
    public Set<Map.Entry<K, V>> entrySet()
    {
        Set entrySet =
            new AbstractSet<Map.Entry<K, V>>()
            {
                /**
                 * Gets an iterator over the set.
                 *
                 * @return An iterator over the set.
                 */
                public Iterator<Map.Entry<K, V>> iterator()
                {
                    return new Iterator<Entry<K, V>>()
                        {
                            Iterator<K> keyIterator = keyToIndex.keySet().iterator();

                            public boolean hasNext()
                            {
                                return keyIterator.hasNext();
                            }

                            public Entry<K, V> next()
                            {
                                final K key = keyIterator.next();
                                final V data = get(key);

                                return new Entry<K, V>()
                                    {
                                        public K getKey()
                                        {
                                            return key;
                                        }

                                        public V getValue()
                                        {
                                            return data;
                                        }

                                        public V setValue(V v)
                                        {
                                            throw new NotImplementedException();
                                        }
                                    };
                            }

                            public void remove()
                            {
                                throw new NotImplementedException();
                            }
                        };
                }

                /**
                 * Checks if the set contains the specified object.
                 *
                 * @param o The object to check if the set contains.
                 */
                public boolean contains(Object o)
                {
                    return data.contains(o);
                }

                /**
                 * Removes the specified object from the set.
                 *
                 * @param  o The object to remove.
                 *
                 * @return True if an object was removed and false if not.
                 */
                public boolean remove(Object o)
                {
                    Object removed = HashArray.this.remove(o);

                    return removed != null;
                }

                /**
                 * Gets the size of the set.
                 *
                 * @return The size of the set.
                 */
                public int size()
                {
                    return HashArray.this.size();
                }

                /** Removes everything from the set. */
                public void clear()
                {
                    HashArray.this.clear();
                }
            };

        return entrySet;
    }

    /**
     * Compares the specified object with this map for equality.
     *
     * @param  o The object to compare to.
     *
     * @return True if this hash array exactly equals the test one.
     */
    public boolean equals(Object o)
    {
        // Check that the object has the same type as this
        if (!(o instanceof HashArray))
        {
            return false;
        }

        // Check that the object matches the index map and its data
        return keyToIndex.equals(((HashArray) o).keyToIndex) && data.equals(((HashArray) o).data);
    }

    /**
     * Returns the value to which this map maps the specified key.
     *
     * @param  key The key to get the value from this map for.
     *
     * @return The object stored under the specified key, or null if the key is not in this map.
     */
    public V get(Object key)
    {
        // Get the index from the map
        Integer index = keyToIndex.get(key);

        // Check that the key is in the map
        if (index == null)
        {
            return null;
        }

        // Get the data from the array
        return data.get(index.intValue());
    }

    /**
     * Returns the index to which this map maps the specified key.
     *
     * @param  key The key to get the index from this map for.
     *
     * @return The index of the specified key, or -1 if the key is not in this map.
     */
    public int getIndexOf(Object key)
    {
        // Get the index from the map
        Integer index = keyToIndex.get(key);

        // Check that the key is in the map and return -1 if it is not.
        if (index == null)
        {
            return -1;
        }

        return index;
    }

    /**
     * Returns the value at the specified index.
     *
     * @param  index The index to get the value from this array for.
     *
     * @return The object stored at the specified index.
     *
     * @throws IndexOutOfBoundsException If the index is out of the range covered by this data structure.
     */
    public V get(int index) throws IndexOutOfBoundsException
    {
        return data.get(index);
    }

    /**
     * Returns a hash code for this map.
     *
     * @return A hash code for this map.
     */
    public int hashCode()
    {
        return keyToIndex.hashCode();
    }

    /**
     * Returns true if this map contains no key-value mappings.
     *
     * @return True if this map contains no key-value mappings.
     */
    public boolean isEmpty()
    {
        return keyToIndex.isEmpty();
    }

    /**
     * Returns a set view of the keys contained in this map.
     *
     * @return A set view of the keys contained in this map.
     */
    public Set keySet()
    {
        // return keyToIndex.keySet();
        return keySet;
    }

    /**
     * Associates the specified value with the specified key in this map.
     *
     * @param  key   The key to store against in this map.
     * @param  value The value to store against the key.
     *
     * @return The value that was previously stored against the key, or null if there was none.
     */
    public V put(K key, V value)
    {
        // Remove any existing matching key from the data
        V removedObject = remove(key);

        // Insert the data into the array
        data.add(value);

        // Insert a key into the map that points to the end of the array
        keyToIndex.put(key, data.size() - 1);

        // Create an entry in the key set to track the insertion order of the keys (automatically goes at the end of
        // a linked hash set)
        keySet.add(key);

        // Return the replaced value if there was one
        return removedObject;
    }

    /**
     * Inserts the element at the specified index. This only works if this index already exists.
     *
     * @param  index The index to insert at.
     * @param  value The value to store at that index.
     *
     * @return The value that was previously stored at that index.
     *
     * @throws IndexOutOfBoundsException If the index is out of the range covered by this data structure.
     */
    public V set(int index, V value) throws IndexOutOfBoundsException
    {
        // Check if the index does not already exist
        if (index >= data.size())
        {
            throw new IndexOutOfBoundsException();
        }

        return data.set(index, value);
    }

    /**
     * Copies all of the mappings from the specified map to this map.
     *
     * @param t The map to copy into this one.
     */
    public void putAll(Map<? extends K, ? extends V> t)
    {
        for (Map.Entry<? extends K, ? extends V> entry : t.entrySet())
        {
            this.put(entry.getKey(), entry.getValue());
        }
    }

    /**
     * Removes the mapping for the specified key from this map if present.
     *
     * @param  key The key to remove from this map.
     *
     * @return The value that stored at that key, or null if there was none.
     */
    public V remove(Object key)
    {
        // Check if the key is in the map
        Integer index = keyToIndex.get(key);

        if (index == null)
        {
            return null;
        }

        // Leave the data in the array but remove its key
        keyToIndex.remove(key);
        keySet.remove(key);

        // Remove the data from the array
        V removedValue = data.remove(index.intValue());

        // Go through the whole key to index map reducing by one the value of any indexes greater that the removed index
        for (K nextKey : keyToIndex.keySet())
        {
            Integer nextIndex = keyToIndex.get(nextKey);

            if (nextIndex > index)
            {
                keyToIndex.put(nextKey, nextIndex - 1);
            }
        }

        // Return the removed object
        return removedValue;
    }

    /**
     * Removes the specified index from the data structure. This only works if the index already exists.
     *
     * @param  index The index to remove.
     *
     * @return The value that stored at that index.
     *
     * @throws IndexOutOfBoundsException If the index is out of the range covered by this data structure.
     */
    public V remove(int index) throws IndexOutOfBoundsException
    {
        // Check that the index is not too large
        if (index >= data.size())
        {
            throw new IndexOutOfBoundsException();
        }

        // Get the key for the index by scanning through the key to index mapping
        for (K nextKey : keyToIndex.keySet())
        {
            int nextIndex = keyToIndex.get(nextKey);

            // Found the key for the index, now remove it
            if (index == nextIndex)
            {
                return remove(nextKey);
            }
        }

        // No matching index was found
        throw new IndexOutOfBoundsException();
    }

    /**
     * Returns the number of key-value mappings in this map.
     *
     * @return The size of this map.
     */
    public int size()
    {
        return keyToIndex.size();
    }

    /**
     * Returns a collection view of the value contained in this map.
     *
     * @return The collection of values in this map.
     */
    public Collection values()
    {
        return data;
    }

    /**
     * Returns a list view of the values conatins in this map.
     *
     * @return A list view of the values conatins in this map.
     */
    public List valuesAsList()
    {
        return data;
    }

    /**
     * Prints out the contents of the map, usefull for debugging.
     *
     * @return A string of the index and key/value pairs in this map.
     */
    public String toString()
    {
        StringBuffer result = new StringBuffer();

        result.append("[");

        // Cycle through all the indexes
        for (int i = 0; i < data.size(); i++)
        {
            // This will be used to hold the key found to match the current index
            Object nextKey = null;

            // Find the matching key for next index by scanning through the key to index mapping
            for (K k : keyToIndex.keySet())
            {
                nextKey = k;

                int nextIndex = keyToIndex.get(nextKey);

                // Check if the the key for the index has been found
                if (i == nextIndex)
                {
                    // Stop at the key that matches the current index
                    break;
                }
            }

            // Find the data for the next index
            Object nextData = data.get(i);

            // Write out (index, key, value) into the output string
            result.append("(" + i + ", " + nextKey + ", " + nextData + ")");

            // Add a comma and a space to the output string if more results will follow
            if (i < (data.size() - 1))
            {
                result.append(", ");
            }
        }

        result.append("]");

        return result.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.state.impl;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * PropertyIntrospectorBase provides methods for instrospecting and calling the setter and getter methods of beans.
 *
 *
The getter methods must take no arguments and the setter methods must take exactly one argument. Calling getter
 * methods to extract values is straight forward because there can only ever be one getter method for each property
 * name. Calling setter methods can be more complex because there may be multiple setter methods for each property name,
 * each of which may be called with arguments of different types. This implementation provides a way of matching up the
 * type of the actual arguments given with a setter method that accepts arguments of that type.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Get properties as attributes by name.
 *
 Set properties from attribute by name.
 *
 Check if properties exist on a bean.
 *

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

    /** Holds a cache of getter methods by property name. */
    private Map<String, Method> getters = new HashMap<String, Method>();

    /** Holds a cache of setter methods by property name. */
    private Map<String, Method[]> setters = new HashMap<String, Method[]>();

    /** A flag used to indicate that initialization has been performed. */
    private boolean initialized;

    /**
     * Checks if the bean has a named property. Note that if the property value is set to null on the bean, this method
     * will still return true, it tests for the existance of a named property, including null ones.
     *
     * @param  property The property to check if this state contains.
     *
     * @return <tt>true</tt> if this state has the property, <tt>false</tt> if it does not.
     */
    public boolean hasProperty(String property)
    {
        // Check if a getter method exists for the property.
        Method getterMethod = getters.get(property);

        return getterMethod != null;
    }

    /**
     * Sets the value of a property of the bean by name.
     *
     * @param callee   The object to call the setter method on.
     * @param property The name of the property to set.
     * @param value    The value of the property to set.
     */
    protected void setProperty(Object callee, String property, Object value)
    {
        // Initialize this meta bean if it has not already been initialized.
        if (!initialized)
        {
            initialize(callee);
        }

        // Check that at least one setter method exists for the property.
        Method[] setterMethods = setters.get(property);

        if ((setterMethods == null) || (setterMethods.length == 0))
        {
            throw new IllegalArgumentException("No setter method for the property " + property + " exists.");
        }

        // Choose which setter method to call based on the type of the value argument. If the value argument is null
        // then call the first available one.
        Method setterMethod = null;
        Class valueType = (value == null) ? null : value.getClass();

        // Check if the value is null and use the first available setter if so, as type cannot be extracted.
        if (value == null)
        {
            setterMethod = setterMethods[0];
        }

        // Loop through the available setter methods for one that matches the arguments type.
        else
        {
            for (Method method : setterMethods)
            {
                Class argType = method.getParameterTypes()[0];

                if (argType.isAssignableFrom(valueType))
                {
                    setterMethod = method;

                    break;
                }

                // Check if the arg type is primitive but the value type is a wrapper type that matches it.
                else if (argType.isPrimitive() && !valueType.isPrimitive() &&
                        isAssignableFromPrimitive(valueType, argType))
                {
                    setterMethod = method;

                    break;
                }

                // Check if the arg type is a wrapper but the value type is a primitive type that matches it.
                else if (valueType.isPrimitive() && !argType.isPrimitive() &&
                        isAssignableFromPrimitive(argType, valueType))
                {
                    setterMethod = method;

                    break;
                }
            }

            // Check if this point has been reached but no matching setter method could be found, in which case raise
            // an exception.
            if (setterMethod == null)
            {
                Class calleeType = (callee == null) ? null : callee.getClass();

                throw new IllegalArgumentException("No setter method for property " + property + ", of type, " +
                    calleeType + " will accept the type of value specified, " + valueType + ".");
            }
        }

        // Call the setter method with the value.
        try
        {
            Object[] args = new Object[] { value };
            setterMethod.invoke(callee, args);
        }
        catch (InvocationTargetException e)
        {
            throw new IllegalArgumentException("The setter method for the property " + property +
                " threw an invocation target exception.", e);
        }

        // This should never happen as the initiliazed method should already have checked this.
        catch (IllegalAccessException e)
        {
            throw new IllegalStateException("The setter method for the property " + property + " cannot be accessed.", e);
        }
    }

    /**
     * Returns a single named property of the bean.
     *
     * @param  callee   The object to call the setter method on.
     * @param  property The property of this state to get the value of.
     *
     * @return A single Object value of the bean for the specified property name.
     */
    protected Object getProperty(Object callee, String property)
    {
        // Initialize this meta bean if it has not already been initialized.
        if (!initialized)
        {
            initialize(callee);
        }

        // Check if a getter method exists for the property being fetched.
        Method getterMethod = getters.get(property);

        if (getterMethod == null)
        {
            throw new IllegalArgumentException("No getter method for the property " + property + " exists.");
        }

        // Fetch the value by calling the getter method.
        Object result;

        try
        {
            result = getterMethod.invoke(callee);
        }

        // This should never happen as the initiliazation method should already have checked this.
        catch (InvocationTargetException e)
        {
            throw new IllegalStateException("The getter method for the property " + property +
                " threw an invocation target exception.", e);
        }

        // This should never happen as the initiliazation method should already have checked this.
        catch (IllegalAccessException e)
        {
            throw new IllegalStateException("The getter method for the property " + property + " cannot be accessed.", e);
        }

        return result;
    }

    /**
     * Checks if a wrapper type is assignable from a primtive type.
     *
     * @param  wrapperType   The wrapper type.
     * @param  primitiveType The primitive type.
     *
     * @return <tt>true</tt> if the wrapper type can be assinged from the primitive.
     */
    private boolean isAssignableFromPrimitive(Class wrapperType, Class primitiveType)
    {
        boolean result = false;

        if (primitiveType.equals(boolean.class) && wrapperType.equals(Boolean.class))
        {
            result = true;
        }
        else if (primitiveType.equals(byte.class) && wrapperType.equals(Byte.class))
        {
            result = true;
        }
        else if (primitiveType.equals(char.class) && wrapperType.equals(Character.class))
        {
            result = true;
        }
        else if (primitiveType.equals(short.class) && wrapperType.equals(Short.class))
        {
            result = true;
        }
        else if (primitiveType.equals(int.class) && wrapperType.equals(Integer.class))
        {
            result = true;
        }
        else if (primitiveType.equals(long.class) && wrapperType.equals(Long.class))
        {
            result = true;
        }
        else if (primitiveType.equals(float.class) && wrapperType.equals(Float.class))
        {
            result = true;
        }
        else if (primitiveType.equals(double.class) && wrapperType.equals(Double.class))
        {
            result = true;
        }
        else
        {
            result = false;
        }

        return result;
    }

    /**
     * Initialized this property introspector on a specified object, building the caches of getter and setter methods.
     *
     * @param callee The object to call the getter and setter methods on.
     */
    private void initialize(Object callee)
    {
        // This is used to build up all the setter methods in.
        Map<String, List<Method>> settersTemp = new HashMap<String, List<Method>>();

        // Get all the property getters and setters on this class.
        Method[] methods = callee.getClass().getMethods();

        for (Method nextMethod : methods)
        {
            String methodName = nextMethod.getName();

            // Check if it is a getter method.
            if (methodName.startsWith("get") && (methodName.length() >= 4) &&
                    Character.isUpperCase(methodName.charAt(3)) && Modifier.isPublic(nextMethod.getModifiers()) &&
                    (nextMethod.getParameterTypes().length == 0))
            {
                String propertyName = methodName.substring(3, 4).toLowerCase() + methodName.substring(4);

                getters.put(propertyName, nextMethod);
            }

            // Check if it is a setter method.
            else if (methodName.startsWith("set") && Modifier.isPublic(nextMethod.getModifiers()) &&
                    (nextMethod.getParameterTypes().length == 1))
            {
                /*log.fine("Found setter method.");*/

                String propertyName = methodName.substring(3, 4).toLowerCase() + methodName.substring(4);
                /*log.fine("propertyName = " + propertyName);*/

                // Check the setter to see if any for this name already exist, and start a new list if not.
                List<Method> setterMethodsForName = settersTemp.get(propertyName);

                if (setterMethodsForName == null)
                {
                    setterMethodsForName = new ArrayList<Method>();
                    settersTemp.put(propertyName, setterMethodsForName);
                }

                // Add the setter method to the list of setter methods for the named property.
                setterMethodsForName.add(nextMethod);
            }
        }

        // Convert all the lists of setter methods into arrays.
        for (Map.Entry<String, List<Method>> entries : settersTemp.entrySet())
        {
            String nextPropertyName = entries.getKey();
            List<Method> nextMethodList = entries.getValue();

            Method[] methodArray = nextMethodList.toArray(new Method[nextMethodList.size()]);
            setters.put(nextPropertyName, methodArray);
        }

        // Initialization completed, set the initialized flag.
        initialized = 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.debugger.monitor;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Map;

import com.thesett.text.api.model.TextTableModel;

/**
 * MemoryLayoutMonitor watches the memory layout registers of the machine, and updates a table model that contains the
 * layout values to those in the register set.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Create a table model to hold the layout register set values.

 *
 Update a table model to the values in the layout register set.

 *

 *
 * @author Rupert Smith
 */
public class MemoryLayoutMonitor implements PropertyChangeListener
{
    /** The register names. */
    private static final String[][] REGISTER_NAMES_BY_COL =
        new String[][]
        {
            { "regBase", "regSize", "heapBase", "heapSize", "stackBase", "stackSize", },
            { "trailBase", "trailSize", "pdlBase", "pdlSize" }
        };

    /** The register property names, used to label the table rows. */
    private static final String[][] REGISTER_LABELS_BY_COL =
        new String[][]
        {
            { "regBase", "regSize", "heapBase", "heapSize", "stackBase", "stackSize", },
            { "trailBase", "trailSize", "pdlBase", "pdlSize" }
        };

    /** The table to store the registers in. */
    private final TextTableModel table;

    /** A labeled view onto the register table. */
    private final Map<String, String> labeledTable;

    /**
     * Constructs a table model with labelled rows and columns to hold the register values.
     *
     * @param table The table to output the register values to.
     */
    public MemoryLayoutMonitor(TextTableModel table)
    {
        this.table = table;
        labeledTable = table.withCellLabels();

        for (int j = 0; j < REGISTER_NAMES_BY_COL.length; j++)
        {
            String[] labelColumn = REGISTER_LABELS_BY_COL[j];

            for (int i = 0; i < labelColumn.length; i++)
            {
                String label = labelColumn[i];
                this.table.labelCell(label, (j * 2) + 1, i);
                this.table.put(j * 2, i, REGISTER_NAMES_BY_COL[j][i]);
                this.table.put((j * 2) + 1, i, "        ");
            }
        }
    }

    /** {@inheritDoc} */
    public void propertyChange(PropertyChangeEvent evt)
    {
        String hex = String.format("%08X", evt.getNewValue());
        labeledTable.put(evt.getPropertyName(), hex);
    }
}


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

/**
 * Implements the integer/1 runtime type check, that checks its argument is instantiated to a float.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Checks that a term is instantiated to a float value.  {@link ResolutionState}.
 *

 *
 * @author Rupert Smith
 */
public class FloatCheck extends BaseBuiltIn implements BuiltIn
{
    /**
     * Creates a float built-in to implement the specified functor.
     *
     * @param functor The functor to implement as a built in.
     */
    public FloatCheck(Functor functor)
    {
        super(functor);
    }

    /** {@inheritDoc} */
    public boolean proofStep(ResolutionState state)
    {
        Functor goalTerm = state.getGoalStack().poll().getFunctor();
        Term argument = goalTerm.getArgument(0).getValue();

        // Check that the argument is not a free variable.
        return argument.isNumber() && ((NumericType) argument.getValue()).isReal();
    }
}


/*
 * 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.learning.decisiontree.prototype;

import java.util.Iterator;

import com.thesett.aima.state.OrdinalAttribute;
import com.thesett.aima.state.State;
import com.thesett.common.util.Tree;

/**
 * A Decision is a switch on the {@link OrdinalAttribute} value of the property of a
 * {@link com.thesett.aima.state.State}. For each possible value of the attribute a decision maps onto a decision tree
 * which implements the remainder of the decision process onto a classification. In addition, a Decision also specifies
 * the output attribute value that a preceding decision must find in the input state in order to procede to this
 * decision.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Perform a choice based on the value of a property of a state.
 *

 *
 * @author Rupert Smith
 */
public class Decision extends DecisionTreeElement
{
    /* Holds the entropy of the decision.*/
    //private double entropy;

    /* Holds the information gain of the decision.*/
    //private double gain;

    /* Holds the gain ratio of the decision.*/
    //private double gainRatio;

    /** Holds the name of the property that this decision acts on. */
    private final String propertyName;

    /** Holds the number of outcomes that the decision can have. */
    private final int numOutcomes;

    /**
     * Holds a lookup table from the ordinal of the possible attribute values to the child decision tree that computes
     * the remainder of the decision.
     */
    private DecisionTree[] decisions;

    /**
     * Builds a decision on the named property with the specified number of outcomes. The number of decision outcomes is
     * equal to the number of possible values that the property can take on.
     *
     * @param property    The property to decide on.
     * @param numOutcomes The number of possible values that the property can take (this must be finite).
     * @param matching    the matching attribute value that a parent decision must match in order to arrive at this
     *                    decision node.
     */
    public Decision(String property, int numOutcomes, OrdinalAttribute matching)
    {
        // Keep the property name and number of possible values.
        this.propertyName = property;
        this.numOutcomes = numOutcomes;

        // Keep the attribute that the parent decision must match to follow this branch in the decision tree.
        attributeValue = matching;

        // Create a lookup table big enough to hold all the possible outcomes.
        decisions = new DecisionTree[numOutcomes];
    }

    /**
     * Gets the number of outcomes that this decision can have.
     *
     * @return The number of possible outcomes that this decision can have.
     */
    public int getNumOutcomes()
    {
        return numOutcomes;
    }

    /**
     * Performs the actual decision based on a property of the state. If the quick lookup table has been initialized
     * then the decision is taken straight from it. If not then the supplied reference to the decision tree at this
     * point is used to find the outcome by scanning over its children.
     *
     * @param  state the {@link com.thesett.aima.state.State} to decide on.
     *
     * @return a {@link DecisionTree} to continue the decision process with.
     */
    public DecisionTree decide(State state)
    {
        // Extract the value of the property being decided from state to be classified.
        OrdinalAttribute attributeValue = (OrdinalAttribute) state.getProperty(propertyName);

        // Extract the child decision tree that matches the property value, using the attributes ordinal for a quick
        // look up.
        return decisions[attributeValue.ordinal()];
    }

    /**
     * Initializes the lookup table for this decision node. The specified decision tree that corresponds to this node is
     * used to extract all the possible outcomes for this decision and these are stored in a lookup table so that future
     * decisions made with this tree will run faster.
     *
     * @param thisNode the decision tree that this decision node is the element from.
     */
    public void initializeLookups(DecisionTree thisNode)
    {
        // Scan over all the decision trees children at this point inserting them into the lookup table depending
        // on the ordinal of the attribute value that matches them.
        for (Iterator<Tree<DecisionTreeElement>> i = thisNode.getChildIterator(); i.hasNext();)
        {
            DecisionTree nextChildTree = (DecisionTree) i.next();

            // Get the matching attribute value from the childs decision tree element.
            OrdinalAttribute matchingValue = nextChildTree.getElement().getAttributeValue();

            // Insert the matching sub-tree into the lookup table.
            decisions[matchingValue.ordinal()] = nextChildTree;
        }
    }
}


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

import com.thesett.aima.logic.fol.Functor;
import com.thesett.aima.logic.fol.Term;
import com.thesett.aima.logic.fol.TermUtils;
import com.thesett.aima.logic.fol.Unifier;
import com.thesett.aima.logic.fol.Variable;

/**
 * A prolog unifier is a single threaded unification algorithm that ommits the occurs check. Ommitting the occurs check
 * makes it logically unsound, but in practice this is avoided by the carefull arrangement of prolog style logic
 * programs.
 *
 *
This unification algorithm is based on the one presented on page 303 of Artificial Intelligence a Modern
 * Approach, the basic outline of that algorithm is still present, but the details have changed significantly.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Attempt to unify two terms.  {@link Term}
 *

 *
 * @author Rupert Smith
 */
public class PrologUnifier implements Unifier<Term>
{
    /** Used for debugging. */
    /* private static final Logger log = Logger.getLogger(PrologUnifier.class.getName()); */

    /**
     * Unifies two terms and produces a list of bound variables that form the unification, when it it possible.
     *
     * @param  query     The left term to unify.
     * @param  statement The right term to unify.
     *
     * @return A list of bound variables to form the unification, or <tt>null</tt> when no unification is possible.
     */
    public List<Variable> unify(Term query, Term statement)
    {
        /*log.fine("unify(Term left = " + query + ", Term right = " + statement + "): called");*/

        // Find all free variables in the query.
        Set<Variable> freeVars = TermUtils.findFreeNonAnonymousVariables(query);

        // Build up all the variable bindings in both sides of the unification in these bindings.
        List<Variable> queryBindings = new LinkedList<Variable>();
        List<Variable> statementBindings = new LinkedList<Variable>();

        // Fund the most general unifier, if possible.
        boolean unified = unifyInternal(query, statement, queryBindings, statementBindings);
        List<Variable> results = null;

        // If a unification was found, only retain the free variables in the query in the results returned.
        if (unified)
        {
            queryBindings.retainAll(freeVars);
            results = new ArrayList<Variable>(queryBindings);
        }

        return results;
    }

    /**
     * Attempts to unify one term with another, against a background of already unified variables in both terms. In the
     * case where two terms are being unified from scratch the variable assignments will be empty.
     *
     * @param  left       The left hand term to unify with.
     * @param  right      The right hand term to unify against.
     * @param  leftTrail  The trail of bound variables in the left hand term.
     * @param  rightTrail The trail of bound variables in the right hand term.
     *
     * @return <tt>true</tt> if the terms were unified, <tt>false</tt> otherwise.
     */
    public boolean unifyInternal(Term left, Term right, List<Variable> leftTrail, List<Variable> rightTrail)
    {
        /*log.fine("public boolean unifyInternal(Term left = " + left + ", Term right = " + right +
            ", List<Variable> trail = " + leftTrail + "): called");*/

        if (left == right)
        {
            /*log.fine("Terms are identical objects.");*/

            return true;
        }

        if (!left.isVar() && !right.isVar() && left.isConstant() && right.isConstant() && left.equals(right))
        {
            /*log.fine("Terms are equal atoms or literals.");*/

            return true;
        }
        else if (left.isVar())
        {
            /*log.fine("Left is a variable.");*/

            return unifyVar((Variable) left, right, leftTrail, rightTrail);
        }
        else if (right.isVar())
        {
            /*log.fine("Right is a variable.");*/

            return unifyVar((Variable) right, left, rightTrail, leftTrail);
        }
        else if (left.isFunctor() && right.isFunctor())
        {
            /*log.fine("Terms are functors, at least one of which is not an atom.");*/

            Functor leftFunctor = (Functor) left;
            Functor rightFunctor = (Functor) right;

            // Check if the functors may be not be equal (that is, they do not have the same name and arity), in
            // which case they cannot possibly be unified.
            if (!left.equals(right))
            {
                return false;
            }

            /*log.fine("Terms are functors with same name and arity, both are compound.");*/

            // Pairwise unify all of the arguments of the functor.
            int arity = leftFunctor.getArity();

            for (int i = 0; i < arity; i++)
            {
                Term leftArgument = leftFunctor.getArgument(i);
                Term rightArgument = rightFunctor.getArgument(i);

                boolean result = unifyInternal(leftArgument, rightArgument, leftTrail, rightTrail);

                if (!result)
                {
                    /*log.fine("Non unifying arguments in functors encountered, left = " + leftArgument + ", right = " +
                        rightArgument);*/

                    return false;
                }
            }

            return true;
        }
        else
        {
            return false;
        }
    }

    /**
     * Unifies a variable with a term. If the variable is bound, then the bound value is unified with the term. If the
     * term is a bound variable, and the variable is free, then the vairable is unified with the bound value of the
     * term. Otherwise, the variable is free and is bound to the value of the term.
     *
     * @param  leftVar    The variable to unify.
     * @param  rightTerm  The term to unify against.
     * @param  leftTrail  The built up trail of substitutions in the left hand side.
     * @param  rightTrail The built up trail of substitutions in the right hand side.
     *
     * @return <tt>true</tt> if the variable unifies with the term, <tt>false</tt> otherwise.
     */
    protected boolean unifyVar(Variable leftVar, Term rightTerm, List<Variable> leftTrail, List<Variable> rightTrail)
    {
        /*log.fine("protected boolean unifyVar(Variable var = " + leftVar + ", Term term = " + rightTerm +
            ", List<Variable> trail = " + leftTrail + "): called");*/

        // Check if the variable is bound (in the trail, but no need to explicitly check the trail as the binding is
        // already held against the variable).
        if (leftVar.isBound())
        {
            /*log.fine("Variable is bound.");*/

            return unifyInternal(leftVar.getValue(), rightTerm, leftTrail, rightTrail);
        }
        else if (rightTerm.isVar() && ((Variable) rightTerm).isBound())
        {
            // The variable is free, but the term itself is a bound variable, in which case unify againt the value
            // of the term.
            /*log.fine("Term is a bound variable.");*/

            return unifyInternal(leftVar, rightTerm.getValue(), leftTrail, rightTrail);
        }
        else
        {
            // Otherwise, unify by binding the variable to the value of the term.
            /*log.fine("Variable is free, substituting in the term for it.");*/
            leftVar.setSubstitution(rightTerm);
            leftTrail.add(leftVar.getStorageCell(leftVar));
            //leftTrail.add(leftVar);

            return true;
        }

        // Occurs can go above if desired.
        /*else if (var occurs anywhere in x)
        {
            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.logic.fol.wam.compiler;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

import com.thesett.aima.logic.fol.AllTermsVisitor;
import com.thesett.aima.logic.fol.Clause;
import com.thesett.aima.logic.fol.DelegatingAllTermsVisitor;
import com.thesett.aima.logic.fol.Functor;
import com.thesett.aima.logic.fol.FunctorName;
import com.thesett.aima.logic.fol.LogicCompiler;
import com.thesett.aima.logic.fol.LogicCompilerObserver;
import com.thesett.aima.logic.fol.PositionalTermVisitor;
import com.thesett.aima.logic.fol.Sentence;
import com.thesett.aima.logic.fol.Term;
import com.thesett.aima.logic.fol.TermUtils;
import com.thesett.aima.logic.fol.Variable;
import com.thesett.aima.logic.fol.VariableAndFunctorInterner;
import com.thesett.aima.logic.fol.compiler.PositionalTermTraverser;
import com.thesett.aima.logic.fol.compiler.PositionalTermTraverserImpl;
import com.thesett.aima.logic.fol.compiler.TermWalker;
import com.thesett.aima.logic.fol.wam.TermWalkers;
import com.thesett.aima.logic.fol.wam.builtins.BuiltIn;
import com.thesett.aima.logic.fol.wam.builtins.Cut;
import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.REG_ADDR;
import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.STACK_ADDR;
import com.thesett.aima.logic.fol.wam.machine.WAMMachine;
import com.thesett.aima.logic.fol.wam.optimizer.Optimizer;
import com.thesett.aima.logic.fol.wam.optimizer.WAMOptimizer;
import com.thesett.aima.logic.fol.wam.printer.WAMCompiledPredicatePrintingVisitor;
import com.thesett.aima.logic.fol.wam.printer.WAMCompiledQueryPrintingVisitor;
import com.thesett.aima.logic.fol.wam.printer.WAMCompiledTermsPrintingVisitor;
import com.thesett.aima.search.QueueBasedSearchMethod;
import com.thesett.aima.search.SearchMethod;
import com.thesett.aima.search.util.Searches;
import com.thesett.aima.search.util.backtracking.DepthFirstBacktrackingSearch;
import com.thesett.aima.search.util.uninformed.BreadthFirstSearch;
import com.thesett.common.parsing.SourceCodeException;
import com.thesett.common.util.SizeableLinkedList;
import com.thesett.common.util.SizeableList;
import com.thesett.common.util.doublemaps.SymbolKey;
import com.thesett.common.util.doublemaps.SymbolTable;

/**
 * WAMCompiled implements a compiler for the logical language, WAM, into a form suitable for passing to an
 * {@link WAMMachine}. The WAMMachine accepts sentences in the language that are compiled into a byte code form. The
 * byte instructions used in the compiled language are enumerated as constants in the {@link WAMInstruction} class.
 *
 *
The compilation process is described in "Warren's Abstract Machine, A Tutorial Reconstruction, by Hassan
 * Ait-Kaci" and is followed as closely as possible to the WAM compiler given there. The description of the L0
 * compilation process is very clear in the text but the WAM compilation is a little ambiguous. It does not fully
 * describe the flattening process and presents some conflicting examples of register assignment. (The flattening
 * process is essentially the same as for L0, except that each argument of the outermost functor is flattened/compiled
 * independently). The register assignment process is harder to fathom, on page 22, the register assignment for p(Z,
 * h(Z,W), f(W)) is presented with the following assignment given:
 *
 *

 * A1 = Z
 * A2 = h(A1,X4)
 * A3 = f(X4)
 * X4 = W
 *

 *
 * In figure 2.9 a compilation example is given, from which it can be seen that the assignment should be:
 *
 *

 * A1 = Z (loaded from X4)
 * A2 = h(X4,X5)
 * A3 = f(X5)
 * X4 = Z
 * X5 = W
 *

 *
 *
From figure 2.9 it was concluded that argument registers may only be assigned to functors. Functors can be
 * created on the heap and assigned to argument registers directly. Argument registers for variables, should be loaded
 * from a separate register assigned to the variable, that comes after the argument registers; so that a variable
 * assignment can be copied into multiple arguments, where the same variable is presented multiple times in a predicate
 * call. The register assignment process is carried out in two phases to do this, the first pass covers the argument
 * registers and the arguments of the outermost functor, only assigning to functors, the second pass continues for
 * higher numbered registers, starts again at the beginning of the arguments, and assigns to variables and functors (not
 * already assigned) as for the L0 process.
 *
 *
A brief overview of the compilation process is:
 *
 *

 *
Terms to be compiled are allocated registers, breadth first, enumerating from outermost functors down to
 *    innermost atoms or variables.

 *
The outermost functor itself is treated specially, and is not allocated to a register. Its i arguments are
 *     allocated to registers, and are additionally associated with the first i argument registers. The outermost functor
 *     is the instigator of a call, in the case of queries, or the recipient of a call, in the case of programs.
 *
Queries are 'flattened' by traversing each of their arguments in postfix order of their functors, then exploring
 *     the functors arguments.

 *
Programs are 'flattened' by traversing each of their arguments breadth first, the same as for the original
 *     register allocation, then exploring the functors arguments.

 *

 *
 *
Query terms are compiled into a sequence of instructions, that build up a representation of their argument terms,
 * to be unified, on the heap, and assigning registers to refer to those terms on the heap, then calling the matching
 * program for the query terms name and arity. Program terms are compiled into a sequence of instructions that, when run
 * against the argument registers, attempt to unify all of the arguments with the heap.
 *
 *
The effect of flattening queries using a post fix ordering, is that the values of inner functors and variables
 * are loaded into registers first, before their containing functor is executed, which writes the functor and its
 * arguments onto the heap. Programs do not need to be expanded in this way, they simply match functors followed by
 * their arguments against the heap, so a breadth first traversal is all that is needed.
 *
 *
Evaluating a flattened query consists of doing the following as different query tokens are encountered:
 *
 *

 *
For the outermost functor, process all arguments, then make a CALL (functor) to the matching program.
 *
For a register associated with an inner functor, push an STR onto the heap and copy that cell into the register.
 *     A put_struc (functor, register) instruction is created for this.

 *
For a variable in argument position i in the outermost functor, push a REF onto the heap that refers to itself,
 *     and copy that value into that variables register, as well as argument register i. A put_var (register, register)
 *     instruction is emitted for this.
 *
For a register argument of an inner functor, not previously seen, push a REF onto the heap that refers to itself,
 *     and copy that cell into the register. A set_var (register) instruction is emitted for this.

 *
For a variables in argument position i in the outermost functor, previously seen, copy its assigned register
 *     into its argument register. A put_val (register, register) instruction is emitted for this.

 *
For a register argument previously seen, push a new cell onto the heap and copy into it the register's value.
 *     A set_val (register) instruction is emitted for this.

 *

 *
 *
Evaluating a flattened program consists of doing the following as different program tokens are encountered:
 *
 *

 *
For the outermost functor, process all arguments, then execute a PROCEED instruction to indicate success.
 *
For a register associated with an inner functor, load that register with a reference to the functor. A get_struc
 *     (functor, register) instruction is created for this.

 *
For a variable in argument position i in the outermost functor, copy its argument register into its assigned
 *     register. A get_var (register, register) instruction is emitted for this.
 *
For a register argument of an inner functor, not previously seen, bind that register to its argument. A
 *     unify_var (register) instruction is output for this.

 *
For a variable in argument position i in the outermost functor, unify its assigned register with the
 *     argument register. A get_val (register, register) instruction is emitted for this.

 *
For a register argument of an inner functor, previously seen, unify that register against the heap. A
 *     unify_val (register) instruction is emitted for this.

 *

 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Transform WAM sentences into compiled byte code.
 *      {@link WAMMachine}, {@link WAMCompiledPredicate}
 *

 *
 * @author Rupert Smith
 */
public class InstructionCompiler extends DefaultBuiltIn
    implements LogicCompiler<Clause, WAMCompiledPredicate, WAMCompiledQuery>
{
    /** Used for debugging. */
    /* private static final Logger log = Logger.getLogger(InstructionCompiler.class.getName()); */

    /** Holds a list of all predicates encountered in the current scope. */
    protected Queue<SymbolKey> predicatesInScope = new LinkedList<SymbolKey>();

    /** Holds the compiler output observer. */
    private LogicCompilerObserver<WAMCompiledPredicate, WAMCompiledQuery> observer;

    /** This is used to keep track of the number of permanent variables. */
    protected int numPermanentVars;

    /**
     * This is used to keep track of the position of the cut level variable, for deep cuts, if there is one. <tt>-1</tt>
     * means no deep cut exists in the clause, and a value gte to zero means there is one, and references its slot.
     */
    protected int cutLevelVarSlot = -1;

    /** Keeps count of the current compiler scope, to keep symbols in each scope fresh. */
    protected int scope;

    /** Holds the current nested compilation scope symbol table. */
    private SymbolTable<Integer, String, Object> scopeTable;

    /** Holds the instruction optimizer. */
    private final Optimizer optimizer;

    /**
     * Creates a new InstructionCompiler.
     *
     * @param symbolTable The symbol table.
     * @param interner    The machine to translate functor and variable names.
     */
    protected InstructionCompiler(SymbolTable<Integer, String, Object> symbolTable, VariableAndFunctorInterner interner)
    {
        super(symbolTable, interner);
        optimizer = new WAMOptimizer(symbolTable, interner);
    }

    /** {@inheritDoc} */
    public void setCompilerObserver(LogicCompilerObserver<WAMCompiledPredicate, WAMCompiledQuery> observer)
    {
        this.observer = observer;
    }

    /** {@inheritDoc} */
    public void endScope() throws SourceCodeException
    {
        // Loop over all predicates in the current scope, found in the symbol table, and consume and compile them.
        for (SymbolKey predicateKey = predicatesInScope.poll(); predicateKey != null;
                predicateKey = predicatesInScope.poll())
        {
            List<Clause> clauseList = (List<Clause>) scopeTable.get(predicateKey, SymbolTableKeys.SYMKEY_PREDICATES);

            // Used to keep track of where within the predicate the current clause is.
            int size = clauseList.size();
            int current = 0;
            boolean multipleClauses = size > 1;

            // Used to build up the compiled predicate in.
            WAMCompiledPredicate result = null;

            for (Iterator<Clause> iterator = clauseList.iterator(); iterator.hasNext(); iterator.remove())
            {
                Clause clause = iterator.next();

                if (result == null)
                {
                    result = new WAMCompiledPredicate(clause.getHead().getName());
                }

                // Compile the single clause, adding it to the parent compiled predicate.
                compileClause(clause, result, current == 0, current >= (size - 1), multipleClauses, current);
                current++;
            }

            // Run the optimizer on the output.
            result = optimizer.apply(result);

            displayCompiledPredicate(result);
            observer.onCompilation(result);

            // Move up the low water mark on the predicates table.
            symbolTable.setLowMark(predicateKey, SymbolTableKeys.SYMKEY_PREDICATES);
        }

        // Clear up the symbol table, and bump the compilation scope up by one.
        symbolTable.clearUpToLowMark(SymbolTableKeys.SYMKEY_PREDICATES);
        scopeTable = null;
        scope++;
    }

    /**
     * {@inheritDoc}
     *
     *
Compiles a sentence into a binary form, that provides a Java interface into the compiled structure.
     *
     *
The clausal sentence may be a query, or a program statement. If it is a query, it is compiled immediately. If
     * it is a clause, it is retained against the predicate which it forms part of, and compiled on the
     * {@link #endScope()} method is invoked.
     */
    public void compile(Sentence<Clause> sentence) throws SourceCodeException
    {
        /*log.fine("public WAMCompiledClause compile(Sentence<Term> sentence = " + sentence + "): called");*/

        // Extract the clause to compile from the parsed sentence.
        Clause clause = sentence.getT();

        // Classify the sentence to compile by the different sentence types in the language.
        if (clause.isQuery())
        {
            compileQuery(clause);
        }
        else
        {
            // Initialise a nested symbol table for the current compilation scope, if it has not already been.
            if (scopeTable == null)
            {
                scopeTable = symbolTable.enterScope(scope);
            }

            // Check in the symbol table, if a compiled predicate with name matching the program clause exists, and if
            // not create it.
            SymbolKey predicateKey = scopeTable.getSymbolKey(clause.getHead().getName());
            Collection<Clause> clauseList = (List<Clause>) scopeTable.get(predicateKey, SymbolTableKeys.SYMKEY_PREDICATES);

            if (clauseList == null)
            {
                clauseList = new LinkedList<Clause>();
                scopeTable.put(predicateKey, SymbolTableKeys.SYMKEY_PREDICATES, clauseList);
                predicatesInScope.offer(predicateKey);
            }

            // Add the clause to compile to its parent predicate for compilation at the end of the current scope.
            clauseList.add(clause);
        }
    }

    /**
     * Compiles a program clause, and adds its instructions to a compiled predicate.
     *
     * @param  clause            The source clause to compile.
     * @param  compiledPredicate The predicate to add instructions to.
     * @param  isFirst           <tt>true</tt> iff the clause is the first in the predicate.
     * @param  isLast            <tt>true</tt> iff the clause is the last in the predicate.
     * @param  multipleClauses   <tt>true</tt> iff the predicate contains >1 clause.
     * @param  clauseNumber      The position of the clause within the predicate.
     *
     * @throws SourceCodeException If there is an error in the source code preventing its compilation.
     */
    private void compileClause(Clause clause, WAMCompiledPredicate compiledPredicate, boolean isFirst, boolean isLast,
        boolean multipleClauses, int clauseNumber) throws SourceCodeException
    {
        // Used to build up the compiled clause in.
        WAMCompiledClause result = new WAMCompiledClause(compiledPredicate);

        // Check if the clause to compile is a fact (no body).
        boolean isFact = clause.getBody() == null;

        // Check if the clause to compile is a chain rule, (one called body).
        boolean isChainRule = (clause.getBody() != null) && (clause.getBody().length == 1);

        // Used to keep track of registers as they are seen during compilation. The first time a variable is seen,
        // a variable is written onto the heap, subsequent times its value. The first time a functor is seen,
        // its structure is written onto the heap, subsequent times it is compared with.
        seenRegisters = new TreeSet<Integer>();

        // This is used to keep track of the next temporary register available to allocate.
        lastAllocatedTempReg = findMaxArgumentsInClause(clause);

        // This is used to keep track of the number of permanent variables.
        numPermanentVars = 0;

        // This is used to keep track of the allocation slot for the cut level variable, when needed. -1 means it is
        // not needed, so it is initialized to this.
        cutLevelVarSlot = -1;

        // These are used to generate pre and post instructions for the clause, for example, for the creation and
        // clean-up of stack frames.
        SizeableList<WAMInstruction> preFixInstructions = new SizeableLinkedList<WAMInstruction>();
        SizeableList<WAMInstruction> postFixInstructions = new SizeableLinkedList<WAMInstruction>();

        // Find all the free non-anonymous variables in the clause.
        Set<Variable> freeVars = TermUtils.findFreeNonAnonymousVariables(clause);
        Collection<Integer> freeVarNames = new TreeSet<Integer>();

        for (Variable var : freeVars)
        {
            freeVarNames.add(var.getName());
        }

        // Allocate permanent variables for a program clause. Program clauses only use permanent variables when really
        // needed to preserve variables across calls.
        allocatePermanentProgramRegisters(clause);

        // Gather information about the counts and positions of occurrence of variables and constants within the clause.
        gatherPositionAndOccurrenceInfo(clause);

        // Labels the entry point to each choice point.
        FunctorName fn = interner.getFunctorFunctorName(clause.getHead());
        WAMLabel entryLabel = new WAMLabel(fn, clauseNumber);

        // Label for the entry point to the next choice point, to backtrack to.
        WAMLabel retryLabel = new WAMLabel(fn, clauseNumber + 1);

        // Create choice point instructions for the clause, depending on its position within the containing predicate.
        // The choice point instructions are only created when a predicate is built from multiple clauses, as otherwise
        // there are no choices to be made.
        if (isFirst && !isLast && multipleClauses)
        {
            // try me else.
            preFixInstructions.add(new WAMInstruction(entryLabel, WAMInstruction.WAMInstructionSet.TryMeElse,
                    retryLabel));
        }
        else if (!isFirst && !isLast && multipleClauses)
        {
            // retry me else.
            preFixInstructions.add(new WAMInstruction(entryLabel, WAMInstruction.WAMInstructionSet.RetryMeElse,
                    retryLabel));
        }
        else if (isLast && multipleClauses)
        {
            // trust me.
            preFixInstructions.add(new WAMInstruction(entryLabel, WAMInstruction.WAMInstructionSet.TrustMe));
        }

        // Generate the prefix code for the clause.
        // Rules may chain multiple, so require stack frames to preserve registers across calls.
        // Facts are always leafs so can use the global continuation point register to return from calls.
        // Chain rules only make one call, so also do not need a stack frame.
        if (!(isFact || isChainRule))
        {
            // Allocate a stack frame at the start of the clause.
            /*log.fine("ALLOCATE " + numPermanentVars);*/
            preFixInstructions.add(new WAMInstruction(WAMInstruction.WAMInstructionSet.Allocate));
        }

        // Deep cuts require the current choice point to be kept in a permanent variable, so that it can be recovered
        // once deeper choice points or environments have been reached.
        if (cutLevelVarSlot >= 0)
        {
            /*log.fine("GET_LEVEL "+ cutLevelVarSlot);*/
            preFixInstructions.add(new WAMInstruction(WAMInstruction.WAMInstructionSet.GetLevel,
                    (byte) cutLevelVarSlot));
        }

        result.addInstructions(preFixInstructions);

        // Compile the clause head.
        Functor expression = clause.getHead();

        SizeableLinkedList<WAMInstruction> instructions = compileHead(expression);
        result.addInstructions(expression, instructions);

        // Compile all of the conjunctive parts of the body of the clause, if there are any.
        if (!isFact)
        {
            Functor[] expressions = clause.getBody();

            for (int i = 0; i < expressions.length; i++)
            {
                expression = expressions[i];

                boolean isLastBody = i == (expressions.length - 1);
                boolean isFirstBody = i == 0;

                Integer permVarsRemaining =
                    (Integer) symbolTable.get(expression.getSymbolKey(), SymbolTableKeys.SYMKEY_PERM_VARS_REMAINING);

                // Select a non-default built-in implementation to compile the functor with, if it is a built-in.
                BuiltIn builtIn;

                if (expression instanceof BuiltIn)
                {
                    builtIn = (BuiltIn) expression;
                }
                else
                {
                    builtIn = this;
                }

                // The 'isFirstBody' parameter is only set to true, when this is the first functor of a rule.
                instructions = builtIn.compileBodyArguments(expression, i == 0, fn, i);
                result.addInstructions(expression, instructions);

                // Call the body. The number of permanent variables remaining is specified for environment trimming.
                instructions =
                    builtIn.compileBodyCall(expression, isFirstBody, isLastBody, isChainRule, permVarsRemaining);
                result.addInstructions(expression, instructions);
            }
        }

        // Generate the postfix code for the clause. Rules may chain, so require stack frames.
        // Facts are always leafs so can use the global continuation point register to return from calls.
        if (isFact)
        {
            /*log.fine("PROCEED");*/
            postFixInstructions.add(new WAMInstruction(WAMInstruction.WAMInstructionSet.Proceed));
        }

        result.addInstructions(postFixInstructions);
    }

    /**
     * Compiles a clause as a query. The clause should have no head, only a body.
     *
     * @param  clause The clause to compile as a query.
     *
     * @throws SourceCodeException If there is an error in the source code preventing its compilation.
     */
    private void compileQuery(Clause clause) throws SourceCodeException
    {
        // Used to build up the compiled result in.
        WAMCompiledQuery result;

        // A mapping from top stack frame slots to interned variable names is built up in this.
        // This is used to track the stack positions that variables in a query are assigned to.
        Map<Byte, Integer> varNames = new TreeMap<Byte, Integer>();

        // Used to keep track of registers as they are seen during compilation. The first time a variable is seen,
        // a variable is written onto the heap, subsequent times its value. The first time a functor is seen,
        // its structure is written onto the heap, subsequent times it is compared with.
        seenRegisters = new TreeSet<Integer>();

        // This is used to keep track of the next temporary register available to allocate.
        lastAllocatedTempReg = findMaxArgumentsInClause(clause);

        // This is used to keep track of the number of permanent variables.
        numPermanentVars = 0;

        // This is used to keep track of the allocation slot for the cut level variable, when needed. -1 means it is
        // not needed, so it is initialized to this.
        cutLevelVarSlot = -1;

        // These are used to generate pre and post instructions for the clause, for example, for the creation and
        // clean-up of stack frames.
        SizeableList<WAMInstruction> preFixInstructions = new SizeableLinkedList<WAMInstruction>();
        SizeableList<WAMInstruction> postFixInstructions = new SizeableLinkedList<WAMInstruction>();

        // Find all the free non-anonymous variables in the clause.
        Set<Variable> freeVars = TermUtils.findFreeNonAnonymousVariables(clause);
        Set<Integer> freeVarNames = new TreeSet<Integer>();

        for (Variable var : freeVars)
        {
            freeVarNames.add(var.getName());
        }

        // Allocate permanent variables for a query. In queries all variables are permanent so that they are preserved
        // on the stack upon completion of the query.
        allocatePermanentQueryRegisters(clause, varNames);

        // Gather information about the counts and positions of occurrence of variables and constants within the clause.
        gatherPositionAndOccurrenceInfo(clause);

        result = new WAMCompiledQuery(varNames, freeVarNames);

        // Generate the prefix code for the clause. Queries require a stack frames to hold their environment.
        /*log.fine("ALLOCATE " + numPermanentVars);*/
        preFixInstructions.add(new WAMInstruction(WAMInstruction.WAMInstructionSet.AllocateN, REG_ADDR,
                (byte) (numPermanentVars & 0xff)));

        // Deep cuts require the current choice point to be kept in a permanent variable, so that it can be recovered
        // once deeper choice points or environments have been reached.
        if (cutLevelVarSlot >= 0)
        {
            /*log.fine("GET_LEVEL "+ cutLevelVarSlot);*/
            preFixInstructions.add(new WAMInstruction(WAMInstruction.WAMInstructionSet.GetLevel, STACK_ADDR,
                    (byte) cutLevelVarSlot));
        }

        result.addInstructions(preFixInstructions);

        // Compile all of the conjunctive parts of the body of the clause, if there are any.
        Functor[] expressions = clause.getBody();

        // The current query does not have a name, so invent one for it.
        FunctorName fn = new FunctorName("tq", 0);

        for (int i = 0; i < expressions.length; i++)
        {
            Functor expression = expressions[i];
            boolean isFirstBody = i == 0;

            // Select a non-default built-in implementation to compile the functor with, if it is a built-in.
            BuiltIn builtIn;

            if (expression instanceof BuiltIn)
            {
                builtIn = (BuiltIn) expression;
            }
            else
            {
                builtIn = this;
            }

            // The 'isFirstBody' parameter is only set to true, when this is the first functor of a rule, which it
            // never is for a query.
            SizeableLinkedList<WAMInstruction> instructions = builtIn.compileBodyArguments(expression, false, fn, i);
            result.addInstructions(expression, instructions);

            // Queries are never chain rules, and as all permanent variables are preserved, bodies are never called
            // as last calls.
            instructions = builtIn.compileBodyCall(expression, isFirstBody, false, false, numPermanentVars);
            result.addInstructions(expression, instructions);
        }

        // Generate the postfix code for the clause.
        /*log.fine("DEALLOCATE");*/
        postFixInstructions.add(new WAMInstruction(WAMInstruction.WAMInstructionSet.Suspend));
        postFixInstructions.add(new WAMInstruction(WAMInstruction.WAMInstructionSet.Deallocate));

        result.addInstructions(postFixInstructions);

        // Run the optimizer on the output.
        result = optimizer.apply(result);

        displayCompiledQuery(result);

        observer.onQueryCompilation(result);
    }

    /**
     * Examines all top-level functors within a clause, including any head and body, and determines which functor has
     * the highest number of arguments.
     *
     * @param  clause The clause to determine the highest number of arguments within.
     *
     * @return The highest number of arguments within any top-level functor in the clause.
     */
    private int findMaxArgumentsInClause(Clause clause)
    {
        int result = 0;

        Functor head = clause.getHead();

        if (head != null)
        {
            result = head.getArity();
        }

        Functor[] body = clause.getBody();

        if (body != null)
        {
            for (int i = 0; i  result) ? arity : result;
            }
        }

        return result;
    }

    /**
     * Compiles the head of a clause into an instruction listing in WAM.
     *
     * @param  expression The clause head to compile.
     *
     * @return A listing of the instructions for the clause head in the WAM instruction set.
     */
    private SizeableLinkedList<WAMInstruction> compileHead(Functor expression)
    {
        // Used to build up the results in.
        SizeableLinkedList<WAMInstruction> instructions = new SizeableLinkedList<WAMInstruction>();

        // Allocate argument registers on the body, to all functors as outermost arguments.
        // Allocate temporary registers on the body, to all terms not already allocated.
        allocateArgumentRegisters(expression);
        allocateTemporaryRegisters(expression);

        // Program instructions are generated in the same order as the registers are assigned, the postfix
        // ordering used for queries is not needed.
        SearchMethod outInSearch = new BreadthFirstSearch<Term, Term>();
        outInSearch.reset();
        outInSearch.addStartState(expression);

        Iterator<Term> treeWalker = Searches.allSolutions(outInSearch);

        // Skip the outermost functor.
        treeWalker.next();

        // Allocate argument registers on the body, to all functors as outermost arguments.
        // Allocate temporary registers on the body, to all terms not already allocated.

        // Keep track of processing of the arguments to the outermost functor as get_val and get_var instructions
        // need to be output for variables encountered in the arguments only.
        int numOutermostArgs = expression.getArity();

        for (int j = 0; treeWalker.hasNext(); j++)
        {
            Term nextTerm = treeWalker.next();

            /*log.fine("nextTerm = " + nextTerm);*/

            // For each functor encountered: get_struc.
            if (nextTerm.isFunctor())
            {
                Functor nextFunctor = (Functor) nextTerm;
                int allocation =
                    (Integer) symbolTable.get(nextFunctor.getSymbolKey(), SymbolTableKeys.SYMKEY_ALLOCATION);

                byte addrMode = (byte) ((allocation & 0xff00) >> 8);
                byte address = (byte) (allocation & 0xff);

                // Ouput a get_struc instruction, except on the outermost functor.
                /*log.fine("GET_STRUC " + interner.getFunctorName(nextFunctor) + "/" + nextFunctor.getArity() +
                    ((addrMode == REG_ADDR) ? ", X" : ", Y") + address);*/

                WAMInstruction instruction =
                    new WAMInstruction(WAMInstruction.WAMInstructionSet.GetStruc, addrMode, address,
                        interner.getFunctorFunctorName(nextFunctor), nextFunctor);
                instructions.add(instruction);

                // For each argument of the functor.
                int numArgs = nextFunctor.getArity();

                for (int i = 0; i < numArgs; i++)
                {
                    Term nextArg = nextFunctor.getArgument(i);
                    allocation = (Integer) symbolTable.get(nextArg.getSymbolKey(), SymbolTableKeys.SYMKEY_ALLOCATION);
                    addrMode = (byte) ((allocation & 0xff00) >> 8);
                    address = (byte) (allocation & 0xff);

                    /*log.fine("nextArg = " + nextArg);*/

                    // If it is register not seen before: unify_var.
                    // If it is register seen before: unify_val.
                    if (!seenRegisters.contains(allocation))
                    {
                        /*log.fine("UNIFY_VAR " + ((addrMode == REG_ADDR) ? "X" : "Y") + address);*/

                        seenRegisters.add(allocation);

                        instruction =
                            new WAMInstruction(WAMInstruction.WAMInstructionSet.UnifyVar, addrMode, address, nextArg);

                        // Record the way in which this variable was introduced into the clause.
                        symbolTable.put(nextArg.getSymbolKey(), SymbolTableKeys.SYMKEY_VARIABLE_INTRO,
                            VarIntroduction.Unify);
                    }
                    else
                    {
                        // Check if the variable is 'local' and use a local instruction on the first occurrence.
                        VarIntroduction introduction =
                            (VarIntroduction) symbolTable.get(nextArg.getSymbolKey(),
                                SymbolTableKeys.SYMKEY_VARIABLE_INTRO);

                        if (isLocalVariable(introduction, addrMode))
                        {
                            /*log.fine("UNIFY_LOCAL_VAL " + ((addrMode == REG_ADDR) ? "X" : "Y") +
                                address);*/

                            instruction =
                                new WAMInstruction(WAMInstruction.WAMInstructionSet.UnifyLocalVal, addrMode, address,
                                    nextArg);

                            symbolTable.put(nextArg.getSymbolKey(), SymbolTableKeys.SYMKEY_VARIABLE_INTRO, null);
                        }
                        else
                        {
                            /*log.fine("UNIFY_VAL " + ((addrMode == REG_ADDR) ? "X" : "Y") + address);*/

                            instruction =
                                new WAMInstruction(WAMInstruction.WAMInstructionSet.UnifyVal, addrMode, address,
                                    nextArg);
                        }
                    }

                    instructions.add(instruction);
                }
            }
            else if (j < numOutermostArgs)
            {
                Term nextVar = (Variable) nextTerm;
                int allocation = (Integer) symbolTable.get(nextVar.getSymbolKey(), SymbolTableKeys.SYMKEY_ALLOCATION);
                byte addrMode = (byte) ((allocation & 0xff00) >> 8);
                byte address = (byte) (allocation & 0xff);

                WAMInstruction instruction;

                // If it is register not seen before: get_var.
                // If it is register seen before: get_val.
                if (!seenRegisters.contains(allocation))
                {
                    /*log.fine("GET_VAR " + ((addrMode == REG_ADDR) ? "X" : "Y") + address + ", A" + j);*/

                    seenRegisters.add(allocation);

                    instruction =
                        new WAMInstruction(WAMInstruction.WAMInstructionSet.GetVar, addrMode, address,
                            (byte) (j & 0xff));

                    // Record the way in which this variable was introduced into the clause.
                    symbolTable.put(nextVar.getSymbolKey(), SymbolTableKeys.SYMKEY_VARIABLE_INTRO, VarIntroduction.Get);
                }
                else
                {
                    /*log.fine("GET_VAL " + ((addrMode == REG_ADDR) ? "X" : "Y") + address + ", A" + j);*/

                    instruction =
                        new WAMInstruction(WAMInstruction.WAMInstructionSet.GetVal, addrMode, address,
                            (byte) (j & 0xff));
                }

                instructions.add(instruction);
            }
        }

        return instructions;
    }

    /**
     * Allocates stack slots where needed to the variables in a program clause. The algorithm here is fairly complex.
     *
     *
A clause head and first body functor are taken together as the first unit, subsequent clause body functors
     * are taken as subsequent units. A variable appearing in more than one unit is said to be permanent, and must be
     * stored on the stack, rather than a register, otherwise the register that it occupies may be overwritten by calls
     * to subsequent units. These variables are called permanent, which really means that they are local variables on
     * the call stack.
     *
     *
In addition to working out which variables are permanent, the variables are also ordered by reverse position
     * of last body of occurrence, and assigned to allocation slots in this order. The number of permanent variables
     * remaining at each body call is also calculated and recorded against the body functor in the symbol table using
     * column {@link SymbolTableKeys#SYMKEY_PERM_VARS_REMAINING}. This allocation ordering of the variables and the
     * count of the number remaining are used to implement environment trimming.
     *
     * @param clause The clause to allocate registers for.
     */
    private void allocatePermanentProgramRegisters(Clause clause)
    {
        // A bag to hold variable occurrence counts in.
        Map<Variable, Integer> variableCountBag = new HashMap<Variable, Integer>();

        // A mapping from variables to the body number in which they appear last.
        Map<Variable, Integer> lastBodyMap = new HashMap<Variable, Integer>();

        // Holds the variable that are in the head and first clause body argument.
        Collection<Variable> firstGroupVariables = new HashSet<Variable>();

        // Get the occurrence counts of variables in all clauses after the initial head and first body grouping.
        // In the same pass, pick out which body variables last occur in.
        if ((clause.getBody() != null))
        {
            for (int i = clause.getBody().length - 1; i >= 1; i--)
            {
                Set<Variable> groupVariables = TermUtils.findFreeVariables(clause.getBody()[i]);

                // Add all their counts to the bag and update their last occurrence positions.
                for (Variable variable : groupVariables)
                {
                    Integer count = variableCountBag.get(variable);
                    variableCountBag.put(variable, (count == null) ? 1 : (count + 1));

                    if (!lastBodyMap.containsKey(variable))
                    {
                        lastBodyMap.put(variable, i);
                    }

                    // If the cut level variable is seen, automatically add it to the first group variables,
                    // so that it will be counted as a permanent variable, and assigned a stack slot. This
                    // will only occur for deep cuts, that is where the cut comes after the first group.
                    if (variable instanceof Cut.CutLevelVariable)
                    {
                        firstGroupVariables.add(variable);
                    }
                }
            }
        }

        // Get the set of variables in the head and first clause body argument.
        if (clause.getHead() != null)
        {
            Set<Variable> headVariables = TermUtils.findFreeVariables(clause.getHead());
            firstGroupVariables.addAll(headVariables);
        }

        if ((clause.getBody() != null) && (clause.getBody().length > 0))
        {
            Set<Variable> firstArgVariables = TermUtils.findFreeVariables(clause.getBody()[0]);
            firstGroupVariables.addAll(firstArgVariables);
        }

        // Add their counts to the bag, and set their last positions of occurrence as required.
        for (Variable variable : firstGroupVariables)
        {
            Integer count = variableCountBag.get(variable);
            variableCountBag.put(variable, (count == null) ? 1 : (count + 1));

            if (!lastBodyMap.containsKey(variable))
            {
                lastBodyMap.put(variable, 0);
            }
        }

        // Sort the variables by reverse position of last occurrence.
        List<Map.Entry<Variable, Integer>> lastBodyList =
            new ArrayList<Map.Entry<Variable, Integer>>(lastBodyMap.entrySet());
        Collections.sort(lastBodyList, new Comparator<Map.Entry<Variable, Integer>>()
            {
                public int compare(Map.Entry<Variable, Integer> o1, Map.Entry<Variable, Integer> o2)
                {
                    return o2.getValue().compareTo(o1.getValue());
                }
            });

        // Holds counts of permanent variable last appearances against the body in which they last occur.
        int[] permVarsRemainingCount = new int[(clause.getBody() != null) ? clause.getBody().length : 0];

        // Search the count bag for all variable occurrences greater than one, and assign them to stack slots.
        // The variables are examined by reverse position of last occurrence, to ensure that later variables
        // are assigned to lower permanent allocation slots for environment trimming purposes.
        for (Map.Entry<Variable, Integer> entry : lastBodyList)
        {
            Variable variable = entry.getKey();
            Integer count = variableCountBag.get(variable);
            int body = entry.getValue();

            if ((count != null) && (count > 1))
            {
                /*log.fine("Variable " + variable + " is permanent, count = " + count);*/

                int allocation = (numPermanentVars++ & (0xff)) | (WAMInstruction.STACK_ADDR << 8);
                symbolTable.put(variable.getSymbolKey(), SymbolTableKeys.SYMKEY_ALLOCATION, allocation);

                // Check if the variable is the cut level variable, and cache its stack slot in 'cutLevelVarSlot', so that
                // the clause compiler knows which variable to use for the get_level instruction.
                if (variable instanceof Cut.CutLevelVariable)
                {
                    //cutLevelVarSlot = allocation;
                    cutLevelVarSlot = numPermanentVars - 1;
                    /*log.fine("cutLevelVarSlot = " + cutLevelVarSlot);*/
                }

                permVarsRemainingCount[body]++;
            }
        }

        // Roll up the permanent variable remaining counts from the counts of last position of occurrence and
        // store the count of permanent variables remaining against the body.
        int permVarsRemaining = 0;

        for (int i = permVarsRemainingCount.length - 1; i >= 0; i--)
        {
            symbolTable.put(clause.getBody()[i].getSymbolKey(), SymbolTableKeys.SYMKEY_PERM_VARS_REMAINING,
                permVarsRemaining);
            permVarsRemaining += permVarsRemainingCount[i];
        }
    }

    /**
     * Allocates stack slots to all free variables in a query clause.
     *
     *
At the end of processing a query its variable bindings are usually printed. For this reason all free
     * variables in a query are marked as permanent variables on the call stack, to ensure that they are preserved.
     *
     * @param clause   The clause to allocate registers for.
     * @param varNames A map of permanent variables to variable names to record the allocations in.
     */
    private void allocatePermanentQueryRegisters(Term clause, Map<Byte, Integer> varNames)
    {
        // Allocate local variable slots for all variables in a query.
        QueryRegisterAllocatingVisitor allocatingVisitor =
            new QueryRegisterAllocatingVisitor(symbolTable, varNames, null);

        PositionalTermTraverser positionalTraverser = new PositionalTermTraverserImpl();
        positionalTraverser.setContextChangeVisitor(allocatingVisitor);

        TermWalker walker =
            new TermWalker(new DepthFirstBacktrackingSearch<Term, Term>(), positionalTraverser, allocatingVisitor);

        walker.walk(clause);
    }

    /**
     * Gather information about variable counts and positions of occurrence of constants and variable within a clause.
     *
     * @param clause The clause to check the variable occurrence and position of occurrence within.
     */
    private void gatherPositionAndOccurrenceInfo(Term clause)
    {
        PositionalTermTraverser positionalTraverser = new PositionalTermTraverserImpl();
        PositionAndOccurrenceVisitor positionAndOccurrenceVisitor =
            new PositionAndOccurrenceVisitor(interner, symbolTable, positionalTraverser);
        positionalTraverser.setContextChangeVisitor(positionAndOccurrenceVisitor);

        TermWalker walker =
            new TermWalker(new DepthFirstBacktrackingSearch<Term, Term>(), positionalTraverser,
                positionAndOccurrenceVisitor);

        walker.walk(clause);
    }

    /**
     * Pretty prints a compiled predicate.
     *
     * @param predicate The compiled predicate to pretty print.
     */
    private void displayCompiledPredicate(Term predicate)
    {
        // Pretty print the clause.
        StringBuffer result = new StringBuffer();

        PositionalTermVisitor displayVisitor =
            new WAMCompiledPredicatePrintingVisitor(interner, symbolTable, result);

        TermWalkers.positionalWalker(displayVisitor).walk(predicate);

        /*log.fine(result.toString());*/
    }

    /**
     * Pretty prints a compiled query.
     *
     * @param query The compiled query to pretty print.
     */
    private void displayCompiledQuery(Term query)
    {
        // Pretty print the clause.
        StringBuffer result = new StringBuffer();

        PositionalTermVisitor displayVisitor =
            new WAMCompiledQueryPrintingVisitor(interner, symbolTable, result);

        TermWalkers.positionalWalker(displayVisitor).walk(query);

        /*log.fine(result.toString());*/
    }

    /**
     * QueryRegisterAllocatingVisitor visits named variables in a query, and if they are not already allocated to a
     * permanent stack slot, allocates them one. All named variables in queries are stack allocated, so that they are
     * preserved on the stack at the end of the query. Anonymous variables in queries are singletons, and not included
     * in the query results, so can be temporary.
     */
    public class QueryRegisterAllocatingVisitor extends DelegatingAllTermsVisitor
    {
        /** The symbol table. */
        private final SymbolTable<Integer, String, Object> symbolTable;

        /** Holds a map of permanent variables to variable names to record the allocations in. */
        private final Map<Byte, Integer> varNames;

        /**
         * Creates a query variable allocator.
         *
         * @param symbolTable The symbol table.
         * @param varNames    A map of permanent variables to variable names to record the allocations in.
         * @param delegate    The term visitor that this delegates to.
         */
        public QueryRegisterAllocatingVisitor(SymbolTable<Integer, String, Object> symbolTable,
            Map<Byte, Integer> varNames, AllTermsVisitor delegate)
        {
            super(delegate);
            this.symbolTable = symbolTable;
            this.varNames = varNames;
        }

        /**
         * {@inheritDoc}
         *
         *
Allocates unallocated variables to stack slots.
         */
        public void visit(Variable variable)
        {
            if (symbolTable.get(variable.getSymbolKey(), SymbolTableKeys.SYMKEY_ALLOCATION) == null)
            {
                if (variable.isAnonymous())
                {
                    /*log.fine("Query variable " + variable + " is temporary.");*/

                    int allocation = (lastAllocatedTempReg++ & (0xff)) | (REG_ADDR << 8);
                    symbolTable.put(variable.getSymbolKey(), SymbolTableKeys.SYMKEY_ALLOCATION, allocation);
                    varNames.put((byte) allocation, variable.getName());
                }
                else
                {
                    /*log.fine("Query variable " + variable + " is permanent.");*/

                    int allocation = (numPermanentVars++ & (0xff)) | (WAMInstruction.STACK_ADDR << 8);
                    symbolTable.put(variable.getSymbolKey(), SymbolTableKeys.SYMKEY_ALLOCATION, allocation);
                    varNames.put((byte) allocation, variable.getName());
                }
            }

            super.visit(variable);
        }
    }
}