/*
 * 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.FilterWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.StringTokenizer;
import java.util.logging.Level;

import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;

import com.thesett.common.error.UserReadableError;

/**
 * ErrorHandler is a top-level error handler for struts based web applications. It defines a single static method for
 * handling exceptions, logging them as errors and translating them into Struts ActionErrors. This is defined here
 * rather than in {@link BaseAction} because the error handling code may also be called directly from a JSP page and not
 * just from Struts actions.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Log all top-level exceptions as errors.
 *
 Translate exceptions into errors.
 *

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

    /**
     * Converts an exception into struts action errors. The exception stack trace is stored under the 'exception'
     * message key. The message resource 'error.internalerror' is stored under the message key 'generalerror'. The stack
     * trace is pretty printed in HTML.
     *
     * @param exception The exception to be converted into struts action errors.
     * @param errors    The struts action errors object into which the action errors should be placed.
     *
     * @todo  This method can be modified to check if the exception is a user readable exception and to insert the user
     *        readable message under the 'generalerror' message key. Currently it does not handle user readable errors
     *        like this.
     */
    public static void handleErrors(Throwable exception, ActionErrors errors)
    {
        // Log the error.
        log.log(Level.SEVERE, exception.getMessage(), exception);

        if (exception.getCause() == null)
        {
            log.fine("Exception.getCause() is null");
        }

        // Unwrap the exception if it is a WrappedStrutsServletException, which is a place holder for returning
        // other throwables from struts actions.
        // See BaseAction and WrappedStrutsServletException for more information.
        if ((exception instanceof WrappedStrutsServletException) && (exception.getCause() != null))
        {
            exception = exception.getCause();
            log.fine("Unwrapped WrappedStrutsServletException");
        }

        // Create an error called 'exception' in the Struts errors for debugging purposes
        // Debugging code can print this piece of html containing the exception stack trace at the bottom
        // of the page for convenience.
        Writer stackTrace = new StringWriter();

        exception.printStackTrace(new PrintWriter(new HTMLFilter(stackTrace)));
        errors.add("exception", new ActionError("error.general", stackTrace));

        // Check if the exception is a user readable exception
        if (exception instanceof UserReadableError)
        {
            UserReadableError userError = (UserReadableError) exception;

            // Check that it contains a user readable message
            if (userError.isUserReadable())
            {
                // Check if there is an error message key to use
                if (userError.getUserMessageKey() != null)
                {
                    errors.add("generalerror",
                        new ActionError(userError.getUserMessageKey(), userError.getUserMessageKey()));
                }

                // There is no error message key to use so default to error.general and pass the error message as an
                // argument so that it will be displayed
                else
                {
                    errors.add("generalerror", new ActionError("error.general", userError.getUserMessage()));
                }

                return;
            }
        }

        // Not a user reable exception so print a standard error message
        errors.add("generalerror", new ActionError("error.internalerror"));
    }
}

/**
 * Filter writer that converts from text to HTML. This filter replaces newline characters '\n' with html line breaks.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Filter new lines into HTML line breaks.
 *

 *
 * @author Rupert Smith
 * @todo   Add more HTML filtering to this.
 */
class HTMLFilter extends FilterWriter
{
    /**
     * Creates a new HTMLFilter object.
     *
     * @param out The writer to filter output to.
     */
    public HTMLFilter(Writer out)
    {
        super(out);
    }

    /**
     * Writed a single character to the filtered writer. No filtering is done for this method.
     *
     * @param  c The character to write.
     *
     * @throws IOException If the writer won't accept the character.
     */
    public void write(int c) throws IOException
    {
        out.write(c);
    }

    /**
     * Writes an array of characters to the filtered writer. No filtering is done for this method.
     *
     * @param  cbuf The character array to write.
     * @param  off  The offset into the array to begin writing from.
     * @param  len  The number of characters to write.
     *
     * @throws IOException If the writer won't accept the character.
     */
    public void write(char[] cbuf, int off, int len) throws IOException
    {
        out.write(cbuf, off, len);
    }

    /**
     * Writes a string of characters to the filtered writer. Any newline characters '\n' are replaced with an HTML break
     * tag "<br>".
     *
     * @param  str The character array to write.
     * @param  off The offset into the array to begin writing from.
     * @param  len The number of characters to write.
     *
     * @throws IOException If the writer won't accept the string.
     */
    public void write(String str, int off, int len) throws IOException
    {
        // Get just the portion of the input string to display
        String inputString = str.substring(off, off + len);

        StringBuffer outputString = new StringBuffer();

        // Build a string tokenizer that uses '\n' as its splitting character
        // Cycle through all tokens
        for (StringTokenizer tokenizer = new StringTokenizer(inputString, "\n", true); tokenizer.hasMoreTokens();)
        {
            // Replace '\n' token with a

            String nextToken = tokenizer.nextToken();

            if ("\n".equals(nextToken))
            {
                outputString.append("
");
            }
            else
            {
                outputString.append(nextToken);
            }
        }

        // Write out the generated string
        out.write(outputString.toString());
    }
}


package com.hibegin.http.server.handler;
/*
 * @(#)ChannelIOSecure.java	1.2 04/07/26
 *
 * Copyright (c) 2004 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * -Redistribution of source code must retain the above copyright notice, this
 *  list of conditions and the following disclaimer.
 *
 * -Redistribution in binary form must reproduce the above copyright notice,
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 *
 * Neither the name of Sun Microsystems, Inc. or the names of contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * You acknowledge that this software is not designed, licensed or intended
 * for use in the design, construction, operation or maintenance of any
 * nuclear facility.
 */

import com.hibegin.common.util.BytesUtil;
import com.hibegin.common.util.LoggerUtil;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
import javax.net.ssl.SSLEngineResult.Status;
import javax.net.ssl.SSLException;
import java.io.EOFException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * A helper class which performs I/O using the SSLEngine API.
 *

 * Each connection has a SocketChannel and a SSLEngine that is
 * used through the lifetime of the Channel.  We allocate byte buffers
 * for use as the outbound and inbound network buffers.
 *

 *

 * Application Data
 * src      requestBB
 * |           ^
 * |     |     |
 * v     |     |
 * +----+-----|-----+----+
 * |          |          |
 * |       SSL|Engine    |
 * wrap()  |          |          |  unwrap()
 * | OUTBOUND | INBOUND  |
 * |          |          |
 * +----+-----|-----+----+
 * |     |     ^
 * |     |     |
 * v           |
 * outNetBB     inNetBB
 * Net data
 *

 *

 * These buffers handle all of the intermediary data for the SSL
 * connection.  To make things easy, we'll require outNetBB be
 * completely flushed before trying to wrap any more data, but we
 * could certainly remove that restriction by using larger buffers.
 *

 * There are many, many ways to handle compute and I/O strategies.
 * What follows is a relatively simple one.  The reader is encouraged
 * to develop the strategy that best fits the application.
 *

 * In most of the non-blocking operations in this class, we let the
 * Selector tell us when we're ready to attempt an I/O operation (by the
 * application repeatedly calling our methods).  Another option would be
 * to attempt the operation and return from the method when no forward
 * progress can be made.
 *

 * There's lots of room for enhancements and improvement in this example.
 *

 * We're checking for SSL/TLS end-of-stream truncation attacks via
 * sslEngine.closeInbound().  When you reach the end of a input stream
 * via a read() returning -1 or an IOException, we call
 * sslEngine.closeInbound() to signal to the sslEngine that no more
 * input will be available.  If the peer's close_notify message has not
 * yet been received, this could indicate a trucation attack, in which
 * an attacker is trying to prematurely close the connection.   The
 * closeInbound() will throw an exception if this condition were
 * present.
 *
 * @author Brad R. Wetmore
 * @author Mark Reinhold
 * @version 1.2, 04/07/26
 */
public class SSLReadWriteSelectorHandler extends PlainReadWriteSelectorHandler {

