/*
 * ForgeGradle
 * Copyright (C) 2018 Forge Development LLC
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
 * USA
 */

package net.minecraftforge.gradle.userdev.tasks;

import org.gradle.api.file.FileCollection;
import org.gradle.api.tasks.compile.JavaCompile;
import org.gradle.util.GradleVersion;

import java.lang.reflect.Method;

// A terrible hack to use JavaCompile while bypassing
// Gradle's normal task infrastructure.
public class HackyJavaCompile extends JavaCompile {

    public void doHackyCompile() {

        // What follows is a horrible hack to allow us to call JavaCompile
        // from our dependency resolver.
        // As described in https://github.com/MinecraftForge/ForgeGradle/issues/550,
        // invoking Gradle tasks in the normal way can lead to deadlocks
        // when done from a dependency resolver.

        // To avoid these issues, we invoke the 'compile' method on JavaCompile
        // using reflection.

        // Normally, the output history is set by Gradle. Since we're bypassing
        // the normal gradle task infrastructure, we need to do it ourselves.

        // TaskExecutionHistory is removed in 5.1.0, so we only try to set it
        // on versions below 5.1.0

        if (GradleVersion.current().compareTo(GradleVersion.version("5.1.0")) < 0) {
            try {
                Class<?> taskExectionHistory = Class.forName("org.gradle.api.internal.TaskExecutionHistory");
                Method setHistory = this.getOutputs().getClass().getMethod("setHistory", taskExectionHistory);
                Object dummyHistory = Class.forName("net.minecraftforge.gradle.userdev.util.DummyTaskExecutionHistory").newInstance();
                setHistory.invoke(this.getOutputs(), dummyHistory);
            } catch (Exception e) {
                throw new RuntimeException("Exception calling setHistory", e);
            }
        } else {
            try {
                Method setPreviousOutputFiles = this.getOutputs().getClass().getMethod("setPreviousOutputFiles", FileCollection.class);
                setPreviousOutputFiles.invoke(this.getOutputs(), this.getProject().files());
            } catch (Exception e) {
                throw new RuntimeException("Exception calling setPreviousOutputFiles ", e);
            }
        }

        // Do the actual compilation,
        // bypassing a bunch of Gradle's other stuff (e.g. internal event listener mechanism)
        this.compile();
    }

}

@@ -921,16 +921,25 @@
 dle.api.
+internal.
 tasks.co
@@ -944,16 +944,24 @@
 compile.
+Cleaning
 JavaComp
@@ -967,48 +967,569 @@
 pile
-;%0Aimport org.gradle.util.GradleVersion;%0A
+r;%0Aimport org.gradle.api.internal.tasks.compile.DefaultJavaCompileSpec;%0Aimport org.gradle.api.internal.tasks.compile.JavaCompileSpec;%0Aimport org.gradle.api.tasks.WorkResult;%0Aimport org.gradle.api.tasks.compile.JavaCompile;%0Aimport org.gradle.internal.operations.BuildOperationExecutor;%0Aimport org.gradle.jvm.internal.toolchain.JavaToolChainInternal;%0Aimport org.gradle.language.base.internal.compile.Compiler;%0Aimport org.gradle.language.base.internal.compile.CompilerUtil;%0Aimport org.gradle.util.GradleVersion;%0A%0Aimport java.lang.reflect.InvocationTargetException;
 %0Aimp
@@ -3096,32 +3096,201 @@
 );%0A            %7D
+%0A%0A            // Do the actual compilation,%0A            // bypassing a bunch of Gradle's other stuff (e.g. internal event listener mechanism)%0A            this.compile();
 %0A        %7D else 
@@ -3692,166 +3692,1095 @@
     
-%7D%0A%0A        // Do the actual compilation,%0A        // bypassing a bunch of Gradle's other stuff (e.g. internal event listener mechanism)%0A        this.compile();
+    try %7B%0A                final DefaultJavaCompileSpec spec;%0A                try %7B%0A                    Method createSpec = JavaCompile.class.getDeclaredMethod(%22createSpec%22);%0A                    createSpec.setAccessible(true);%0A                    spec = (DefaultJavaCompileSpec) createSpec.invoke(this);%0A                %7D catch (NoSuchMethodException %7C IllegalAccessException %7C InvocationTargetException e) %7B%0A                    throw new RuntimeException(%22Exception calling createSpec %22, e);%0A                %7D%0A                spec.setSourceFiles(getSource());%0A                Compiler%3CJavaCompileSpec%3E javaCompiler = CompilerUtil.castCompiler(((JavaToolChainInternal) getToolChain()).select(getPlatform()).newCompiler(spec.getClass()));%0A                CleaningJavaCompiler compiler = new CleaningJavaCompiler(javaCompiler, getOutputs());%0A                final WorkResult execute = compiler.execute(spec);%0A                setDidWork(execute.getDidWork());%0A            %7D catch (Exception e) %7B%0A                throw new RuntimeException(%22Exception compiling %22, e);%0A            %7D%0A        %7D%0A
 %0A   

Fix HackyCompile for Gradle 5.1+ to ignore compilation time reporting. (#625)