package org.activityinfo.model.expr.eval;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import org.activityinfo.model.expr.SymbolExpr;
import org.activityinfo.model.expr.diagnostic.AmbiguousSymbolException;
import org.activityinfo.model.expr.diagnostic.SymbolNotFoundException;
import org.activityinfo.model.form.FormClass;
import org.activityinfo.model.form.FormField;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* Maps symbol names to fields in a FormClass
*/
public class FormSymbolTable {
private Map<String, FormField> idMap = Maps.newHashMap();
private Multimap<String, FormField> codeMap = HashMultimap.create();
private Multimap<String, FormField> labelMap = HashMultimap.create();
public FormSymbolTable(FormClass formClass) {
for (FormField field : formClass.getFields()) {
// ID has first priority
FormField prevValue = idMap.put(field.getId().asString(), field);
assert prevValue == null : "Duplicated id [" + field.getId() + "] in FormClass " + formClass.getId();
// Then we try codes
if(field.hasCode()) {
codeMap.put(field.getCode().toLowerCase(), field);
}
// And finally labels, if they're unique
labelMap.put(field.getLabel().toLowerCase(), field);
}
}
public FormSymbolTable(List<FormField> fields) {
for (FormField field : fields) {
// ID has first priority
idMap.put(field.getId().asString(), field);
// Then we try codes
if(field.hasCode()) {
codeMap.put(field.getCode().toLowerCase(), field);
}
// And finally labels, if they're unique
labelMap.put(field.getLabel().toLowerCase(), field);
}
}
public FormField resolveFieldById(String id) {
FormField field = idMap.get(id);
if(field == null) {
throw new IllegalArgumentException(id);
}
return field;
}
public FormField resolveSymbol(SymbolExpr symbolExpr) {
return resolveSymbol(symbolExpr.getName());
}
public FormField resolveSymbol(String name) {
FormField field = idMap.get(name);
if(field != null) {
return field;
}
Collection<FormField> matching = codeMap.get(name.toLowerCase());
if(matching.isEmpty()) {
// as last resort, try matching against label
matching = labelMap.get(name.toLowerCase());
}
if (matching.size() > 1) {
throw new AmbiguousSymbolException(name);
} else if (matching.isEmpty()) {
throw new SymbolNotFoundException(name);
}
return Iterables.getOnlyElement(matching);
}
}