package jfun.yan.xml.nuts.optional;
import java.util.ArrayList;
import java.util.HashMap;
import jfun.util.Misc;
import jfun.yan.Binder;
import jfun.yan.Creator;
import jfun.yan.xml.nut.BinderNut;
/**
* This Nut class creates a typecase tag that evaluates to a
* {@link jfun.yan.Binder} object.
* <p>
* Upon receiving a component instance, it checks the type of
* the instance and runs the proper Binder object defined in
* the corresponding case that matches the type.
* </p>
* <p>
* @author Ben Yu
* Nov 10, 2005 12:14:46 AM
*/
public class TypeCaseNut extends BinderNut {
private final ArrayList cases = new ArrayList();
private Binder def;
private final HashMap casemap = new HashMap();
public void addCase(BinderCase cs){
final Class type = cs.getType();
if(casemap.containsKey(type)){
raise("duplicate case: "+Misc.getTypeName(type));
}
casemap.put(type, cs);
cases.add(cs);
}
public void addDefault(BinderDefault def){
checkDuplicate("default", this.def);
this.def = def.getBinder();
}
public Binder eval(){
if(cases.isEmpty() && def==null){
throw raise("empty " + getTagName());
}
return new Binder(){
public Creator bind(Object v)
throws Throwable{
final int sz = cases.size();
for(int i=0; i<sz; i++){
final BinderCase bc = (BinderCase)cases.get(i);
if(bc.getType().isInstance(v)){
return bc.getBinder().bind(v);
}
}
if(def!=null)
return def.bind(v);
else
throw raise("unmatched type case for "
+ Misc.getTypeName(getType(v)));
}
public String toString(){
return "typecase";
}
};
}
private static final Class getType(Object v){
return v==null?null:v.getClass();
}
}