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

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

import com.thesett.common.util.Pair;
import com.thesett.common.util.doublemaps.DoubleKeyedMap;
import com.thesett.common.util.doublemaps.HashMapXY;
import com.thesett.text.api.TextTableEvent;
import com.thesett.text.api.TextTableListener;
import com.thesett.text.api.model.TextTableModel;

/**
 * TextTableImpl provides an implementation of the {@link TextTableModel}.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Add or remove strings to table cells.

 *
 Provide the table size.

 *
 Monitor maximum text width of columns.

 *
 Provide ability to register listeners for changes to the table.

 *
 Allow table columns and rows to be labelled.

 *

 *
 * @author Rupert Smith
 */
public class TextTableImpl implements TextTableModel
{
    /** Holds the maximum row sizes in the grid. */
    Map<Integer, Integer> maxRowSizes = new HashMap<Integer, Integer>();

    /** Holds the maximum column sizes in the grid. */
    Map<Integer, Integer> maxColumnSizes = new HashMap<Integer, Integer>();

    /** Used to count the maximum row with data in it. */
    private int maxRows;

    /** Used to count the maximum column with data in it. */
    private int maxColumns;

    /** Holds a table with cell data to pretty print. */
    DoubleKeyedMap<Long, Long, String> grid = new HashMapXY<String>(10);

    /** Holds any interested listeners for updates to the table model. */
    protected Collection<TextTableListener> listeners = new HashSet<TextTableListener>();

    /** Holds any column labels. */
    private final Map<String, Integer> columnLabels = new HashMap<String, Integer>();

    /** Holds any row labels. */
    private final Map<String, Integer> rowLabels = new HashMap<String, Integer>();

    /** Holds any individual cell labels. */
    private final Map<String, Pair<Integer, Integer>> cellLabels = new HashMap<String, Pair<Integer, Integer>>();

    /**
     * Updates the maximum row count of the data table.
     *
     * @param row The maximum row count reached.
     */
    public void setMaxRowCount(int row)
    {
        if (maxRows < row)
        {
            maxRows = row;
        }
    }

    /**
     * Updates the maximum row height for a row of the data table.
     *
     * @param row    The row to update.
     * @param height The max height reached.
     */
    public void setMaxRowHeight(int row, int height)
    {
        Integer previousValue = maxRowSizes.get(row);

        if (previousValue == null)
        {
            maxRowSizes.put(row, height);
        }
        else if (previousValue < height)
        {
            maxRowSizes.put(row, height);
        }
    }

    /** {@inheritDoc} */
    public void clear()
    {
        grid.clear();
    }

    /** {@inheritDoc} */
    public boolean containsKey(Integer col, Integer row)
    {
        return grid.containsKey((long) col, (long) row);
    }

    /** {@inheritDoc} */
    public String put(Integer col, Integer row, String value)
    {
        maxColumns = (col > maxColumns) ? col : maxColumns;
        maxRows = (row > maxRows) ? row : maxRows;

        updateMaxColumnWidth(col, value.length());

        String result = grid.put((long) col, (long) row, value);

        updateListeners(col, row);

        return result;
    }

    /** {@inheritDoc} */
    public String get(Integer col, Integer row)
    {
        return grid.get((long) col, (long) row);
    }

    /** {@inheritDoc} */
    public String remove(Integer col, Integer row)
    {
        String result = grid.remove((long) col, (long) row);

        updateListeners(col, row);

        return result;
    }

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

    /** {@inheritDoc} */
    public boolean isEmpty()
    {
        return grid.isEmpty();
    }

    /** {@inheritDoc} */
    public int getRowCount()
    {
        return maxRows + 1;
    }

    /** {@inheritDoc} */
    public int getColumnCount()
    {
        return maxColumns + 1;
    }

    /** {@inheritDoc} */
    public int getMaxColumnSize(int col)
    {
        Integer result = maxColumnSizes.get(col);

        return (result == null) ? 0 : result;
    }

    /** {@inheritDoc} */
    public void addTextTableListener(TextTableListener listener)
    {
        listeners.add(listener);
    }

    /** {@inheritDoc} */
    public void removeTextTableListener(TextTableListener listener)
    {
        listeners.remove(listener);
    }

    /** {@inheritDoc} */
    public void labelColumn(String label, int column)
    {
        columnLabels.put(label, column);
    }

    /** {@inheritDoc} */
    public void labelRow(String label, int row)
    {
        rowLabels.put(label, row);
    }

    /** {@inheritDoc} */
    public void labelCell(String label, int col, int row)
    {
        cellLabels.put(label, new Pair<Integer, Integer>(col, row));
    }

    /** {@inheritDoc} */
    public DoubleKeyedMap<String, Integer, String> withColumnLabels()
    {
        return new ColumnLabelView();
    }

    /** {@inheritDoc} */
    public DoubleKeyedMap<Integer, String, String> withRowLabels()
    {
        return new RowLabelView();
    }

    /** {@inheritDoc} */
    public DoubleKeyedMap<String, String, String> withLabels()
    {
        return new RowAndColumnLabelView();
    }

    /** {@inheritDoc} */
    public Map<String, String> withCellLabels()
    {
        return new CellLabelView();
    }

