package net.jangaroo.ide.idea.exml;
import com.intellij.codeInsight.TargetElementUtilBase;
import com.intellij.codeInsight.navigation.actions.GotoDeclarationHandler;
import com.intellij.lang.javascript.JavascriptLanguage;
import com.intellij.lang.javascript.psi.JSFile;
import com.intellij.lang.javascript.psi.JSFunction;
import com.intellij.lang.javascript.psi.JSSourceElement;
import com.intellij.lang.javascript.psi.JSVariable;
import com.intellij.lang.javascript.psi.ecmal4.JSPackageStatement;
import com.intellij.lang.properties.IProperty;
import com.intellij.lang.properties.PropertiesReferenceManager;
import com.intellij.lang.properties.psi.PropertiesFile;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.intellij.psi.impl.source.tree.LeafPsiElement;
import net.jangaroo.utils.CompilerUtils;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* @author Frank Wienberg
*/
public class PropertyAccessGotoDeclarationHandler implements GotoDeclarationHandler {
private static final String RESOURCE_BUNDLE_INSTANCE_NAME = "INSTANCE";
private static final String PROPERTIES_AS_SUFFIX = "_properties.as";
@Nullable
@Override
public PsiElement[] getGotoDeclarationTargets(PsiElement element, int offset, Editor editor) {
if (element instanceof LeafPsiElement
&& ((LeafPsiElement)element).getElementType().getLanguage() == JavascriptLanguage.INSTANCE) {
PsiReference reference = TargetElementUtilBase.findReference(editor, offset);
if (reference != null) {
return getGotoDeclarationTargetsForPropertyAccess(reference.resolve());
}
}
return null;
}
private PsiElement[] getGotoDeclarationTargetsForPropertyAccess(PsiElement resolvedElement) {
if (resolvedElement instanceof JSFunction
|| resolvedElement instanceof JSVariable && RESOURCE_BUNDLE_INSTANCE_NAME.equals(((JSVariable)resolvedElement).getName())) {
PsiFile jsFile = resolvedElement.getContainingFile();
if (jsFile instanceof JSFile && jsFile.getName().endsWith(PROPERTIES_AS_SUFFIX)) {
Module module = ProjectFileIndex.SERVICE.getInstance(resolvedElement.getProject()).getModuleForFile(jsFile.getVirtualFile());
String bundleName = getQName((JSFile)jsFile);
if (module != null && bundleName != null) {
List<PropertiesFile> propertiesFiles = PropertiesReferenceManager.getInstance(resolvedElement.getProject()).findPropertiesFiles(module, bundleName);
String propertyName = resolvedElement instanceof JSFunction ? ((JSFunction)resolvedElement).getName() : null;
return pimpUpResult(propertiesFiles, propertyName);
}
}
}
return null;
}
private static String getQName(JSFile jsFile) {
String bundleName = null;
JSSourceElement[] statements = jsFile.getStatements();
if (statements.length > 0 && statements[0] instanceof JSPackageStatement) {
bundleName = CompilerUtils.qName(((JSPackageStatement)statements[0]).getQualifiedName(),
jsFile.getName().substring(0, jsFile.getName().length() - PROPERTIES_AS_SUFFIX.length()));
}
return bundleName;
}
private PsiElement[] pimpUpResult(List<PropertiesFile> propertiesFiles, String propertyName) {
Collections.sort(propertiesFiles, new Comparator<PropertiesFile>() {
@Override
public int compare(PropertiesFile o1, PropertiesFile o2) {
return o1.getName().compareTo(o2.getName());
}
});
PsiElement[] result = new PsiElement[propertiesFiles.size()];
for (int i = 0; i < propertiesFiles.size(); i++) {
PropertiesFile propertiesFile = propertiesFiles.get(i);
result[i] = propertiesFile.getContainingFile();
if (propertyName != null) {
IProperty property = propertiesFile.findPropertyByKey(propertyName);
if (property != null) {
result[i] = property.getPsiElement();
}
}
}
return result;
}
public String getActionText(DataContext paramDataContext) {
return null;
}
}