/*
 * Copyright 2020 the original author or authors.
 *
 * 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 org.gradle.docs.samples;

import org.gradle.api.UncheckedIOException;
import org.gradle.api.logging.configuration.WarningMode;
import org.gradle.integtests.fixtures.executer.ExecutionFailure;
import org.gradle.integtests.fixtures.executer.ExecutionResult;
import org.gradle.integtests.fixtures.executer.GradleContextualExecuter;
import org.gradle.integtests.fixtures.executer.GradleDistribution;
import org.gradle.integtests.fixtures.executer.GradleExecuter;
import org.gradle.integtests.fixtures.executer.IntegrationTestBuildContext;
import org.gradle.integtests.fixtures.executer.UnderDevelopmentGradleDistribution;
import org.gradle.samples.executor.CommandExecutor;
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

class IntegrationTestSamplesExecutor extends CommandExecutor {

    private static final String WARNING_MODE_FLAG_PREFIX = "--warning-mode=";

    private final File workingDir;
    private final boolean expectFailure;
    private final GradleExecuter gradle;

    IntegrationTestSamplesExecutor(File workingDir, boolean expectFailure) {
        this.workingDir = workingDir;
        this.expectFailure = expectFailure;
        GradleDistribution distribution = new UnderDevelopmentGradleDistribution(IntegrationTestBuildContext.INSTANCE);
        this.gradle = new GradleContextualExecuter(distribution, new TestNameTestDirectoryProvider(IntegrationTestSamplesExecutor.class), IntegrationTestBuildContext.INSTANCE);
    }

    @Override
    protected int run(String executable, List<String> args, List<String> flags, OutputStream outputStream) {
        List<String> filteredFlags = new ArrayList<>();
        WarningMode warningMode = WarningMode.Fail;
        for (String flag : flags) {
            if (flag.startsWith(WARNING_MODE_FLAG_PREFIX)) {
                warningMode = WarningMode.valueOf(capitalize(flag.replace(WARNING_MODE_FLAG_PREFIX, "").toLowerCase()));
            } else {
                filteredFlags.add(flag);
            }
        }
        configureAvailableJdks(filteredFlags);
        GradleExecuter executer = gradle.inDirectory(workingDir).ignoreMissingSettingsFile()
            .withStacktraceDisabled()
            .noDeprecationChecks()
            .withWarningMode(warningMode)
            .withToolchainDetectionEnabled()
            .withArguments(filteredFlags)
            .withTasks(args);
        try {
            if (expectFailure) {
                ExecutionFailure result = executer.runWithFailure();
                outputStream.write((result.getOutput() + result.getError()).getBytes());
            } else {
                ExecutionResult result = executer.run();
                outputStream.write(result.getOutput().getBytes());
            }
            return expectFailure ? 1 : 0;
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    // TODO: [bm] switch to ENV variables, essentially doing what EnvVariableJvmLocator does
    private void configureAvailableJdks(List<String> flags) {
        final File jdkFolder = new File("/opt/jdk");
        if(jdkFolder.exists()) {
            File[] files = jdkFolder.listFiles();
            if(files != null) {
                String allJdkPaths = Arrays.stream(files).map(File::getAbsolutePath).collect(Collectors.joining(","));
                flags.add("-Porg.gradle.java.installations.paths=" + allJdkPaths);
            }
        }
    }

    private static String capitalize(String s) {
        return s.substring(0, 1).toUpperCase() + s.substring(1);
    }
}

@@ -745,16 +745,74 @@
 ngMode;%0A
+import org.gradle.integtests.fixtures.AvailableJavaHomes;%0A
 import o
@@ -1286,32 +1286,68 @@
 leDistribution;%0A
+import org.gradle.internal.jvm.Jvm;%0A
 import org.gradl
@@ -1561,33 +1561,8 @@
 st;%0A
-import java.util.Arrays;%0A
 impo
@@ -3760,294 +3760,141 @@
     
-// TODO: %5Bbm%5D switch to ENV variables, essentially doing what EnvVariableJvmLocator does%0A    private void configureAvailableJdks(List%3CString%3E flags) %7B%0A        final File jdkFolder = new File(%22/opt/jdk%22);%0A        if(jdkFolder.exists()) %7B%0A            File%5B%5D files = jdkFolder.listFiles
+private void configureAvailableJdks(List%3CString%3E flags) %7B%0A        String allJdkPaths = AvailableJavaHomes.getAvailableJvms().stream
 ()
-;
 %0A   
@@ -3906,85 +3906,43 @@
     
-if(files != null) %7B%0A                String allJdkPaths = Arrays.stream(files)
+.map(Jvm::getJavaHome)%0A            
 .map
@@ -3964,16 +3964,29 @@
 utePath)
+%0A            
 .collect
@@ -4008,32 +4008,24 @@
 ning(%22,%22));%0A
-        
         flag
@@ -4091,32 +4091,8 @@
 s);%0A
-            %7D%0A        %7D%0A
     

Use already detected installations