    private static final Logger LOGGER = LoggerUtil.getLogger(SSLReadWriteSelectorHandler.class);
    /*
     * An empty ByteBuffer for use when one isn't available, say
     * as a source buffer during initial handshake wraps or for close
     * operations.
     */
    private static ByteBuffer hsBB = ByteBuffer.allocate(0);
    private SSLEngine sslEngine = null;
    /*
     * All I/O goes through these buffers.
     *

     * It might be nice to use a cache of ByteBuffers so we're
     * not alloc/dealloc'ing ByteBuffer's for each new SSLEngine.
     *

     * We use our superclass' requestBB for our application input buffer.
     * Outbound application data is supplied to us by our callers.
     */
    private ByteBuffer inNetBB;
    private ByteBuffer outNetBB;
    /*
     * The FileChannel we're currently transferTo'ing (reading).
     */
    private ByteBuffer fileChannelBB = null;

    /*
     * During our initial handshake, keep track of the next
     * SSLEngine operation that needs to occur:
     *
     *     NEED_WRAP/NEED_UNWRAP
     *
     * Once the initial handshake has completed, we can short circuit
     * handshake checks with initialHSComplete.
     */
    private HandshakeStatus initialHSStatus;
    private boolean initialHSComplete;

    /*
     * We have received the shutdown request by our caller, and have
     * closed our outbound side.
     */
    private boolean shutdown = false;

    /*
     * Constructor for a secure ChannelIO variant.
     */
    public SSLReadWriteSelectorHandler(SocketChannel sc, SelectionKey selectionKey,
                                       SSLContext sslContext) throws IOException {
        super(sc);

        sslEngine = sslContext.createSSLEngine();
        sslEngine.setUseClientMode(false);
        initialHSStatus = HandshakeStatus.NEED_UNWRAP;
        initialHSComplete = false;

        int netBBSize = sslEngine.getSession().getPacketBufferSize();
        inNetBB = ByteBuffer.allocate(netBBSize);
        outNetBB = ByteBuffer.allocate(netBBSize);
        outNetBB.position(0);
        outNetBB.limit(0);

        int appBBSize = sslEngine.getSession().getApplicationBufferSize();
        requestBB = ByteBuffer.allocate(appBBSize);

        while (!doHandshake(selectionKey)) ;
    }

    /*
     * Writes bb to the SocketChannel.
     *

     * Returns true when the ByteBuffer has no remaining data.
     */
    private boolean tryFlush(ByteBuffer bb) throws IOException {
        sc.write(bb);
        return !bb.hasRemaining();
    }

    /*
     * Perform any handshaking processing.
     *

     * If a SelectionKey is passed, register for selectable
     * operations.
     *

     * In the blocking case, our caller will keep calling us until
     * we finish the handshake.  Our reads/writes will block as expected.
     *

     * In the non-blocking case, we just received the selection notification
     * that this channel is ready for whatever the operation is, so give
     * it a try.
     *

     * return:
     *		true when handshake is done.
     *		false while handshake is in progress
     */
    boolean doHandshake(SelectionKey sk) throws IOException {

        SSLEngineResult result;

        if (initialHSComplete) {
            return true;
        }

	/*
     * Flush out the outgoing buffer, if there's anything left in
	 * it.
	 */
        if (outNetBB.hasRemaining()) {

            if (!tryFlush(outNetBB)) {
                return false;
            }

            // See if we need to switch from write to read mode.

            switch (initialHSStatus) {

	    /*
         * Is this the last buffer?
	     */
                case FINISHED:
                    initialHSComplete = true;
                    // Fall-through to reregister need for a Read.

                case NEED_UNWRAP:
                    if (sk != null) {
                        sk.interestOps(SelectionKey.OP_READ);
                    }
                    break;
            }

            return initialHSComplete;
        }

        switch (initialHSStatus) {

            case NEED_UNWRAP:
                if (sc.read(inNetBB) == -1) {
                    sslEngine.closeInbound();
                    return initialHSComplete;
                }

                needIO:
                while (initialHSStatus == HandshakeStatus.NEED_UNWRAP) {
        /*
         * Don't need to resize requestBB, since no app data should
		 * be generated here.
		 */
                    inNetBB.flip();
                    result = sslEngine.unwrap(inNetBB, requestBB);
                    inNetBB.compact();

                    initialHSStatus = result.getHandshakeStatus();

                    switch (result.getStatus()) {

                        case OK:
                            switch (initialHSStatus) {
                                case NOT_HANDSHAKING:
                                    throw new IOException(
                                            "Not handshaking during initial handshake");

                                case NEED_TASK:
                                    initialHSStatus = doTasks();
                                    break;

                                case FINISHED:
                                    initialHSComplete = true;
                                    break needIO;
                            }

                            break;

                        case BUFFER_UNDERFLOW:
            /*
             * Need to go reread the Channel for more data.
		     */
                            if (sk != null) {
                                sk.interestOps(SelectionKey.OP_READ);
                            }
                            break needIO;

                        default: // BUFFER_OVERFLOW/CLOSED:
                            throw new IOException("Received" + result.getStatus() +
                                    "during initial handshaking");
                    }
                }  // "needIO" block.

	    /*
         * Just transitioned from read to write.
	     */
                if (initialHSStatus != HandshakeStatus.NEED_WRAP) {
                    break;
                }

                // Fall through and fill the write buffers.

            case NEED_WRAP:
        /*
         * The flush above guarantees the out buffer to be empty
	     */
                outNetBB.clear();
                result = sslEngine.wrap(hsBB, outNetBB);
                outNetBB.flip();

                initialHSStatus = result.getHandshakeStatus();

                switch (result.getStatus()) {
                    case OK:

                        if (initialHSStatus == HandshakeStatus.NEED_TASK) {
                            initialHSStatus = doTasks();
                        }

                        if (sk != null) {
                            sk.interestOps(SelectionKey.OP_WRITE);
                        }

                        break;

                    default: // BUFFER_OVERFLOW/BUFFER_UNDERFLOW/CLOSED:
                        throw new IOException("Received" + result.getStatus() +
                                "during initial handshaking");
                }
                break;

            default: // NOT_HANDSHAKING/NEED_TASK/FINISHED
                throw new RuntimeException("Invalid Handshaking State" +
                        initialHSStatus);
        } // switch

        return initialHSComplete;
    }

    /*
     * Do all the outstanding handshake tasks in the current Thread.
     */
    private SSLEngineResult.HandshakeStatus doTasks() {

        Runnable runnable;

	/*
     * We could run this in a separate thread, but
	 * do in the current for now.
	 */
        while ((runnable = sslEngine.getDelegatedTask()) != null) {
            runnable.run();
        }
        return sslEngine.getHandshakeStatus();
    }

