package org.erlide.ui.actions;
import java.util.Collection;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.texteditor.ITextEditor;
import org.erlide.engine.ErlangEngine;
import org.erlide.engine.model.ErlElementKind;
import org.erlide.engine.model.ErlModelException;
import org.erlide.engine.model.IErlElement;
import org.erlide.engine.model.erlang.ErlangFunction;
import org.erlide.engine.model.erlang.IErlFunction;
import org.erlide.engine.model.erlang.IErlImport;
import org.erlide.engine.model.erlang.IErlRecordDef;
import org.erlide.engine.model.erlang.ISourceRange;
import org.erlide.engine.model.erlang.ISourceReference;
import org.erlide.engine.model.root.IErlElementLocator;
import org.erlide.engine.model.root.IErlModel;
import org.erlide.engine.model.root.IErlModule;
import org.erlide.engine.model.root.IErlProject;
import org.erlide.engine.services.search.ModelFindService;
import org.erlide.engine.services.search.OpenResult;
import org.erlide.engine.services.search.OpenService;
import org.erlide.runtime.rpc.RpcException;
import org.erlide.ui.prefs.plugin.NavigationPreferencePage;
import org.erlide.ui.util.ErlModelUtils;
import com.ericsson.otp.erlang.OtpErlangObject;
import com.ericsson.otp.erlang.OtpErlangRangeException;
import com.ericsson.otp.erlang.OtpErlangString;
public class OpenUtils {
private final ModelFindService modelFindService;
public OpenUtils() {
modelFindService = ErlangEngine.getInstance().getModelFindService();
}
public void openOpenResult(final ITextEditor editor, final IErlModule module,
final int offset, final IErlProject erlProject, final OpenResult openResult,
final IErlElement element)
throws CoreException, ErlModelException, PartInitException,
BadLocationException, OtpErlangRangeException, RpcException {
if (editor == null) {
return;
}
final Object found = findOpenResult(editor, module, erlProject, openResult,
element);
if (found instanceof IErlElement) {
ErlModelUtils.openElement((IErlElement) found);
} else if (found instanceof ISourceRange) {
ErlModelUtils.openSourceRange(module, (ISourceRange) found);
}
}
public Object findOpenResult(final ITextEditor editor, final IErlModule module,
final IErlProject project, final OpenResult openResult,
final IErlElement element) throws CoreException, ErlModelException,
OtpErlangRangeException, RpcException, BadLocationException {
final IErlElementLocator.Scope scope = NavigationPreferencePage
.getCheckAllProjects() ? IErlElementLocator.Scope.ALL_PROJECTS
: IErlElementLocator.Scope.REFERENCED_PROJECTS;
final IErlElementLocator model = ErlangEngine.getInstance().getModel();
Object found = null;
if (openResult.isExternalCall()) {
found = findExternalCallOrType(module, openResult, project, element, scope);
} else if (openResult.isInclude()) {
found = modelFindService.findInclude(model, project, module,
openResult.getName(), openResult.getPath());
} else if (openResult.isLocalCall()) {
found = findLocalCall(module, project, openResult, element, scope);
} else if (openResult.isVariable() && element instanceof ISourceReference) {
final ISourceReference sref = (ISourceReference) element;
final ISourceRange range = sref.getSourceRange();
final String elementText = editor.getDocumentProvider()
.getDocument(editor.getEditorInput())
.get(range.getOffset(), range.getLength());
found = modelFindService.findVariable(range, openResult.getName(),
elementText);
} else if (openResult.isRecord() || openResult.isMacro()) {
final ErlElementKind kind = openResult.isMacro() ? ErlElementKind.MACRO_DEF
: ErlElementKind.RECORD_DEF;
found = modelFindService.findPreprocessorDef(module, openResult.getName(),
kind);
} else if (openResult.isField()) {
final IErlRecordDef def = (IErlRecordDef) modelFindService
.findPreprocessorDef(module, openResult.getFun(),
ErlElementKind.RECORD_DEF);
if (def != null) {
found = def.getFieldNamed(openResult.getName());
}
}
return found;
}
private IErlElement findLocalCall(final IErlModule module,
final IErlProject erlProject, final OpenResult res, final IErlElement element,
final IErlElementLocator.Scope scope) throws RpcException, CoreException {
if (isTypeDefOrRecordDef(element, res)) {
return modelFindService.findTypespec(module, res.getFun());
}
final IErlFunction foundElement = module.findFunction(res.getFunction());
if (foundElement != null) {
return foundElement;
}
// imported functions
OtpErlangObject res2 = null;
String moduleName = null;
final IErlImport ei = module.findImport(res.getFunction());
if (ei != null) {
final IErlModel model = ErlangEngine.getInstance().getModel();
moduleName = ei.getImportModule();
res2 = ErlangEngine.getInstance().getService(OpenService.class)
.getSourceFromModule(model.getPathVars(), moduleName,
erlProject.getProperties().getExternalModules());
}
if (res2 instanceof OtpErlangString && moduleName != null) {
// imported from otp module
final OtpErlangString otpErlangString = (OtpErlangString) res2;
final String modulePath = otpErlangString.stringValue();
final IErlElementLocator model = ErlangEngine.getInstance().getModel();
return modelFindService.findFunction(model, erlProject, module, moduleName,
modulePath, res.getFunction(), scope);
}
// functions defined in include files
final Collection<IErlModule> allIncludedFiles = ErlangEngine.getInstance()
.getModelSearcherService().findAllIncludedFiles(module);
for (final IErlModule includedModule : allIncludedFiles) {
final IErlFunction function = includedModule.findFunction(res.getFunction());
if (function != null) {
return function;
}
}
return null;
}
public boolean isTypeDefOrRecordDef(final IErlElement element, final OpenResult res) {
if (element != null) {
if (element.getKind() == ErlElementKind.RECORD_DEF) {
return true;
}
if (element.getKind() == ErlElementKind.TYPESPEC) {
if (!res.getFun().equals(element.getName())) {
return true;
}
}
}
return false;
}
private IErlElement findExternalCallOrType(final IErlModule module,
final OpenResult res, final IErlProject project, final IErlElement element,
final IErlElementLocator.Scope scope) throws CoreException {
final IErlElementLocator model = ErlangEngine.getInstance().getModel();
if (isTypeDefOrRecordDef(element, res)) {
return modelFindService.findTypeDef(model, project, module, res.getName(),
res.getFun(), res.getPath(), scope);
}
final IErlFunction result = modelFindService.findFunction(model, project, module,
res.getName(), res.getPath(), res.getFunction(), scope);
if (result != null) {
return result;
}
return modelFindService.findFunction(model, project, module, res.getName(),
res.getPath(), new ErlangFunction(res.getFun(), ErlangFunction.ANY_ARITY),
scope);
}
}