package org.fandev.utils;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.JavaSdk;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.impl.file.PsiDirectoryFactory;
import com.intellij.psi.util.PsiTreeUtil;
import fan.sys.Map;
import fan.sys.Env;
import org.fandev.actions.generation.FanTemplatesFactory;
import org.fandev.actions.generation.TemplateProperty;
import org.fandev.lang.fan.psi.FanFile;
import org.fandev.lang.fan.psi.api.statements.FanVariable;
import org.fandev.lang.fan.psi.api.statements.expressions.FanClosureExpression;
import org.fandev.lang.fan.psi.api.statements.typeDefs.FanBuildScriptDefinition;
import org.fandev.lang.fan.psi.api.statements.typeDefs.FanEnumDefinition;
import org.fandev.lang.fan.psi.api.statements.typeDefs.FanTypeDefinition;
import org.fandev.lang.fan.psi.api.statements.typeDefs.members.FanField;
import org.fandev.lang.fan.psi.api.statements.typeDefs.members.FanMethod;
import org.fandev.lang.fan.psi.impl.FanListReferenceType;
import org.fandev.lang.fan.psi.impl.FanMapType;
import org.fandev.module.FanModuleType;
import org.fandev.module.pod.PodModel;
import org.fandev.module.wizard.FanModuleBuilder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
/**
* @author Dror Bereznitsky
* @date Jan 21, 2009 4:48:30 PM
*/
public class FanUtil {
private static final Logger logger = Logger.getInstance("org.fandev.utils.FanUtil");
static {
System.setProperty("fan.debug", "true");
}
public static boolean isFanModuleType(@Nullable final Module module) {
return module != null && FanModuleType.getInstance() == module.getModuleType();
}
public static Sdk getSdk(final Module module) {
if (module != null) {
if (FanUtil.isFanModuleType(module)) {
return ModuleRootManager.getInstance(module).getSdk();
}
}
return null;
}
public static void setFanHome(final Module module) {
setFanHome(getSdk(module));
}
public static void setFanHome(@NotNull final Sdk moduleSdk) {
System.setProperty("fan.home", moduleSdk.getHomePath());
}
public static void setFanHome(@NotNull final String home) {
System.setProperty("fan.home", home);
}
@Nullable
public static URLClassLoader getSysClassloader(@NotNull final String sdkHome) {
final VirtualFile sysJar = VirtualFileUtil.refreshAndFindFileByLocalPath(sdkHome + "/lib/java/sys.jar");
try {
if (sysJar.exists()) {
return new URLClassLoader(new URL[]{new java.io.File(sysJar.getPath()).toURI().toURL()});
}
} catch (Exception e) {
logger.error("Could load sys.jar", e);
}
return null;
}
public static java.io.File getJdkHome(final Sdk moduleSdk) {
setFanHome(moduleSdk);
final Map env = Env.cur().vars();
String fanJavaHome = (String) env.get("java.home");
if (fanJavaHome != null) {
// Fallback to current Java version
fanJavaHome = System.getProperty("java.home");
}
return new java.io.File(fanJavaHome);
}
public static Sdk createFanJdk(final Sdk moduleSdk) {
return JavaSdk.getInstance().createJdk("Fantom JDK", getJdkHome(moduleSdk).getAbsolutePath());
}
public static VariableKind getVariableKind(@NotNull final PsiVariable paramPsiVariable) {
if (paramPsiVariable instanceof PsiField) {
if (paramPsiVariable.hasModifierProperty("static")) {
if (paramPsiVariable.hasModifierProperty("final")) {
return VariableKind.STATIC_FINAL_FIELD;
}
return VariableKind.STATIC_FIELD;
}
return VariableKind.FIELD;
}
if (paramPsiVariable instanceof PsiParameter) {
if (((PsiParameter) paramPsiVariable).getDeclarationScope() instanceof PsiForeachStatement) {
return VariableKind.LOCAL_VARIABLE;
}
return VariableKind.PARAMETER;
}
if (paramPsiVariable instanceof PsiLocalVariable) {
return VariableKind.LOCAL_VARIABLE;
}
return VariableKind.LOCAL_VARIABLE;
}
public static VirtualFile generateBuildScript(final String contentPath, final Project project, final PodModel pod) {
final VirtualFile contentEntryPath = VirtualFileManager.getInstance().refreshAndFindFileByUrl(
VirtualFileUtil.constructLocalUrl(contentPath));
VirtualFile buildScript = null;
try {
buildScript = ApplicationManager.getApplication().runWriteAction(new Computable<VirtualFile>() {
public VirtualFile compute() {
final EnumMap<TemplateProperty, String> parameters = new EnumMap<TemplateProperty, String>(TemplateProperty.class);
parameters.put(TemplateProperty.NAME, pod.getName());
parameters.put(TemplateProperty.VERSION, pod.getVersion());
parameters.put(TemplateProperty.DESCRIPTION, pod.getDescription());
parameters.put(TemplateProperty.OUT_DIR, "`" + pod.getOutDir() + "`");
parameters.put(TemplateProperty.DOC_API, String.valueOf(pod.getDocApi()));
parameters.put(TemplateProperty.DOC_SRC, String.valueOf(pod.getDocSrc()));
parameters.put(TemplateProperty.POD_DEPENDS, listToString(pod.getDependencies()));
parameters.put(TemplateProperty.POD_SRC_DIRS, listPairToUrl(pod.getSrcDirs()));
parameters.put(TemplateProperty.POD_RES_DIRS, listPairToUrl(pod.getResDirs()));
parameters.put(TemplateProperty.METAS, listPairToString(pod.getMetas()));
parameters.put(TemplateProperty.INDEXES, listPairToString(pod.getIndexes()));
final PsiFile buildScript = FanTemplatesFactory.createFromTemplate(
PsiDirectoryFactory.getInstance(project).createDirectory(contentEntryPath),
pod.getBuildScriptName(), "FanBuildScript.fan", parameters);
return buildScript.getVirtualFile();
}
});
} catch (Exception e) {
e.printStackTrace();
}
pod.setBuildScriptFile(buildScript);
return buildScript;
}
@Nullable
public static FanTypeDefinition getContainingType(@NotNull final PsiElement element) {
final PsiElement maybeClazz = PsiTreeUtil.getParentOfType(element, FanTypeDefinition.class, FanFile.class);
if (FanUtil.isFanType(maybeClazz)) {
return (FanTypeDefinition) maybeClazz;
}
return null;
}
public static boolean isFanTypeDefinition(final PsiElement element) {
return isOfType(element, FanTypeDefinition.class);
}
public static boolean isFanEnumDefinition(final PsiElement element) {
return isOfType(element, FanEnumDefinition.class);
}
public static boolean isFanClosure(final PsiElement element) {
return isOfType(element, FanClosureExpression.class);
}
public static boolean isPsiCodeBlock(final PsiElement element) {
return isOfType(element, PsiCodeBlock.class);
}
public static boolean isFanMethod(final PsiElement element) {
return isOfType(element, FanMethod.class);
}
public static boolean isFanField(final PsiElement element) {
return isOfType(element, FanField.class);
}
public static boolean isFanVariable(final PsiElement element) {
return isOfType(element, FanVariable.class);
}
public static boolean isFanFile(final PsiElement element) {
return isOfType(element, FanFile.class);
}
public static boolean isFanType(final PsiElement element) {
return isOfType(element, FanTypeDefinition.class);
}
public static boolean isFanBuildScript(final PsiElement element) {
return isOfType(element, FanBuildScriptDefinition.class);
}
public static boolean isFanMapType(final PsiType element) {
return isOfType(element, FanMapType.class);
}
public static boolean isFanListType(final PsiType element) {
return isOfType(element, FanListReferenceType.class);
}
public static boolean isOfType(final PsiElement element, final Class<?> type) {
return element != null && type.isAssignableFrom(element.getClass());
}
public static boolean isOfType(final PsiType element, final Class<?> type) {
return element != null && type.isAssignableFrom(element.getClass());
}
// helpers for converting FanModel parameter settings to and from strings to sets.
public static String listToString(final List<String> set) {
final StringBuilder sb = new StringBuilder();
int i = 0;
for (final String s : set) {
if (i != 0) {
sb.append(", ");
}
sb.append("\"");
sb.append(s);
sb.append("\"");
i++;
}
return sb.toString();
}
public static String listPairToUrl(final List<Pair<String,String>> list) {
final StringBuilder sb = new StringBuilder();
int i = 0;
for (final Pair<String,String> s : list) {
if (i != 0) {
sb.append(", ");
}
sb.append("`");
sb.append(s.getFirst());
if (!s.getFirst().endsWith("/")) {
sb.append("/");
}
sb.append("`");
i++;
}
return sb.toString();
}
public static String listPairToString(final List<Pair<String,String>> set) {
final StringBuilder sb = new StringBuilder();
int i = 0;
for (final Pair<String,String> s : set) {
if (i != 0) {
sb.append(", ");
}
sb.append("\"");
sb.append(s.getFirst());
sb.append("\"");
sb.append(" : ");
sb.append("\"");
sb.append(s.getSecond());
sb.append("\"");
i++;
}
return sb.toString();
}
public static String listPairToFirstString(final List<Pair<String,String>> set) {
final StringBuilder sb = new StringBuilder();
int i = 0;
for (final Pair<String,String> s : set) {
if (i != 0) {
sb.append(", ");
}
sb.append(s.getFirst());
i++;
}
return sb.toString();
}
public static List<String> stringToList(String value) {
final List<String> list = new LinkedList<String>();
if (TextUtil.isEmpty(value)) {
return list;
}
value = value.replaceAll("\"", "");
final String[] values = value.split(",");
for (int i = 0; i < values.length; i++) {
list.add(values[i].trim());
}
return list;
}
public static List<Pair<String,String>> urlToListPair(String value) {
final List<Pair<String,String>> list = new LinkedList<Pair<String,String>>();
if (TextUtil.isEmpty(value)) {
return list;
}
value = value.replaceAll("`", "");
final String[] values = value.split(",");
for (int i = 0; i < values.length; i++) {
final String s = values[i].trim();
list.add(new Pair<String,String>(s,s));
}
return list;
}
public static List<Pair<String,String>> stringToListPair(String value) {
final List<Pair<String,String>> list = new LinkedList<Pair<String,String>>();
if (TextUtil.isEmpty(value)) {
return list;
}
value = value.replaceAll("\"", "");
final String[] values = value.split(",");
for (int i = 0; i < values.length; i++) {
final String[] element = values[i].split(":{1}?");
if (element.length > 1) {
String t = element[1];
if (element.length > 2) {
final StringBuilder sb = new StringBuilder();
for (int j = 1; j< element.length; j++) {
if (TextUtil.isEmpty(element[j])) {
sb.append("::");
} else {
sb.append(element[j]);
}
}
t = sb.toString();
}
final Pair<String,String> pair = new Pair<String,String>(element[0].trim(),t.trim());
list.add(pair);
}
}
return list;
}
public static List<Pair<String,String>> firstStringToListPair(String value) {
final List<Pair<String,String>> list = new LinkedList<Pair<String,String>>();
if (TextUtil.isEmpty(value)) {
return list;
}
value = value.replaceAll("\"", "");
final String[] values = value.split(",");
for (int i = 0; i < values.length; i++) {
final String s = values[i].trim();
final Pair<String,String> pair = new Pair<String,String>(s,s);
list.add(pair);
}
return list;
}
}