public interface ListEvent<E> {

    int getSizeBefore();

    int getSizeAfter();

    /**
     * @returns the previous index, or {@code -1} if this element didn't exist
     *      before the change.
     */
    int getIndexBefore(int indexAfter);

    /**
     * @returns the new index, or {@code -1} if this element doesn't exist
     *      after the change.
     */
    int getIndexAfter(int indexBefore);

    ObservableList<E> getSource();

    /**
     * Returns a new cursor that iterates over each change in this event.
     */
    Cursor<E> cursor();

    /**
     * A cursor navigates over each changed index in this event.
     *
     * <p>For example, the following listener keeps a buffer in sync with the
     * List it observes:
     *
     * <pre><code>
     * for (Cursor cursor = listEvent.cursor(); cursor.next(); ) {
     *     int changed = cursor.getIndex();
     *     if (cursor.getType() == ELEMENT_ADDED) {
     *         buffer.add(changed, cursor.getValueAfter());
     *     } else if (cursor.getType() == REPLACED) {
     *         buffer.set(changed, cursor.getValueAfter());
     *     } else if (cursor.getType() == ELEMENT_REMOVED) {
     *         buffer.remove(changed);
     *     }
     * }
     * </code></pre>
     */
    interface Cursor<E> {

        /**
         * Advance this cursor to the next change.
         *
         * @returns true if there are more changes, or false if there are none
         */
        boolean next();

        boolean isAdded();

        boolean isRemoved();

        /**
         * Returns the current index of the cursor.
         */
        int getIndex();

        /**
         * Returns the index of the changed element before the change or
         * {@code -1} if the element was not previously in the list.
         */
        int getIndexBefore();

        /**
         * Returns the index of the changed element after the change or
         * {@code -1} if the element is no longer in the list.
         */
        int getIndexAfter();

        /**
         * Returns the value before the change.
         */
        E getValueBefore();

        /**
         * Returns the value after the change.
         */
        E getValueAfter();
    }
}

