/**
* Copyright (c) 2008 Aptana, Inc.
*
* 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. If redistributing this code,
* this entire header must remain intact.
*
* This file is based on a JDT equivalent:
********************************************************************************
* Copyright (c) 2000, 2006 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
* Matt Chapman, mpchapman@gmail.com - 89977 Make JDT .java agnostic
*******************************************************************************/
package org.rubypeople.rdt.internal.ui.wizards;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceProxy;
import org.eclipse.core.resources.IResourceProxyVisitor;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.rubypeople.rdt.core.ILoadpathEntry;
import org.rubypeople.rdt.core.IRubyScript;
import org.rubypeople.rdt.core.RubyConventions;
import org.rubypeople.rdt.core.RubyCore;
import org.rubypeople.rdt.core.RubyModelException;
import org.rubypeople.rdt.ui.PreferenceConstants;
/**
*/
public class LoadPathDetector implements IResourceProxyVisitor {
private HashMap fSourceFolders;
private IProject fProject;
private ILoadpathEntry[] fResultLoadpath;
private IProgressMonitor fMonitor;
private static class LPSorter implements Comparator {
private Collator fCollator= Collator.getInstance();
public int compare(Object o1, Object o2) {
ILoadpathEntry e1= (ILoadpathEntry) o1;
ILoadpathEntry e2= (ILoadpathEntry) o2;
return fCollator.compare(e1.getPath().toString(), e2.getPath().toString());
}
}
public LoadPathDetector(IProject project, IProgressMonitor monitor) throws CoreException {
fSourceFolders= new HashMap();
fProject= project;
fResultLoadpath= null;
if (monitor == null) {
monitor = new NullProgressMonitor();
}
detectLoadpath(monitor);
}
/**
* Method detectLoadpath.
* @param monitor The progress monitor (not null)
* @throws CoreException
*/
private void detectLoadpath(IProgressMonitor monitor) throws CoreException {
try {
monitor.beginTask(NewWizardMessages.LoadPathDetector_operation_description, 2);
fMonitor= monitor;
fProject.accept(this, IResource.NONE);
monitor.worked(1);
ArrayList cpEntries= new ArrayList();
detectSourceFolders(cpEntries);
if (monitor.isCanceled()) {
throw new OperationCanceledException();
}
monitor.worked(1);
if (cpEntries.isEmpty()) {
return;
}
ILoadpathEntry[] jreEntries= PreferenceConstants.getDefaultRubyVMLibrary();
for (int i= 0; i < jreEntries.length; i++) {
cpEntries.add(jreEntries[i]);
}
ILoadpathEntry[] entries= (ILoadpathEntry[]) cpEntries.toArray(new ILoadpathEntry[cpEntries.size()]);
if (!RubyConventions.validateLoadpath(RubyCore.create(fProject), entries, null).isOK()) {
return;
}
fResultLoadpath= entries;
} finally {
monitor.done();
}
}
private void detectSourceFolders(ArrayList resEntries) {
ArrayList res= new ArrayList();
Set sourceFolderSet= fSourceFolders.keySet();
for (Iterator iter= sourceFolderSet.iterator(); iter.hasNext();) {
IPath path= (IPath) iter.next();
ArrayList excluded= new ArrayList();
for (Iterator inner= sourceFolderSet.iterator(); inner.hasNext();) {
IPath other= (IPath) inner.next();
if (!path.equals(other) && path.isPrefixOf(other)) {
IPath pathToExclude= other.removeFirstSegments(path.segmentCount()).addTrailingSeparator();
excluded.add(pathToExclude);
}
}
IPath[] excludedPaths= (IPath[]) excluded.toArray(new IPath[excluded.size()]);
ILoadpathEntry entry= RubyCore.newSourceEntry(path, excludedPaths);
res.add(entry);
}
Collections.sort(res, new LPSorter());
resEntries.addAll(res);
}
private void visitRubyScript(IFile file) {
IRubyScript cu= RubyCore.createRubyScriptFrom(file);
if (cu != null) {
IRubyScript workingCopy= null;
try {
workingCopy= cu.getWorkingCopy(null);
IPath packPath= file.getParent().getFullPath();
String cuName= file.getName();
addToMap(fSourceFolders, packPath, new Path(cuName));
} catch (RubyModelException e) {
// ignore
} finally {
if (workingCopy != null) {
try {
workingCopy.discardWorkingCopy();
} catch (RubyModelException ignore) {
}
}
}
}
}
private void addToMap(HashMap map, IPath folderPath, IPath relPath) {
List list= (List) map.get(folderPath);
if (list == null) {
list= new ArrayList(50);
map.put(folderPath, list);
}
list.add(relPath);
}
private boolean isValidScriptName(String name) {
return !RubyConventions.validateRubyScriptName(name).matches(IStatus.ERROR);
}
/* (non-Javadoc)
* @see org.eclipse.core.resources.IResourceProxyVisitor#visit(org.eclipse.core.resources.IResourceProxy)
*/
public boolean visit(IResourceProxy proxy) {
if (fMonitor.isCanceled()) {
throw new OperationCanceledException();
}
if (proxy.getType() == IResource.FILE) {
String name= proxy.getName();
if (isValidScriptName(name)) {
visitRubyScript((IFile) proxy.requestResource());
}
return false;
}
return true;
}
public ILoadpathEntry[] getLoadpath() {
return fResultLoadpath;
}
}