    /*
     * Read the channel for more information, then unwrap the
     * (hopefully application) data we get.
     *

     * If we run out of data, we'll return to our caller (possibly using
     * a Selector) to get notification that more is available.
     *

     * Each call to this method will perform at most one underlying read().
     */
    ByteBuffer read() throws IOException {
        SSLEngineResult result;

        if (!initialHSComplete) {
            throw new IllegalStateException();
        }

        int pos = requestBB.position();

        if (sc.read(inNetBB) == -1) {
            sslEngine.closeInbound();  // probably throws exception
            throw new EOFException();
        }

        do {
            resizeRequestBB(inNetBB.remaining());    // guarantees enough room for unwrap
            inNetBB.flip();
            result = sslEngine.unwrap(inNetBB, requestBB);
            inNetBB.compact();

	    /*
         * Could check here for a renegotation, but we're only
	     * doing a simple read/write, and won't have enough state
	     * transitions to do a complete handshake, so ignore that
	     * possibility.
	     */
            switch (result.getStatus()) {

                case BUFFER_UNDERFLOW:
                case OK:
                    if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
                        doTasks();
                    }
                    break;

                default:
                    throw new IOException("sslEngine error during data read: " +
                            result.getStatus());
            }
        } while ((inNetBB.position() != 0) &&
                result.getStatus() != Status.BUFFER_UNDERFLOW);
        int readLength = requestBB.position() - pos;
        ByteBuffer byteBuffer = ByteBuffer.allocate(readLength);
        byteBuffer.put(BytesUtil.subBytes(requestBB.array(), pos, readLength));
        return byteBuffer;
    }

    /*
     * Try to flush out any existing outbound data, then try to wrap
     * anything new contained in the src buffer.
     *

     * Return the number of bytes actually consumed from the buffer,
     * but the data may actually be still sitting in the output buffer,
     * waiting to be flushed.
     */
    private int doWrite(ByteBuffer src) throws IOException {
        int retValue = 0;

        if (outNetBB.hasRemaining() && !tryFlush(outNetBB)) {
            return retValue;
        }

	/*
     * The data buffer is empty, we can reuse the entire buffer.
	 */
        outNetBB.clear();

        SSLEngineResult result = sslEngine.wrap(src, outNetBB);
        retValue = result.bytesConsumed();

        outNetBB.flip();

        switch (result.getStatus()) {

            case OK:
                if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
                    doTasks();
                }
                break;

            default:
                throw new IOException("sslEngine error during data write: " +
                        result.getStatus());
        }

	/*
     * Try to flush the data, regardless of whether or not
	 * it's been selected.  Odds of a write buffer being full
	 * is less than a read buffer being empty.
	 */
        tryFlush(src);
        if (outNetBB.hasRemaining()) {
            tryFlush(outNetBB);
        }

        return retValue;
    }

    /*
     * Flush any remaining data.
     *

     * Return true when the fileChannelBB and outNetBB are empty.
     */
    boolean dataFlush() throws IOException {
        boolean fileFlushed = true;

        if ((fileChannelBB != null) && fileChannelBB.hasRemaining()) {
            doWrite(fileChannelBB);
            fileFlushed = !fileChannelBB.hasRemaining();
        } else if (outNetBB.hasRemaining()) {
            tryFlush(outNetBB);
        }

        return (fileFlushed && !outNetBB.hasRemaining());
    }

    /*
     * Begin the shutdown process.
     *

     * Close out the SSLEngine if not already done so, then
     * wrap our outgoing close_notify message and try to send it on.
     *

     * Return true when we're done passing the shutdown messsages.
     */
    boolean shutdown() throws IOException {

        if (!shutdown) {
            sslEngine.closeOutbound();
            shutdown = true;
        }

        if (outNetBB.hasRemaining() && tryFlush(outNetBB)) {
            return false;
        }

	/*
     * By RFC 2616, we can "fire and forget" our close_notify
	 * message, so that's what we'll do here.
	 */
        outNetBB.clear();
        SSLEngineResult result = sslEngine.wrap(hsBB, outNetBB);
        if (result.getStatus() != Status.CLOSED) {
            throw new SSLException("Improper close state");
        }
        outNetBB.flip();

	/*
     * We won't wait for a select here, but if this doesn't work,
	 * we'll cycle back through on the next select.
	 */
        if (outNetBB.hasRemaining()) {
            tryFlush(outNetBB);
        }

        return (!outNetBB.hasRemaining() &&
                (result.getHandshakeStatus() != HandshakeStatus.NEED_WRAP));
    }

    @Override
    public void handleWrite(ByteBuffer byteBuffer) throws IOException {
        byteBuffer.flip();
        while (byteBuffer.hasRemaining() && sc.isOpen()) {
            int len = doWrite(byteBuffer);
            if (len < 0) {
                throw new EOFException();
            }
        }
    }

    @Override
    public ByteBuffer handleRead() throws IOException {
        return read();
    }

    @Override
    public void close() {
        try {
            while (!dataFlush()) {

            }
            do {
            } while (!shutdown());
            super.close();
        } catch (IOException e) {
            LOGGER.log(Level.SEVERE, "", e);
        }
    }
}


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

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

import com.thesett.aima.logic.fol.Clause;
import com.thesett.aima.logic.fol.ClauseTraverser;
import com.thesett.aima.logic.fol.ClauseVisitor;
import com.thesett.aima.logic.fol.Functor;
import com.thesett.aima.logic.fol.FunctorTraverser;
import com.thesett.aima.logic.fol.Predicate;
import com.thesett.aima.logic.fol.PredicateTraverser;
import com.thesett.aima.logic.fol.PredicateVisitor;
import com.thesett.aima.logic.fol.Term;
import com.thesett.aima.search.Operator;
import com.thesett.aima.search.util.backtracking.Reversable;
import com.thesett.common.util.StackQueue;

/**
 * BasicTraverser provides methods to produce reversible {@link Operator}s to transition over the structure of a
 * {@link Term}. Structurally terms are built up as clauses, and functors, and default methods are provided to iterate
 * over these constructions, with flags to set to determines whether heads or bodies of clauses are explored first, and
 * whether the arguments of functors are explored left-to-right or right-to-left.
 *
 *
A BasicTraverser can be extended to form a concrete traverser over terms by providing implementations of the
 * methods to create operators for traversing into clause heads or bodies, and the arguments of functors. Any optional
 * visit method to visit the root of a clause being traversed may be also be implemented, usually to initialize the root
 * context of the traversal.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Establish an initial positional context upon visiting a clause.
 *
 Provide traversal operators over clauses.
 *
 Provide traversal operators over functors.
 *

 *
 * @author Rupert Smith
 */
