/**
 * OW2 Specifications
 * Copyright (C) 2010 Bull S.A.S.
 * Contact: easybeans@ow2.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id: Query.java 5417 2010-03-24 09:04:14Z benoitf $
 * --------------------------------------------------------------------------
 */

package javax.persistence;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Interface used to control query execution.
 * @see <a href="http://jcp.org/en/jsr/detail?id=317">JPA 2.0 specification</a>
 * @author Florent Benoit
 * @since JPA 1.0 version.
 */

public interface Query {
    /**
     * Execute a SELECT query and return the query results as a List.
     * @return a list of the results
     * @throws IllegalStateException if called for a Java Persistence query language UPDATE or DELETE statement
     */
    List getResultList();

    /**
     * Execute a SELECT query that returns a single result.
     * @return the result
     * @throws NoResultException if there is no result
     * @throws NonUniqueResultException if more than one result
     * @throws IllegalStateException if called for a Java Persistence query language UPDATE or DELETE statement
     */
    Object getSingleResult();

    /**
     * Execute an update or delete statement.
     * @return the number of entities updated or deleted
     * @throws IllegalStateException if called for a Java Persistence query language SELECT statement
     * @throws TransactionRequiredException if there is no transaction
     */
    int executeUpdate();

    /**
     * Set the maximum number of results to retrieve.
     * @param maxResult the given max number.
     * @return the same query instance
     * @throws IllegalArgumentException if argument is negative
     */
    Query setMaxResults(int maxResult);

    /**
     * The maximum number of results the query object was set to
     * retrieve. Returns Integer.MAX_VALUE if setMaxResults was not
     * applied to the query object.
     * @return maximum number of results
     */
    int getMaxResults();

    /**
     * Set the position of the first result to retrieve.
     * @param startPosition position of the first result, numbered from 0
     * @return the same query instance
     * @throws IllegalArgumentException if argument is negative
     */
    Query setFirstResult(int startPosition);

    /**
     * The position of the first result the query object was set to retrieve. Returns 0 if setFirstResult was not applied to the
     * query object.
     * @return position of the first result
     */
    int getFirstResult();

    /**
     * Set an implementation-specific hint. If the hint name is not recognized, it is silently ignored.
     * @param hintName the name of the hint.
     * @param value the value of the hint.
     * @return the same query instance
     * @throws IllegalArgumentException if the second argument is not valid for the implementation
     */
    Query setHint(String hintName, Object value);

    /**
     * Get the properties and hints and associated values that are in effect for the query instance.
     * @return query properties and hints
     */
    Map<String, Object> getHints();

    /**
     * Bind the value of a Parameter object.
     * @param param parameter object
     * @param value parameter value
     * @return the same query instance
     * @throws IllegalArgumentException if the parameter does not correspond to a parameter of the query
     */
    <T> Query setParameter(Parameter<T> param, T value);

    /**
     * Bind an instance of java.util.Calendar to a Parameter object.
     * @param param parameter object
     * @param value parameter value
     * @param temporalType
     * @return the same query instance
     * @throws IllegalArgumentException if the parameter does not correspond to a parameter of the query
     */
    Query setParameter(Parameter<Calendar> param, Calendar value, TemporalType temporalType);

    /**
     * Bind an instance of java.util.Date to a Parameter object.
     * @param param parameter object
     * @param value parameter value
     * @param temporalType
     * @return the same query instance
     * @throws IllegalArgumentException if the parameter does not correspond to a parameter of the query
     */
    Query setParameter(Parameter<Date> param, Date value, TemporalType temporalType);

    /**
     * Bind an argument to a named parameter.
     * @param name parameter name
     * @param value parameter value
     * @return the same query instance
     * @throws IllegalArgumentException if the parameter name does not correspond to a parameter of the query or if the argument
     * is of incorrect type
     */
    Query setParameter(String name, Object value);

    /**
     * Bind an instance of java.util.Calendar to a named parameter.
     * @param name parameter name
     * @param value parameter value
     * @param temporalType
     * @return the same query instance
     * @throws IllegalArgumentException if the parameter name does not correspond to a parameter of the query or if the value
     * argument is of incorrect type
     */
    Query setParameter(String name, Calendar value, TemporalType temporalType);

    /**
     * Bind an instance of java.util.Date to a named parameter.
     * @param name parameter name
     * @param value parameter value
     * @param temporalType
     * @return the same query instance
     * @throws IllegalArgumentException if the parameter name does not correspond to a parameter of the query or if the value
     * argument is of incorrect type
     */
    Query setParameter(String name, Date value, TemporalType temporalType);

    /**
     * Bind an argument to a positional parameter.
     * @param position
     * @param value parameter value
     * @return the same query instance
     * @throws IllegalArgumentException if position does not correspond to a positional parameter of the query or if the argument
     * is of incorrect type
     */
    Query setParameter(int position, Object value);

