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

import io.spine.validate.ValidationException;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.nullToEmpty;
import static com.google.common.base.Throwables.getRootCause;
import static com.google.common.base.Throwables.getStackTraceAsString;

/**
 * Utility class for working with {@link Error}s.
 */
public final class Errors {

    /** Prevents instantiation of this utility class. */
    private Errors() {
    }

    /**
     * Creates new instance of {@link Error} by the passed {@code Throwable}.
     */
    public static Error fromThrowable(Throwable throwable) {
        Error.Builder result = toErrorBuilder(throwable);
        return result.build();
    }

    /**
     * Creates an instance by the root cause of the passed {@link Throwable}.
     *
     * @param throwable the {@code Throwable} to convert
     * @return new instance of {@link Error}
     */
    public static Error causeOf(Throwable throwable) {
        Error.Builder error = toBuilderCauseOf(throwable);
        return error.build();
    }

    /**
     * Creates an instance by the root cause of the given {@link Throwable} with
     * the given error code.
     *
     * <p>The error code may represent a number in an enum or a native error number
     *
     * @param throwable the {@code Throwable} to convert
     * @param errorCode the error code to include in the resulting {@link Error}
     * @return new instance of {@link Error}
     * @see #causeOf(Throwable) as the recommended overload
     */
    public static Error causeOf(Throwable throwable, int errorCode) {
        Error.Builder error = toBuilderCauseOf(throwable).setCode(errorCode);
        return error.build();
    }

    private static Error.Builder toBuilderCauseOf(Throwable throwable) {
        return toErrorBuilder(getRootCause(throwable));
    }

    private static Error.Builder toErrorBuilder(Throwable throwable) {
        checkNotNull(throwable);
        String type = throwable.getClass()
                               .getName();
        String message = nullToEmpty(throwable.getMessage());
        String stacktrace = getStackTraceAsString(throwable);
        Error.Builder result = Error.newBuilder()
                                     .setType(type)
                                     .setMessage(message)
                                     .setStacktrace(stacktrace);
        if (throwable instanceof ValidationException) {
            ValidationException validationException = (ValidationException) throwable;
            result.setValidationError(validationException.asValidationError());
        }
        return result;
    }
}

@@ -1867,32 +1867,47 @@
 @param throwable
+%0A     *        
  the %7B@code Thro
@@ -2336,16 +2336,17 @@
 r number
+.
 %0A     *%0A
@@ -2368,16 +2368,31 @@
 hrowable
+%0A     *        
  the %7B@c
@@ -2440,16 +2440,31 @@
 rrorCode
+%0A     *        
  the err
@@ -2939,32 +2939,717 @@
 wable));%0A    %7D%0A%0A
+    /**%0A     * Converts the given %7B@code Throwable%7D into an %7B@link Error%7D builder.%0A     *%0A     * %3Cp%3EThe class FQN of the %7B@code Throwable%7D becomes the %7B@code Error.type%7D.%0A     *%0A     * %3Cp%3EThe message of the %7B@code Throwable%7D becomes the %7B@code Error.message%7D.%0A     *%0A     * %3Cp%3EThe %7B@code Error.stacktrace%7D is populated by dumping the stacktrace of%0A     * the %7B@code Throwable%7D into a string.%0A     *%0A     * %3Cp%3EIf the %7B@code Throwable%7D is a %7B@link ValidationException%7D,%0A     * the %7B@code Error.validation_error%7D is populated from the validation exception.%0A     *%0A     * @param throwable%0A     *         the %7B@code Throwable%7D to convert%0A     * @return new builder of %7B@link Error%7D%0A     */%0A
     private stat
@@ -3814,16 +3814,25 @@
     .get
+Canonical
 Name();%0A
@@ -3995,21 +3995,8 @@
 rror
-.newBuilder()
 %0A   
@@ -4000,37 +4000,46 @@
                 
-     
+.newBuilder()%0A
                 
@@ -4053,37 +4053,16 @@
 e(type)%0A
-                     
         
@@ -4090,37 +4090,16 @@
 essage)%0A
-                     
         

Document `Errors`