public abstract class BasicTraverser implements PredicateTraverser, ClauseTraverser, FunctorTraverser, ClauseVisitor,
    PredicateVisitor
{
    /** Used for debugging purposes. */
    /* private static final Logger log = Logger.getLogger(BasicTraverser.class.getName()); */

    /** Flag used to indicate that clause heads should come before bodies in the left-to-right ordering of clauses. */
    protected boolean clauseHeadFirst;

    /** Flag used to indicate that clause bodies should be taken in the intuitive left-to-right ordering. */
    protected boolean leftToRightClauseBodies;

    /** Flag used to indicate that predicate bodies should be taken in the intuitive left-to-right ordering. */
    protected boolean leftToRightPredicateBodies;

    /** Flag used to indicate that functor arguments should be taken in the intuitive left-to-right ordering. */
    protected boolean leftToRightFunctorArgs;

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

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

    /**
     * {@inheritDoc}
     *
     *
Can be used to visit a predicate, to set up an initial context for predicate traversals.
     */
    public abstract void visit(Predicate predicate);

    /**
     * {@inheritDoc}
     *
     *
Can be used to visit a clause, to set up an initial context for clause traversals.
     */
    public abstract void visit(Clause clause);

    /** {@inheritDoc} */
    public Iterator<Operator<Term>> traverse(Predicate predicate, boolean reverse)
    {
        /*log.fine("Traversing predicate " + predicate.toString());*/

        Clause[] body = predicate.getBody();

        Queue<Operator<Term>> queue = (!reverse) ? new StackQueue<Operator<Term>>() : new LinkedList<Operator<Term>>();

        // For the predicate bodies.
        if (body != null)
        {
            for (int i = leftToRightPredicateBodies ? 0 : (body.length - 1);
                    leftToRightPredicateBodies ? (i = 0);
                    i = i + (leftToRightPredicateBodies ? 1 : -1))
            {
                Clause bodyClause = body[i];

                bodyClause.setReversable(createClauseOperator(bodyClause, i, body, predicate));
                bodyClause.setTermTraverser(this);
                queue.offer(bodyClause);
            }
        }

        return queue.iterator();
    }

    /** {@inheritDoc} */
    public Iterator<Operator<Term>> traverse(Clause clause, boolean reverse)
    {
        /*log.fine("Traversing clause " + clause.toString());*/

        Functor head = clause.getHead();
        Functor[] body = clause.getBody();

        Queue<Operator<Term>> queue = (!reverse) ? new StackQueue<Operator<Term>>() : new LinkedList<Operator<Term>>();

        // For the head functor, set the top-level flag, set in head context.
        if (head != null)
        {
            head.setReversable(createHeadOperator(head, clause));
            head.setTermTraverser(this);
            queue.offer(head);
        }

        // For the body functors, set the top-level flag, clear in head context.
        if (body != null)
        {
            for (int i = leftToRightClauseBodies ? 0 : (body.length - 1);
                    leftToRightClauseBodies ? (i = 0); i = i + (leftToRightClauseBodies ? 1 : -1))
            {
                Functor bodyFunctor = body[i];

                bodyFunctor.setReversable(createBodyOperator(bodyFunctor, i, body, clause));
                bodyFunctor.setTermTraverser(this);
                queue.offer(bodyFunctor);
            }
        }

        return queue.iterator();
    }

    /** {@inheritDoc} */
    public Iterator<Operator<Term>> traverse(Functor functor, boolean reverse)
    {
        /*log.fine("Traversing functor " + functor.toString());*/

        Queue<Operator<Term>> queue = (!reverse) ? new StackQueue<Operator<Term>>() : new LinkedList<Operator<Term>>();

        Term[] arguments = functor.getArguments();

        // For a top-level functor clear top-level flag, so that child functors are not taken as top-level.
        if (arguments != null)
        {
            for (int i = leftToRightFunctorArgs ? 0 : (arguments.length - 1);
                    leftToRightFunctorArgs ? (i < arguments.length) : (i >= 0);
                    i = i + (leftToRightFunctorArgs ? 1 : -1))
            {
                Term argument = arguments[i];
                argument.setReversable(createTermOperator(argument, i, functor));
                argument.setTermTraverser(this);
                queue.offer(argument);
            }
        }

        return queue.iterator();
    }

    /**
     * When traversing the head of a clause, creates a reversible operator to use to transition into the head.
     *
     * @param  head   The head to transition into.
     * @param  clause The containing clause.
     *
     * @return A reversable operator.
     */
    protected abstract StackableOperator createHeadOperator(Functor head, Clause clause);

    /**
     * When traversing the body functors of a clause, creates a reversible operator to use to transition into each body
     * functor.
     *
     * @param  bodyFunctor The body functor to transition into.
     * @param  pos         The position of the body functor within the body.
     * @param  body        The containing body.
     * @param  clause      The containing clause.
     *
     * @return A reversable operator.
     */
    protected abstract StackableOperator createBodyOperator(Functor bodyFunctor, int pos, Functor[] body,
        Clause clause);

    /**
     * When traversing the body clauses of a predicate, creates a reversible operator to use to transition into each
     * body clause.
     *
     * @param  bodyClause The body clause to transition into.
     * @param  pos        The position of the body clause within the body.
     * @param  body       The containing body.
     * @param  predicate  The containing predicate.
     *
     * @return A reversable operator.
     */
    protected abstract StackableOperator createClauseOperator(Clause bodyClause, int pos, Clause[] body,
        Predicate predicate);

    /**
     * When traversing the argument terms of a functor, creates a reversible operator to use to transition into each
     * argument term.
     *
     * @param  argument The argument term to transition into.
     * @param  pos      The position of the argument within the functor.
     * @param  functor  The containing functor.
     *
     * @return A reversable operator.
     */
    protected abstract StackableOperator createTermOperator(Term argument, int pos, Functor functor);

    /**
     * StackableOperator is a {@link Reversable} operator that can also delegates to another stackable operation by
     * default. This allows stack of operators to be built and applied or undone on every state transition.
     *
     *

CRC Card

     *
 Responsibilities  Collaborations
     *
 Delegate to a stackable operation.
     *

     */
    protected class StackableOperator implements Reversable
    {
        /** The optional stackable delegate operation. */
        StackableOperator delegate;

        /**
         * Creates an reversible operator with a delegate.
         *
         * @param delegate An optional delegate to chain onto, may be <tt>null</tt>.
         */
        public StackableOperator(StackableOperator delegate)
        {
            this.delegate = delegate;
        }

        /** {@inheritDoc} */
        public void applyOperator()
        {
            if (delegate != null)
            {
                delegate.applyOperator();
            }
        }

        /** {@inheritDoc} */
        public void undoOperator()
        {
            if (delegate != null)
            {
                delegate.undoOperator();
            }
        }
    }
}


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

import com.thesett.aima.logic.fol.BasePositionalVisitor;
import com.thesett.aima.logic.fol.Functor;
import com.thesett.aima.logic.fol.PositionalTermVisitor;
import com.thesett.aima.logic.fol.Term;
import com.thesett.aima.logic.fol.VariableAndFunctorInterner;
import com.thesett.aima.logic.fol.compiler.PositionalContext;
import com.thesett.aima.logic.fol.compiler.PositionalTermTraverser;
import com.thesett.aima.logic.fol.wam.builtins.Conjunction;
import com.thesett.aima.logic.fol.wam.builtins.Disjunction;
import com.thesett.common.util.doublemaps.SymbolTable;

/**
 * Conjunctions and disjunctions are treated specially by this transform. The conjunction and disjunction operators may
 * appear within any structure, but are only to be compiled as such if they are 'top-level'. They are considered
 * top-level when they appear at the top-level within a clause, or directly beneath a parent conjunction or disjunction
 * that is considered to be top-level. Effectively they are flattened into the top-level of the clause in which they
 * appear, but the original structure is preserved rather than actually flattened at this time, as it can change meaning
 * depending on how the term is bracketed.
 *
 *
This traversal simply marks all conjunctions and disjunctions that are part of the clause top-level, with the
 * top-level flag. The functors appearing as arguments to those terms, are also marked as top-level, since they will be
 * evaluated by the clause, not treated as structure definitions.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Check which functors are considered to be top-level within a clause.

 *

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

    /**
     * Creates the visitor with the supplied interner, symbol table and traverser.
     *
     * @param interner    The name interner.
     * @param symbolTable The compiler symbol table.
     * @param traverser   The positional context traverser.
     */
    TopLevelCheckVisitor(VariableAndFunctorInterner interner, SymbolTable<Integer, String, Object> symbolTable,
        PositionalTermTraverser traverser)
    {
        super(interner, symbolTable, traverser);
    }

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

    /**
     * {@inheritDoc}
     *
     *
Sets the top-level flag on a functor, if appropriate.
     */
    protected void enterFunctor(Functor functor)
    {
        if (isTopLevel())
        {
            symbolTable.put(functor.getSymbolKey(), SymbolTableKeys.SYMKEY_TOP_LEVEL_FUNCTOR, true);
        }
    }

    /**
     * Functors are considered top-level when they appear at the top-level within a clause, or directly beneath a parent
     * conjunction or disjunction that is considered to be top-level.
     *
     * @return <tt>true</tt> iff the current position is considered to be top-level.
     */
    private boolean isTopLevel()
    {
        if (traverser.isTopLevel())
        {
            return true;
        }
        else
        {
            PositionalContext parentContext = traverser.getParentContext();

            if (parentContext != null)
            {
                Term parentTerm = parentContext.getTerm();

                if ((parentTerm instanceof Conjunction) || (parentTerm instanceof Disjunction))
                {
                    Boolean isTopLevel =
                        (Boolean) symbolTable.get(parentTerm.getSymbolKey(), SymbolTableKeys.SYMKEY_TOP_LEVEL_FUNCTOR);

                    return (isTopLevel == null) ? false : isTopLevel;
                }
            }
        }

        return false;
    }
}


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

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

import com.thesett.common.util.doublemaps.HashMapXY;
import com.thesett.text.api.TextGridEvent;
import com.thesett.text.api.TextTableEvent;
import com.thesett.text.api.TextTableListener;
import com.thesett.text.impl.model.TextGridImpl;
import com.thesett.text.impl.model.TextTableGridRenderer;

/**
 * EnhancedTextGridImpl provides an implementation of the enhanced text grid model.
 *
 *

CRC Card

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

 *
 Insert text attributes into grid columns.

 *
 Insert text attributes into grid rows.

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

 *

 *
 * @author Rupert Smith
 */
public class EnhancedTextGridImpl extends TextGridImpl implements EnhancedTextGrid
{
    /** The attributes arranged in a grid. */
    protected final AttributeGrid attributeGrid = new AttributeGridImpl();

    /** The horizontal and vertical separators. */
    protected final XYGridSeparators separators = new XYGridSeparatorsImpl();

    /** Holds selection listeners, that will receive mouse events translated to table coordinates. */
    private final Collection<TextGridSelectionListener> textGridSelectionListeners = new HashSet<TextGridSelectionListener>();

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

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

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