    /**
     * Bind an instance of java.util.Calendar to a positional parameter.
     * @param position
     * @param value parameter value
     * @param temporalType
     * @return the same query instance
     * @throws IllegalArgumentException if position does not correspond to a positional parameter of the query or if the value
     * argument is of incorrect type
     */
    Query setParameter(int position, Calendar value, TemporalType temporalType);

    /**
     * Bind an instance of java.util.Date to a positional parameter.
     * @param position
     * @param value parameter value
     * @param temporalType
     * @return the same query instance
     * @throws IllegalArgumentException if position does not correspond to a positional parameter of the query or if the value
     * argument is of incorrect type
     */
    Query setParameter(int position, Date value, TemporalType temporalType);

    /**
     * Get the parameter objects corresponding to the declared parameters of the query. Returns empty set if the query has no
     * parameters. This method is not required to be supported for native queries.
     * @return set of the parameter objects
     * @throws IllegalStateException if invoked on a native query when the implementation does not support this use
     */
    Set<Parameter<?>> getParameters();

    /**
     * Get the parameter object corresponding to the declared parameter of the given name. This method is not required to be
     * supported for native queries.
     * @param name
     * @return parameter object
     * @throws IllegalArgumentException if the parameter of the specified name does not exist
     * @throws IllegalStateException if invoked on a native query when the implementation does not support this use
     */
    Parameter<?> getParameter(String name);

    /**
     * Get the parameter object corresponding to the declared parameter of the given name and type. This method is required to be
     * supported for criteria queries only.
     * @param name parameter name
     * @param type
     * @return parameter object
     * @throws IllegalArgumentException if the parameter of the specified name does not exist or is not assignable to the type
     * @throws IllegalStateException if invoked on a native query or Java Persistence query language query when the implementation
     * does not support this use
     */
    <T> Parameter<T> getParameter(String name, Class<T> type);

    /**
     * Get the parameter object corresponding to the declared positional parameter with the given position. This method is not
     * required to be supported for native queries.
     * @param position
     * @return parameter object
     * @throws IllegalArgumentException if the parameter with the specified position does not exist
     * @throws IllegalStateException if invoked on a native query when the implementation does not support this use
     */
    Parameter<?> getParameter(int position);

    /**
     * Get the parameter object corresponding to the declared positional parameter with the given position and type. This method
     * is not required to be supported by the provider.
     * @param position
     * @param type
     * @return parameter object
     * @throws IllegalArgumentException if the parameter with the specified position does not exist or is not assignable to the
     * type
     * @throws IllegalStateException if invoked on a native query or Java Persistence query language query when the implementation
     * does not support this use
     */
    <T> Parameter<T> getParameter(int position, Class<T> type);

    /**
     * Return a boolean indicating whether a value has been bound to the parameter.
     * @param param parameter object
     * @return boolean indicating whether parameter has been bound
     */
    boolean isBound(Parameter<?> param);

    /**
     * Return the value bound to the parameter.
     * @param param parameter object
     * @return parameter value
     * @throws IllegalArgumentException if the parameter is not a parameter of the query
     * @throws IllegalStateException if the parameter has not been been bound
     */
    <T> T getParameterValue(Parameter<T> param);

    /**
     * Return the value bound to the named parameter.
     * @param name parameter name
     * @return parameter value
     * @throws IllegalStateException if the parameter has not been been bound
     * @throws IllegalArgumentException if the parameter of the specified name does not exist
     */
    Object getParameterValue(String name);

    /**
     * Return the value bound to the positional parameter.
     * @param position
     * @return parameter value
     * @throws IllegalStateException if the parameter has not been been bound
     * @throws IllegalArgumentException if the parameter with the specified position does not exist
     */
    Object getParameterValue(int position);

    /**
     * Set the flush mode type to be used for the query execution. The flush mode type applies to the query regardless of the
     * flush mode type in use for the entity manager.
     * @param flushMode
     * @return the same query instance
     */
    Query setFlushMode(FlushModeType flushMode);

    /**
     * Get the flush mode in effect for the query execution. If a flush mode has not been set for the query object, returns the
     * flush mode in effect for the entity manager.
     * @return flush mode
     */
    FlushModeType getFlushMode();

    /**
     * Set the lock mode type to be used for the query execution.
     * @param lockMode
     * @return the same query instance
     * @throws IllegalStateException if the query is found not to be a Java Persistence query language SELECT query or a Criteria
     * API query
     */
    Query setLockMode(LockModeType lockMode);

    /**
     * Get the current lock mode for the query.
     * @return lock mode
     * @throws IllegalStateException if the query is found not to be a Java Persistence query language SELECT query or a Criteria
     * API query
     */
    LockModeType getLockMode();

    /**
     * Return an object of the specified type to allow access to the provider-specific API. If the provider's query implementation
     * does not support the specified class, the PersistenceException is thrown.
     * @param cls the class of the object to be returned. This is normally either the underlying query implementation class or an
     * interface that it implements.
     * @return an instance of the specified class
     * @throws PersistenceException if the provider does not support the call
     */
    <T> T unwrap(Class<T> cls);
}
