package immibis.bon.cui;
import java.io.File;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.util.List;
public abstract class CUIBase {
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME)
public static @interface Option {
String value();
}
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME)
public static @interface Required {
}
protected abstract void showUsage() throws Exception;
protected abstract void run() throws Exception;
private Field getOptionField(String name) {
for(Field f : getClass().getFields()) {
Option o = f.getAnnotation(Option.class);
if(o != null && o.value().equals(name))
return f;
}
return null;
}
@SuppressWarnings("unchecked")
private boolean parseOptions(String[] args) throws Exception {
if((args.length % 2) == 1) {
System.err.println("Expected an even number of arguments.");
return false;
}
boolean ok = true;
for(int k = 0; k < args.length; k += 2) {
String opt = args[k];
String val = args[k + 1];
Field f = getOptionField(opt);
if(f == null) {
System.err.println("Unknown option: " + opt);
ok = false;
continue;
}
if(Enum.class.isAssignableFrom(f.getType())) {
try {
f.set(this, Enum.valueOf(f.getType().asSubclass(Enum.class), val));
} catch(EnumConstantNotPresentException e) {
System.err.println("Invalid option for "+opt+": "+val);
System.err.println("Valid values: " + f.getType().getEnumConstants());
ok = false;
continue;
}
} else if(f.getType() == String.class) {
if(f.get(this) != null) {
System.err.println("Option specified more than once: " + opt);
ok = false;
} else
f.set(this, val);
} else if(f.getType() == File.class) {
if(f.get(this) != null) {
System.err.println("Option specified more than once: " + opt);
ok = false;
} else
f.set(this, new File(val));
} else if(f.getType() == List.class) {
((List<String>)f.get(this)).add(val);
} else {
System.err.println("BUG: Invalid option type "+f.getType().getName()+" for option field "+f.getName()+" for option "+opt);
ok = false;
}
}
return ok;
}
protected boolean checkOptions() throws Exception {
boolean ok = true;
for(Field f : getClass().getFields()) {
if(f.isAnnotationPresent(Required.class) && f.get(this) == null) {
System.err.println("Required option "+f.getAnnotation(Option.class).value()+" not present.");
ok = false;
}
}
return ok;
}
protected void run(String[] args) throws Exception {
if(args.length == 0)
showUsage();
else if(parseOptions(args) && checkOptions())
run();
}
}