    /** Notifies all interested listeners of an update to this model. */
    protected void updateListeners(int col, int row)
    {
        TextTableEvent event = new TextTableEvent(this, row, col);

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

    /**
     * Updates the maximum column width for a column of the data table.
     *
     * @param column The column to update.
     * @param width  The max width reached.
     */
    private void updateMaxColumnWidth(int column, int width)
    {
        Integer previousValue = maxColumnSizes.get(column);

        if (previousValue == null)
        {
            maxColumnSizes.put(column, width);
        }
        else if (previousValue < width)
        {
            maxColumnSizes.put(column, width);
        }
    }

    /**
     * Provides a base implementation for the label views.
     */
    public abstract class ViewBase
    {
        /** {@inheritDoc} */
        public void clear()
        {
            TextTableImpl.this.clear();
        }

        /** {@inheritDoc} */
        public int size()
        {
            return TextTableImpl.this.size();
        }

        /** {@inheritDoc} */
        public boolean isEmpty()
        {
            return TextTableImpl.this.isEmpty();
        }
    }

    /**
     * Provides a view onto the table with labeled columns.
     */
    private class ColumnLabelView extends ViewBase implements DoubleKeyedMap<String, Integer, String>
    {
        /** {@inheritDoc} */
        public boolean containsKey(String label, Integer row)
        {
            Integer col = columnLabels.get(label);

            if (col == null)
            {
                return false;
            }
            else
            {
                return TextTableImpl.this.containsKey(col, row);
            }
        }

        /** {@inheritDoc} */
        public String put(String label, Integer row, String value)
        {
            Integer col = columnLabels.get(label);

            if (col != null)
            {
                return TextTableImpl.this.put(col, row, value);
            }
            else
            {
                return null;
            }
        }

        /** {@inheritDoc} */
        public String get(String label, Integer row)
        {
            Integer col = columnLabels.get(label);

            if (col != null)
            {
                return TextTableImpl.this.get(col, row);
            }
            else
            {
                return null;
            }
        }

        /** {@inheritDoc} */
        public String remove(String label, Integer row)
        {
            Integer col = columnLabels.get(label);

            if (col != null)
            {
                return TextTableImpl.this.remove(col, row);
            }
            else
            {
                return null;
            }
        }
    }

    /**
     * Provides a view onto the table with labeled rows.
     */
    private class RowLabelView extends ViewBase implements DoubleKeyedMap<Integer, String, String>
    {
        /** {@inheritDoc} */
        public boolean containsKey(Integer col, String label)
        {
            Integer row = rowLabels.get(label);

            if (row == null)
            {
                return false;
            }
            else
            {
                return TextTableImpl.this.containsKey(col, row);
            }
        }

        /** {@inheritDoc} */
        public String put(Integer col, String label, String value)
        {
            Integer row = rowLabels.get(label);

            if (row != null)
            {
                return TextTableImpl.this.put(col, row, value);
            }
            else
            {
                return null;
            }
        }

        /** {@inheritDoc} */
        public String get(Integer col, String label)
        {
            Integer row = rowLabels.get(label);

            if (row != null)
            {
                return TextTableImpl.this.get(col, row);
            }
            else
            {
                return null;
            }
        }

        /** {@inheritDoc} */
        public String remove(Integer col, String label)
        {
            Integer row = rowLabels.get(label);

            if (row != null)
            {
                return TextTableImpl.this.remove(col, row);
            }
            else
            {
                return null;
            }
        }
    }

    /**
     * Provides a view onto the table with labeled rows and columns.
     */
    private class RowAndColumnLabelView extends ViewBase implements DoubleKeyedMap<String, String, String>
    {
        /** {@inheritDoc} */
        public boolean containsKey(String colLabel, String rowLabel)
        {
            Integer row = rowLabels.get(rowLabel);
            Integer col = columnLabels.get(colLabel);

            if ((row != null) && (col != null))
            {
                return TextTableImpl.this.containsKey(col, row);
            }
            else
            {
                return false;
            }
        }

        /** {@inheritDoc} */
        public String put(String colLabel, String rowLabel, String value)
        {
            Integer row = rowLabels.get(rowLabel);
            Integer col = columnLabels.get(colLabel);

            if ((row != null) && (col != null))
            {
                return TextTableImpl.this.put(col, row, value);
            }
            else
            {
                return null;
            }
        }

        /** {@inheritDoc} */
        public String get(String colLabel, String rowLabel)
        {
            Integer row = rowLabels.get(rowLabel);
            Integer col = columnLabels.get(colLabel);

            if ((row != null) && (col != null))
            {
                return TextTableImpl.this.get(col, row);
            }
            else
            {
                return null;
            }
        }

        /** {@inheritDoc} */
        public String remove(String colLabel, String rowLabel)
        {
            Integer row = rowLabels.get(rowLabel);
            Integer col = columnLabels.get(colLabel);

            if ((row != null) && (col != null))
            {
                return TextTableImpl.this.remove(col, row);
            }
            else
            {
                return null;
            }
        }
    }

    /**
     * Provides a view onto the table with individually labelled cells.
     */
    private class CellLabelView extends ViewBase implements Map<String, String>
    {
        /** {@inheritDoc} */
        public boolean containsKey(Object key)
        {
            return cellLabels.containsKey(key);
        }

        /** {@inheritDoc} */
        public boolean containsValue(Object value)
        {
            throw new UnsupportedOperationException();
        }

        /** {@inheritDoc} */
        public String get(Object key)
        {
            Pair<Integer, Integer> cell = cellLabels.get(key);

            if (cell != null)
            {
                return TextTableImpl.this.get(cell.getFirst(), cell.getSecond());
            }
            else
            {
                return null;
            }
        }

        /** {@inheritDoc} */
        public String put(String key, String value)
        {
            Pair<Integer, Integer> cell = cellLabels.get(key);

            if (cell != null)
            {
                return TextTableImpl.this.put(cell.getFirst(), cell.getSecond(), value);
            }
            else
            {
                return null;
            }
        }

        /** {@inheritDoc} */
        public String remove(Object key)
        {
            Pair<Integer, Integer> cell = cellLabels.get(key);

            if (cell != null)
            {
                return TextTableImpl.this.remove(cell.getFirst(), cell.getSecond());
            }
            else
            {
                return null;
            }
        }

        /** {@inheritDoc} */
        public void putAll(Map<? extends String, ? extends String> m)
        {
            for (Map.Entry<? extends String, ? extends String> entry : m.entrySet())
            {
                put(entry.getKey(), entry.getValue());
            }
        }

        /** {@inheritDoc} */
        public Set<String> keySet()
        {
            return cellLabels.keySet();
        }

        /** {@inheritDoc} */
        public Collection<String> values()
        {
            throw new UnsupportedOperationException();
        }

        /** {@inheritDoc} */
        public Set<Entry<String, String>> entrySet()
        {
            throw new UnsupportedOperationException();
        }
    }
}


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

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;

import com.thesett.common.util.PagedList;

/**
 * PageAction is a Struts action class that facilitates dividing web pages into multiple sections with an index and
 * forward and back buttons to move through the pages. A typical example of such a control is found in search results
 * where the results are split into many pages.
 *
 *
The collection to be split into pages must be placed into a {@link com.thesett.common.util.PagedList} which is a
 * list data structure that splits its contents into sub-lists. This action expects to find such an object in the
 * session scope variable named in the <tt>varName</tt> property of the page form. The page form should be set up in the
 * struts-config file as:
 *
 *

 * <form-bean name="pageform" type="org.apache.struts.action.DynaActionForm">
 *   <form-property name="varName" type="java.lang.String"/>
 *   <form-property name="number" type="int"/>
 *   <form-property name="index" type="int"/>
 * </form-bean>
 *

 *
 *
This action simply updates the current page and optionally the index of the
 * {@link com.thesett.common.util.PagedList} and forwards to its success location.
 *
 *
An entry should be created in the struts-config file for each page control needed as the SUCCESS location will
 * need to be configured to point back to the same page that the paging control is on in order for the web page to be
 * updated to the newly selected page. For example:
 *
 *
See {@link com.thesett.common.webapp.tags.PageControlTag} for information about a useful tag for rendering a set
 * of paging controls.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Update current page or index offset of paged list
 *      {@link com.thesett.common.util.PagedList}
 *

 *
 * @author Rupert Smith
 */
public class PageAction extends BaseAction
{
    /** Used for logging. */
    private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(PageAction.class.getName());

    /** Holds the parameter name that the name of the session scope variable holding the paged list is passed in. */
    public static final String VAR_NAME_PARAM = "varName";

    /** Holds the parameter name that the page number to go to is passed in. */
    public static final String NUMBER_PARAM = "number";

    /** Holds the parameter name that the optional new page index is passed in. */
    public static final String INDEX_PARAM = "index";

    /** Holds the forward name of the success location. */
    private static final String SUCCESS_FORWARD = "success";

    /**
     * Updates the current page or index offset of a paged list in the session scope.
     *
     *
This perform method is the same as the normal perform method but it is called from inside an error wrapper
     * that catches all throwables. The wrapper automatically generates Struts error messages for any Java throwable
     * that may fall through this method.
     *
     *
Implementations should override this method to use the default error handling.
     *
     * @param  mapping  The ActionMapping used to select this instance
     * @param  form     The optional ActionForm bean for this request (if any)
     * @param  request  The HTTP request.
     * @param  response The HTTP response.
     * @param  errors   A struts errors object to write any error messages to.
     *
     * @return A struts forward to tell struts where to go after this action.
     *
     * @throws Exception Any exceptions are allowed to fall through to the top level handler.
     */
    public ActionForward executeWithErrorHandling(ActionMapping mapping, ActionForm form, HttpServletRequest request,
        HttpServletResponse response, ActionErrors errors) throws Exception
    {
        // Get a reference to the session.
        HttpSession session = request.getSession(false);

        // Extract the page form.
        DynaActionForm pageForm = (DynaActionForm) form;
        log.fine("pageForm = " + pageForm);

        // Get the paged list object from the session.
        String listingVarName = pageForm.getString(VAR_NAME_PARAM);
        log.fine("listingVarName = " + listingVarName);

        PagedList pagedList = (PagedList) session.getAttribute(listingVarName);

        // Set its current page.
        pagedList.setCurrentPage((Integer) pageForm.get(NUMBER_PARAM));

        // Set its index offset if one is specified.
        Integer index = (Integer) pageForm.get(INDEX_PARAM);

        if (index != null)
        {
            pagedList.setCurrentIndex(index);
        }

        // Forward to the success location.
        return mapping.findForward(SUCCESS_FORWARD);
    }
}


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

import com.thesett.aima.logic.fol.Clause;
import com.thesett.aima.logic.fol.LogicCompiler;
import com.thesett.aima.logic.fol.LogicCompilerObserver;
import com.thesett.aima.logic.fol.Sentence;
import com.thesett.aima.logic.fol.TermTransformer;
import com.thesett.aima.logic.fol.VariableAndFunctorInterner;
import com.thesett.aima.logic.fol.prolog.expressions.BuiltInExpressionTransform;
import com.thesett.common.parsing.SourceCodeException;

/**
 * PrologCompiler implements a translation from {@link Clause}s to {@link PrologCompiledClause}s.
 *
 *
This compiler translates all free variables in domain clauses into {@link StackVariable}s with assigned storage
 * locations relative to a stack frame. The clause is then set up as the binding context supplier to the variable. When
 * evaluating against a clause a binding context accepting stack variables needs to be set up on it, binding stack
 * variables will then defer the storage of their bindings onto the stack frame location rather than the variable
 * itself. This means that the domain clause can have variable bindings relative to a particular stack frame, and
 * evaluating the domain clause in a different stack frame context will allow a different binding of its variables.
 *
 *
The compiler also replaces any occurences of built-in expressions with their implementations.
 *
 *
Query clauses are not transformed with stack variables. There is only one query at the top level of any execution
 * chain, so it does not need to be re-used in the way that domain clauses do.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Assign stack frame storage locations for variables.
 *      {@link StackVariable}, {@link StackVariableTransform}.
 *
 Replace built in expressions with their implementations.
 *      {@link BuiltInExpressionTransform}.
 *

 *
 * @author Rupert Smith
 */
public class PrologCompiler implements LogicCompiler<Clause, PrologCompiledClause, PrologCompiledClause>
{
    /** Used to intern variables and functors with. */
    private final VariableAndFunctorInterner interner;

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

