/*
 * Copyright 2021, TeamDev. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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.client;

import io.spine.annotation.Internal;
import io.spine.query.ColumnName;
import io.spine.query.CustomColumn;
import io.spine.reflect.GenericTypeIndex;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;

import java.util.function.Supplier;

import static io.spine.util.Exceptions.newIllegalStateException;

/**
 * A common type for the lifecycle column definitions which are declared as a part of a client-side
 * query language.
 */
@SuppressWarnings({"Immutable"})  //TODO:2021-01-18:alex.tymchenko: document!
@Internal
public abstract class EntityLifecycleColumn<V> extends CustomColumn<Supplier<V>, V> {

    private final ColumnName name;

    private volatile @MonotonicNonNull Class<V> valueType;

    @Override
    @SuppressWarnings("unchecked")   // Ensured by the declaration of the generic parameter.
    public Class<V> type() {
        if (valueType == null) {
            valueType = (Class<V>) GenericParameter.VALUE.argumentIn(getClass());
        }
        return valueType;
    }

    EntityLifecycleColumn(String name) {
        super();
        this.name = ColumnName.of(name);
    }

    @Override
    public ColumnName name() {
        return name;
    }

    @Override
    public final V valueIn(Supplier<V> source) {
        throw newIllegalStateException("`EntityLifecycleColumn.valueIn(..)` " +
                                               "must not be called directly.");
    }

    /**
     * Enumeration of generic type parameters of this class.
     */
    @SuppressWarnings("rawtypes")
    private enum GenericParameter implements GenericTypeIndex<EntityLifecycleColumn> {

        /** The index of the generic type {@code <V>}. */
        VALUE(0);

        private final int index;

        GenericParameter(int index) {
            this.index = index;
        }

        @Override
        public int index() {
            return this.index;
        }
    }
}

@@ -1712,87 +1712,429 @@
 .%0A *
-/%0A@SuppressWarnings(%7B%22Immutable%22%7D)  //TODO:2021-01-18:alex.tymchenko: document!
+%0A * @apiNote Unlike other types of %7B@link io.spine.query.Column Column%7Ds, the descendants of%0A *         this type are intended just to introduce the definitions of columns into the query DSL.%0A *         Therefore, the API for obtaining the column values from entities and entity records%0A *         is disabled by explicit throwing an %7B@code IllegalStateException%7Ds in respective method.%0A */%0A@SuppressWarnings(%22Immutable%22)
 %0A@In
@@ -2375,17 +2375,17 @@
 ed%22)   /
-/
+*
  Ensured
@@ -2429,16 +2429,19 @@
 rameter.
+ */
 %0A    pub
@@ -2616,24 +2616,117 @@
 ype;%0A    %7D%0A%0A
+    /**%0A     * Creates an instance of this class with the passed name of the column.%0A     */%0A
     EntityLi
@@ -2884,32 +2884,409 @@
 rn name;%0A    %7D%0A%0A
+    /**%0A     * Always throws an %7B@code IllegalStateException%7D.%0A     *%0A     * The descendant types of this class are designed to be a part of the query DSL,%0A     * but not the real means to extract column values. Therefore, the implementation of this method%0A     * prohibits obtaining the column values.%0A     *%0A     * @throws IllegalStateException%0A     *         always%0A     */%0A
     @Override%0A  

Document the type.