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

import io.spine.base.FieldPaths;
import io.spine.validate.ConstraintViolation;

import java.util.Collection;
import java.util.List;

import static com.google.common.base.Preconditions.checkNotNull;
import static java.lang.String.format;
import static java.lang.System.lineSeparator;
import static java.util.stream.Collectors.joining;

/**
 * Provides error diagnostic text for a violation of a validation constraint.
 *
 * <p>If a {@link ConstraintViolation} has nested violations, they are listed in separate lines.
 */
public final class ViolationText {

    private final ConstraintViolation violation;

    private ViolationText(ConstraintViolation violation) {
        this.violation = violation;
    }

    /**
     * Creates a new instance of the text for the passed violation.
     */
    public static ViolationText of(ConstraintViolation violation) {
        checkNotNull(violation);
        return new ViolationText(violation);
    }

    /**
     * Creates text with diagnostics for the passed violations, starting each of them from
     * a new line.
     */
    public static String ofAll(Collection<ConstraintViolation> violations) {
        String result =
                violations.stream()
                          .map(ViolationText::of)
                          .map(ViolationText::toString)
                          .collect(joining(lineSeparator()));
        return result;
    }

    @Override
    public String toString() {
        StringBuilder builder = buildMessage();
        for (ConstraintViolation violation : this.violation.getViolationList()) {
            builder.append(lineSeparator());
            ViolationText nested = of(violation);
            builder.append(nested.toString());
        }
        return builder.toString();
    }

    private StringBuilder buildMessage() {
        String fieldPath = FieldPaths.toString(violation.getFieldPath());

        String format = violation.getMsgFormat();
        List<String> params = violation.getParamList();
        String formattedMessage = format(format, params.toArray());

        StringBuilder result = new StringBuilder();
        if (!fieldPath.isEmpty()) {
            result.append("At ")
                  .append(fieldPath)
                  .append(": ");
        }
        result.append(formattedMessage);
        return result;
    }
}

@@ -2855,24 +2855,76 @@
 Message() %7B%0A
+        String typeName = violation.getTypeName();%0A%0A
         Stri
@@ -3225,124 +3225,279 @@
     
-if (!fieldPath.isEmpty()) %7B%0A            result.append(%22At %22)%0A         
+appendPrefix(result, typeName);%0A        appendPrefix(result, fieldPath);%0A        result.append(formattedMessage);%0A        return result;%0A
     
+%7D%0A%0A
     
- .append(fieldPath)%0A                  
+private static void appendPrefix(StringBuilder target, String prefix) %7B%0A        if (!prefix.isEmpty()) %7B%0A            target
 .app
@@ -3505,13 +3505,13 @@
 nd(%22
-:
+At
  %22)
-;
 %0A   
@@ -3515,26 +3515,24 @@
         
-%7D%0A
         
 result.a
@@ -3519,38 +3519,34 @@
             
-result
+  
 .append(
 formattedMes
@@ -3537,49 +3537,58 @@
 end(
-formattedMessage);%0A        return result;
+prefix)%0A                  .append(%22: %22);%0A        %7D
 %0A   

Print type name in the validation error text.