/*
 * 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.storage.datastore;

import com.google.cloud.datastore.LongValue;
import com.google.cloud.datastore.Query;
import com.google.cloud.datastore.StringValue;
import com.google.cloud.datastore.TimestampValue;
import io.spine.server.delivery.ShardIndex;
import io.spine.server.delivery.ShardSessionRecord;

import java.util.Iterator;
import java.util.Optional;

import static com.google.cloud.Timestamp.fromProto;
import static io.spine.server.storage.datastore.DatastoreWrapper.MAX_ENTITIES_PER_WRITE_REQUEST;

/**
 * A Datastore-based storage which contains {@code ShardSessionRecord}s.
 */
public final class DsSessionStorage
        extends DsMessageStorage<ShardIndex, ShardSessionRecord, ShardSessionReadRequest> {

    private static final boolean multitenant = false;

    DsSessionStorage(DatastoreStorageFactory factory) {
        super(factory.systemWrapperFor(DsSessionStorage.class, multitenant), multitenant);
    }

    @Override
    ShardIndex idOf(ShardSessionRecord message) {
        return message.getIndex();
    }

    @Override
    MessageColumn<ShardSessionRecord>[] columns() {
        return Column.values();
    }

    /**
     * Obtains all the session records present in the storage.
     */
    Iterator<ShardSessionRecord> readAll() {
        return readAll(Query.newEntityQueryBuilder(), MAX_ENTITIES_PER_WRITE_REQUEST);
    }

    /**
     * Obtains the session record for the shard with the given index.
     */
    Optional<ShardSessionRecord> read(ShardIndex index) {
        return read(new ShardSessionReadRequest(index));
    }

    /**
     * The columns of the {@link ShardSessionRecord} message stored in Datastore.
     */
    private enum Column implements MessageColumn<ShardSessionRecord> {

        shardIndex("work_shard", (m) -> {
            return LongValue.of(m.getIndex()
                                 .getIndex());
        }),

        ofTotalShards("of_total_work_shards", (m) -> {
            return LongValue.of(m.getIndex()
                                 .getOfTotal());
        }),

        nodeId("nodeId", (m) -> {
            return StringValue.of(m.getPickedBy()
                                   .getValue());
        }),

        whenLastPicked("when_last_picked", (m) -> {
            return TimestampValue.of(fromProto(m.getWhenLastPicked()));
        });

        /**
         * The column name.
         */
        private final String name;

        /**
         * Obtains the value of the column from the given message.
         */
        @SuppressWarnings("NonSerializableFieldInSerializableClass")  // This enum isn't serialized.
        private final Getter<ShardSessionRecord> getter;

        Column(String name,
               Getter<ShardSessionRecord> getter) {
            this.name = name;
            this.getter = getter;
        }

        @Override
        public String columnName() {
            return name;
        }

        @Override
        public Getter<ShardSessionRecord> getter() {
            return getter;
        }
    }
}

@@ -2778,28 +2778,9 @@
 hard
-Index(%22work_shard%22, 
+(
 (m) 
@@ -2901,46 +2901,21 @@
     
-ofTotalShards(%22of_
 total_
-work_
 shards
-%22, 
+(
 (m) 
@@ -3042,21 +3042,9 @@
 node
-Id(%22nodeId%22, 
+(
 (m) 
@@ -3172,24 +3172,8 @@
     
-whenLastPicked(%22
 when
@@ -3188,11 +3188,9 @@
 cked
-%22, 
+(
 (m) 
@@ -3306,264 +3306,75 @@
   * 
-The column name.%0A         */%0A        private final String name;%0A%0A        /**%0A         * Obtains the value of the column from the given message.%0A         */%0A        @SuppressWarnings(%22NonSerializableFieldInSerializableClass%22)  // This enum isn't serialized.
+Obtains the value of the column from the given message.%0A         */
 %0A   
@@ -3447,36 +3447,8 @@
 umn(
-String name,%0A               
 Gett
@@ -3484,38 +3484,8 @@
 ) %7B%0A
-            this.name = name;%0A
     
@@ -3603,16 +3603,18 @@
 urn name
+()
 ;%0A      

Clean up shard session record column names