    /** {@inheritDoc} */
    public AttributeSet getAttributeAt(int c, int r)
    {
        return attributeGrid.getAttributeAt(c, r);
    }

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

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

    /** {@inheritDoc} */
    public void insertHorizontalSeparator(int r, int pixelHeight)
    {
        separators.insertHorizontalSeparator(r, pixelHeight);
    }

    /** {@inheritDoc} */
    public void insertVerticalSeparator(int c, int pixelWidth)
    {
        separators.insertVerticalSeparator(c, pixelWidth);
    }

    /** {@inheritDoc} */
    public SortedMap<Integer, Integer> getHorizontalSeparators()
    {
        return separators.getHorizontalSeparators();
    }

    /** {@inheritDoc} */
    public SortedMap<Integer, Integer> getVerticalSeparators()
    {
        return separators.getVerticalSeparators();
    }

    /** {@inheritDoc} */
    public void select(int row, int col)
    {
        for (TextGridSelectionListener listener : textGridSelectionListeners)
        {
            listener.select(new TextGridEvent(this, row, col));
        }
    }

    /** {@inheritDoc} */
    public void addTextGridSelectionListener(TextGridSelectionListener listener)
    {
        textGridSelectionListeners.add(listener);
    }

    /** {@inheritDoc} */
    public void removeTextGridSelectionListener(TextGridSelectionListener listener)
    {
        textGridSelectionListeners.remove(listener);
    }

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

        textTable.addTextTableListener(new EnhancedTableListener());

        return textTable;
    }

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


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

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

import com.thesett.aima.learning.ClassifyingFailureException;
import com.thesett.aima.learning.decisiontree.DecisionTreeMachine;
import com.thesett.aima.state.OrdinalAttribute;
import com.thesett.aima.state.State;

/**
 * ProtoDTMachine is a classifying machine that is backed by a decision tree. It takes a state and classifies it by
 * passing the state down its decision tree, branching on the assigned values of its properties at each decision node,
 * until is reaches a leaf that assigns a classification to the state. It returns this as its belief about the
 * classification of the state.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Perform a classification on a state using a decision tree  {@link DecisionTree}
 *

 *
 * @author Rupert Smith
 * @todo   Decide what happens if a state is missing a decision property?
 * @todo   Decide what happens if a state has a property but its attribute value does not match the type expected by the
 *         decision tree. Could either throw an exception or behave as if the property is missing.
 */
public class ProtoDTMachine implements DecisionTreeMachine
{
    /** Used to hold the decision tree that backs the machine. */
    private DecisionTree dt;

    /**
     * Sets the decision tree that the machine operates on.
     *
     * @param tree The decision tree to control the dt machine with.
     */
    public void setDecisionTree(DecisionTree tree)
    {
        this.dt = tree;
    }

    /**
     * Classifies a state using the decision tree.
     *
     * @param  state The input data point to classify.
     *
     * @return A classification of the data point as an mapping from the output property that the decision tree was
     *         trained on to this classifiers belief abouts its value.
     *
     * @throws ClassifyingFailureException If the decision tree is not completed and this classifier encounters a
     *                                     pending node in the tree that is still to be built.
     */
    public Map<String, OrdinalAttribute> classify(State state) throws ClassifyingFailureException
    {
        // Start at the root of the decision tree.
        DecisionTree currentNode = dt;

        // Loop down the decision tree until a leaf node is found.
        while (true) // !currentNode.isLeaf())
        {
            DecisionTreeElement element = currentNode.getElement();

            // Check that the current element really is a decision.
            if (element instanceof Decision)
            {
                Decision decision = (Decision) element;

                // Apply the decision at the current node to the state to be classified to get a new tree.
                currentNode = decision.decide(state); // , currentNode);
            }
            else if (element instanceof Assignment)
            {
                // Cast the element to an Assignment as this is the only type of leaf that is possible.
                Assignment assignment = (Assignment) element;

                // Return the assignment in a map.
                Map<String, OrdinalAttribute> assignmentMap = new HashMap<String, OrdinalAttribute>();

                assignmentMap.put(assignment.getPropertyName(), assignment.getAttribute());

                return assignmentMap;
            }

            // It is possible that a node may be of type Pending if an incomplete tree has been used to
            // run this classification on.
            else
            {
                // Throw a classification exception due to an incomplete decision tree.
                throw new ClassifyingFailureException("A node which is not a decision was encountered.", null);
            }
            // What happens if the decision could not operate on the state, either because of a missing property or
            // because its property was not of the type that the decision was expecting? Can either throw an exception,
            // return an empty assignment, or implement an algorithm for coping with missing properties.
        }
    }
}


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

import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;

import org.hobsoft.microbrowser.Form;
import org.hobsoft.microbrowser.FormNotFoundException;
import org.hobsoft.microbrowser.Link;
import org.hobsoft.microbrowser.LinkNotFoundException;
import org.hobsoft.microbrowser.MicrodataItem;
import org.hobsoft.microbrowser.MicrodataProperty;
import org.hobsoft.microbrowser.MicrodataPropertyNotFoundException;
import org.junit.Test;

import com.squareup.okhttp.mockwebserver.MockResponse;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.empty;
import static org.hobsoft.microbrowser.tck.support.MicrobrowserMatchers.link;
import static org.hobsoft.microbrowser.tck.support.mockwebserver.MockWebServerUtils.url;
import static org.junit.Assert.assertThat;

/**
 * TCK for {@code MicrodataItem}.
 */
public abstract class MicrodataItemTck extends AbstractMicrobrowserTest
{
	// ----------------------------------------------------------------------------------------------------------------
	// getId tests
	// ----------------------------------------------------------------------------------------------------------------

	@Test
	public void getIdReturnsId() throws MalformedURLException
	{
		server().enqueue(new MockResponse().setBody(""
			+ "
"
			+ ""));

		URL actual = newBrowser().get(url(server()))
			.getItem("http://y")
			.getId();

		assertThat("item id", actual, is(new URL("http://x")));
	}

	@Test
	public void getIdReturnsTrimmedId() throws MalformedURLException
	{
		server().enqueue(new MockResponse().setBody(""
			+ "
"
			+ ""));

		URL actual = newBrowser().get(url(server()))
			.getItem("http://y")
			.getId();

		assertThat("item id", actual, is(new URL("http://x")));
	}

	@Test
	public void getIdWhenInvalidReturnsNull()
	{
		server().enqueue(new MockResponse().setBody(""
			+ "
"
			+ ""));

		URL actual = newBrowser().get(url(server()))
			.getItem("http://y")
			.getId();

		assertThat("item id", actual, is(nullValue()));
	}

	@Test
	public void getIdWhenNotFoundReturnsNull()
	{
		server().enqueue(new MockResponse().setBody(""
			+ "
"
			+ ""));

		URL actual = newBrowser().get(url(server()))
			.getItem("http://y")
			.getId();

		assertThat("item id", actual, is(nullValue()));
	}

	// ----------------------------------------------------------------------------------------------------------------
	// getType tests
	// ----------------------------------------------------------------------------------------------------------------

	@Test
	public void getTypeReturnsType() throws MalformedURLException
	{
		server().enqueue(new MockResponse().setBody(""
			+ "
"
			+ ""));

		URL actual = newBrowser().get(url(server()))
			.getItem("http://x")
			.getType();

		assertThat("item type", actual, is(new URL("http://x")));
	}

	// ----------------------------------------------------------------------------------------------------------------
	// getProperty tests
	// ----------------------------------------------------------------------------------------------------------------

	@Test
	public void getPropertyReturnsProperty()
	{
		server().enqueue(new MockResponse().setBody(""
			+ "
"
			+ "
"
			+ "
"
			+ ""));

		MicrodataProperty actual = newBrowser().get(url(server()))
			.getItem("http://i")
			.getProperty("x");

		assertThat("item property", actual.getName(), is("x"));
	}

	@Test
	public void getPropertyWithUnknownNameThrowsException()
	{
		server().enqueue(new MockResponse().setBody(""
			+ "
"
			+ ""));

		MicrodataItem item = newBrowser().get(url(server()))
			.getItem("http://i");

		thrown().expect(MicrodataPropertyNotFoundException.class);
		thrown().expectMessage("x");

		item.getProperty("x");
	}

