/*
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira.drafts
 */
package net.ranides.assira.index;

import java.util.Comparator;
import java.util.function.Consumer;
import java.util.function.Function;
import net.ranides.assira.collection.query.CQuery;

/**
 * Extension of CQuery interface, offering optimized filtering by index.
 * Index can be selected by name, or by "indexing function" (most preferably by identity).
 *
 * IQuery does not define interface for index creation, only for index searching.
 * IQuery should be returned by some storage class, for example {@link IQueryMap} offers
 * storage and indexing services and then gives access to search functionality by calling method {@code find}
 *
 * Please note, that IQuery can work in two modes: returning records with exact match, or returning records with
 * exact match or null value.
 *
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 * @param <V> type of results
 */
public interface IQuery<V> extends CQuery<V> {

    /**
     * Add indexed filter condition: only elements with field = value.
     * It uses comparison index, has O(logN) complexity.
     * Null values are ignored.
     *
     * @param index index
     * @param value value
     * @return filtered query
     */
    IQuery<V> eq(Comparator<V> index, V value);

    /**
     * Add indexed filter condition: only elements with field = value.
     * It uses comparison index, has O(logN) complexity.
     * Null values can be accepted.
     *
     * @param index index
     * @param nullable match nulls
     * @param value value
     * @return filtered query
     */
    IQuery<V> eq(Comparator<V> index, boolean nullable, V value);

    /**
     * Add indexed filter condition: only elements with field = value.
     * It uses transformation index, has O(logN) complexity.
     * Null values are ignored.
     *
     * @param index index
     * @param value value
     * @return filtered query
     * @param <T> type of index
     */
    <T> IQuery<V> eq(Function<V,T> index, T value);

    /**
     * Add indexed filter condition: only elements with field = value.
     * It uses transformation index, has O(logN) complexity.
     * Null values can be accepted.
     *
     * @param index index
     * @param nullable match nulls
     * @param value value
     * @return filtered query
     * @param <T> type of index
     */
    <T> IQuery<V> eq(Function<V,T> index, boolean nullable, T value);

    /**
     * Add indexed filter condition: only elements with field = value.
     * It uses named index, has O(logN) complexity.
     * Null values are ignored.
     *
     * @param index index
     * @param value value
     * @return filtered query
     */
    IQuery<V> eq(String index, Object value);

    /**
     * Add indexed filter condition: only elements with field = value.
     * It uses named index, has O(logN) complexity.
     * Null values can be accepted.
     *
     * @param index index
     * @param nullable match nulls
     * @param value value
     * @return filtered query
     */
    IQuery<V> eq(String index, boolean nullable, Object value);

    /**
     * Add indexed filter condition: only elements with field > value.
     * It uses comparison index, has O(logN) complexity.
     * Null values are ignored.
     *
     * @param index index
     * @param value value
     * @return filtered query
     */
    IQuery<V> gt(Comparator<V> index, V value);

    /**
     * Add indexed filter condition: only elements with field > value.
     * It uses comparison index, has O(logN) complexity.
     * Null values can be accepted.
     *
     * @param index index
     * @param nullable match nulls
     * @param value value
     * @return filtered query
     */
    IQuery<V> gt(Comparator<V> index, boolean nullable, V value);

    /**
     * Add indexed filter condition: only elements with field > value.
     * It uses transformation index, has O(logN) complexity.
     * Null values are ignored.
     *
     * @param index index
     * @param value value
     * @return filtered query
     * @param <T> type of index
     */
    <T> IQuery<V> gt(Function<V,T> index, T value);

    /**
     * Add indexed filter condition: only elements with field > value.
     * It uses transformation index, has O(logN) complexity.
     * Null values can be accepted.
     *
     * @param index index
     * @param nullable match nulls
     * @param value value
     * @return filtered query
     * @param <T> type of index
     */
    <T> IQuery<V> gt(Function<V,T> index, boolean nullable, T value);

    /**
     * Add indexed filter condition: only elements with field > value.
     * It uses named index, has O(logN) complexity.
     * Null values are ignored.
     *
     * @param index index
     * @param value value
     * @return filtered query
     */
    IQuery<V> gt(String index, Object value);

    /**
     * Add indexed filter condition: only elements with field > value.
     * It uses named index, has O(logN) complexity.
     * Null values can be accepted.
     *
     * @param index index
     * @param nullable match nulls
     * @param value value
     * @return filtered query
     */
    IQuery<V> gt(String index, boolean nullable, Object value);

