/*
 * 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.validate.given;

import com.google.common.collect.ImmutableList;
import com.google.protobuf.ByteString;
import com.google.protobuf.Duration;
import com.google.protobuf.ProtocolStringList;
import com.google.protobuf.StringValue;
import com.google.protobuf.Timestamp;
import io.spine.base.FieldPath;
import io.spine.base.Time;
import io.spine.validate.ConstraintViolation;

import static com.google.protobuf.util.Timestamps.add;
import static com.google.protobuf.util.Timestamps.subtract;
import static io.spine.base.Identifier.newUuid;
import static io.spine.base.Time.setProvider;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class MessageValidatorTestEnv {

    public static final double EQUAL_MIN = 16.5;
    public static final double GREATER_THAN_MIN = EQUAL_MIN + 5;
    public static final double LESS_THAN_MIN = EQUAL_MIN - 5;

    public static final double EQUAL_MAX = 64.5;
    public static final double GREATER_THAN_MAX = EQUAL_MAX + 5;

    public static final double INT_DIGIT_COUNT_GREATER_THAN_MAX = 123.5;
    public static final double INT_DIGIT_COUNT_EQUAL_MAX = 12.5;

    public static final String VALUE = "value";
    public static final String EMAIL = "email";
    public static final String OUTER_MSG_FIELD = "outer_msg_field";
    public static final String LESS_THAN_MIN_MSG = "Number must be greater than or equal to 16.5.";
    public static final String GREATER_MAX_MSG = "Number must be less than or equal to 64.5.";
    public static final String MATCH_REGEXP_MSG = "String must match the regular expression '%s'.";

    public static final int SECONDS_IN_MINUTE = 60;

    public static final int SECONDS_IN_5_MINUTES = 5 * SECONDS_IN_MINUTE;
    public static final int FIFTY_NANOSECONDS = 50;
    public static final int ZERO_NANOSECONDS = 0;
    public static final double INT_DIGIT_COUNT_LESS_THAN_MAX = 1.5;
    public static final double LESS_THAN_MAX = EQUAL_MAX - 5;

    /** Prevent instantiation of this test environment. */
    private MessageValidatorTestEnv() {
    }

    public static Timestamp currentTimeWithNanos(int nanos) {
        Timestamp result = timeWithNanos(Time.currentTime(), nanos);
        return result;
    }

    public static Timestamp timeWithNanos(Timestamp time, int nanos) {
        Timestamp result =
                time.toBuilder()
                    .setNanos(nanos)
                    .build();
        return result;
    }

    public static Duration newDuration(int seconds) {
        Duration result =
                Duration.newBuilder()
                        .setSeconds(seconds)
                        .build();
        return result;
    }
    
    /**
     * Freezes time for current thread by setting the time provider to a 
     * {@link ConstantTimeProvider}.
     *
     * @param time time to be returned upon {@link Time#currentTime()} call.
     */
    public static void freezeTime(Timestamp time) {
        Time.Provider frozenTimeProvider = new ConstantTimeProvider(time);
        setProvider(frozenTimeProvider);
    }

    public static void assertFieldPathIs(ConstraintViolation violation, String... expectedFields) {
        FieldPath path = violation.getFieldPath();
        ProtocolStringList actualFields = path.getFieldNameList();
        assertEquals(expectedFields.length, actualFields.size());
        assertEquals(ImmutableList.copyOf(expectedFields), ImmutableList.copyOf(actualFields));
    }

    public static Timestamp getFuture() {
        Timestamp future = add(Time.currentTime(), newDuration(SECONDS_IN_5_MINUTES));
        return future;
    }

    public static Timestamp getPast() {
        Timestamp past = subtract(Time.currentTime(), newDuration(SECONDS_IN_5_MINUTES));
        return past;
    }

    public static StringValue newStringValue() {
        return StringValue.of(newUuid());
    }

    public static ByteString newByteString() {
        ByteString bytes = ByteString.copyFromUtf8(newUuid());
        return bytes;
    }

    /**
     * The provider of the current time with value that does not change.
     */
    private static class ConstantTimeProvider implements Time.Provider {
        private final Timestamp timestamp;

        private ConstantTimeProvider(Timestamp timestamp) {
            this.timestamp = timestamp;
        }

        @Override
        public Timestamp currentTime() {
            return timestamp;
        }
    }
}

@@ -1131,45 +1131,8 @@
 ng;%0A
-import com.google.protobuf.Duration;%0A
 impo