	// ----------------------------------------------------------------------------------------------------------------
	// getLink tests
	// ----------------------------------------------------------------------------------------------------------------

	@Test
	public void getLinkWhenAnchorReturnsLink() throws MalformedURLException
	{
		server().enqueue(new MockResponse().setBody(""
			+ "
"
			+ ""
			+ "
"
			+ ""));

		Link actual = newBrowser().get(url(server()))
			.getItem("http://i")
			.getLink("x");

		assertThat("link", actual, is(link("x", "http://y/")));
	}

	@Test
	public void getLinkWhenLinkReturnsLink() throws MalformedURLException
	{
		server().enqueue(new MockResponse().setBody(""
			+ "
"
			+ "<link rel='x' href='http://y/'/>"
			+ "
"
			+ ""));

		Link actual = newBrowser().get(url(server()))
			.getItem("http://i")
			.getLink("x");

		assertThat("link", actual, is(link("x", "http://y/")));
	}

	@Test
	public void getLinkWithUnknownRelThrowsException()
	{
		server().enqueue(new MockResponse().setBody(""
			+ "
"
			+ ""));

		MicrodataItem item = newBrowser().get(url(server()))
			.getItem("http://i");

		thrown().expect(LinkNotFoundException.class);
		thrown().expectMessage("x");

		item.getLink("x");
	}

	// ----------------------------------------------------------------------------------------------------------------
	// getLinks tests
	// ----------------------------------------------------------------------------------------------------------------

	@Test
	public void getLinksWhenAnchorReturnsLink() throws MalformedURLException
	{
		server().enqueue(new MockResponse().setBody(""
			+ "
"
			+ ""
			+ "
"
			+ ""));

		List<Link> actual = newBrowser().get(url(server()))
			.getItem("http://i")
			.getLinks("x");

		assertThat("links", actual, contains(link("x", "http://y/")));
	}

	@Test
	public void getLinksWhenAnchorsReturnsLinks() throws MalformedURLException
	{
		server().enqueue(new MockResponse().setBody(""
			+ "
"
			+ ""
			+ ""
			+ "
"
			+ ""));

		List<Link> actual = newBrowser().get(url(server()))
			.getItem("http://i")
			.getLinks("x");

		assertThat("links", actual, contains(
			link("x", "http://y/"),
			link("x", "http://z/")
		));
	}

	@Test
	public void getLinksWhenLinkReturnsLink() throws MalformedURLException
	{
		server().enqueue(new MockResponse().setBody(""
			+ "
"
			+ "<link rel='x' href='http://y/'/>"
			+ "
"
			+ ""));

		List<Link> actual = newBrowser().get(url(server()))
			.getItem("http://i")
			.getLinks("x");

		assertThat("link", actual, contains(link("x", "http://y/")));
	}

	@Test
	public void getLinksWhenLinksReturnsLinks() throws MalformedURLException
	{
		server().enqueue(new MockResponse().setBody(""
			+ "
"
			+ "<link rel='x' href='http://y/'/>"
			+ "<link rel='x' href='http://z/'/>"
			+ "
"
			+ ""));

		List<Link> actual = newBrowser().get(url(server()))
			.getItem("http://i")
			.getLinks("x");

		assertThat("link", actual, contains(
			link("x", "http://y/"),
			link("x", "http://z/")
		));
	}

	@Test
	public void getLinksWithUnknownRelReturnsEmptyList()
	{
		server().enqueue(new MockResponse().setBody(""
			+ "
"
			+ ""));

		List<Link> actual = newBrowser().get(url(server()))
			.getItem("http://i")
			.getLinks("x");

		assertThat("link", actual, is(empty()));
	}

	// ----------------------------------------------------------------------------------------------------------------
	// getForm tests
	// ----------------------------------------------------------------------------------------------------------------

	@Test
	public void getFormReturnsForm()
	{
		server().enqueue(new MockResponse().setBody(""
			+ "
"
			+ "<form name='x'/>"
			+ "
"
			+ ""));

		Form actual = newBrowser().get(url(server()))
			.getItem("http://i")
			.getForm("x");

		assertThat("form", actual.getName(), is("x"));
	}

	@Test
	public void getFormRetainsSetControlValues()
	{
		server().enqueue(new MockResponse().setBody(""
			+ "
"
			+ "<form name='f'>"
			+ "<input type='text' name='c'/>"
			+ "</form>"
			+ "
"
			+ ""));

		MicrodataItem item = newBrowser().get(url(server()))
			.getItem("http://i");
		item.getForm("f")
			.setControlValue("c", "x");

		assertThat("form control value", item.getForm("f").getControlValue("c"), is("x"));
	}

	@Test
	public void getFormWhenNotFoundThrowsException()
	{
		server().enqueue(new MockResponse().setBody(""
			+ "
"
			+ ""));

		MicrodataItem item = newBrowser().get(url(server()))
			.getItem("http://i");

		thrown().expect(FormNotFoundException.class);
		thrown().expectMessage("x");

		item.getForm("x");
	}

	// ----------------------------------------------------------------------------------------------------------------
	// unwrap tests
	// ----------------------------------------------------------------------------------------------------------------

	@Test
	public void unwrapWithUnknownTypeThrowsException()
	{
		server().enqueue(new MockResponse().setBody(""
			+ "
"
			+ ""));

		MicrodataItem item = newBrowser().get(url(server()))
			.getItem("http://i");

		thrown().expect(IllegalArgumentException.class);
		thrown().expectMessage("Cannot unwrap to: class java.lang.Void");

		item.unwrap(Void.class);
	}
}


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

import java.util.Comparator;

/**
 * PartialOrdering is an adapter class that turns a binary prediciate that is also a partial ordering into a Comparator.
 * A partial ordering is a binary predicate on the cross product of a set with itself, that is reflexive, antisymetric,
 * and transitive. That is to say that for the relation, R, the following rules hold:
 *
 *

 *

 *
aRa

 *
aRb && bRa => a = b (though not strictly that a.equals(b)

 *
aRb && bRc => aRc

 *

 *
 *
The rules for Comparators in Java are that:
 *
 *

 *

 *
sgn(compare(x, y)) == -sgn(compare(y, x))

 *
((compare(x, y)>0) && (compare(y, z)>0)) implies compare(x, z)>0

 *
compare(x, y)==0  implies that sgn(compare(x, z))==sgn(compare(y, z))

 *

 *
 *
To express a binary predicate that is also a partial ordering as a Comparator, the following rules for the
 * evaluation of the compare method are used:
 *
 *

 *

 *
if aRb and bRa then compare(a, b) == 0

 *
if aRb then compare(a, b) == 1

 *
if !aRb then compare(a, b) == -1

 *

 *
 *

CRC Card

 *
ResponsibilitiesCollaborations
 *
Express a partial ordering as a comparator.
 *

 *
 * @author Rupert Smith
 */
public class PartialOrdering<T> implements Comparator<T>
{
    /** Holds the partial ordering to use as a comparator. */
    BinaryPredicate<T, T> partialOrdering;

    /**
     * Creates a partial ordering comparator from a binary predicate that is a partial ordering.
     *
     * @param pred The binary predicate, this must be a partial order.
     */
    public PartialOrdering(BinaryPredicate<T, T> pred)
    {
        partialOrdering = pred;
    }

    /**
     * Translates the partial order into the +1, 0, -1 convention needed by Comparators.
     *
     * @param  a The first item to compare.
     * @param  b The second item to compare.
     *
     * @return 0 if the two elements are equal under the partial ordering, 1 if aRb, and -1 if !aRb.
     */
    public int compare(T a, T b)
    {
        boolean aRb = partialOrdering.evaluate(a, b);

        if (!aRb)
        {
            return -1;
        }

        boolean bRa = partialOrdering.evaluate(b, a);

        return (aRb && bRa) ? 0 : 1;
    }
}


