package com.redhat.ceylon.eclipse.core.builder;
import static com.redhat.ceylon.eclipse.core.builder.CeylonBuilder.isCompilable;
import static com.redhat.ceylon.eclipse.java2ceylon.Java2CeylonProxies.vfsJ2C;
import static com.redhat.ceylon.model.typechecker.model.ModelUtil.formatPath;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.List;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.SubMonitor;
import com.redhat.ceylon.compiler.typechecker.TypeChecker;
import com.redhat.ceylon.compiler.typechecker.context.PhasedUnit;
import com.redhat.ceylon.compiler.typechecker.context.PhasedUnits;
import com.redhat.ceylon.eclipse.core.builder.CeylonBuilder.RootFolderType;
import com.redhat.ceylon.ide.common.model.BaseIdeModelLoader;
import com.redhat.ceylon.ide.common.model.IdeModuleManager;
import com.redhat.ceylon.ide.common.model.IdeModuleSourceMapper;
import com.redhat.ceylon.ide.common.vfs.FileVirtualFile;
import com.redhat.ceylon.ide.common.vfs.FolderVirtualFile;
import com.redhat.ceylon.model.typechecker.model.Module;
import com.redhat.ceylon.model.typechecker.model.Package;
final class RootFolderScanner implements IResourceVisitor {
private final Module defaultModule;
private final BaseIdeModelLoader modelLoader;
private final IdeModuleManager<IProject,IResource,IFolder,IFile> moduleManager;
private final IdeModuleSourceMapper<IProject,IResource,IFolder,IFile> moduleSourceMapper;
private final FolderVirtualFile<IProject, IResource, IFolder, IFile> rootDir;
private final TypeChecker typeChecker;
private final List<IFile> scannedFiles;
private final PhasedUnits phasedUnits;
private Module module;
private SubMonitor monitor;
private boolean isInResourceForlder = false;
private boolean isInSourceForlder = false;
private RootFolderType rootFolderType;
RootFolderScanner(RootFolderType rootFolderType, Module defaultModule, BaseIdeModelLoader modelLoader,
IdeModuleManager<IProject,IResource,IFolder,IFile> moduleManager,
IdeModuleSourceMapper<IProject,IResource,IFolder,IFile> moduleSourceMapper,
FolderVirtualFile<IProject, IResource, IFolder, IFile> rootDir, TypeChecker typeChecker,
List<IFile> scannedFiles, PhasedUnits phasedUnits, SubMonitor monitor) {
this.rootFolderType = rootFolderType;
this.isInResourceForlder = rootFolderType.equals(RootFolderType.RESOURCE);
this.isInSourceForlder = rootFolderType.equals(RootFolderType.SOURCE);
this.defaultModule = defaultModule;
this.modelLoader = modelLoader;
this.moduleManager = moduleManager;
this.moduleSourceMapper = moduleSourceMapper;
this.rootDir = rootDir;
this.typeChecker = typeChecker;
this.scannedFiles = scannedFiles;
this.phasedUnits = phasedUnits;
this.monitor = monitor;
}
public boolean visit(IResource resource) throws CoreException {
Package pkg;
monitor.setWorkRemaining(10000);
monitor.worked(1);
if (resource.equals(rootDir.getNativeResource())) {
resource.setSessionProperty(CeylonBuilder.RESOURCE_PROPERTY_PACKAGE_MODEL, new WeakReference<Package>(modelLoader.findPackage("")));
resource.setSessionProperty(CeylonBuilder.RESOURCE_PROPERTY_ROOT_FOLDER, rootDir.getNativeResource());
resource.setSessionProperty(CeylonBuilder.RESOURCE_PROPERTY_ROOT_FOLDER_TYPE, rootFolderType);
return true;
}
if (resource.getParent().equals(rootDir.getNativeResource())) {
// We've come back to a source directory child :
// => reset the current Module to default and set the package to emptyPackage
module = defaultModule;
pkg = modelLoader.findPackage("");
assert(pkg != null);
}
String pkgNameAsString;
IFolder pkgFolder;
if (resource instanceof IFolder) {
pkgFolder = (IFolder) resource;
} else {
pkgFolder = (IFolder) resource.getParent();
}
List<String> pkgName = getPackageName(pkgFolder);
pkgNameAsString = formatPath(pkgName);
if ( module != defaultModule ) {
if (! pkgNameAsString.startsWith(module.getNameAsString() + ".")) {
// We've ran above the last module => reset module to default
module = defaultModule;
}
}
Module realModule = modelLoader.getLoadedModule(pkgNameAsString, null);
if (realModule != null) {
// The module descriptor had probably been found in another source directory
module = realModule;
}
pkg = modelLoader.findOrCreatePackage(module, pkgNameAsString);
if (resource instanceof IFolder) {
resource.setSessionProperty(CeylonBuilder.RESOURCE_PROPERTY_PACKAGE_MODEL, new WeakReference<Package>(pkg));
resource.setSessionProperty(CeylonBuilder.RESOURCE_PROPERTY_ROOT_FOLDER, rootDir.getNativeResource());
return true;
}
if (resource instanceof IFile) {
IFile file = (IFile) resource;
if (file.exists()) {
boolean isSourceFile = isInSourceForlder && isCompilable(file);
if (isInResourceForlder || isSourceFile ) {
if (scannedFiles != null) {
scannedFiles.add((IFile)resource);
}
if (isSourceFile) {
if (CeylonBuilder.isCeylon(file)) {
FileVirtualFile<IProject, IResource, IFolder, IFile> virtualFile = vfsJ2C().createVirtualFile(file, moduleManager.getCeylonProject());
try {
PhasedUnit newPhasedUnit = CeylonBuilder.parseFileToPhasedUnit(moduleManager, moduleSourceMapper,
typeChecker, virtualFile, rootDir, pkg);
phasedUnits.addPhasedUnit(virtualFile, newPhasedUnit);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
return false;
}
private List<String> getPackageName(IContainer container) {
List<String> pkgName = Arrays.asList(container.getProjectRelativePath()
.makeRelativeTo(rootDir.getNativeResource().getProjectRelativePath()).segments());
return pkgName;
}
}