<commit_before>
/*
 * Copyright (C) 2011 <NAME>. All rights reserved.
 *
 * $Id$
 */

package org.dellroad.stuff.vaadin7;

import java.util.Collection;
import java.util.List;

/**
 * A specialization of {@link AbstractQueryContainer} that doesn't require up-front knowledge of the underlying data's size.
 *
 * <p>
 * Subclasses only need support retrieving a contiguous window of fixed size from the underlying data
 * via {@link #queryWindow queryWindow()}; when the requested window goes beyond the end of the underlying data,
 * a short or empty result is returned. Based on just this information, this class maintains an estimate of
 * the size of the underlying data. Each time that size estimate changes, {@link #handleSizeChange} is invoked
 * to schedule a (non-reentrant) property set change notification.
 * </p>
 *
 * <p>
 * When used to back a Vaadin table, the user will see a table that automatically grows as the user scrolls
 * downward, until the actual end of the data is detected.
 * </p>
 *
 * @param <T> the type of the Java objects that back each {@link com.vaadin.data.Item} in the container
 * @see AbstractQueryContainer
 */
@SuppressWarnings("serial")
public abstract class AbstractUnsizedContainer<T> extends AbstractQueryContainer<T> {

    public static final int DEFAULT_WINDOW_SIZE = 500;

    private final int windowSize;

    private long size;

// Constructors

    /**
     * Convenience constructor. Equivalent to:
     *  <blockquote><code>
     *      {@link #AbstractUnsizedContainer(int) AbstractUnsizedContainer}({@link #DEFAULT_WINDOW_SIZE})
     *  </code></blockquote>
     *
     * <p>
     * After using this constructor, subsequent invocations of {@link #setPropertyExtractor setPropertyExtractor()}
     * and {@link #setProperties setProperties()} are required to define the properties of this container
     * and how to extract them.
     * </p>
     */
    protected AbstractUnsizedContainer() {
        this(DEFAULT_WINDOW_SIZE);
    }

    /**
     * Convenience constructor. Equivalent to:
     *  <blockquote><code>
     *      {@link #AbstractUnsizedContainer(int, PropertyExtractor) AbstractUnsizedContainer}({@link #DEFAULT_WINDOW_SIZE},
     *          propertyExtractor)
     *  </code></blockquote>
     *
     * <p>
     * After using this constructor, a subsequent invocation of {@link #setProperties setProperties()} is required
     * to define the properties of this container.
     * </p>
     *
     * @param propertyExtractor used to extract properties from the underlying Java objects;
     *  may be null but then container is not usable until one is configured via
     * {@link #setPropertyExtractor setPropertyExtractor()}
     */
    protected AbstractUnsizedContainer(PropertyExtractor<? super T> propertyExtractor) {
        this(DEFAULT_WINDOW_SIZE, propertyExtractor);
    }

    /**
     * Convenience constructor. Equivalent to:
     *  <blockquote><code>
     *      {@link #AbstractUnsizedContainer(int, PropertyExtractor, Collection) AbstractUnsizedContainer}({@link
     *          #DEFAULT_WINDOW_SIZE}, propertyExtractor, propertyDefs)
     *  </code></blockquote>
     *
     * @param propertyExtractor used to extract properties from the underlying Java objects;
     *  may be null but then container is not usable until one is configured via
     * {@link #setPropertyExtractor setPropertyExtractor()}
     * @param propertyDefs container property definitions; null is treated like the empty set
     */
    protected AbstractUnsizedContainer(PropertyExtractor<? super T> propertyExtractor,
      Collection<? extends PropertyDef<?>> propertyDefs) {
        this(DEFAULT_WINDOW_SIZE, propertyExtractor, propertyDefs);
    }

    /**
     * Constructor.
     *
     * <p>
     * After using this constructor, subsequent invocations of {@link #setPropertyExtractor setPropertyExtractor()}
     * and {@link #setProperties setProperties()} are required to define the properties of this container
     * and how to extract them.
     * </p>
     *
     * @param windowSize size of the query window
     * @throws IllegalArgumentException if {@code windowSize} is less than 1
     */
    protected AbstractUnsizedContainer(int windowSize) {
        this(windowSize, null);
    }

    /**
     * Constructor.
     *
     * <p>
     * After using this constructor, a subsequent invocation of {@link #setProperties setProperties()} is required
     * to define the properties of this container.
     * </p>
     *
     * @param windowSize size of the query window
     * @param propertyExtractor used to extract properties from the underlying Java objects;
     *  may be null but then container is not usable until one is configured via
     * {@link #setPropertyExtractor setPropertyExtractor()}
     * @throws IllegalArgumentException if {@code windowSize} is less than 1
     */
    protected AbstractUnsizedContainer(int windowSize, PropertyExtractor<? super T> propertyExtractor) {
        this(windowSize, propertyExtractor, null);
    }

