package org.jetbrains.plugins.groovy.runner;

import com.intellij.execution.CantRunException;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.JavaParameters;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.projectRoots.JavaSdkType;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.project.Project;
import com.intellij.util.PathUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.config.GroovyConfigUtils;

import java.io.File;
import java.io.IOException;
import java.util.regex.Pattern;

/**
 * @author peter
 */
public abstract class GroovyScriptRunner {

  public abstract boolean isValidModule(@NotNull Module module);

  public abstract boolean ensureRunnerConfigured(@Nullable Module module, final String confName, final Project project) throws ExecutionException;

  public abstract void configureCommandLine(JavaParameters params, @Nullable Module module, boolean tests, VirtualFile script,
                                            GroovyScriptRunConfiguration configuration) throws CantRunException;

  protected static String getConfPath(final String groovyHomePath) {
    String confpath = FileUtil.toSystemDependentName(groovyHomePath + "/conf/groovy-starter.conf");
    if (new File(confpath).exists()) {
      return confpath;
    }

    try {
      final String jarPath = PathUtil.getJarPathForClass(GroovyScriptRunner.class);
      if (new File(jarPath).isFile()) { //jar; distribution mode
        return new File(jarPath, "../groovy-starter.conf").getCanonicalPath();
      }

      //else, it's directory in out, development mode
      return new File(jarPath, "conf/groovy-starter.conf").getCanonicalPath();
    }
    catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  protected static void setGroovyHome(JavaParameters params, String groovyHome) {
    params.getVMParametersList().addParametersString("-Dgroovy.home=" + "\"" + groovyHome + "\"");
    if (groovyHome.contains("grails")) { //a bit of a hack
      params.getVMParametersList().addParametersString("-Dgrails.home=" + "\"" + groovyHome + "\"");
    }
    if (groovyHome.contains("griffon")) { //a bit of a hack
      params.getVMParametersList().addParametersString("-Dgriffon.home=" + "\"" + groovyHome + "\"");
    }
  }

  protected static void setToolsJar(JavaParameters params) {
    Sdk jdk = params.getJdk();
    if (jdk != null && jdk.getSdkType() instanceof JavaSdkType) {
      String toolsPath = ((JavaSdkType)jdk.getSdkType()).getToolsPath(jdk);
      if (toolsPath != null) {
        params.getVMParametersList().add("-Dtools.jar=" + toolsPath);
      }
    }
  }

  @Nullable
  protected static VirtualFile findGroovyJar(@NotNull Module module) {
    final Pattern pattern = Pattern.compile(".*[\\\\/]groovy[^\\\\/]*jar");
    for (Library library : GroovyConfigUtils.getInstance().getSDKLibrariesByModule(module)) {
      for (VirtualFile root : library.getFiles(OrderRootType.CLASSES)) {
        if (pattern.matcher(root.getPresentableUrl()).matches()) {
          return root;
        }
      }
    }
    return null;
  }

  protected static void addClasspathFromRootModel(@Nullable Module module, boolean isTests, JavaParameters params) throws CantRunException {
    if (module == null) {
      return;
    }

    final JavaParameters tmp = new JavaParameters();
    tmp.configureByModule(module, isTests ? JavaParameters.JDK_AND_CLASSES_AND_TESTS : JavaParameters.JDK_AND_CLASSES);
    StringBuffer buffer = RunnerUtil.getClearClassPathString(tmp, module);
    if (buffer.length() > 0) {
      params.getProgramParametersList().add("--classpath");
      params.getProgramParametersList().add(buffer.toString());
    }
  }

}

@@ -237,24 +237,69 @@
 ule.Module;%0A
+import com.intellij.openapi.project.Project;%0A
 import com.i
@@ -386,16 +386,69 @@
 ts.Sdk;%0A
+import com.intellij.openapi.roots.ModuleRootManager;%0A
 import c
@@ -619,23 +619,28 @@
 api.
-vfs.VirtualF
+util.text.StringUt
 il
-e
 ;%0Aim
@@ -661,39 +661,39 @@
 lij.openapi.
-project.Project
+vfs.VirtualFile
 ;%0Aimport com
@@ -863,16 +863,72 @@
 igUtils;
+%0Aimport org.jetbrains.plugins.groovy.util.LibrariesUtil;
 %0A%0Aimport
@@ -966,24 +966,56 @@
 OException;%0A
+import java.util.LinkedHashSet;%0A
 import java.
@@ -3891,32 +3891,24 @@
 aParameters.
-JDK_AND_
 CLASSES_AND_
@@ -3934,134 +3934,823 @@
 ers.
-JDK_AND_
 CLASSES
+_ONLY
 );%0A    
-StringBuffer buffer = RunnerUtil.getClearClassPathString(tmp, module);%0A    if (buffer.length() %3E 0) %7B%0A  
+if (tmp.getClassPath().getVirtualFiles().isEmpty()) %7B%0A      return;%0A    %7D%0A%0A%0A    final boolean embeddable =%0A      LibrariesUtil.isEmbeddableDistribution(ModuleRootManager.getInstance(module).getFiles(OrderRootType.CLASSES));%0A    if (embeddable) %7B%0A      params.getProgramParametersList().add(%22--classpath%22);%0A      params.getProgramParametersList().add(tmp.getClassPath().getPathsString());%0A      return;%0A    %7D%0A%0A    final LinkedHashSet%3CString%3E pathList = new LinkedHashSet%3CString%3E(tmp.getClassPath().getPathList());%0A    for (Library library : GroovyConfigUtils.getInstance().getSDKLibrariesByModule(module)) %7B%0A      for (VirtualFile file : library.getFiles(OrderRootType.CLASSES)) %7B%0A        pathList.remove(file.getPresentableUrl());%0A      %7D%0A    %7D%0A    if (pathList.isEmpty()) %7B%0A      return;%0A    %7D%0A%0A
     
@@ -4799,34 +4799,32 @@
 lasspath%22);%0A    
-  
 params.getProgra
@@ -4849,33 +4849,55 @@
 add(
-buffer.toString());%0A    %7D
+StringUtil.join(pathList, File.pathSeparator));
 %0A  %7D

add groovy-all.jar to script classpath in case of embeddable distribution