package com.vikingsen.sonar;

import com.vikingsen.sonar.dto.DtoIssue;
import com.vikingsen.sonar.dto.DtoIssues;
import com.vikingsen.sonar.dto.DtoLocation;
import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.Sensor;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.batch.fs.FilePredicates;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.component.ResourcePerspectives;
import org.sonar.api.config.Settings;
import org.sonar.api.issue.Issuable;
import org.sonar.api.issue.Issue;
import org.sonar.api.profiles.RulesProfile;
import org.sonar.api.resources.Project;
import org.sonar.api.rules.ActiveRule;

import java.io.File;
import java.io.IOException;

public class AndroidLintSensor implements Sensor {

    private final FileSystem fileSystem;
    private final FilePredicates predicates;
    private final ResourcePerspectives perspectives;
    private final RulesProfile rulesProfile;

    private final Logger log = LoggerFactory.getLogger(AndroidLintSensor.class);
    private final File lintXml;

    public AndroidLintSensor(FileSystem fileSystem, ResourcePerspectives perspectives, RulesProfile rulesProfile, Settings settings) {
        this.fileSystem = fileSystem;
        this.predicates = fileSystem.predicates();
        this.perspectives = perspectives;
        this.rulesProfile = rulesProfile;
        lintXml = getFile(settings.getString(AndroidLintPlugin.ANDROID_LINT_REPORT));
        log.debug("Looking for Lint Report at {}", lintXml.getPath());
    }

    @Override
    public boolean shouldExecuteOnProject(Project project) {
        boolean execute = lintXml.exists();
        if (!execute) {
            log.info("Lint report was not found at {}. Skipping Android Lint", lintXml.getPath());
            log.debug("Set {} if lint-results.xml is not at {}.", AndroidLintPlugin.ANDROID_LINT_REPORT, AndroidLintPlugin.ANDROID_LINT_REPORT_DEFAULT);
        }
        return execute;
    }

    @Override
    public void analyse(Project project, SensorContext sensorContext) {
        Serializer serializer = new Persister();
        try {
            DtoIssues dtoIssues = serializer.read(DtoIssues.class, lintXml);
            for (DtoIssue dtoIssue : dtoIssues.getIssueList()) {
                processIssue(sensorContext, dtoIssue);
            }
        } catch (Exception e) {
            log.error("Exception reading " + lintXml.toString(), e);
        }
    }

    private void processIssue(SensorContext sensorContext, DtoIssue dtoIssue) {
        ActiveRule rule = rulesProfile.getActiveRule(AndroidLintRulesDefinition.KEY, dtoIssue.getId());
        if (rule != null) {
            log.debug("Processing Issue: {}", dtoIssue.getId());
            for (DtoLocation dtoLocation : dtoIssue.getLocations()) {
                processIssueForLocation(rule, dtoIssue, dtoLocation);
            }
        } else {
            log.debug("Unable to find rule for {}", dtoIssue.getId());
        }
    }

    private void processIssueForLocation(ActiveRule rule, DtoIssue dtoIssue, DtoLocation dtoLocation) {
        InputFile inputFile = fileSystem.inputFile(predicates.hasAbsolutePath(dtoLocation.getFile()));
        if (inputFile != null) {
            Issuable issuable = perspectives.as(Issuable.class, inputFile);
            if (issuable != null) {
                Issue issue = issuable.newIssueBuilder()
                        .ruleKey(rule.getRule().ruleKey())
                        .message(dtoIssue.getMessage())
                        .line(dtoLocation.getLine())
                        .build();
                issuable.addIssue(issue);
            }
        }
    }

    @Override
    public String toString() {
        return AndroidLintSensor.class.getSimpleName();
    }

    private File getFile(String path) {
        File file = new File(path);
        if (!file.isAbsolute()) {
            try {
                file = new File(fileSystem.baseDir(), path).getCanonicalFile();
            } catch (IOException e) {
                throw new IllegalStateException("Unable to resolve path \'" + path + "\'", e);
            }
        }
        return file;
    }
}

@@ -813,36 +813,8 @@
 ile;
-%0Aimport java.io.IOException;
 %0A%0Apu
@@ -1734,16 +1734,35 @@
 xecute =
+ lintXml != null &&
  lintXml
@@ -1874,16 +1874,34 @@
 d Lint%22,
+ lintXml != null ?
  lintXml
@@ -1906,24 +1906,31 @@
 ml.getPath()
+ : null
 );%0A         
@@ -3956,24 +3956,42 @@
 ing path) %7B%0A
+        try %7B%0A    
         File
@@ -4018,24 +4018,28 @@
 h);%0A        
+ 
+   
 if (!file.is
@@ -4058,24 +4058,8 @@
 %7B%0A  
-          try %7B%0A
     
@@ -4068,18 +4068,16 @@
         
-  
 file = n
@@ -4145,24 +4145,59 @@
        %7D
+%0A            return file;%0A        %7D
  catch (
 IOExcept
@@ -4192,10 +4192,8 @@
 ch (
-IO
 Exce
@@ -4219,104 +4219,46 @@
     
-    throw new IllegalStateException(%22Unable to resolve path %5C'%22 + path + %22%5C'%22, e);%0A            %7D
+log.warn(%22Unable to resolve path%22, e);
 %0A   
@@ -4275,26 +4275,26 @@
      return 
-file
+null
 ;%0A    %7D%0A%7D%0A

Handle null file correctly.