    /**
     * Primary constructor.
     *
     * @param windowSize size of the query window (how big of a chunk we query at one time)
     * @param propertyExtractor used to extract properties from the underlying Java objects;
     *  may be null but then container is not usable until one is configured via
     * {@link #setPropertyExtractor setPropertyExtractor()}
     * @param propertyDefs container property definitions; null is treated like the empty set
     * @throws IllegalArgumentException if {@code windowSize} is less than 1
     */
    protected AbstractUnsizedContainer(int windowSize, PropertyExtractor<? super T> propertyExtractor,
      Collection<? extends PropertyDef<?>> propertyDefs) {
        if (windowSize < 1)
            throw new IllegalArgumentException("windowSize = " + windowSize);
        this.windowSize = windowSize;
        this.setPropertyExtractor(propertyExtractor);
        this.setProperties(propertyDefs);
    }

    @Override
    protected QueryList<T> query(long hint) {

        // Clip hint value
        hint = Math.min(hint, this.size - 1);
        hint = Math.max(hint, 0);

        // Query underlying data for the window of items centered at "hint"
        final long offset = Math.max(0, hint - this.windowSize / 2);
        final List<? extends T> window = this.queryWindow(offset, this.windowSize);
        final int querySize = window.size();

        // Check size of the returned window
        final long previousSize = this.size;
        if (querySize <= 0)                     // the underlying data has shrunk on us
            this.size = this.shrink(offset);
        else if (querySize < this.windowSize)   // we overlapped the end; now we know the exact size
            this.size = offset + querySize;
        else                                    // we are somewhere in the middle; we have a (possibly new) lower bound on the size
            this.size = Math.max(this.size, offset + querySize + 1);

        // See if size changed
        if (this.size != previousSize)
            this.handleSizeChange();

        // Return QueryList
        return new WindowQueryList<T>(offset, window, this.size);
    }

    /**
     * Get the window size configured at construction time.
     */<commit_msg>Remove unnecessary invocation of handleSizeChange(): superclass will handle it.<commit_after>
/*
 * Copyright (C) 2011 <NAME>. All rights reserved.
 *
 * $Id$
 */

package org.dellroad.stuff.vaadin7;

import java.util.Collection;
import java.util.List;

/**
 * A specialization of {@link AbstractQueryContainer} that doesn't require up-front knowledge of the underlying data's size.
 *
 * <p>
 * Subclasses only need support retrieving a contiguous window of fixed size from the underlying data
 * via {@link #queryWindow queryWindow()}; when the requested window goes beyond the end of the underlying data,
 * a short or empty result is returned. Based on just this information, this class maintains an estimate of
 * the size of the underlying data. Each time that size estimate changes, {@link #handleSizeChange} is invoked
 * to schedule a (non-reentrant) property set change notification.
 * </p>
 *
 * <p>
 * When used to back a Vaadin table, the user will see a table that automatically grows as the user scrolls
 * downward, until the actual end of the data is detected.
 * </p>
 *
 * @param <T> the type of the Java objects that back each {@link com.vaadin.data.Item} in the container
 * @see AbstractQueryContainer
 */
@SuppressWarnings("serial")
public abstract class AbstractUnsizedContainer<T> extends AbstractQueryContainer<T> {

    public static final int DEFAULT_WINDOW_SIZE = 500;

    private final int windowSize;

    private long size;

// Constructors

    /**
     * Convenience constructor. Equivalent to:
     *  <blockquote><code>
     *      {@link #AbstractUnsizedContainer(int) AbstractUnsizedContainer}({@link #DEFAULT_WINDOW_SIZE})
     *  </code></blockquote>
     *
     * <p>
     * After using this constructor, subsequent invocations of {@link #setPropertyExtractor setPropertyExtractor()}
     * and {@link #setProperties setProperties()} are required to define the properties of this container
     * and how to extract them.
     * </p>
     */
    protected AbstractUnsizedContainer() {
        this(DEFAULT_WINDOW_SIZE);
    }

    /**
     * Convenience constructor. Equivalent to:
     *  <blockquote><code>
     *      {@link #AbstractUnsizedContainer(int, PropertyExtractor) AbstractUnsizedContainer}({@link #DEFAULT_WINDOW_SIZE},
     *          propertyExtractor)
     *  </code></blockquote>
     *
     * <p>
     * After using this constructor, a subsequent invocation of {@link #setProperties setProperties()} is required
     * to define the properties of this container.
     * </p>
     *
     * @param propertyExtractor used to extract properties from the underlying Java objects;
     *  may be null but then container is not usable until one is configured via
     * {@link #setPropertyExtractor setPropertyExtractor()}
     */
    protected AbstractUnsizedContainer(PropertyExtractor<? super T> propertyExtractor) {
        this(DEFAULT_WINDOW_SIZE, propertyExtractor);
    }