/*
 * 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 java.util.PriorityQueue;
import java.util.Queue;

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

/**
 * Implements an A* search algorithm. This is one that always follows the search node that has the highest f value (f =
 * heuristic + cost).
 *
 *
The A* search is created by using a {@link BaseHeuristicSearch} combined with {@link HeuristicSearchNode}s and a
 * priority queue ordered with an {@link AStarComparator} that ensures that nodes with the highest f value are always at
 * the front of the queue. The default {@link com.thesett.aima.search.impl.MaxStepsAlgorithm} is not overridden.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Do an A* search.
 *

 *
 * @author Rupert Smith
 * @todo   Provide an A* implementation that uses a fibonacci heap as its priority queue.
 */
public class AStarSearch<O, T extends Traversable<O>> extends BaseHeuristicSearch<O, T>
{
    /**
     * Creates a new AStarSearch object.
     *
     * @param heuristic The heuristic to use to guide the search.
     */
    public AStarSearch(Heuristic<O, T> heuristic)
    {
        super(heuristic);
    }

    /**
     * Creates a priority queue with an {@link AStarComparator} to control the search ordering of the basic queue search
     * algorithm.
     *
     * @return The A* priority queue.
     */
    public Queue<SearchNode<O, T>> createQueue()
    {
        return new PriorityQueue<SearchNode<O, T>>(11, new AStarComparator());
    }
}


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

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

import com.thesett.aima.logic.fol.AllTermsVisitor;
import com.thesett.aima.logic.fol.Clause;
import com.thesett.aima.logic.fol.Functor;
import com.thesett.aima.logic.fol.IntegerType;
import com.thesett.aima.logic.fol.LiteralType;
import com.thesett.aima.logic.fol.Predicate;
import com.thesett.aima.logic.fol.Term;
import com.thesett.aima.logic.fol.Variable;
import com.thesett.aima.logic.fol.VariableAndFunctorInterner;
import com.thesett.aima.search.Operator;
import com.thesett.common.util.StackQueue;
import com.thesett.common.util.TraceIndenter;
import com.thesett.common.util.doublemaps.SymbolKey;
import com.thesett.common.util.doublemaps.SymbolTable;

/**
 * SymbolKeyTraverser is a {@link com.thesett.aima.logic.fol.ClauseTraverser} and
 * {@link com.thesett.aima.logic.fol.FunctorTraverser}, that creates entries within a {@link SymbolTable} for every
 * clause or functor it visits, and sets up {@link com.thesett.common.util.doublemaps.SymbolKey}s on those terms, so
 * that they can directly link to any fields held against them in the symbol table.
 *
 *
SymbolKeyTraverser is an {@link AllTermsVisitor} and like a
 * {@link com.thesett.aima.logic.fol.DelegatingAllTermsVisitor} accepts an optional delegate. All visit operations by
 * default defer onto the delegate.
 *
 *

CRC Card

 *
 Responsibilities  Collaborations
 *
 Visit a term.
 *
 Visit a clause.
 *
 Visit a functor.
 *
 Visit a variable.
 *
 Visit a literal.
 *
 Visit an integer literal.
 *

 *
 * @author Rupert Smith
 */
public class SymbolKeyTraverser extends PositionalTermTraverserImpl implements PositionalTermTraverser, AllTermsVisitor
{
    /** Used for debugging purposes. */
    /* private static final Logger log = Logger.getLogger(SymbolKeyTraverser.class.getName()); */

    /** Holds the symbol table field which holds the number of clauses in each predicate. */
    public static final String CLAUSE_NO_SYMBOL_FIELD = "clause_no";

    /** The symbol table scope under which clause heads are stored. */
    public static final int CLAUSE_HEAD_INDEX = 0;

    /** The symbol table scope under which clause bodies are stored. */
    public static final int CLAUSE_BODY_INDEX = 1;

    /** The symbol table scope under which free variables in a clause are stored. */
    public static final int CLAUSE_FREEVAR_INDEX = 2;

    /** The optional delegate. */
    protected AllTermsVisitor delegate;

    /** Holds the symbol name interner. */
    private final VariableAndFunctorInterner interner;

    /** Holds the root symbol table. */
    protected SymbolTable<Integer, String, Object> rootSymbolTable;

    /** Holds the current symbol table for the position within the term. */
    protected SymbolTable<Integer, String, Object> currentSymbolTable;

    /** Holds the symbol table for the current clause. */
    private SymbolTable<Integer, String, Object> clauseScopedSymbolTable;

    /**
     * Holds the current positional context within a surrounding term that has child elements. The elements are always
     * numbered from zero.
     */
    protected int currentPosition;

    /** Used for trace indenting when log statements are enabled. */
    private final TraceIndenter indenter = new TraceIndenter(true);

    /**
     * Creates a basic positional context traverser over terms, using the specified root symbol table as the starting
     * top-level for the term to be traversed.
     *
     * @param interner    The name interner.
     * @param symbolTable The root symbol table for the term to be traversed.
     * @param delegate    An optional AllTermsVisitor to delegate to.
     */
    public SymbolKeyTraverser(VariableAndFunctorInterner interner, SymbolTable<Integer, String, Object> symbolTable,
        AllTermsVisitor delegate)
    {
        this.delegate = delegate;
        this.rootSymbolTable = symbolTable;
        this.currentSymbolTable = symbolTable;
        this.interner = interner;
    }

    /** {@inheritDoc} */
    public Iterator<Operator<Term>> traverse(Clause clause, boolean reverse)
    {
        /*log.fine("Traversing clause " + clause.toString(interner, true, false));*/

        Functor head = clause.getHead();
        Functor[] body = clause.getBody();

        Queue<Operator<Term>> queue = (!reverse) ? new StackQueue<Operator<Term>>() : new LinkedList<Operator<Term>>();

        // Create a nested scope in the symbol table for the clause, under its functor name/arity.
        int predicateName;
        int clauseIndex;

        if (clause.isQuery())
        {
            predicateName = -1;
        }
        else
        {
            predicateName = head.getName();
        }

        Integer numberOfClauses = (Integer) rootSymbolTable.get(predicateName, CLAUSE_NO_SYMBOL_FIELD);

        if (numberOfClauses == null)
        {
            numberOfClauses = 0;
        }

        rootSymbolTable.put(predicateName, CLAUSE_NO_SYMBOL_FIELD, numberOfClauses + 1);

        clauseIndex = numberOfClauses;

        SymbolTable<Integer, String, Object> predicateScopedSymbolTable = rootSymbolTable.enterScope(predicateName);
        /*log.fine(indenter.generateTraceIndent(2) + "Enter predicate scope " + predicateName);*/

        clauseScopedSymbolTable = predicateScopedSymbolTable.enterScope(clauseIndex);
        /*log.fine(indenter.generateTraceIndent(2) + "Enter clause scope " + clauseIndex);*/

        // For the head functor, clear the top-level flag, set in head context.
        if (head != null)
        {
            head.setReversable(new ContextOperator(clauseScopedSymbolTable, 0, createHeadOperator(head, clause)));
            head.setTermTraverser(this);
            queue.offer(head);

            /*log.fine("Set SKT as traverser on " + head.toString(interner, true, false));*/
            /*log.fine("Created: " + ("head operator " + 0 + " on " + head.toString(interner, true, false)));*/
        }

        // For the body functors, set the top-level flag, clear in head context.
        if (body != null)
        {
            for (int i = 0; i < body.length; i++)
            {
                Functor bodyFunctor = body[i];

                bodyFunctor.setReversable(new ContextOperator(clauseScopedSymbolTable, i + 1,
                        createBodyOperator(bodyFunctor, i, body, clause)));
                bodyFunctor.setTermTraverser(this);
                queue.offer(bodyFunctor);

                /*log.fine("Set SKT as traverser on " + bodyFunctor.toString(interner, true, false));*/
                /*log.fine("Created: " +
                    ("body operator " + (i + 1) + " on " + bodyFunctor.toString(interner, true, false)));*/
            }
        }

        return queue.iterator();
    }

