/**
* (c) 2011, Alejandro Serrano
* Released under the terms of the EPL.
*/
package net.sf.eclipsefp.haskell.browser.items;
import java.util.ArrayList;
/**
* Represents a declaration and all the possible packages
* and modules where it can be found.
*
* @author Alejandro Serrano
*/
public class QueryItem {
Declaration declaration;
ArrayList<PackageIdentifier> packages;
ArrayList<QueryItem> innerItems;
public QueryItem(Declaration declaration) {
this.declaration = declaration;
this.packages = new ArrayList<>();
this.innerItems = new ArrayList<>();
}
public QueryItem(Packaged<Declaration> pDecl) {
this(pDecl.getElement());
this.addPackage(pDecl.getPackage());
}
public Declaration getDeclaration() {
return this.declaration;
}
public DeclarationType getType() {
return this.declaration.getType();
}
public String getName() {
return this.declaration.getName();
}
public boolean isSimilarTo(Declaration otherDecl) {
if (this.declaration.getType() == otherDecl.getType()) {
if (this.declaration.type == DeclarationType.INSTANCE)
return this.declaration.getCompleteDefinition().equals(otherDecl.getCompleteDefinition());
else
return this.declaration.getName().equals(otherDecl.getName());
} else {
return false;
}
}
public ArrayList<PackageIdentifier> getPackages() {
return this.packages;
}
public void addPackage(PackageIdentifier pkg) {
this.packages.add(pkg);
}
public ArrayList<QueryItem> getInnerItems() {
return this.innerItems;
}
public void addInnerItem(QueryItem item) {
this.innerItems.add(item);
}
public static ArrayList<QueryItem> convertToQueryItem(Packaged<Declaration>[] decls) {
// Remove duplication of items
ArrayList<QueryItem> items = new ArrayList<>();
removeDuplicateQueryItems(decls, items);
// Separate instances, classes, gadts and other things
ArrayList<QueryItem> instances = new ArrayList<>();
ArrayList<QueryItem> classes = new ArrayList<>();
ArrayList<QueryItem> gadts = new ArrayList<>();
ArrayList<QueryItem> allOthers = new ArrayList<>();
for (QueryItem item : items) {
switch(item.getType()) {
case INSTANCE:
instances.add(item);
break;
case TYPE_CLASS:
classes.add(item);
break;
case DATA_TYPE:
case NEW_TYPE:
case TYPE_SYNONYM:
gadts.add(item);
break;
default:
allOthers.add(item);
break;
}
}
// Add instances to the corresponding item
ArrayList<QueryItem> noItemInstances = new ArrayList<>();
for (QueryItem item : instances) {
boolean added = false;
// Try to add to typeclasses
Instance inst = (Instance)item.getDeclaration();
for (QueryItem tclass : classes) {
if (tclass.getName().equals(inst.getName())) {
tclass.addInnerItem(item);
added = true;
// We should only find a typeclass this way
break;
}
}
// Try to add to types
for (QueryItem gadt : gadts) {
String gadtName = gadt.getName();
// The type must be in one of the variables part
for (String tvar : inst.getTypeVariables()) {
// Split in tokens and compare
String[] tvarElts = tvar.replace('(', ' ').replace(')', ' ').split("\\s");
for (String tvarElt : tvarElts) {
if (tvarElt.equals(gadtName)) {
gadt.addInnerItem(item);
added = true;
}
}
}
}
// For instances that went nowhere
if (!added)
noItemInstances.add(item);
}
// Add the rest of elements for returning
noItemInstances.addAll(classes);
noItemInstances.addAll(gadts);
noItemInstances.addAll(allOthers);
return noItemInstances;
}
private static void removeDuplicateQueryItems(Packaged<Declaration>[] decls, ArrayList<QueryItem> items) {
for (Packaged<Declaration> decl : decls) {
QueryItem similar = null;
for (QueryItem item : items) {
if (item.isSimilarTo(decl.getElement())) {
similar = item;
break;
}
}
if (similar == null) {
// New item to add
QueryItem newItem = new QueryItem(decl);
items.add(newItem);
} else {
similar.addPackage(decl.getPackage());
}
}
}
}