package com.jetbrains.actionscript.profiler.sampler;
import com.intellij.lang.javascript.flex.XmlBackedJSClassImpl;
import com.intellij.lang.javascript.psi.ecmal4.JSClass;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.Navigatable;
import com.intellij.psi.PsiElement;
import com.intellij.psi.search.GlobalSearchScope;
import com.jetbrains.actionscript.profiler.util.ResolveUtil;
import org.jetbrains.annotations.Nullable;
import java.io.File;
public class SampleLocationResolver implements Navigatable {
private @Nullable VirtualFile resolvedFile;
private @Nullable PsiElement resolvedElement;
private final GlobalSearchScope scope;
private final FrameInfo frameInfo;
public SampleLocationResolver(FrameInfo frameInfo, GlobalSearchScope scope) {
this.frameInfo = frameInfo;
this.scope = scope;
// resolve via qname package::Class/((get|set) )?method name()
PsiElement element = ResolveUtil.findClassByQName(frameInfo.getQName(), scope);
if (element instanceof XmlBackedJSClassImpl) {
final PsiElement candidateElement = frameInfo.findFunctionOrField((XmlBackedJSClassImpl)element);
if (candidateElement != null) element = candidateElement;
}
else {
if (element != null) element = element.getNavigationElement();
if (element instanceof JSClass) {
final PsiElement candidateElement = frameInfo.findFunctionOrField((JSClass)element);
if (candidateElement != null) element = candidateElement;
}
}
if (element instanceof Navigatable) {
resolvedElement = element;
}
final boolean resolved = resolvedFile != null || resolvedElement != null;
if (!resolved && frameInfo.getFileName() != null) {
// try navigate from debug info [path;package path;file:line] , btw it can be invalid for SDK
String dir = frameInfo.getFileDirectory();
String packageName = frameInfo.getPackageName();
String filename = frameInfo.getFileName();
if (packageName != null && packageName.length() > 0) {
dir += File.separatorChar + packageName.replace('.', File.separatorChar);
}
dir += File.separatorChar;
final int endIndex = filename != null ? filename.indexOf(':') : -1;
dir += endIndex != -1 ? filename.substring(0, endIndex) : filename;
VirtualFile relativeFile = VfsUtil.findRelativeFile(dir, null);
if (relativeFile == null && packageName != null && filename != null) {
String className = packageName.replace('\\', '.').replace('/', '.');
if (className.length() > 0) className += ".";
className += filename.substring(0, filename.indexOf('.'));
PsiElement classElement = ResolveUtil.findClassByQName(className, scope);
if (classElement != null) classElement = classElement.getNavigationElement();
if (classElement != null && classElement.isWritable()) {
relativeFile = classElement.getContainingFile().getVirtualFile();
}
}
if (relativeFile != null) {
resolvedFile = relativeFile;
}
}
}
@Override
public void navigate(boolean requestFocus) {
if (resolvedElement != null) {
((Navigatable)resolvedElement).navigate(true);
}
else if (resolvedFile != null && scope.getProject() != null) {
int line = Math.max(0, frameInfo.getFileLine() - 1);
new OpenFileDescriptor(scope.getProject(), resolvedFile, line, 0).navigate(true);
}
}
@Override
public boolean canNavigate() {
return canNavigateToSource();
}
@Override
public boolean canNavigateToSource() {
return resolvedElement != null || resolvedFile != null;
}
}