package edu.hm.hafner.analysis.parser;

import java.util.regex.Matcher;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;

import edu.hm.hafner.analysis.Issue;
import edu.hm.hafner.analysis.Priority;
import edu.hm.hafner.analysis.RegexpLineParser;

/**
 * A parser for the MSBuild/PcLint compiler warnings.
 *
 * @author Ullrich Hafner
 */
public class MsBuildParser extends RegexpLineParser {
    private static final long serialVersionUID = -2141974437420906595L;
    private static final String MS_BUILD_WARNING_PATTERN = "(?:^(?:.*)Command line warning ([A-Za-z0-9]+):\\s*(.*)" +
            "\\s*\\[(.*)\\])|" + ANT_TASK + "(?:(?:\\s*\\d+>)?(?:(?:(?:(.*)\\((\\d*)(?:,(\\d+))?.*\\)|.*LINK)\\s*:|(" +
            ".*):)\\s*([A-z-_]*\\s?(?:[Nn]ote|[Ii]nfo|[Ww]arning|(?:fatal\\s*)?[Ee]rror))\\s*:?\\s*([A-Za-z0-9]+)" +
            "\\s*:\\s(?:\\s*([A-Za-z0-9.]+)\\s*:)?\\s*(.*?)(?: \\[([^\\]]*)[/\\\\][^\\]\\\\]+\\])?" + "|(.*)\\s*:" +
            ".*error\\s*(LNK[0-9]+):\\s*(.*)))$";

    /**
     * Creates a new instance of {@link MsBuildParser}.
     */
    public MsBuildParser() {
        super("msbuild", MS_BUILD_WARNING_PATTERN);
    }

    @Override
    protected Issue createWarning(final Matcher matcher) {
        String fileName = determineFileName(matcher);

        if (StringUtils.isNotBlank(matcher.group(2))) {
            return issueBuilder().setFileName(fileName).setLineStart(0).setCategory(matcher.group(1))
                                 .setMessage(matcher.group(2)).setPriority(Priority.NORMAL).build();
        } else if (StringUtils.isNotBlank(matcher.group(13))) {
            return issueBuilder().setFileName(fileName).setLineStart(0).setCategory(matcher.group(14))
                                 .setMessage(matcher.group(15)).setPriority(Priority.HIGH).build();
        } else {
            Issue warning;
            if (StringUtils.isNotEmpty(matcher.group(10))) {
                warning = issueBuilder().setFileName(fileName).setLineStart(parseInt(matcher.group(5)))
                                        .setColumnStart(parseInt(matcher.group(6))).setCategory(matcher.group(9))
                                        .setType(matcher.group(10)).setMessage(matcher.group(11))
                                        .setPriority(determinePriority(matcher)).build();
            } else {
                String category = matcher.group(9);
                if ("Expected".matches(category)) {
                    return FALSE_POSITIVE;
                }
                warning = issueBuilder().setFileName(fileName).setLineStart(parseInt(matcher.group(5)))
                                        .setColumnStart(parseInt(matcher.group(6))).setCategory(category)
                                        .setMessage(matcher.group(11)).setPriority(determinePriority(matcher)).build();
            }
            return warning;
        }
    }

    /**
     * Determines the name of the file that is cause of the warning.
     *
     * @param matcher the matcher to get the matches from
     * @return the name of the file with a warning
     */
    private String determineFileName(final Matcher matcher) {
        String fileName;

        if (StringUtils.isNotBlank(matcher.group(3))) {
            fileName = matcher.group(3);
        } else if (StringUtils.isNotBlank(matcher.group(7))) {
            fileName = matcher.group(7);
        } else if (StringUtils.isNotBlank(matcher.group(13))) {
            fileName = matcher.group(13);
        } else {
            fileName = matcher.group(4);
        }

        if (StringUtils.isBlank(fileName)) {
            fileName = StringUtils.substringBetween(matcher.group(11), "'");
        }

        if (StringUtils.isBlank(fileName)) {
            fileName = "unknown.file";
        }

        String projectDir = matcher.group(12);
        if (StringUtils.isNotBlank(projectDir) &&
                FilenameUtils.getPrefixLength(fileName) == 0 &&
                !fileName.trim().equals("MSBUILD")) {

            // resolve fileName relative to projectDir
            fileName = FilenameUtils.concat(projectDir, fileName);
        }

        return fileName;
    }

    /**
     * Determines the priority of the warning.
     *
     * @param matcher the matcher to get the matches from
     * @return the priority of the warning
     */
    private Priority determinePriority(final Matcher matcher) {
        if (isOfType(matcher, "note") || isOfType(matcher, "info")) {
            return Priority.LOW;
        }

        if (isOfType(matcher, "warning")) {
            return Priority.NORMAL;
        }

        return Priority.HIGH;
    }

    /**
     * Returns whether the warning type is of the specified type.
     *
     * @param matcher the matcher
     * @param type    the type to match with
     * @return <code>true</code> if the warning type is of the specified type
     */
    private boolean isOfType(final Matcher matcher, final String type) {
        return StringUtils.containsIgnoreCase(matcher.group(8), type);
    }
}


@@ -1309,17 +1309,16 @@
 tcher);%0A
-%0A
         
@@ -1569,32 +1569,40 @@
 ild();%0A        %7D
+%0A       
  else if (String
@@ -1844,32 +1844,40 @@
 ild();%0A        %7D
+%0A       
  else %7B%0A        
@@ -2367,32 +2367,44 @@
 );%0A            %7D
+%0A           
  else %7B%0A        
@@ -3237,17 +3237,16 @@
 leName;%0A
-%0A
         
@@ -3335,32 +3335,40 @@
 up(3);%0A        %7D
+%0A       
  else if (String
@@ -3451,24 +3451,32 @@
 );%0A        %7D
+%0A       
  else if (St
@@ -3569,16 +3569,24 @@
        %7D
+%0A       
  else %7B%0A
@@ -3628,33 +3628,32 @@
 p(4);%0A        %7D%0A
-%0A
         if (Stri
@@ -3760,33 +3760,32 @@
 %22'%22);%0A        %7D%0A
-%0A
         if (Stri
@@ -3867,24 +3867,30 @@
  %7D%0A%0A        
+final 
 String proje
@@ -3965,32 +3965,16 @@
 tDir) &&
-%0A               
  Filenam
@@ -4013,32 +4013,16 @@
  == 0 &&
-%0A               
  !fileNa
@@ -4030,16 +4030,124 @@
 e.trim()
+%0A                                                                                                           
 .equals(
@@ -4160,17 +4160,16 @@
 LD%22)) %7B%0A
-%0A
         
@@ -4284,33 +4284,32 @@
 ame);%0A        %7D%0A
-%0A
         return f
@@ -4672,25 +4672,24 @@
       %7D%0A
-%0A
         
 if (isOf
@@ -4672,32 +4672,37 @@
       %7D%0A        
+else 
 if (isOfType(mat
@@ -4759,33 +4759,32 @@
 RMAL;%0A        %7D%0A
-%0A
         return P

Revert "Some cleanup, removed redundant else if()"