/*
 * Copyright 2019, TeamDev. All rights reserved.
 *
 * Redistribution and use in source and/or binary forms, with or without
 * modification, must retain the above copyright notice and the following
 * disclaimer.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package io.spine.server.delivery;

import io.spine.annotation.SPI;
import io.spine.server.storage.Storage;
import io.spine.validate.Validated;

import java.util.List;
import java.util.Optional;

import static com.google.common.collect.Streams.stream;
import static io.spine.server.delivery.InboxMessageStatus.DELIVERED;
import static io.spine.server.delivery.InboxMessageStatus.TO_CATCH_UP;
import static java.util.stream.Collectors.toList;

/**
 * A contract for storages of {@link Inbox} messages.
 *
 * <p>The records a storage of this type are spreads across shards identified by a
 * {@linkplain ShardIndex shard index}.
 *
 * <p>Typically, the storage instance is specific to the
 * {@linkplain io.spine.server.ServerEnvironment server environment} and is used across
 * {@code BoundedContext}s to store the delivered messages.
 */
@SPI
public interface InboxStorage
        extends Storage<InboxMessageId, InboxMessage, InboxReadRequest> {

    /**
     * Reads the contents of the storage by the given shard index and returns the first page
     * of the results.
     *
     * <p>The older items go first.
     *
     * @param index
     *         the shard index to return the results for
     * @param pageSize
     *         the maximum number of the elements per page
     * @return the first page of the results
     */
    Page<InboxMessage> readAll(ShardIndex index, int pageSize);

    /**
     * Finds the newest message {@linkplain InboxMessageStatus#TO_DELIVER to deliver}
     * in the given shard.
     *
     * @param index
     *         the shard index to look in
     * @return the message found or {@code Optional.empty()} if there are no messages to deliver
     *         in the specified shard
     */
    Optional<InboxMessage> newestMessageToDeliver(ShardIndex index);

    /**
     * Writes a message to the storage.
     *
     * @param message
     *         a message to write
     */
    void write(InboxMessage message);

    /**
     * Writes several messages to the storage.
     *
     * @param messages
     *         messages to write
     */
    void writeAll(Iterable<InboxMessage> messages);

    /**
     * Removes the passed messages from the storage.
     *
     * <p>Does nothing for messages that aren't in the storage already.
     *
     * @param messages
     *         the messages to remove
     */
    void removeAll(Iterable<InboxMessage> messages);

    /**
     * Marks the messages as {@linkplain InboxMessageStatus#DELIVERED delivered} and writes
     * the updated messages.
     *
     * @param messages
     *         the messages to mark as delivered
     * @implNote The messages aren't additionally validated after marking as delivered to
     *         improve the performance.
     */
    default void markDelivered(Iterable<InboxMessage> messages) {
        List<@Validated InboxMessage> updated =
                stream(messages).map((m) -> m.toBuilder()
                                             .setStatus(DELIVERED)
                                             .build())
                                .collect(toList());
        writeAll(updated);
    }

    default void markCatchingUp(Iterable<InboxMessage> messages) {
        List<@Validated InboxMessage> updated =
                stream(messages).map((m) -> m.toBuilder()
                                             .setStatus(TO_CATCH_UP)
                                             .build())
                                .collect(toList());
        writeAll(updated);
    }
}

@@ -1117,340 +1117,34 @@
 ge;%0A
-import io.spine.validate.Validated;%0A%0Aimport java.util.List;%0Aimport java.util.Optional;%0A%0Aimport static com.google.common.collect.Streams.stream;%0Aimport static io.spine.server.delivery.InboxMessageStatus.DELIVERED;%0Aimport static io.spine.server.delivery.InboxMessageStatus.TO_CATCH_UP;%0Aimport static java.util.stream.Collectors.toList
+%0Aimport java.util.Optional
 ;%0A%0A/
@@ -3111,1116 +3111,7 @@
 es);
-%0A%0A    /**%0A     * Marks the messages as %7B@linkplain InboxMessageStatus#DELIVERED delivered%7D and writes%0A     * the updated messages.%0A     *%0A     * @param messages%0A     *         the messages to mark as delivered%0A     * @implNote The messages aren't additionally validated after marking as delivered to%0A     *         improve the performance.%0A     */%0A    default void markDelivered(Iterable%3CInboxMessage%3E messages) %7B%0A        List%3C@Validated InboxMessage%3E updated =%0A                stream(messages).map((m) -%3E m.toBuilder()%0A                                             .setStatus(DELIVERED)%0A                                             .build())%0A                                .collect(toList());%0A        writeAll(updated);%0A    %7D%0A%0A    default void markCatchingUp(Iterable%3CInboxMessage%3E messages) %7B%0A        List%3C@Validated InboxMessage%3E updated =%0A                stream(messages).map((m) -%3E m.toBuilder()%0A                                             .setStatus(TO_CATCH_UP)%0A                                             .build())%0A                                .collect(toList());%0A        writeAll(updated);%0A    %7D
 %0A%7D%0A

Remove the unused methods.