/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package ca.weblite.netbeans.mirah;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.netbeans.api.java.classpath.ClassPath;
import org.openide.filesystems.FileObject;
/**
*
* @author shannah
*/
public class ClassIndex {
public abstract static class Query implements Comparable<Query> {
private int priority;
private String simpleName;
private String prefix = "";
private static int nextId = 0;
private int id;
protected Query(int priority, String simpleName, String prefix){
this.priority = priority;
this.simpleName = simpleName;
this.prefix = prefix;
id = nextId++;
}
@Override
public int compareTo(Query o) {
if ( priority < o.priority ){
return -1;
} else if ( priority > o.priority ){
return 1;
} else if ( id < o.id ){
return -1;
} else if ( id > o.id ){
return 1;
} else {
return 0;
}
}
public abstract FileObject[] getRoots();
}
public static class ClassPathQuery extends Query {
ClassPath classPath;
public ClassPathQuery(int priority, String simpleName, String prefix, ClassPath classPath){
super(priority, simpleName, prefix);
this.classPath = classPath;
}
@Override
public FileObject[] getRoots() {
return classPath.getRoots();
}
}
public static class FileObjectQuery extends Query {
FileObject root;
public FileObjectQuery(int priority, String simpleName, String prefix, FileObject root){
super(priority, simpleName, prefix);
this.root = root;
}
@Override
public FileObject[] getRoots() {
return new FileObject[]{root};
}
}
public static class CompoundQuery extends Query {
SortedSet<Query> queries = new TreeSet<Query>();
public CompoundQuery(int priority){
super(priority, "*", "");
}
public void addQuery(Query query){
queries.add(query);
}
@Override
public FileObject[] getRoots() {
List<FileObject> roots = new ArrayList<FileObject>();
for ( Query q : queries ){
for ( FileObject root : q.getRoots() ){
roots.add(root);
}
}
return roots.toArray(new FileObject[0]);
}
}
public abstract static class Future {
List<String> matches = new ArrayList<String>();
Set<String> matchSet = new HashSet<String>();
protected abstract void resultsAdded();
public List<String> getMatches(){
return matches;
}
public void addMatch(String match){
if ( matchSet.contains(match)){
//System.out.println("Matchset already contains "+match);
return;
}
//System.out.println("Adding match "+match);
matchSet.add(match);
//System.out.println(matchSet);
while ( match.indexOf(".")==0 ){
match = match.substring(1);
}
matches.add(match);
resultsAdded();
}
}
public void findClass(CompoundQuery query, Future results){
for ( Query q : query.queries ){
findClass(q, results);
}
}
public void findClass(Query query, Future results){
for ( FileObject root : query.getRoots() ){
int numBefore = results.getMatches().size();
findClass(root, results.getMatches(), query.simpleName, query.prefix);
int numAfter = results.getMatches().size();
if ( numBefore != numAfter ){
results.resultsAdded();
}
}
}
private static void findClass(FileObject root, List<String> matches, final String simpleName){
findClass(root, matches, simpleName, "");
}
private static void findClass(FileObject root, List<String> matches, final String simpleName, final String prefix) {
FileObject start = root;
String[] prefixSegments = prefix.split("/");
for ( String seg : prefixSegments ){
if ( start.getFileObject(seg) != null ){
start = start.getFileObject(seg);
}
}
Object cmp = new Object(){
@Override
public boolean equals(Object obj) {
if ( obj instanceof FileObject ){
FileObject fo = (FileObject)obj;
String name = fo.getName();
//if ( name.contains("JMenu")){
// System.err.println("Name "+name+" simple name "+simpleName+" fo "+fo+" ext "+fo.getExt());
//}
return ("class".equals(fo.getExt()) && (simpleName.equals(name) || name.endsWith("$"+simpleName)));
}
return false;
}
};
List<FileObject> foMatches = new ArrayList<FileObject>();
find(start, foMatches, cmp);
for ( FileObject fo : foMatches ){
String fqn = getFQN(root, fo);
matches.add(fqn);
}
}
private static void findClass(ClassPath cp, List<String> matches, final String simpleName){
for ( FileObject root : cp.getRoots()){
findClass(root, matches, simpleName);
}
}
private static void findClass(ClassPath[] classPaths, List<String> matches, String simpleName){
for ( ClassPath cp : classPaths ){
findClass(cp, matches, simpleName);
}
}
private static String getFQN(FileObject root, FileObject fo){
if ( !fo.getPath().startsWith(root.getPath())){
throw new IllegalArgumentException("The root must be an ancestor of the file object in question.");
} else {
String path = fo.getPath();
path = path.substring(root.getPath().length(), path.lastIndexOf("."));
if ( path.indexOf(".")==0){
path = path.substring(1);
}
return path.replace("/", ".").replace("$", ".");
}
}
private static void find(FileObject root, List<FileObject> results, Object cmp){
//System.err.println("File Root "+root);
if ( cmp.equals(root)){
results.add(root);
}
for ( FileObject child : root.getChildren()){
//System.err.println("CHILD "+child+" of PARENT "+root);
find(child, results, cmp);
}
}
}