    /** {@inheritDoc} */
    public Iterator<Operator<Term>> traverse(Functor functor, boolean reverse)
    {
        /*log.fine("Traversing functor " + functor.toString(interner, true, false));*/

        Queue<Operator<Term>> queue = (!reverse) ? new StackQueue<Operator<Term>>() : new LinkedList<Operator<Term>>();

        Term[] arguments = functor.getArguments();

        // For a top-level functor clear top-level flag, so that child functors are not taken as top-level.
        if (arguments != null)
        {
            for (int i = 0; i < arguments.length; i++)
            {
                Term argument = arguments[i];

                // When navigating onto a variable, the variable is scoped within a clause, and may appear many times
                // within it. Therefore it always uses its unique id relative to the root symbol table for the
                // clause as its contextual position. Other terms use their position path and are relative to the
                // the current positions symbol table.
                SymbolTable<Integer, String, Object> contextSymbolTable;

                if (argument.isVar())
                {
                    contextSymbolTable = clauseScopedSymbolTable.enterScope(CLAUSE_FREEVAR_INDEX);
                    /*log.fine("Enter freevar scope");*/

                    argument.setReversable(new ContextOperator(contextSymbolTable,
                            createTermOperator(argument, i, functor)));
                    argument.setTermTraverser(this);
                    queue.offer(argument);

                    /*log.fine("Created: " +
                        ("var argument operator on " + argument.toString(interner, true, false)));*/
                }
                else
                {
                    contextSymbolTable = null;

                    argument.setReversable(new ContextOperator(contextSymbolTable, i,
                            createTermOperator(argument, i, functor)));
                    argument.setTermTraverser(this);
                    queue.offer(argument);

                    /*log.fine("Created: " +
                        ("argument operator " + i + " on " + argument.toString(interner, true, false)));*/
                }

            }
        }

        return queue.iterator();
    }

    /**
     * {@inheritDoc}
     *
     *
Assigns symbol keys to non-variable terms, based on the positional path to the term within its containing
     * clause.
     */
    public void visit(Term term)
    {
        if (isEnteringContext())
        {
            SymbolKey key = currentSymbolTable.getSymbolKey(currentPosition);
            term.setSymbolKey(key);
        }

        if (delegate != null)
        {
            delegate.visit(term);
        }
    }

    /**
     * {@inheritDoc}
     *
     *
Assigns symbol keys to variables, based on the variables id.
     */
    public void visit(Variable variable)
    {
        if (isEnteringContext())
        {
            SymbolKey key = currentSymbolTable.getSymbolKey(variable.getId());
            variable.setSymbolKey(key);

            /*log.fine(variable.toString(interner, true, false) + " assigned " + key);*/
        }
        else if (isLeavingContext())
        {
            variable.setTermTraverser(null);
        }

        if (delegate != null)
        {
            delegate.visit(variable);
        }
    }

    /** {@inheritDoc} */
    public void visit(Predicate predicate)
    {
        if (isEnteringContext())
        {
            super.visit(predicate);
        }
        else if (isLeavingContext())
        {
            predicate.setTermTraverser(null);
        }

        if (delegate != null)
        {
            delegate.visit(predicate);
        }
    }

    /** {@inheritDoc} */
    public void visit(Clause clause)
    {
        if (isEnteringContext())
        {
            super.visit(clause);
        }
        else if (isLeavingContext())
        {
            clause.setTermTraverser(null);
        }

        if (delegate != null)
        {
            delegate.visit(clause);
        }
    }

    /** {@inheritDoc} */
    public void visit(Functor functor)
    {
        if (isEnteringContext())
        {
            SymbolKey key = currentSymbolTable.getSymbolKey(currentPosition);
            functor.setSymbolKey(key);

            /*log.fine(functor.toString(interner, true, false) + " assigned " + key);*/
        }
        else if (isLeavingContext())
        {
            functor.setTermTraverser(null);
        }

        if (delegate != null)
        {
            delegate.visit(functor);
        }
    }

    /** {@inheritDoc} */
    public void visit(IntegerType literal)
    {
        if (isEnteringContext())
        {
            SymbolKey key = currentSymbolTable.getSymbolKey(currentPosition);
            literal.setSymbolKey(key);
        }
        else if (isLeavingContext())
        {
            literal.setTermTraverser(null);
        }

        if (delegate != null)
        {
            delegate.visit(literal);
        }
    }

    /** {@inheritDoc} */
    public void visit(LiteralType literal)
    {
        if (isEnteringContext())
        {
            SymbolKey key = currentSymbolTable.getSymbolKey(currentPosition);
            literal.setSymbolKey(key);
        }
        else if (isLeavingContext())
        {
            literal.setTermTraverser(null);
        }

        if (delegate != null)
        {
            delegate.visit(literal);
        }
    }

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

CRC Card

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

     */
    private class ContextOperator extends StackableOperator
    {
        /** The root symbol table that contains the new context to be established. */
        private final SymbolTable<Integer, String, Object> contextSymbolTable;

        /** Used to retain the previous symbol table if overwritten by a new one. */
        private SymbolTable<Integer, String, Object> previousSymbolTable;

        /** The new positional context to establish. */
        private final int contextPosition;

        /** The previous positional context to restore. */
        private int previousPosition;

        /** Flag indicating whether or not this operator has a position. */
        private final boolean hasPosition;

        /**
         * Creates a context establishing operation.
         *
         * @param symbolTable A new root symbol table to establish context within, or <tt>null</tt> if the current
         *                    symbol table should be used (default).
         * @param position    The new positional context to establish.
         * @param delegate    A stackable operator to chain onto this one.
         */
        private ContextOperator(SymbolTable<Integer, String, Object> symbolTable, int position,
            StackableOperator delegate)
        {
            super(delegate);

            contextSymbolTable = symbolTable;
            contextPosition = position;
            hasPosition = true;
        }

        /**
         * Creates a context establishing operation.
         *
         * @param symbolTable A new root symbol table to establish context within, or <tt>null</tt> if the current
         *                    symbol table should be used (default).
         * @param delegate    A stackable operator to chain onto this one.
         */
        private ContextOperator(SymbolTable<Integer, String, Object> symbolTable, StackableOperator delegate)
        {
            super(delegate);

            contextSymbolTable = symbolTable;
            contextPosition = -1;
            hasPosition = false;
        }

        /** {@inheritDoc} */
        public void applyOperator()
        {
            previousSymbolTable = currentSymbolTable;
            previousPosition = currentPosition;

            // If a starting context is given, move to it first.
            if (contextSymbolTable != null)
            {
                currentSymbolTable = contextSymbolTable;
            }

            if (hasPosition)
            {
                currentSymbolTable = (currentSymbolTable.enterScope(contextPosition));
                /*log.fine(indenter.generateTraceIndent(2) + "Enter scope " + contextPosition);*/
            }

            currentPosition = contextPosition;

            super.applyOperator();
        }

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

            currentSymbolTable = previousSymbolTable;
            currentPosition = previousPosition;
        }
    }
}


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

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * A distributed list is a list that is designed to be used with distributed systems. The actual values in the list are
 * held in a java.util.ArrayList. Only the iterator method of ArrayList has been overriden in this class. It provides an
 * iterator that is serializable and can be sent over the network to be used by a client to access the contents of the
 * list one at a time. This means that elements of the list can be accessed as needed rather than sending the whole list
 * over the network at once.
 *
 *

CRC Card

 *
ResponsibilitiesCollaborations
 *
Provide distributed iterator for a list  {@link DistributedIteratorImpl}
 *

 *
 * @author Rupert Smith
 */
public class DistributedList extends ArrayList
{
    /**
     * Returns a distriubuted iterator that can provide elements of the list on demand over a remote connection.
     *
     * @return A {@link com.thesett.common.util.distributed.DistributedIterator} that provides the elements of the list
     *         on demand instead of all at once.
     */
    public Iterator iterator()
    {
        try
        {
            DistributedIteratorImpl di;

            di = new DistributedIteratorImpl(super.iterator());

            return new ClientIterator(di);
        }
        catch (RemoteException e)
        {
            // Rethrow the RemoteException as a RuntimeException so as not to conflict with the interface of ArrayList
            throw new IllegalStateException("There was a RemoteExcpetion.", e);
        }
    }
}