package nu.studer.teamcity.buildscan.agent;

import jetbrains.buildServer.agent.BuildRunnerContext;
import jetbrains.buildServer.agent.ToolCannotBeFoundException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * Executes Maven commands and returns their output, both standard output and standard error, when given a {@link BuildRunnerContext}.
 */
final class MavenCommandExecutor {

    private final BuildRunnerContext runnerContext;

    MavenCommandExecutor(BuildRunnerContext context) {
        this.runnerContext = context;
    }

    @NotNull
    Result execute(String args) throws IOException {
        File mavenExe = getMavenExe();
        if (mavenExe == null) {
            return new Result();
        }

        String command = mavenExe.getAbsolutePath() + " " + args;
        ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "))
            .redirectErrorStream(true);
        return new Result(processBuilder.start());
    }

    @Nullable
    private File getMavenExe() {
        try {
            String mavenPath = runnerContext.getToolPath("maven");
            String mvnExe = System.getProperty("os.name").toLowerCase().contains("win") ? "mvn.cmd" : "mvn";
            return new File(mavenPath, "bin/" + mvnExe);
        } catch (ToolCannotBeFoundException e) {
            return null;
        }
    }

    public static class Result {

        private final Process process;
        private String output;

        public Result() {
            process = null;
        }

        public Result(Process process) {
            this.process = process;
        }

        public boolean isSuccessful() throws InterruptedException {
            if (process == null) {
                return false;
            }

            process.waitFor();

            return process.exitValue() == 0;
        }

        @NotNull
        public String getOutput() throws InterruptedException, IOException {
            if (!isSuccessful() || process == null) {
                return "";
            }

            if (output == null) {
                // this logic eagerly consumes the entire output into memory, which should not be an issue when only
                // used for `mvn --version`, which generates ~5 lines of output
                // this may should be revisited if other commands are executed here
                StringBuilder sb = new StringBuilder();
                BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));

                int ch;
                while ((ch = reader.read()) != -1) {
                    sb.append((char) ch);
                }

                output = sb.toString();
            }

            return output;
        }

    }

}

@@ -780,22 +780,22 @@
 nExe
+c
  = getM
-ave
+v
 nExe
+c
 ();%0A
@@ -814,16 +814,17 @@
 mavenExe
+c
  == null
@@ -904,16 +904,17 @@
 mavenExe
+c
 .getAbso
@@ -1016,29 +1016,16 @@
 it(%22 %22))
-%0A            
 .redirec
@@ -1141,20 +1141,45 @@
 getM
-ave
+v
 nExe
+c
 () %7B%0A
+        String mavenPath;%0A
     
@@ -1192,39 +1192,32 @@
 y %7B%0A            
-String 
 mavenPath = runn
@@ -1248,24 +1248,167 @@
 aven%22);%0A    
+    %7D catch (ToolCannotBeFoundException e) %7B%0A            return null;%0A        %7D%0A%0A        File installationBinDir = new File(mavenPath, %22bin%22);%0A
         Stri
@@ -1416,16 +1416,27 @@
 g mvnExe
+cutableName
  = Syste
@@ -1511,36 +1511,32 @@
  %22mvn%22;%0A        
-    
 return new File(
@@ -1539,120 +1539,47 @@
 ile(
-mavenPath, %22bin/%22 + mvnExe);%0A        %7D catch (ToolCannotBeFoundException e) %7B%0A            return null;%0A        %7D
+installationBinDir, mvnExecutableName);
 %0A   
@@ -2190,42 +2190,42 @@
 if (
-!isSuccessful() %7C%7C process == null
+process == null %7C%7C !isSuccessful()
 ) %7B%0A
@@ -2525,12 +2525,8 @@
 his 
-may 
 shou

Refactor a bit for consistency