@@ -1218,46 +1218,8 @@
 ue;%0A
-import com.google.protobuf.Timestamp;%0A
 impo
@@ -1250,35 +1250,8 @@
 th;%0A
-import io.spine.base.Time;%0A
 impo
@@ -1297,123 +1297,8 @@
 n;%0A%0A
-import static com.google.protobuf.util.Timestamps.add;%0Aimport static com.google.protobuf.util.Timestamps.subtract;%0A
 impo
@@ -1345,54 +1345,8 @@
 id;%0A
-import static io.spine.base.Time.setProvider;%0A
 impo
@@ -2338,237 +2338,8 @@
 %22;%0A%0A
-    public static final int SECONDS_IN_MINUTE = 60;%0A%0A    public static final int SECONDS_IN_5_MINUTES = 5 * SECONDS_IN_MINUTE;%0A    public static final int FIFTY_NANOSECONDS = 50;%0A    public static final int ZERO_NANOSECONDS = 0;%0A
     
@@ -2593,2352 +2593,606 @@
 tic 
-Timestamp currentTimeWithNanos(int nanos) %7B%0A        Timestamp result = timeWithNanos(Time.currentTime(), nanos);%0A        return result;%0A    %7D%0A%0A    public static Timestamp timeWithNanos(Timestamp time, int nanos) %7B%0A        Timestamp result =%0A                time.toBuilder()%0A                    .setNanos(nanos)%0A                    .build();%0A        return result;%0A    %7D%0A%0A    public static Duration newDuration(int seconds) %7B%0A        Duration result =%0A                Duration.newBuilder()%0A                        .setSeconds(seconds)%0A                        .build();%0A        return result;%0A    %7D%0A    %0A    /**%0A     * Freezes time for current thread by setting the time provider to a %0A     * %7B@link ConstantTimeProvider%7D.%0A     *%0A     * @param time time to be returned upon %7B@link Time#currentTime()%7D call.%0A     */%0A    public static void freezeTime(Timestamp time) %7B%0A        Time.Provider frozenTimeProvider = new ConstantTimeProvider(time);%0A        setProvider(frozenTimeProvider);%0A    %7D%0A%0A    public static void assertFieldPathIs(ConstraintViolation violation, String... expectedFields) %7B%0A        FieldPath path = violation.getFieldPath();%0A        ProtocolStringList actualFields = path.getFieldNameList();%0A        assertEquals(expectedFields.length, actualFields.size());%0A        assertEquals(ImmutableList.copyOf(expectedFields), ImmutableList.copyOf(actualFields));%0A    %7D%0A%0A    public static Timestamp getFuture() %7B%0A        Timestamp future = add(Time.currentTime(), newDuration(SECONDS_IN_5_MINUTES));%0A        return future;%0A    %7D%0A%0A    public static Timestamp getPast() %7B%0A        Timestamp past = subtract(Time.currentTime(), newDuration(SECONDS_IN_5_MINUTES));%0A        return past;%0A    %7D%0A%0A    public static StringValue newStringValue() %7B%0A        return StringValue.of(newUuid());%0A    %7D%0A%0A    public static ByteString newByteString() %7B%0A        ByteString bytes = ByteString.copyFromUtf8(newUuid());%0A        return bytes;%0A    %7D%0A%0A    /**%0A     * The provider of the current time with value that does not change.%0A     */%0A    private static class ConstantTimeProvider implements Time.Provider %7B%0A        private final Timestamp timestamp;%0A%0A        private ConstantTimeProvider(Timestamp timestamp) %7B%0A            this.timestamp = timestamp;%0A        %7D%0A%0A        @Override%0A        public Timestamp currentTime() %7B%0A            return timestamp;%0A        %7D
+void assertFieldPathIs(ConstraintViolation violation, String... expectedFields) %7B%0A        FieldPath path = violation.getFieldPath();%0A        ProtocolStringList actualFields = path.getFieldNameList();%0A        assertEquals(expectedFields.length, actualFields.size());%0A        assertEquals(ImmutableList.copyOf(expectedFields), ImmutableList.copyOf(actualFields));%0A    %7D%0A%0A    public static StringValue newStringValue() %7B%0A        return StringValue.of(newUuid());%0A    %7D%0A%0A    public static ByteString newByteString() %7B%0A        ByteString bytes = ByteString.copyFromUtf8(newUuid());%0A        return bytes;
 %0A   

Clean up.