    /**
     * Creates a new compiler using the specified interner.
     *
     * @param interner The interner to use.
     */
    public PrologCompiler(VariableAndFunctorInterner interner)
    {
        this.interner = interner;
    }

    /**
     * {@inheritDoc}
     *
     *
Compiles a clause by replacing all free variable occurrences within domain clauses with stack storage
     * locations. The clause is set up as the binding context supplier to these variables. Query clauses are not set up
     * with stack variables, as the query can have its variables bound directly.
     */
    public void compile(Sentence<Clause> clauseSentence) throws SourceCodeException
    {
        Clause clause = clauseSentence.getT();
        PrologCompiledClause result = new PrologCompiledClause(clause.getHead(), clause.getBody());

        // Create stack frame slots for all variables in a program.
        if (!clause.isQuery())
        {
            StackVariableTransform stackVariableTransform = new StackVariableTransform(0, result);
            result = (PrologCompiledClause) result.acceptTransformer(stackVariableTransform);

            // Set the required stack frame size on the compiled clause.
            result.setStackSize(stackVariableTransform.offset);
        }

        // Apply the built-in transformation to map any built-ins to their implementations.
        TermTransformer builtInTransformation = new BuiltInExpressionTransform(interner);
        result = (PrologCompiledClause) result.acceptTransformer(builtInTransformation);

        // Return the compiled version of the clause.
        if (clause.isQuery())
        {
            observer.onQueryCompilation(result);
        }
        else
        {
            observer.onCompilation(result);
        }
    }

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

    /** {@inheritDoc} */
    public void endScope()
    {
    }
}


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

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

import com.thesett.aima.logic.fol.BaseTermTransformer;
import com.thesett.aima.logic.fol.Functor;
import com.thesett.aima.logic.fol.FunctorName;
import com.thesett.aima.logic.fol.FunctorTransformer;
import com.thesett.aima.logic.fol.Term;
import com.thesett.aima.logic.fol.VariableAndFunctorInterner;
import com.thesett.aima.logic.fol.prolog.builtins.BuiltInFunctor;
import com.thesett.common.util.ReflectionUtils;

/**
 * BuiltInTransform implements a compilation transformation over term syntax trees, that substitutes for functors that
 * map onto Prolog built-ins, an extension of the functor type that implements the built-in.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Transform functors to built in functors where appropriate.
 *      {@link BuiltInFunctor}, {@link VariableAndFunctorInterner}.
 *

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

    /** Holds a mapping from functor name to built-in expression implementations. */
    private final Map<FunctorName, Class<? extends BuiltInExpressionOperator>> builtInExpressions =
        new HashMap<FunctorName, Class<? extends BuiltInExpressionOperator>>();

    /** Used to extract functor names to match. */
    private final VariableAndFunctorInterner interner;

    /**
     * Initializes the built-in transformation by population the the table of mappings of functors onto their built-in
     * implementations.
     *
     * @param interner The interner to use to extract functor names to match as built-ins.
     */
    public BuiltInExpressionTransform(VariableAndFunctorInterner interner)
    {
        this.interner = interner;

        builtInExpressions.put(new FunctorName("**", 2), Exponential.class);
        builtInExpressions.put(new FunctorName("-", 2), Minus.class);
        builtInExpressions.put(new FunctorName("+", 2), Plus.class);
        builtInExpressions.put(new FunctorName("*", 2), Multiply.class);
        builtInExpressions.put(new FunctorName("/", 2), Divide.class);
        builtInExpressions.put(new FunctorName("-", 1), UMinus.class);
    }

    /**
     * Applies a built-in replacement transformation to functors. If the functor matches built-in, a
     * {@link BuiltInFunctor} is created with a mapping to the functors built-in implementation, and the functors
     * arguments are copied into this new functor. If the functor does not match a built-in, it is returned unmodified.
     *
     * @param  functor The functor to attempt to map onto a built-in.
     *
     * @return The functor umodified, or a {@link BuiltInFunctor} replacement for it.
     */
    public Functor transform(Functor functor)
    {
        FunctorName functorName = interner.getFunctorFunctorName(functor);

        if (builtInExpressions.containsKey(functorName))
        {
            Class<? extends Functor> builtInExpressionClass = builtInExpressions.get(functorName);

            return ReflectionUtils.newInstance(ReflectionUtils.getConstructor(builtInExpressionClass,
                    new Class[] { Integer.TYPE, Term[].class }),
                new Object[] { functor.getName(), functor.getArguments() });
        }
        else
        {
            return functor;
        }
    }
}


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

import com.thesett.aima.search.SearchNode;
import com.thesett.aima.search.SearchNotExhaustiveException;
import com.thesett.aima.search.Successor;
import com.thesett.aima.search.Traversable;

/**
 * HeuristicSearchNode extends {@link SearchNode} with heuristic evaluations of search states. In addition to the
 * properties provided by SearchNode it provides two values, h and f. Both are real valued (floats). h is the heuristic
 * value and f is the heuristic value plus the search path cost required to reach a given state.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Calculate h and f
 *

 *
 * @author Rupert Smith
 */
public class HeuristicSearchNode<O, T extends Traversable<O>> extends SearchNode<O, T>
{
    /** Value of heuristic for search node. */
    protected float h;

    /** Used to hold a reference to the heuristic evaluator for the states being searched. */
    private Heuristic<O, T> heuristic;

    /**
     * No-argument constructor needed for Class.newInstance() call in the {@link SearchNode#makeNode} method to work.
     *
     *
Note that this constructor does not set up the heuristic evaluator or calculate the value of h. These steps
     * are performed by the {@link #makeNode} method which should always be called after using this constructor.
     */
    public HeuristicSearchNode()
    {
    }

    /**
     * Makes a search node for startState that uses the supplied heuristic.
     *
     * @param startState The search state space to create a heuristic search node for.
     * @param heuristic  The heuristic calculation to use for the search node.
     */
    public HeuristicSearchNode(T startState, Heuristic<O, T> heuristic)
    {
        super(startState);

        // Keep the reference to the heuristic evaluator
        this.heuristic = heuristic;

        // Calculate the heuristic evaluation for the start state.
        computeH();
    }

    /**
     * Returns value of the heuristic function. This method assumes that h has already been computed.
     *
     * @return The value of the heuristic function applied to this search node.
     */
    public float getH()
    {
        return h;
    }

    /**
     * Returns f(node), defined as the heuristic + path cost to the node.
     *
     * @return The f value of this search node, where f = heuristic value + path cost to the node.
     */
    public float getF()
    {
        return pathCost + h;
    }

    /**
     * Returns a reference to the heuristic function.
     *
     * @return The heuristic function used to calculate the heuristic for this node.
     */
    public Heuristic<O, T> getHeuristic()
    {
        return heuristic;
    }

    /**
     * Returns a new node based on a successor of this node. This new node will also be a HeuristicSearchNode.
     *
     * @param     successor The successor state in the search space to create a new node for.
     *
     * @return    A completely new heuristic search node for the successor state. This node will be of the correct
     *            class, even for classes that sub-class this one.
     *
     * @exception SearchNotExhaustiveException If a new node cannot be created. This may happen due to class visibility
     *                                         or class loading problems.
     */
    public HeuristicSearchNode<O, T> makeNode(Successor successor) throws SearchNotExhaustiveException
    {
        HeuristicSearchNode<O, T> node = (HeuristicSearchNode<O, T>) super.makeNode(successor);

        // Make sure the new node has a reference to the heuristic evaluator
        node.heuristic = this.heuristic;

        // Compute h for the new node
        node.computeH();

        return node;
    }

    /** Computes and stores the heuristic function for the state. */
    protected void computeH()
    {
        h = heuristic.computeH(state, this);
    }
}


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