    /**
     * Convenience constructor. Equivalent to:
     *  <blockquote><code>
     *      {@link #AbstractUnsizedContainer(int, PropertyExtractor, Collection) AbstractUnsizedContainer}({@link
     *          #DEFAULT_WINDOW_SIZE}, propertyExtractor, propertyDefs)
     *  </code></blockquote>
     *
     * @param propertyExtractor used to extract properties from the underlying Java objects;
     *  may be null but then container is not usable until one is configured via
     * {@link #setPropertyExtractor setPropertyExtractor()}
     * @param propertyDefs container property definitions; null is treated like the empty set
     */
    protected AbstractUnsizedContainer(PropertyExtractor<? super T> propertyExtractor,
      Collection<? extends PropertyDef<?>> propertyDefs) {
        this(DEFAULT_WINDOW_SIZE, propertyExtractor, propertyDefs);
    }

    /**
     * Constructor.
     *
     * <p>
     * After using this constructor, subsequent invocations of {@link #setPropertyExtractor setPropertyExtractor()}
     * and {@link #setProperties setProperties()} are required to define the properties of this container
     * and how to extract them.
     * </p>
     *
     * @param windowSize size of the query window
     * @throws IllegalArgumentException if {@code windowSize} is less than 1
     */
    protected AbstractUnsizedContainer(int windowSize) {
        this(windowSize, null);
    }

    /**
     * Constructor.
     *
     * <p>
     * After using this constructor, a subsequent invocation of {@link #setProperties setProperties()} is required
     * to define the properties of this container.
     * </p>
     *
     * @param windowSize size of the query window
     * @param propertyExtractor used to extract properties from the underlying Java objects;
     *  may be null but then container is not usable until one is configured via
     * {@link #setPropertyExtractor setPropertyExtractor()}
     * @throws IllegalArgumentException if {@code windowSize} is less than 1
     */
    protected AbstractUnsizedContainer(int windowSize, PropertyExtractor<? super T> propertyExtractor) {
        this(windowSize, propertyExtractor, null);
    }

    /**
     * Primary constructor.
     *
     * @param windowSize size of the query window (how big of a chunk we query at one time)
     * @param propertyExtractor used to extract properties from the underlying Java objects;
     *  may be null but then container is not usable until one is configured via
     * {@link #setPropertyExtractor setPropertyExtractor()}
     * @param propertyDefs container property definitions; null is treated like the empty set
     * @throws IllegalArgumentException if {@code windowSize} is less than 1
     */
    protected AbstractUnsizedContainer(int windowSize, PropertyExtractor<? super T> propertyExtractor,
      Collection<? extends PropertyDef<?>> propertyDefs) {
        if (windowSize < 1)
            throw new IllegalArgumentException("windowSize = " + windowSize);
        this.windowSize = windowSize;
        this.setPropertyExtractor(propertyExtractor);
        this.setProperties(propertyDefs);
    }

    @Override
    protected QueryList<T> query(long hint) {

        // Clip hint value
        hint = Math.min(hint, this.size - 1);
        hint = Math.max(hint, 0);

        // Query underlying data for the window of items centered at "hint"
        final long offset = Math.max(0, hint - this.windowSize / 2);
        final List<? extends T> window = this.queryWindow(offset, this.windowSize);
        final int querySize = window.size();

        // Update size estimate
        if (querySize <= 0)                     // the underlying data has shrunk on us
            this.size = this.shrink(offset);
        else if (querySize < this.windowSize)   // we overlapped the end; now we know the exact size
            this.size = offset + querySize;
        else                                    // we are somewhere in the middle; we have a (possibly new) lower bound on the size
            this.size = Math.max(this.size, offset + querySize + 1);

        // Return QueryList
        return new WindowQueryList<T>(offset, window, this.size);
    }

    /**
     * Get the window size configured at construction time.
     */
{'fraction_non_alphanumeric': 0.08539108842598979, 'fraction_numerical': 0.0024831011173955028, 'mean_word_length': 3.0207986688851913, 'pattern_counts': {'":': 0, '<': 87, '<?xml version=': 0, '>': 81, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5217238', 'n_tokens_mistral': 3753, 'n_tokens_neox': 3662, 'n_words': 1395}