    /**
     * Add indexed filter condition: only elements with field < value.
     * It uses comparison index, has O(logN) complexity.
     * Null values are ignored.
     *
     * @param index index
     * @param value value
     * @return filtered query
     */
    IQuery<V> lt(Comparator<V> index, V value);

    /**
     * Add indexed filter condition: only elements with field < value.
     * It uses comparison index, has O(logN) complexity.
     * Null values can be accepted.
     *
     * @param index index
     * @param nullable match nulls
     * @param value value
     * @return filtered query
     */
    IQuery<V> lt(Comparator<V> index, boolean nullable, V value);

    /**
     * Add indexed filter condition: only elements with field < value.
     * It uses transformation index, has O(logN) complexity.
     * Null values are ignored.
     *
     * @param index index
     * @param value value
     * @return filtered query
     * @param <T> type of index
     */
    <T> IQuery<V> lt(Function<V,T> index, T value);

    /**
     * Add indexed filter condition: only elements with field < value.
     * It uses transformation index, has O(logN) complexity.
     * Null values can be accepted.
     *
     * @param index index
     * @param nullable match nulls
     * @param value value
     * @return filtered query
     * @param <T> type of index
     */
    <T> IQuery<V> lt(Function<V,T> index, boolean nullable, T value);

    /**
     * Add indexed filter condition: only elements with field < value.
     * It uses named index, has O(logN) complexity.
     * Null values are ignored.
     *
     * @param index index
     * @param value value
     * @return filtered query
     */
    IQuery<V> lt(String index, Object value);

    /**
     * Add indexed filter condition: only elements with field < value.
     * It uses named index, has O(logN) complexity.
     * Null values can be accepted.
     *
     * @param index index
     * @param nullable match nulls
     * @param value value
     * @return filtered query
     */
    IQuery<V> lt(String index, boolean nullable, Object value);

    /**
     * Add indexed filter condition: only elements with field between [begin;end)
     * It uses comparison index, has O(logN) complexity.
     * Null values are ignored.
     *
     * @param index index
     * @param begin begin
     * @param end end
     * @return filtered query
     */
    IQuery<V> in(Comparator<V> index, V begin, V end);

    /**
     * Add indexed filter condition: only elements with field between [begin;end)
     * It uses comparison index, has O(logN) complexity.
     * Null values can be accepted.
     *
     * @param index index
     * @param nullable match nulls
     * @param begin begin
     * @param end end
     * @return filtered query
     */
    IQuery<V> in(Comparator<V> index, boolean nullable, V begin, V end);

    /**
     * Add indexed filter condition: only elements with field between [begin;end)
     * It uses transformation index, has O(logN) complexity.
     * Null values are ignored.
     *
     * @param index index
     * @param begin begin
     * @param end end
     * @return filtered query
     * @param <T> type of index
     */
    <T> IQuery<V> in(Function<V,T> index, T begin, T end);

    /**
     * Add indexed filter condition: only elements with field between [begin;end)
     * It uses transformation index, has O(logN) complexity.
     * Null values can be accepted.
     *
     * @param index index
     * @param nullable match nulls
     * @param begin begin
     * @param end end
     * @return filtered query
     * @param <T> type of index
     */
    <T> IQuery<V> in(Function<V,T> index, boolean nullable, T begin, T end);

    /**
     * Add indexed filter condition: only elements with field between [begin;end)
     * It uses named index, has O(logN) complexity.
     * Null values are ignored.
     *
     * @param index index
     * @param begin begin
     * @param end end
     * @return filtered query
     */
    IQuery<V> in(String index, Object begin, Object end);

    /**
     * Add indexed filter condition: only elements with field between [begin;end)
     * It uses named index, has O(logN) complexity.
     * Null values can be accepted.
     *
     * @param index index
     * @param nullable match nulls
     * @param begin begin
     * @param end end
     * @return filtered query
     */
    IQuery<V> in(String index, boolean nullable, Object begin, Object end);

    /**
     * Removes records selected by this query.
     */
    void remove();

    /**
     * Changes state of records selected by this query.
     * Every selected record is passed to "consumer", which can modify record in every way.
     * All changes will be respected in indexes.
     *
     * @param consumer consumer
     */
    void update(Consumer<? super V> consumer);
    
}