import java.io.IOException;
import java.util.logging.Level;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import com.thesett.common.error.NotImplementedException;

/**
 * ActionBase is an abstract class which provides some useful com.jpmorgan.grc behaviour for Struts action classes to
 * use. It provides an error handling mechanism for all actions to use. This takes an exception as its input and
 * generates an appropriate error depending on the type of exception.
 *
 *
The user readable error message is interpreted as being a key for an error message in the properties file.
 *
 *
The error handling code has been moved to {@link ErrorHandler}. This class simply defines a useful method that
 * action classes can call locally.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Provide default error handler for all Java Throwables
 *
 Translate exception into struts ActionErrors  {@link ErrorHandler}
 *

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

    /**
     * Processes the action providing default error handling. Implementation should override this method to provide
     * their own error handling if the default is not to be used.
     *
     * @param     mapping  The ActionMapping used to select this instance
     * @param     form     The optional ActionForm bean for this request (if any)
     * @param     request  The HTTP request.
     * @param     response The HTTP response.
     *
     * @return    A struts forward to tell struts where to go after this action.
     *
     * @exception IOException      If an input/output error occurs.
     * @exception ServletException If a servlet exception occurs.
     */
    public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request,
        HttpServletResponse response) throws IOException, ServletException
    {
        log.fine("ActionForward perform(ActionMapping, ActionForm, HttpServletRequest, HttpServletResponse): called");

        // Build an ActionErrors object to hold any errors that occurr
        ActionErrors errors = new ActionErrors();

        // Create reference to the session
        HttpSession session = request.getSession();

        // Use a try block to catch any errors that may occur
        try
        {
            return executeWithErrorHandling(mapping, form, request, response, errors);
        }

        // Catch all exceptions here. This will forward to the error page in the event of
        // any exception that falls through to this top level handler.
        // Don't catch Throwable here as Errors should fall through to the JVM top level and will result in
        // termination of the application.
        catch (Exception t)
        {
            log.log(Level.WARNING, "Caught a Throwable", t);

            // Don't Forward the error to the error handler to interpret it as a Struts error as the exception will
            // automatically be translated by the error page.

            // @todo Could add code here to check if there is a 'error' forward page defined. If there is then call
            // the error handler to translate the throwable into Struts errors and then forward to the 'error' page.
            // This would mean that the error page defined in web.xml would be the default unless an action explicitly
            // defined an alternative 'error' forward.
            // handleErrors(t, errors);

            // Save all the error messages in the request so that they will be displayed
            // request.setAttribute(Action.ERROR_KEY, errors);

            // Rethrow the error as a ServletException here to cause forwarding to error page defined in web.xml
            throw new WrappedStrutsServletException(t);
        }
    }

    /**
     * This perform method is the same as the normal perform method but it is called from inside an error wrapper that
     * catches all throwables. The wrapper automatically generates Struts error messages for any Java throwable that may
     * fall through this message.
     *
     *
Implementations should override this method to use the default error handling.
     *
     * @param  mapping  The ActionMapping used to select this instance
     * @param  form     The optional ActionForm bean for this request (if any)
     * @param  request  The HTTP request.
     * @param  response The HTTP response.
     * @param  errors   A struts errors object to write any error messages to.
     *
     * @return A struts forward to tell struts where to go after this action.
     *
     * @throws Exception Any exceptions are allowed to fall through to the top level handler.
     */
    public ActionForward executeWithErrorHandling(ActionMapping mapping, ActionForm form, HttpServletRequest request,
        HttpServletResponse response, ActionErrors errors) throws Exception
    {
        // Dummy implementation, does nothing useful and should never be called.
        throw new NotImplementedException();
    }

    /**
     * Handles any exceptions that fell though to the top level. This is delegated to the error handler to translate
     * those exceptions into struts action errors.
     *
     * @param exception The exception that fell through.
     * @param errors    A struts action errors obejct to write the error messages into.
     */
    public void handleErrors(Throwable exception, ActionErrors errors)
    {
        // Delegate to the error handler defined in ErrorHandler
        ErrorHandler.handleErrors(exception, errors);
    }
}


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

import com.thesett.aima.logic.fol.Clause;
import com.thesett.aima.logic.fol.LogicCompiler;
import com.thesett.aima.logic.fol.LogicCompilerObserver;
import com.thesett.aima.logic.fol.Sentence;
import com.thesett.aima.logic.fol.Term;
import com.thesett.aima.logic.fol.VariableAndFunctorInterner;
import com.thesett.aima.logic.fol.bytecode.BaseMachine;
import com.thesett.aima.logic.fol.compiler.SymbolKeyTraverser;
import com.thesett.aima.logic.fol.compiler.TermWalker;
import com.thesett.aima.logic.fol.wam.TermWalkers;
import com.thesett.aima.logic.fol.wam.builtins.BuiltInTransform;
import com.thesett.aima.search.util.backtracking.DepthFirstBacktrackingSearch;
import com.thesett.common.parsing.SourceCodeException;
import com.thesett.common.util.doublemaps.SymbolTable;

/**
 * PreCompiler transforms clauses for compilation, substituting built-ins for any built-ins in the source expressions to
 * compile.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Perform the built-ins transformation.
 *

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

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

    /** Holds the default built in, for standard compilation and interners and symbol tables. */
    private final DefaultBuiltIn defaultBuiltIn;

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

    /**
     * Creates a new PreCompiler.
     *
     * @param symbolTable    The symbol table.
     * @param interner       The machine to translate functor and variable names.
     * @param defaultBuiltIn The default built in, for standard compilation and interners and symbol tables.
     */
    public PreCompiler(SymbolTable<Integer, String, Object> symbolTable, VariableAndFunctorInterner interner,
        DefaultBuiltIn defaultBuiltIn)
    {
        super(symbolTable, interner);

        this.defaultBuiltIn = defaultBuiltIn;
        builtInTransform = new BuiltInTransform(defaultBuiltIn);
    }

    /** {@inheritDoc} */
    public void compile(Sentence<Clause> sentence) throws SourceCodeException
    {
        Clause clause = sentence.getT();

        substituteBuiltIns(clause);
        initialiseSymbolTable(clause);
        topLevelCheck(clause);

        if (observer != null)
        {
            if (clause.isQuery())
            {
                observer.onQueryCompilation(sentence);
            }
            else
            {
                observer.onCompilation(sentence);
            }
        }
    }

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

    /** {@inheritDoc} */
    public void endScope() throws SourceCodeException
    {
    }

    /**
     * Substitutes built-ins within a clause, with their built-in definitions.
     *
     * @param clause The clause to transform.
     */
    private void substituteBuiltIns(Term clause)
    {
        TermWalker walk =
            TermWalkers.positionalWalker(new BuiltInTransformVisitor(interner, symbolTable, null, builtInTransform));
        walk.walk(clause);
    }

    /**
     * Runs a symbol key traverser over the clause to be compiled, to ensure that all of its terms and sub-terms have
     * their symbol keys initialised.
     *
     * @param clause The clause to initialise the symbol keys of.
     */
    private void initialiseSymbolTable(Term clause)
    {
        // Run the symbol key traverser over the clause, to ensure that all terms have their symbol keys correctly
        // set up.
        SymbolKeyTraverser symbolKeyTraverser = new SymbolKeyTraverser(interner, symbolTable, null);
        symbolKeyTraverser.setContextChangeVisitor(symbolKeyTraverser);

        TermWalker symWalker =
            new TermWalker(new DepthFirstBacktrackingSearch<Term, Term>(), symbolKeyTraverser, symbolKeyTraverser);
        symWalker.walk(clause);
    }

    /**
     * Finds and marks all functors within the clause that are considered to be top-level.
     *
     * @param clause The clause to top-level check.
     */
    private void topLevelCheck(Term clause)
    {
        TermWalker walk = TermWalkers.positionalWalker(new TopLevelCheckVisitor(interner, symbolTable, null));
        walk.walk(clause);
    }
}


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

import com.thesett.aima.logic.fol.Functor;
import com.thesett.aima.logic.fol.FunctorName;
import com.thesett.aima.logic.fol.Term;
import com.thesett.aima.logic.fol.Variable;
import com.thesett.aima.logic.fol.wam.compiler.DefaultBuiltIn;
import com.thesett.aima.logic.fol.wam.compiler.SymbolTableKeys;
import com.thesett.aima.logic.fol.wam.compiler.WAMInstruction;
import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.WAMInstructionSet.Cut;
import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.WAMInstructionSet.NeckCut;
import com.thesett.common.util.SizeableLinkedList;

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

