/**
* 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.
*/
package org.rubypeople.rdt.refactoring.classnodeprovider;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import org.jruby.ast.ClassNode;
import org.jruby.ast.ModuleNode;
import org.jruby.ast.Node;
import org.jruby.ast.SClassNode;
import org.jruby.lexer.yacc.ISourcePosition;
import org.rubypeople.rdt.refactoring.core.NodeProvider;
import org.rubypeople.rdt.refactoring.documentprovider.IDocumentProvider;
import org.rubypeople.rdt.refactoring.exception.NoClassNodeException;
import org.rubypeople.rdt.refactoring.nodewrapper.ClassNodeWrapper;
import org.rubypeople.rdt.refactoring.nodewrapper.MethodNodeWrapper;
import org.rubypeople.rdt.refactoring.nodewrapper.PartialClassNodeWrapper;
public class ClassNodeProvider {
private Map<String, ClassNodeWrapper> classNodeWrappers;
protected IDocumentProvider documentProvider;
public ClassNodeProvider(IDocumentProvider docProvider) {
this(docProvider, true);
}
public ClassNodeProvider(IDocumentProvider docProvider, boolean addActiveFile) {
classNodeWrappers = new LinkedHashMap<String, ClassNodeWrapper>();
this.documentProvider = docProvider;
if(addActiveFile) {
addSource(docProvider.getActiveFileName());
}
}
public void addSource(String sourceName) {
Node rootNode = documentProvider.getRootNode(sourceName);
createClassNodes(rootNode);
}
private void createClassNodes(Node rootNode) {
if (rootNode == null) {
return;
}
Collection<Node> classNodes = NodeProvider.getSubNodes(rootNode, ClassNode.class);
Collection<Node> moduleNodes = NodeProvider.getSubNodes(rootNode, ModuleNode.class);
classNodes.addAll(NodeProvider.getSubNodes(rootNode, SClassNode.class));
for (Node node : classNodes) {
try {
PartialClassNodeWrapper partialClassNode = PartialClassNodeWrapper.getPartialClassNodeWrapper(node, rootNode);
addEnclosingModules(partialClassNode, moduleNodes);
addPartialClassNode(partialClassNode, classNodeWrappers);
} catch (NoClassNodeException e) {
e.printStackTrace();
}
}
}
private void addEnclosingModules(PartialClassNodeWrapper partialClassNode, Collection<Node> moduleNodes) {
ISourcePosition nodePosition = partialClassNode.getWrappedNode().getPosition();
ArrayList<ModuleNode> enclosingModules = new ArrayList<ModuleNode>();
for (Node currentModule : moduleNodes) {
ISourcePosition modulePosition = currentModule.getPosition();
if (modulePosition.getStartOffset() < nodePosition.getStartOffset() && modulePosition.getEndOffset() > nodePosition.getEndOffset()) {
enclosingModules.add((ModuleNode) currentModule);
}
}
partialClassNode.setEnclosingModules(enclosingModules);
}
private void addPartialClassNode(PartialClassNodeWrapper partialClassNode, Map<String, ClassNodeWrapper> classes) {
String className = partialClassNode.getClassName();
if (classes.containsKey(className)) {
ClassNodeWrapper classNode = classes.get(className);
classNode.addPartialClassNode(partialClassNode);
} else {
ClassNodeWrapper classNode = new ClassNodeWrapper(partialClassNode);
classes.put(className, classNode);
}
}
public void addClassNodeProvider(ClassNodeProvider provider) {
if (provider != null) {
for (ClassNodeWrapper classNode : provider.getAllClassNodes()) {
if (!hasClassNode(classNode.getName())) {
classNodeWrappers.put(classNode.getName(), classNode);
}
}
}
}
public Collection<ClassNodeWrapper> getAllClassNodes() {
return classNodeWrappers.values();
}
public ClassNodeWrapper getClassNode(String className) {
return classNodeWrappers.containsKey(className) ? classNodeWrappers.get(className) : null;
}
public boolean hasClassNode(String className) {
return classNodeWrappers.containsKey(className);
}
public Collection<ClassNodeWrapper> getSubClassesOf(String className) {
Collection<ClassNodeWrapper> childs = new ArrayList<ClassNodeWrapper>();
for (ClassNodeWrapper classNode : getAllClassNodes()) {
if (classNode.getSuperClassName() != null && classNode.getSuperClassName().equals(className))
childs.add(classNode);
}
return childs;
}
public Collection<MethodNodeWrapper> getAllMethodsFor(String className) {
Collection<MethodNodeWrapper> methodNodes = new ArrayList<MethodNodeWrapper>();
for (ClassNodeWrapper classNode : getClassAndAllSuperClassesFor(className)) {
methodNodes.addAll(classNode.getMethods());
}
return methodNodes;
}
public Collection<ClassNodeWrapper> getClassAndAllSuperClassesFor(String className) {
return getClassAndAllSuperClasses(getClassNode(className));
}
public Collection<ClassNodeWrapper> getClassAndAllSuperClasses(ClassNodeWrapper classNode) {
ArrayList<ClassNodeWrapper> classNodes = new ArrayList<ClassNodeWrapper>();
do {
if (classNode != null) {
classNodes.add(classNode);
}
} while (classNode != null && (classNode = getClassNode(classNode.getSuperClassName())) != null);
return classNodes;
}
public Collection<ClassNodeWrapper> getClassAndAllSubClasses(ClassNodeWrapper classNode) {
Collection<ClassNodeWrapper> classes = new ArrayList<ClassNodeWrapper>();
if (classNode == null) {
return classes;
}
classes.add(classNode);
for (ClassNodeWrapper aktClassNode : getAllClassNodes()) {
if (classNode.getName().equals(aktClassNode.getSuperClassName())) {
classes.addAll(getClassAndAllSubClasses(aktClassNode));
}
}
return classes;
}
public ClassNodeWrapper getSuperClassOf(String className) {
for (ClassNodeWrapper classNode : getAllClassNodes()) {
if (classNode.getName() != null && classNode.getName().equals(className))
return classNode;
}
return null;
}
}