/**
 * Copyright 2016 Bryan Kelly
 *
 * 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
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package com.btkelly.gnag.utils;

import com.btkelly.gnag.models.Violation;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;

/**
 * Creates formatted HTML strings representing individual violations.
 */
public final class ViolationFormatter {

    private static final String VIOLATION_FILE_LABEL  = "File: ";
    private static final String VIOLATION_LINE_LABEL  = "Line: ";
    private static final String VIOLATION_NAME_LABEL  = "Violation: ";
    private static final String VIOLATION_NOTES_LABEL = "Notes: ";
    private static final String VIOLATION_REPORTER_LABEL = "Reporter: ";

    /**
     * Use this method to create a formatted HTML string representing a violation that will be posted as an inline
     * comment. Only intended for use when posting inline comments to GitHub.
     */
    public static String getHtmlStringForInlineComment(@NotNull final Violation violation) {
        final Integer violationFileLineNumber = violation.getFileLineNumber();
        final String violationRelativeFilePath = violation.getRelativeFilePath();

        if (violationFileLineNumber == null || violationRelativeFilePath == null) {
            throw new IllegalStateException(
                    "Should only call getHtmlStringForInlineViolationComment when violation location is known");
        }

        final HtmlStringBuilder builder = new HtmlStringBuilder();

        appendViolationReporterToBuilder(violation, builder);
        appendViolationNameToBuilder(violation, builder);
        appendViolationCommentToBuilderIfPresent(violation, builder);

        return builder.toString();
    }

    /**
     * Use this method to create a formatted HTML string representing a violation that will be posted as part of an
     * aggregated comment. Intended for use when generating the local Gnag report, and when posting aggregated comments
     * to GitHub.
     */
    public static String getHtmlStringForAggregatedComment(@NotNull final Violation violation) {
        final HtmlStringBuilder builder = new HtmlStringBuilder();

        appendViolationNameToBuilder(violation, builder);
        appendLocationInformationToBuilderIfPresent(violation, builder);
        appendViolationCommentToBuilderIfPresent(violation, builder);

        return builder.toString();
    }

    private static void appendViolationReporterToBuilder(
            @NotNull final Violation violation,
            @NotNull final HtmlStringBuilder builder) {

        builder.appendBold(VIOLATION_REPORTER_LABEL);
        builder.append(violation.getReporterName());
        builder.insertLineBreak();
    }

    private static void appendViolationNameToBuilder(
            @NotNull final Violation violation,
            @NotNull final HtmlStringBuilder builder) {

        builder.appendBold(VIOLATION_NAME_LABEL);

        final String violationName = violation.getName();
        final String primaryViolationUrl = violation.getPrimaryUrl();

        if (StringUtils.isNotBlank(primaryViolationUrl)) {
            builder.appendLink(violationName, primaryViolationUrl);
        } else {
            builder.append(violationName);
        }
    }

    private static void appendLocationInformationToBuilderIfPresent(
            @NotNull final Violation violation,
            @NotNull final HtmlStringBuilder builder) {

        final String violationRelativeFilePath = violation.getRelativeFilePath();

        if (violationRelativeFilePath != null) {
            appendRelativeFilePathToBuilder(violationRelativeFilePath, builder);

            final Integer violationFileLineNumber = violation.getFileLineNumber();

            if (violationFileLineNumber != null) {
                appendViolationLineNumberToBuilder(violationFileLineNumber, builder);
            }
        }
    }

    private static void appendRelativeFilePathToBuilder(
            @NotNull final String violationRelativeFilePath,
            @NotNull final HtmlStringBuilder builder) {

        builder
                .insertLineBreak()
                .appendBold(VIOLATION_FILE_LABEL)
                .append(violationRelativeFilePath);
    }

    private static void appendViolationLineNumberToBuilder(
            @NotNull final Integer violationFileLineNumber,
            @NotNull final HtmlStringBuilder builder) {

        builder
                .insertLineBreak()
                .appendBold(VIOLATION_LINE_LABEL)
                .append(Integer.toString(violationFileLineNumber));
    }

    private static void appendViolationCommentToBuilderIfPresent(
            @NotNull final Violation violation,
            @NotNull final HtmlStringBuilder builder) {

        final String violationComment = violation.getComment();

        if (violationComment != null) {
            builder
                    .insertLineBreak()
                    .appendBold(VIOLATION_NOTES_LABEL)
                    .append(violationComment);
        }
    }

    private ViolationFormatter() {
        // This constructor intentionally left blank.
    }

}

@@ -748,16 +748,40 @@
 tNull;%0A%0A
+import java.util.List;%0A%0A
 /**%0A * C
@@ -895,352 +895,8 @@
  %7B%0A%0A
-    private static final String VIOLATION_FILE_LABEL  = %22File: %22;%0A    private static final String VIOLATION_LINE_LABEL  = %22Line: %22;%0A    private static final String VIOLATION_NAME_LABEL  = %22Violation: %22;%0A    private static final String VIOLATION_NOTES_LABEL = %22Notes: %22;%0A    private static final String VIOLATION_REPORTER_LABEL = %22Reporter: %22;%0A%0A
     
@@ -1857,32 +1857,99 @@
 ation, builder);
+%0A        appendSecondaryUrlsToBuilderIfPresent(violation, builder);
 %0A%0A        return
@@ -2603,32 +2603,99 @@
 ation, builder);
+%0A        appendSecondaryUrlsToBuilderIfPresent(violation, builder);
 %0A%0A        return
@@ -2916,32 +2916,20 @@
 old(
-VIOLATION_REPORTER_LABEL
+%22Reporter: %22
 );%0A 
@@ -3212,28 +3212,21 @@
 old(
-VIOLATION_NAME_LABEL
+%22Violation: %22
 );%0A%0A
@@ -4456,28 +4456,16 @@
 old(
-VIOLATION_FILE_LABEL
+%22File: %22
 )%0A  
@@ -4781,28 +4781,16 @@
 old(
-VIOLATION_LINE_LABEL
+%22Line: %22
 )%0A  
@@ -5233,77 +5233,964 @@
 old(
-VIOLATION_NOTES_LABEL)%0A                    .append(violationComment);
+%22Notes: %22)%0A                    .append(violationComment);%0A        %7D%0A    %7D%0A%0A    private static void appendSecondaryUrlsToBuilderIfPresent(%0A            @NotNull final Violation violation,%0A            @NotNull final HtmlStringBuilder builder) %7B%0A%0A        final List%3CString%3E secondaryViolationUrls = violation.getSecondaryUrls();%0A%0A        if (!secondaryViolationUrls.isEmpty()) %7B%0A            builder%0A                    .insertLineBreak()%0A                    .appendBold(%22Related Links: %22);%0A            %0A            for (int urlNumber = 0; urlNumber %3C secondaryViolationUrls.size(); urlNumber++) %7B%0A                builder%0A                        .append(%22%5B%22)%0A                        .appendLink(Integer.toString(urlNumber), secondaryViolationUrls.get(urlNumber))%0A                        .append(%22%5D%22);%0A                %0A                if (urlNumber != secondaryViolationUrls.size() - 1) %7B%0A                    builder.append(%22, %22);%0A                %7D%0A            %7D
 %0A   

Add related links to comments