CRC Card

 *
 Responsibilities  Collaborations
 *
 Implement the cut operator.
 *

 *
 * @author Rupert Smith
 */
public class Cut extends BaseBuiltIn
{
    /**
     * Creates a cut built-in to implement the specified functor.
     *
     * @param functor        The functor to implement as a built-in.
     * @param defaultBuiltIn The default built in, for standard compilation and interners and symbol tables.
     */
    public Cut(Functor functor, DefaultBuiltIn defaultBuiltIn)
    {
        // Here the cut functor is transformed from ! to !(Y), where Y is a level variable that may be needed
        // to hold the current choice point.
        super(new Functor(functor.getName(), new Term[] { CutLevelVariable.CUT_LEVEL_VARIABLE }), defaultBuiltIn);
    }

    /** {@inheritDoc} */
    public SizeableLinkedList<WAMInstruction> compileBodyArguments(Functor expression, boolean isFirstBody,
        FunctorName clauseName, int bodyNumber)
    {
        return new SizeableLinkedList<WAMInstruction>();
    }

    /** {@inheritDoc} */
    public SizeableLinkedList<WAMInstruction> compileBodyCall(Functor expression, boolean isFirstBody,
        boolean isLastBody, boolean chainRule, int permVarsRemaining)
    {
        SizeableLinkedList<WAMInstruction> instructions = new SizeableLinkedList<WAMInstruction>();

        if (isFirstBody)
        {
            instructions.add(new WAMInstruction(NeckCut));
        }
        else
        {
            Integer cutLevelVarAllocation =
                (Integer) defaultBuiltIn.getSymbolTable().get(CutLevelVariable.CUT_LEVEL_VARIABLE.getSymbolKey(),
                    SymbolTableKeys.SYMKEY_ALLOCATION);

            instructions.add(new WAMInstruction(Cut, (byte) (cutLevelVarAllocation & 0xff)));
        }

        return instructions;
    }

    /**
     * Creates a string representation of this functor, mostly used for debugging purposes.
     *
     * @return A string representation of this functor.
     */
    public String toString()
    {
        return "Cut";
    }

    /**
     * CutLevelVariable is an internal variable used to hold the current choice point when entering a clause with a deep
     * cut, in order that the choice point may be restored on the cut.
     *
     *
A single instance of this variable is all that is needed, since it is only used temporarily during the
     * compilation of clauses. This instance will be annotated by the symbol key initialization so that it can be found
     * in the correct place within each clause; on compiling a new clause it will be re-initialized into that clauses
     * symbol table.
     *
     *
Note: A singleton instance here will prevent the compiler from ever being multi-threaded, since
     * clauses can no longer be compiled in parallel. This can be worked around easily by making this variable a thread
     * local.
     */
    public static class CutLevelVariable extends Variable
    {
        /** The single cut level variable instance. */
        public static final Term CUT_LEVEL_VARIABLE = new CutLevelVariable();

