/*******************************************************************************
* Copyright (c) 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Zend Technologies
*******************************************************************************/
package org.eclipse.php.internal.core.codeassist.strategies;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.dltk.core.*;
import org.eclipse.dltk.core.environment.EnvironmentPathUtils;
import org.eclipse.dltk.internal.core.ArchiveFolder;
import org.eclipse.dltk.internal.core.ArchiveProjectFragment;
import org.eclipse.dltk.internal.core.ScriptFolder;
import org.eclipse.php.core.PHPToolkitUtil;
import org.eclipse.php.core.codeassist.ICompletionContext;
import org.eclipse.php.core.codeassist.ICompletionReporter;
import org.eclipse.php.core.compiler.ast.nodes.NamespaceReference;
import org.eclipse.php.internal.core.Logger;
import org.eclipse.php.internal.core.codeassist.contexts.IncludeStatementContext;
import org.eclipse.php.internal.core.includepath.IncludePath;
import org.eclipse.php.internal.core.includepath.IncludePathManager;
import org.eclipse.php.internal.core.phar.PharConstants;
import org.eclipse.php.internal.core.phar.PharPath;
/**
* This strategy completes resources (both folders and files) that are available
* to the include statement. {@link IncludeStatementContext}
*/
public class IncludeStatementStrategy extends AbstractCompletionStrategy {
public final static String FOLDER_SEPARATOR = "/"; //$NON-NLS-1$
public IncludeStatementStrategy(ICompletionContext context) {
super(context);
}
public void apply(ICompletionReporter reporter) throws Exception {
ICompletionContext context = getContext();
if (!(context instanceof IncludeStatementContext)) {
return;
}
IncludeStatementContext includeContext = (IncludeStatementContext) context;
String prefix = includeContext.getPrefix();
ISourceRange replaceRange = getReplacementRange(includeContext);
final ISourceModule sourceModule = includeContext.getSourceModule();
if (sourceModule == null || sourceModule.getScriptProject() == null) {
if (DLTKCore.DEBUG_COMPLETION) {
System.out.println("Unable to locate source module or project"); //$NON-NLS-1$
}
return;
}
final IScriptProject scriptProject = sourceModule.getScriptProject();
final IncludePath[] includePaths = IncludePathManager.getInstance().getIncludePaths(scriptProject.getProject());
for (IncludePath includePath : includePaths) {
visitEntry(includePath, prefix, reporter, replaceRange, sourceModule.getScriptProject());
}
}
private void visitEntry(IncludePath includePath, String prefix, ICompletionReporter reporter,
ISourceRange replaceRange, IScriptProject project) {
// the root entry of this element
final Object entry = includePath.getEntry();
final IPath prefixPath = new Path(prefix);
IPath prefixPathFolder = prefixPath;
IPath lastSegmant = new Path(""); //$NON-NLS-1$
if (prefixPath.segmentCount() != 0 && !prefix.endsWith(NamespaceReference.NAMESPACE_DELIMITER)
&& !prefix.endsWith("/")) { //$NON-NLS-1$
prefixPathFolder = prefixPath.removeLastSegments(1);
lastSegmant = new Path(prefixPath.lastSegment());
}
try {
if (!includePath.isBuildpath()) {
addInternalEntries(reporter, replaceRange, entry, prefixPathFolder, lastSegmant);
} else {
addExternalEntries(reporter, replaceRange, project, entry, prefixPathFolder, lastSegmant);
}
} catch (CoreException e) {
Logger.logException(e);
}
}
private void addExternalEntries(ICompletionReporter reporter, ISourceRange replaceRange, IScriptProject project,
final Object entry, IPath prefixPathFolder, IPath lastSegmant) throws ModelException {
switch (((IBuildpathEntry) entry).getEntryKind()) {
case IBuildpathEntry.BPE_CONTAINER:
final IProjectFragment[] findProjectFragments = project.findProjectFragments((IBuildpathEntry) entry);
for (IProjectFragment projectFragment : findProjectFragments) {
// add folders
IModelElement[] children = projectFragment.getChildren();
for (IModelElement element : children) {
if (element instanceof ScriptFolder) {
final IPath relative = ((ScriptFolder) element).getRelativePath();
if (relative.segmentCount() != 0 && isLastSegmantPrefix(lastSegmant, relative)
&& isPathPrefix(prefixPathFolder, relative)) {
reporter.reportResource(element, relative, getSuffix(element), replaceRange);
}
}
}
// add files
final IScriptFolder scriptFolder = projectFragment.getScriptFolder(prefixPathFolder);
children = scriptFolder.getChildren();
for (IModelElement element : children) {
final IPath relative = element.getPath().makeRelativeTo(projectFragment.getPath());
if (isLastSegmantPrefix(lastSegmant, relative)) {
reporter.reportResource(element, relative, getSuffix(element), replaceRange);
}
}
}
break;
case IBuildpathEntry.BPE_PROJECT:
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IProject refProject = (IProject) workspace.getRoot().findMember(((IBuildpathEntry) entry).getPath());
// if(refProject.isAccessible()){
try {
addInternalEntries(reporter, replaceRange, refProject, prefixPathFolder, lastSegmant);
} catch (CoreException e) {
e.printStackTrace();
}
// }
break;
case IBuildpathEntry.BPE_LIBRARY:
final IProjectFragment[] findProjectFragments1 = project.findProjectFragments((IBuildpathEntry) entry);
for (IProjectFragment projectFragment : findProjectFragments1) {
if (projectFragment instanceof ArchiveProjectFragment) {
ArchiveProjectFragment apf = (ArchiveProjectFragment) projectFragment;
IPath path = apf.getPath();
boolean external = false;
if (EnvironmentPathUtils.isFull(path)) {
path = EnvironmentPathUtils.getLocalPath(path);
external = true;
}
IPath pharPath = null;
if (external) {
pharPath = new Path(PharConstants.PHAR_PREFIX + PharConstants.DOUBLE_SPLASH + path.toString());
} else {
pharPath = new Path(PharConstants.PHAR_PREFIX + PharConstants.SPLASH + path.toString());
}
// pharPath = transferToRelativePath(pharPath);
if (prefixPathFolder.segmentCount() == 0) {
// if a phar is not external(in workspace)
// it will not shown in the code assist
// if want to show it remove the if condition below
if (external) {
reporter.reportResource(apf, pharPath, PharConstants.EMPTY_STRING, replaceRange);
}
} else {
if (!PharConstants.PHAR_PREFIX.equals(prefixPathFolder.getDevice())) {
continue;
}
if (external) {
if (!pharPath.isPrefixOf(prefixPathFolder.append(lastSegmant))) {
continue;
}
} else {
PharPath pp = PharPath.getPharPath(prefixPathFolder.append(lastSegmant));
if (pp == null
|| !new Path(pp.getPharName()).lastSegment().equals(pharPath.lastSegment())) {
continue;
} else {
// if the current phar's name equals to the
// phar's name in the
// prefix(equals to
// prefixPathFolder+lastSegmant)
int index = prefixPathFolder.append(lastSegmant).toString()
.indexOf(pharPath.lastSegment());
// adjust pharPath to right path according to
// prefix(equals to
// prefixPathFolder+lastSegmant)
pharPath = new Path(prefixPathFolder.append(lastSegmant).toString().substring(0,
index + pharPath.lastSegment().length()));
}
}
// add folders
IModelElement[] children = projectFragment.getChildren();
for (IModelElement element : children) {
if (element instanceof ArchiveFolder) {
final IPath relative = ((ArchiveFolder) element).getRelativePath();
IPath tempPrefixPathFolder = prefixPathFolder;
boolean isLastSegmantPrefix = isLastSegmantPrefix(lastSegmant, relative);
if (lastSegmant.toString().endsWith(PharConstants.PHAR_EXTENSION_WITH_DOT)) {
isLastSegmantPrefix = true;
tempPrefixPathFolder = prefixPathFolder.append(lastSegmant);
}
IPath fullPath = pharPath.append(relative);
if (relative.segmentCount() != 0
&& !relative.toString().equals(PharConstants.PHAR_EXTENSION_WITH_DOT)
&& isLastSegmantPrefix && isPathPrefix(tempPrefixPathFolder, fullPath)) {
reporter.reportResource(element, fullPath, PharConstants.SPLASH, replaceRange);
}
}
}
IPath tempPrefixPathFolder = prefixPathFolder.append(lastSegmant);
// }
// add files
final IScriptFolder scriptFolder = projectFragment.getScriptFolder(
tempPrefixPathFolder.removeFirstSegments(pharPath.segmentCount()).setDevice(null));
children = scriptFolder.getChildren();
for (IModelElement element : children) {
final IPath relative = tempPrefixPathFolder.append(element.getElementName());
reporter.reportResource(element, relative, getSuffix(element), replaceRange);
}
}
}
}
break;
default:
}
}
private void addInternalEntries(ICompletionReporter reporter, ISourceRange replaceRange, Object entry,
IPath prefixPathFolder, IPath lastSegmant) throws CoreException {
IContainer container = (IContainer) entry;
if (prefixPathFolder.segmentCount() > 0) {
for (IContainer con : getContainers(container)) {
container = con.getFolder(prefixPathFolder);
if (container.isAccessible()) {
entry = con;
break;
}
}
}
if (!container.isAccessible()) {
return;
}
ICompletionContext context = getContext();
if (container instanceof IProject) {
for (IContainer con : getContainers(container)) {
findResource(reporter, replaceRange, con, lastSegmant, context, con);
}
} else {
findResource(reporter, replaceRange, entry, lastSegmant, context, container);
}
}
private IContainer[] getContainers(IContainer container) throws ModelException {
if (container instanceof IProject) {
IScriptProject project = DLTKCore.create((IProject) container);
IProjectFragment[] fragments = project.getProjectFragments();
List<IContainer> containers = new ArrayList<IContainer>();
for (IProjectFragment fragment : fragments) {
if (fragment.getResource() instanceof IFolder || fragment.getResource() instanceof IProject) {
containers.add((IContainer) fragment.getResource());
}
}
return containers.toArray(new IContainer[containers.size()]);
}
return new IContainer[] { container };
}
private void findResource(ICompletionReporter reporter, ISourceRange replaceRange, final Object entry,
IPath lastSegmant, ICompletionContext context, IContainer container) throws CoreException {
IResource[] members = container.members();
for (IResource resource : members) {
final IPath relative = resource.getFullPath().makeRelativeTo(container.getFullPath());
if (isLastSegmantPrefix(lastSegmant, relative)) {
final IPath rel = resource.getFullPath().makeRelativeTo(((IContainer) entry).getFullPath());
final IModelElement modelElement = DLTKCore.create(resource);
if (modelElement == null) {
continue;
}
if (resource.getType() == IResource.FILE) {
if (PHPToolkitUtil.isPHPFile((IFile) resource)
&& !modelElement.equals(((IncludeStatementContext) context).getSourceModule())) {
reporter.reportResource(modelElement, rel, getSuffix(modelElement), replaceRange);
}
} else {
if (resource.getName().charAt(0) != '.') { // filter dot
// resources
reporter.reportResource(modelElement, rel, getSuffix(modelElement), replaceRange);
}
}
}
}
}
private boolean isPathPrefix(IPath prefixPath, IPath path) {
if (prefixPath.segmentCount() != path.segmentCount() - 1) {
return false;
}
return prefixPath.isPrefixOf(path);
}
private boolean isLastSegmantPrefix(IPath prefixPath, IPath relative) {
String lastCurrentSegment = relative.lastSegment();
String lastPrefixSegment = prefixPath.lastSegment();
if (lastCurrentSegment == null) {
lastCurrentSegment = ""; //$NON-NLS-1$
}
if (lastPrefixSegment == null) {
lastPrefixSegment = ""; //$NON-NLS-1$
}
if (StringUtils.startsWithIgnoreCase(lastCurrentSegment, lastPrefixSegment)) {
return true;
}
return false;
}
public String getSuffix(IModelElement modelElement) {
return modelElement.getElementType() == IModelElement.SOURCE_MODULE ? "" : FOLDER_SEPARATOR; //$NON-NLS-1$
}
}