package org.activityinfo.ui.client.component.form.field.hierarchy;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.activityinfo.core.client.ResourceLocator;
import org.activityinfo.model.form.FormClass;
import org.activityinfo.model.resource.ResourceId;
import org.activityinfo.model.type.ReferenceType;
import org.activityinfo.promise.Promise;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Map;
/**
* Models a hierarchy of choices for the user
*/
public class Hierarchy {
private Map<ResourceId, Level> levelMap = Maps.newHashMap();
private List<Level> roots = Lists.newArrayList();
private List<Level> levels = Lists.newArrayList();
public static Promise<Hierarchy> get(final ResourceLocator resourceLocator, ReferenceType type) {
return Promise.map(type.getRange(), new Function<ResourceId, Promise<FormClass>>() {
@Override
public Promise<FormClass> apply(@Nullable ResourceId input) {
return resourceLocator.getFormClass(input);
}
}).then(new Function<List<FormClass>, Hierarchy>() {
@Nullable
@Override
public Hierarchy apply(@Nullable List<FormClass> input) {
return new Hierarchy(input);
}
});
}
public Hierarchy(List<FormClass> rangeFormClasses) {
// Find all of the form class here
for(FormClass formClass : rangeFormClasses) {
if(!levelMap.containsKey(formClass.getId())) {
levelMap.put(formClass.getId(), new Level(formClass));
}
}
// Assign parents...
for(Level level : levelMap.values()) {
if(!level.isRoot()) {
level.parent = levelMap.get(level.parentId);
level.parent.children.add(level);
}
}
// find roots
for(Level level : levelMap.values()) {
if(level.isRoot()) {
roots.add(level);
}
}
// breadth first search to establish presentation order
establishPresentationOrder(roots);
}
public List<Level> getRoots() {
return roots;
}
/**
* @return the Level associated with the given {@code formClassId}
*/
public Level getLevel(ResourceId formClassId) {
return levelMap.get(formClassId);
}
private void establishPresentationOrder(List<Level> parents) {
for(Level child : parents) {
this.levels.add(child);
establishPresentationOrder(child.children);
}
}
/**
*
* @return a list of levels in this tree, in topologically sorted order
*/
public List<Level> getLevels() {
return levels;
}
public boolean hasLevel(ResourceId classId) {
return levelMap.containsKey(classId);
}
}