        /** Private constructor to prevent instantiation other than the singleton. */
        CutLevelVariable()
        {
            super(-1, null, 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;

import java.util.Iterator;

import com.thesett.common.util.SequenceIterator;

/**
 * Cons is a list conjoining functor. It always takes two argument, the next list element and the remainder of this
 * list. This implementation exists purely for the sake of providing a different pretty printing method than standard
 * functors.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Pretty print a list.  {@link Term}.
 *
 Provide a standard Java iterator over the recursive list.
 *

 *
 * @author Rupert Smith
 */
public class Cons extends RecursiveList
{
    /**
     * Creates a cons functor. Two arguments must be specified.
     *
     * @param name      The interned name of the cons functor.
     * @param arguments The arguments; there must be two.
     */
    public Cons(int name, Term[] arguments)
    {
        super(name, arguments);

        if (arguments.length != 2)
        {
            throw new IllegalArgumentException("Cons must always take 2 arguments.");
        }
    }

    /**
     * Reports whether this list is the empty list 'nil'.
     *
     * @return <tt>true</tt> if this is the empty list 'nil'.
     */
    public boolean isNil()
    {
        return false;
    }

    /**
     * Provides a Java iterator over this recursively defined list.
     *
     * @return A Java iterator over this recursively defined list.
     */
    public Iterator<Term> iterator()
    {
        return new ListIterator();
    }

    /** {@inheritDoc} */
    public String toString(VariableAndFunctorInterner interner, boolean printVarName, boolean printBindings)
    {
        return listToString(interner, true, printVarName, printBindings);
    }

    /** {@inheritDoc} */
    public String toString()
    {
        return arguments[0].toString() + " :: [ " + arguments[1].toString() + " ]";
    }

    /**
     * Pretty prints a term relative to the symbol namings provided by the specified interner.
     *
     * @param  interner      The interner use to provide symbol names.
     * @param  isFirst       <tt>true</tt> if this is the first cons in a list, <tt>false</tt> otherwise.
     * @param  printVarName  <tt>true</tt> if the names of bound variables should be printed, <tt>false</tt> if just the
     *                       binding without the variable name should be printed.
     * @param  printBindings <tt>true</tt> if variable binding values should be printed, <tt>false</tt> if just the
     *                       variables name without any binding should be printed.
     *
     * @return A pretty printed string containing the term.
     */
    private String listToString(VariableAndFunctorInterner interner, boolean isFirst, boolean printVarName,
        boolean printBindings)
    {
        String result = "";

        if (isFirst)
        {
            result += "[";
        }

        result += arguments[0].toString(interner, printVarName, printBindings);

        Term consArgument = arguments[1].getValue();

        if (consArgument instanceof Cons)
        {
            result += ", " + ((Cons) consArgument).listToString(interner, false, printVarName, printBindings);
        }

        if (isFirst)
        {
            result += "]";
        }

        return result;
    }

    /**
     * ListIterator provides a standard Java Iterator over a recursively defined list. This iterator follows a chain of
     * 'Cons' operators until there are no more.
     *
     *

CRC Card

     *
 Responsibilities  Collaborations
     *
 Provide a standard Java iterator over the recursive list.  {@link Cons}.
     *

     */
    protected class ListIterator extends SequenceIterator<Term>
    {
        /** Holds the next Cons operator to examine, initially set to the head of the list. */
        Cons nextListElement = Cons.this;

        /**
         * Generates the next element in the sequence. Updates the 'nextElement' field to point to the next 'cons'
         * operator in the list, if there is one.
         *
         * @return The next element from the sequence if one is available, or <tt>null</tt> if the sequence is complete.
         */
        public Term nextInSequence()
        {
            Term value = null;

            if (nextListElement != null)
            {
                value = nextListElement.getArgument(0);

                Term candidateCons = nextListElement.getArgument(1);

                if (candidateCons instanceof Cons)
                {
                    nextListElement = (Cons) candidateCons;
                }
                else
                {
                    nextListElement = null;
                }
            }

            return value;
        }
    }
}


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

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

import com.thesett.common.util.maps.CircularArrayMap;
import com.thesett.common.util.maps.SequentialCuckooFunction;
import com.thesett.common.util.maps.SequentialFunction;

/**
 * SymbolTableImpl is a hash map, that against the primary key, stores a set of fields indexed by the secondary key.
 * This arrangement creates a table of extensible records, to which new fields can be added, or old ones removed. Such
 * an arrangement may be advantageous for processes that want to conserve memory, and carry out computations over a set
 * of records, where fields or groups of fields may only be required for some of the computation; they can be added or
 * computed as needed, and removed when no longer needed.
 *
 *
There are a number of options that can be explored here:
 *
 *

 *
Computing a hash of each key, returns an index into an array, which is the hashtable. A two dimensional array
 * could be used. This would grow (and possibly) shrink with this data structure, but the wasted memory would be the
 * product of the wastage on each dimension of the array.

 *
The primary key could hash to another hash table, and use the secondary key to retrieve fields from it. This
 * would mean that each record would only hold the fields it needs, and there would no be space allocated where some
 * records use a field, but others don't, but those that don't would still have the space allocated anyway.

 *
The secondary key could hash to another hash table, and use the primary key to retrieve fields from it. This would
 * mean that each field would only manage a table big enough for all the records that currently have a value of that
 * field assigned.

 *

 *
 *
This implementation uses the third option above.
 *
 *

CRC Card

 *
ResponsibilitiesCollaborations
 *
Step into a new child scope.
 *
Step out into a parent scope.
 *
Provide an iterable over fields of the table.
 *

 *
 * @author Rupert Smith
 */
public class SymbolTableImpl<K, L, E> implements SymbolTable<K, L, E>
{
    /** Used for debugging purposes. */
    /* private static final Logger log = Logger.getLogger(SymbolTableImpl.class.getName()); */

    /** Default initial size for the field arrays. */
    public static final int DEFAULT_INITIAL_FIELD_SIZE = 128;

    /** Keeps a count of the total number of entries in the table. */
    private int count;

    /** Holds a map of all of the fields that the symbol table contains. */
    private Map<L, CircularArrayMap<E>> fieldMap;

    /** Holds the symbol to array offset hashing function. */
    private SequentialFunction<CompositeKey<K>> hashFunction;

    /** Holds the parent lexical scope. */
    private SymbolTableImpl<K, L, E> parentScope;

    /** Holds the lexical depth of this table. */
    private final int depth;

    /**
     * Holds the sequence key of the parent symbol table that this one is a nested scope within. The top-level table
     * uses a parent sequence key of -1, to ensure that it is not confused with the table that is nested within symbol
     * 0.
     */
    private final int parentSequenceKey;

    /** Creates a new top-level scope empty symbol table. */
    public SymbolTableImpl()
    {
        fieldMap = new LinkedHashMap<L, CircularArrayMap<E>>();
        hashFunction = new SequentialCuckooFunction<CompositeKey<K>>();
        parentSequenceKey = -1;
        depth = 0;
    }

    /**
     * Creates a child symbol table within the scope of the specified parent table. The child table shares the fields
     * and sequence function with the parent table.
     *
     * @param parentScope       The parent table.
     * @param fieldMap          The field map shared with the parent table.
     * @param hashFunction      The symbol sequence function shared with the parent table.
     * @param depth             The lexical depth of the parent table.
     * @param parentSequenceKey The base key path that leads to this scope.
     */
    private SymbolTableImpl(SymbolTableImpl<K, L, E> parentScope, Map<L, CircularArrayMap<E>> fieldMap,
        SequentialFunction<CompositeKey<K>> hashFunction, int depth, int parentSequenceKey)
    {
        this.fieldMap = fieldMap;
        this.hashFunction = hashFunction;
        this.parentScope = parentScope;
        this.depth = depth + 1;

        // Copy the base key path into a new base key, one larger than the parent one.
        this.parentSequenceKey = parentSequenceKey;
    }

    /** {@inheritDoc} */
    public void clear()
    {
        // Clea all fields and records from the table.
        fieldMap = new LinkedHashMap<L, CircularArrayMap<E>>();
        hashFunction = new SequentialCuckooFunction<CompositeKey<K>>();
    }

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

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

    /** {@inheritDoc} */
    public boolean containsKey(K primaryKey, L secondaryKey)
    {
        // Check that the field exists in the table.
        CircularArrayMap<E> field = fieldMap.get(secondaryKey);

        if (field == null)
        {
            return false;
        }

        // Check that the symbol exists in the table.
        CompositeKey<K> compositeKey = new CompositeKey<K>(parentSequenceKey, primaryKey);
        SymbolTableImpl<K, L, E> nextParentScope = parentScope;

        while (true)
        {
            if (hashFunction.containsKey(compositeKey))
            {
                break;
            }

            if (nextParentScope != null)
            {
                compositeKey = new CompositeKey(nextParentScope.parentSequenceKey, primaryKey);
                nextParentScope = nextParentScope.parentScope;
            }
            else
            {
                return false;
            }
        }

        // Calculate the symbols index in the table, and use it to check if a value for that field exists.
        E value = field.get(hashFunction.apply(compositeKey));

        return value != null;
    }

    /** {@inheritDoc} */
    public E put(K primaryKey, L secondaryKey, E value)
    {
        // Create the field column for the secondary key, if it does not already exist.
        CircularArrayMap<E> field = fieldMap.get(secondaryKey);

        if (field == null)
        {
            field = new CircularArrayMap<E>(DEFAULT_INITIAL_FIELD_SIZE);
            fieldMap.put(secondaryKey, field);
        }

        // Create the mapping for the symbol if it does not already exist.
        Integer index = hashFunction.apply(new CompositeKey<K>(parentSequenceKey, primaryKey));

        // Insert the new value for the field into the field map.
        E oldValue = field.put(index, value);
        count++;

        return oldValue;
    }

    /** {@inheritDoc} */
    public E get(K primaryKey, L secondaryKey)
    {
        // Check that the field for the secondary key exists, and return null if not.
        CircularArrayMap<E> field = fieldMap.get(secondaryKey);

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

        // Check that the symbol exists in the table.
        CompositeKey<K> compositeKey = new CompositeKey<K>(parentSequenceKey, primaryKey);
        SymbolTableImpl<K, L, E> nextParentScope = parentScope;

        while (true)
        {
            if (hashFunction.containsKey(compositeKey))
            {
                break;
            }

            if (nextParentScope != null)
            {
                compositeKey = new CompositeKey(nextParentScope.parentSequenceKey, primaryKey);
                nextParentScope = nextParentScope.parentScope;
            }
            else
            {
                return null;
            }
        }

        // Calculate the symbols index in the table, and use it to fetch a value for the field if one exists.
        return field.get(hashFunction.apply(compositeKey));
    }

    /** {@inheritDoc} */
    public E remove(K primaryKey, L secondaryKey)
    {
        CompositeKey<K> compositeKey = new CompositeKey<K>(parentSequenceKey, primaryKey);

        // Check that the symbol exists in the table, and return null if not.
        if (!hashFunction.containsKey(compositeKey))
        {
            return null;
        }

        // Check that the field for the secondary key exists, and return null if not.
        CircularArrayMap<E> field = fieldMap.get(secondaryKey);

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

        // Calculate the symbols index in the table, and use it to fetch remove a value for the field if one exists.
        E oldValue = field.remove(hashFunction.apply(compositeKey));

        // Check if the fields size has been reduced to zero, in which case purge that whole field from the symbol
        // table.
        if (field.isEmpty())
        {
            fieldMap.remove(secondaryKey);
        }

        // Check if an item was really removed from the table, and decrement the size count if so.
        if (oldValue != null)
        {
            count--;
        }

        return oldValue;
    }

    /** {@inheritDoc} */
    public SymbolTable<K, L, E> enterScope(K key)
    {
        // Create an entry in the sequence function for the key, if one does not already exist.
        int scopeSequenceKey = hashFunction.apply(new CompositeKey<K>(parentSequenceKey, key));

        // Create a new child table for the symbol within this table at depth one greater than this.
        return new SymbolTableImpl<K, L, E>(this, fieldMap, hashFunction, depth, scopeSequenceKey);
    }

    /** {@inheritDoc} */
    public SymbolTable<K, L, E> leaveScope()
    {
        return parentScope;
    }

    /** {@inheritDoc} */
    public SymbolKey getSymbolKey(K key)
    {
        // Create an entry in the sequence function for the key, if one does not already exist.
        int scopeSequenceKey = hashFunction.apply(new CompositeKey<K>(parentSequenceKey, key));

        return new SymbolKeyImpl(scopeSequenceKey);
    }

    /** {@inheritDoc} */
    public E get(SymbolKey key, L secondaryKey)
    {
        // Extract the sequence key from the symbol key.
        int sequenceKey = ((SymbolKeyImpl) key).sequenceKey;

        // Check that the field for the secondary key exists, and return null if not.
        CircularArrayMap<E> field = fieldMap.get(secondaryKey);

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

        // Look up the value directly by its sequence key.
        return field.get(sequenceKey);
    }

    /** {@inheritDoc} */
    public E put(SymbolKey key, L secondaryKey, E value)
    {
        // Extract the sequence key from the symbol key.
        int sequenceKey = ((SymbolKeyImpl) key).sequenceKey;

        // Create the field column for the secondary key, if it does not already exist.
        CircularArrayMap<E> field = fieldMap.get(secondaryKey);

        if (field == null)
        {
            field = new CircularArrayMap<E>(DEFAULT_INITIAL_FIELD_SIZE);
            fieldMap.put(secondaryKey, field);
        }

        // Insert the new value for the field into the field map.
        E oldValue = field.put(sequenceKey, value);
        count++;

        return oldValue;
    }

    /** {@inheritDoc} */
    public void clearUpTo(SymbolKey key, L secondaryKey)
    {
        // Extract the sequence key from the symbol key, and clear the field up to it.
        int sequenceKey = ((SymbolKeyImpl) key).sequenceKey;
        CircularArrayMap<E> field = fieldMap.get(secondaryKey);

        if (field != null)
        {
            field.clearUpTo(sequenceKey);
        }
    }

    /** {@inheritDoc} */
    public void setLowMark(SymbolKey key, L secondaryKey)
    {
        // Extract the sequence key from the symbol key, and low mark the field up to it.
        int sequenceKey = ((SymbolKeyImpl) key).sequenceKey;
        CircularArrayMap<E> field = fieldMap.get(secondaryKey);

        if (field != null)
        {
            field.setLowMark(sequenceKey);
        }
    }

    /** {@inheritDoc} */
    public void clearUpToLowMark(L secondaryKey)
    {
        CircularArrayMap<E> field = fieldMap.get(secondaryKey);

        if (field != null)
        {
            field.clearUpToLowMark();
        }
    }

    /** {@inheritDoc} */
    public int getDepth()
    {
        return depth;
    }

    /** {@inheritDoc} */
    public Iterable<E> getValues(L field)
    {
        return fieldMap.get(field);
    }

    /** {@inheritDoc} */
    public String toString()
    {
        StringBuffer result =
            new StringBuffer("SymbolTableImpl: [ count = ").append(count).append(", depth = ").append(depth).append(
                ", [ ");

        for (Iterator<Map.Entry<L, CircularArrayMap<E>>> iterator = fieldMap.entrySet().iterator(); iterator.hasNext();)
        {
            Map.Entry<L, CircularArrayMap<E>> entry = iterator.next();

            L key = entry.getKey();
            CircularArrayMap<E> array = entry.getValue();

            result.append(key).append(".sizeof() = ").append(array.sizeof()).append(iterator.hasNext() ? ", " : " ");
        }

        return result.append("] ]").toString();
    }

    /**
     * Implements the {@link SymbolKey} as the sequence number assigned to a symbol by the sequencing function. This
     * index is used to directly look up values in the field tables.
     */
    private static class SymbolKeyImpl implements SymbolKey
    {
        /** Holds the unique sequence key for a symbol. */
        public int sequenceKey;

        /**
         * Creates a sequence key with the specified sequence number.
         *
         * @param sequenceKey The sequence number for the key.
         */
        private SymbolKeyImpl(int sequenceKey)
        {
            this.sequenceKey = sequenceKey;
        }

        /**
         * Prints the symbol key as a string, mainly for debugging purposes.
         *
         * @return The symbol key as a string.
         */
        public String toString()
        {
            return "SymbolKeyImpl: [ sequenceKey = " + sequenceKey + " ]";
        }
    }

    /**
     * Every symbol key is mapped by the sequential function as a CompositeKey. The composite key, combines the symbol
     * key with the unique sequence number of its parent symbol (or zero, if it has no parent symbol). This allows
     * symbol sequences leading to deeper levels of a table with nested scopes from having to compare the entire key
     * sequence for equality, or compute over the entire key sequence when generating hash codes. These calculations are
     * only performed for the additional step beyond the parent key sequence, which means that the calculations take
     * constant time and do not grow linearly with table depth.
     *
     *

CRC Card

     *
ResponsibilitiesCollaborations
     *
Combine a symbol key with a parent symbol sequence number.
     *
Provide constant time equals and hashCode over arbitrarily nested symbols.
     *

     *
     * @author Rupert Smith
     */
    private static class CompositeKey<K>
    {
        /** The unique sequence key of the parent composite symbol. */
        int parentSequenceKey;

        /** The symbol key to combine with the parent to for a composite key. */
        K key;

        /**
         * Creates a composite key from a parent keys unique sequence number and a symbol key.
         *
         * @param parentSequenceKey The parent keys unique sequence number, or zero for the top-level table.
         * @param key               The symbol key.
         */
        private CompositeKey(int parentSequenceKey, K key)
        {
            this.parentSequenceKey = parentSequenceKey;
            this.key = key;
        }

        /**
         * Compares this composite key to another for equality. They are equal if their parent composite sequence keys
         * are equal, and their keys are equal.
         *
         * @param  o The object to compare to.
         *
         * @return <tt>true</tt> If the comparator is a composite key and their parent composite sequence keys are
         *         equal, and their keys are equal.
         */
        public boolean equals(Object o)
        {
            if (this == o)
            {
                return true;
            }

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

            CompositeKey that = (CompositeKey) o;

            return (parentSequenceKey == that.parentSequenceKey) &&
                !((key != null) ? (!key.equals(that.key)) : (that.key != null));
        }

        /**
         * Computes a hash code for the composite key, based on combing the parent sequence key with the symbol keys
         * hashcode.
         *
         * @return A hash code for the composite key.
         */
        public int hashCode()
        {
            int result;
            result = parentSequenceKey;
            result = (31 * result) + ((key != null) ? key.hashCode() : 0);

            return result;
        }
    }
}


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

import org.jsoup.nodes.Element;
import org.jsoup.nodes.FormElement;

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

/**
 * Radio form control wrapper for a jsoup {@code Element}.
 */
class JsoupRadioControl extends JsoupCheckboxControl
{
	// ----------------------------------------------------------------------------------------------------------------
	// constructors
	// ----------------------------------------------------------------------------------------------------------------

	JsoupRadioControl(Element element)
	{
		super(element);
	}

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

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

		getForm().elements().select(byControlGroup()).removeAttr("checked");

		super.setValue(value);
	}

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

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

	// ----------------------------------------------------------------------------------------------------------------
	// private methods
	// ----------------------------------------------------------------------------------------------------------------

	private FormElement getForm()
	{
		return (FormElement) getElement().parents().select("form").first();
	}

	private String byControlGroup()
	{
		return String.format("[type=radio][name=%s]", getName());
	}
}


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

import com.thesett.aima.logic.fol.wam.debugger.DarkColorScheme;
import com.thesett.aima.logic.fol.wam.debugger.monitor.BreakpointMonitor;
import com.thesett.aima.logic.fol.wam.debugger.monitor.ByteCodeMonitor;
import com.thesett.aima.logic.fol.wam.debugger.monitor.MachineMonitor;
import com.thesett.aima.logic.fol.wam.debugger.monitor.MemoryLayoutMonitor;
import com.thesett.aima.logic.fol.wam.debugger.monitor.RegisterSetMonitor;
import com.thesett.aima.logic.fol.wam.debugger.uifactory.ComponentFactory;
import com.thesett.aima.logic.fol.wam.debugger.uifactory.ControllerLifecycle;
import com.thesett.aima.logic.fol.wam.debugger.uifactory.MainWindow;

/**
 * TopLevelStandaloneController is the top-level controller for the debugger UI. It is responsible for initializing the
 * debugger user interface, building the debugger data model and sub-controller components, and attaching all of these
 * components together to form the debugger application. It is also responsible for closing down the debugger
 * application components. To summarize, it is responsible for handling the top-level lifecycle events to create and
 * destroy the debugger application.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Build the debugger application components.

 *
 Destroy the debugger application components.

 *

 *
 * @author Rupert Smith
 */
public class TopLevelStandaloneController implements ControllerLifecycle
{
    /** Holds the component factory used to build the application components. */
    private final ComponentFactory componentFactory;

    /** Holds the main application window frame. */
    private MainWindow mainWindow;

    /** Holds the top-level machine monitor that is attached to the DPI of the machine being debugged. */
    private MachineMonitor machineMonitor;

    /** Holds the controller for the register set monitor. */
    private RegisterMonitorController registerMonitorController;

    /** Holds the controller for the memory layout monitor. */
    private MemoryLayoutMonitorController memoryLayoutMonitorController;

    /** Holds the controller for the byte code view and breakpoint monitor. */
    private CodeStepController codeStepController;

    /**
     * Creates a standalone debugger application using the supplied UI component factory.
     *
     * @param componentFactory The UI component factory to create the application UI with.
     */
    public TopLevelStandaloneController(ComponentFactory componentFactory)
    {
        this.componentFactory = componentFactory;
    }

    /**
     * {@inheritDoc}
     *
     *
Creates the debugger application from its components.
     */
    public void open()
    {
        // Set up colors.
        componentFactory.setColorScheme(new DarkColorScheme(componentFactory.getColorFactory()));

        // Build the main window frame.
        mainWindow = componentFactory.createMainWindow();
        mainWindow.showMainWindow();

        // Create and initialize the register monitor.
        registerMonitorController = new RegisterMonitorController(componentFactory, mainWindow);
        registerMonitorController.open();

        // Create and initialize the memory layout monitor.
        memoryLayoutMonitorController = new MemoryLayoutMonitorController(componentFactory, mainWindow);
        memoryLayoutMonitorController.open();

        // Create and initialize the byte code view and breakpoint monitor.
        codeStepController = new CodeStepController(componentFactory, mainWindow);
        codeStepController.open();

        // Build the top-level machine monitor, hooking it up to the child components.
        RegisterSetMonitor registerMonitor = registerMonitorController.getRegisterMonitor();
        MemoryLayoutMonitor layoutMonitor = memoryLayoutMonitorController.getLayoutMonitor();
        BreakpointMonitor breakpointMonitor = codeStepController.getBreakpointMonitor();
        ByteCodeMonitor byteCodeMonitor = codeStepController.getByteCodeMonitor();

        machineMonitor = new MachineMonitor(registerMonitor, layoutMonitor, breakpointMonitor, byteCodeMonitor);
    }

    /**
     * {@inheritDoc}
     *
     *
Destroys the debugger application components.
     */
    public void close()
    {
        registerMonitorController.close();
    }

    /**
     * Provides the underlying DPI monitor that this controller is built around.
     *
     * @return The underlying DPI monitor for the machine being debugged.
     */
    public MachineMonitor getMachineMonitor()
    {
        return machineMonitor;
    }
}


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

/**
 * LessThan compares two numbers.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Compare two numbers using integer or floating point arithemtic.  {@link NumericType}.
 *

 *
 * @author Rupert Smith
 */
public class LessThan extends BinaryArithmeticComparison
{
    /**
     * Creates a less-than built-in to implement the specified functor.
     *
     * @param functor The functor to implement as a built in.
     */
    public LessThan(Functor functor)
    {
        super(functor);
    }

    /**
     * Evaluates the arithmetic comparison on its two numeric arguments.
     *
     * @param  firstNumber  The first argument.
     * @param  secondNumber The second argument.
     *
     * @return The result of performing the arithmetic comparison on its arguments.
     */
    protected boolean evaluate(NumericType firstNumber, NumericType secondNumber)
    {
        // If either of the arguments is a real number, then use real number arithmetic, otherwise use integer arithmetic.
        if (firstNumber.isInteger() && secondNumber.isInteger())
        {
            return firstNumber.intValue() < secondNumber.intValue();
        }
        else
        {
            return firstNumber.doubleValue() < secondNumber.doubleValue();
        }
    }
}


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

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import com.thesett.common.util.concurrent.ShutdownHookable;
import com.thesett.common.util.concurrent.StartStopLifecycle;

/**
 * StartStopLifecycleBase provides a base implementation of {@link StartStopLifecycle}, for controlling the run
 * lifecycle of threaded resources.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
Start the resource running.
 *
Cleanly shut-down the resource once all its work is finished.
 *
Immediately shut-down the resource without completing all of its work.
 *
Check if a resource has been requested to shut-down.
 *
Check if a resource has completely stopped running.
 *
Wait for a resource to completely stop running.
 *
Make transitions between lifecycle states.
 *
Provide a shutdown hook, to shut down the resource.
 *

 *
 * @author Rupert Smith
 */
public abstract class StartStopLifecycleBase implements StartStopLifecycle, ShutdownHookable
{
    /** Defines the possible lifecycle states. */
    public enum State
    {
        /** Resource created, not yet running. */
        Initial,

        /** Resource running. */
        Running,

        /** Resource requested to shut down. */
        Shutdown,

        /** Resource terminated. */
        Terminated
    }

    /** The current lifecycle state. */
    protected volatile State state = State.Initial;

    /** Lock used to ensure threads are well-behaved around state changes. */
    protected ReadWriteLock stateLock = new ReentrantReadWriteLock();

    /** Condition used to signal changes of state. */
    protected Condition stateChange = stateLock.writeLock().newCondition();

    /** {@inheritDoc} */
    public void shutdown()
    {
        terminated();
    }

    /** {@inheritDoc} */
    public void shutdownNow()
    {
        terminated();
    }

    /** {@inheritDoc} */
    public Thread getShutdownHook()
    {
        return new Thread(new Runnable()
            {
                public void run()
                {
                    shutdown();
                }
            });
    }

    /**
     * Makes a transaction from the Initial state to the Running state, or no transition if the current state is not
     * Initial.
     */
    public void running()
    {
        try
        {
            stateLock.writeLock().lock();

            if (state == State.Initial)
            {
                state = State.Running;
                stateChange.signalAll();
            }
        }
        finally
        {
            stateLock.writeLock().unlock();
        }

    }

    /**
     * Makes a transaction from the Running state to the Shutdown state, or no transition if the current state is not
     * Running.
     */
    public void terminating()
    {
        try
        {
            stateLock.writeLock().lock();

            if (state == State.Running)
            {
                state = State.Shutdown;
                stateChange.signalAll();
            }
        }
        finally
        {
            stateLock.writeLock().unlock();
        }

    }

    /**
     * Makes a transaction from the Running or Shutdown state to the Terminated state, or no transition if the current
     * state is not Running or Shutdown.
     */
    public void terminated()
    {
        try
        {
            stateLock.writeLock().lock();

            if ((state == State.Shutdown) || (state == State.Running))
            {
                state = State.Terminated;
                stateChange.signalAll();
            }
        }
        finally
        {
            stateLock.writeLock().unlock();
        }

    }

    /** {@inheritDoc} */
    public boolean isShutdown()
    {
        return ((state == State.Shutdown) || (state == State.Terminated));
    }

    /** {@inheritDoc} */
    public boolean isTerminated()
    {
        return state == State.Terminated;
    }

    /** {@inheritDoc} */
    public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException
    {
        try
        {
            stateLock.writeLock().lock();

            while (state != State.Terminated)
            {
                if (!stateChange.await(timeout, unit))
                {
                    return false;
                }
            }
        }
        finally
        {
            stateLock.writeLock().unlock();
        }

        return true;
    }
}


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

import java.util.ArrayList;
import java.util.EventListener;
import java.util.LinkedList;
import java.util.List;

/**
 * EventListenerSupport provides support for managing {@link EventListener}s. A list of listeners is maintained, and
 * listeners can be added/removed from the list. A snapshot of the list may also be obtained, in a thread-safe manner,
 * in order to fire property change events to the listeners.
 *
 *

CRC Card

 *
 Responsibilities 	 Collaborations
 *
 Allow listeners

 *

 */
public class EventListenerSupport<L extends EventListener>
{
    /** The currently active set of listeners. */
    private volatile List<L> activeListeners;

    /** The definitive list of listeners. */
    private final List<L> listeners = new LinkedList<L>();

    /** A lock to use as a mutex around updates to the list of listeners. */
    private final Object listenersLock = new Object();

    /** {@inheritDoc} */
    public void addListener(L listener)
    {
        // Ensure update to the list, and rebuilding the active array happens atomically.
        synchronized (listenersLock)
        {
            listeners.add(listener);
            activeListeners = new ArrayList<L>(listeners);
        }
    }

    /** {@inheritDoc} */
    public void removeListener(L listener)
    {
        // Ensure update to the list, and rebuilding the active array happens atomically.
        synchronized (listenersLock)
        {
            listeners.remove(listener);
            activeListeners = new ArrayList<L>(listeners);
        }
    }

    /**
     * Provides an array of active listeners.
     *
     * @return An array of active listeners.
     */
    public List<L> getActiveListeners()
    {
        return activeListeners;
    }
}


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

/**
 * BaseBuiltIn provides a base-class on which built-in predicates may be implemented. It provides a default
 * implementation of the {@link BuiltIn#createContinuationStates} method, that looks at the next goal to be proved and
 * generates subsequent resolution states for it.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Create subsequent resolution states for the next goal in the proof.
 *      {@link ResolutionState}
 *

 *
 * @author Rupert Smith
 */
public abstract class BaseBuiltIn extends BuiltInFunctor
{
    /**
     * Creates the base built in on the specified functor.
     *
     * @param functor The functor to create a built-in for.
     */
    protected BaseBuiltIn(Functor functor)
    {
        super(functor);
    }

    /** {@inheritDoc} */
    public void createContinuationStates(ResolutionState state)
    {
        BuiltInFunctor nextGoal = state.getGoalStack().peek();
        state.createContinuationStatesForGoal(nextGoal);
    }
}