package miage.shell.command;
import miage.shell.command.option.OptionArgumentRequiredException;
import java.io.PrintStream;
import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import miage.shell.Command;
import miage.shell.Option;
import miage.shell.command.option.BaseOption;
import miage.shell.command.option.OptionException;
import miage.shell.command.option.UnknowOptionException;
/**
*
* @author Schwartz Michaƫl <m.schwartz@epokmedia.fr>
*/
public abstract class AbstractCommand implements Command {
protected Map<String, Option> options = new HashMap<String, Option>();
protected Map<String, Option> optionsByName = new HashMap<String, Option>();
protected Map<Option, String> values;
protected Deque<String> dataArguments;
@Override
public final void execute(List<String> args, PrintStream out, PrintStream err) throws Exception {
dataArguments = new LinkedList<String>();
values = new LinkedHashMap<Option, String>();
try {
this.parse(args.toArray(new String[args.size()]));
this.execute(out, err);
} catch (OptionException ex) {
err.println(ex.getMessage());
}
}
/**
*
* @param options
* @param out
* @param err
*/
protected abstract void execute(PrintStream out, PrintStream err) throws Exception;
/**
*
* @param option
*/
protected void addOption(Option option) {
options.put("-" + option.getShortName(), option);
options.put("--" + option.getName(), option);
optionsByName.put(option.getName(), option);
}
/**
* Extract the options and non-option arguments from the given
* list of command-line arguments. The specified locale is used for
* parsing options whose values might be locale-specific.
*/
protected final void parse(String[] argv) throws OptionException {
int position = 0;
while (position < argv.length) {
String curArg = argv[position];
if (curArg.startsWith("-")) {
if (curArg.equals("--")) {
position += 1;
break;
}
String valueArg = null;
if (curArg.startsWith("--")) {
int equalsPos = curArg.indexOf("=");
if (equalsPos != -1) {
valueArg = curArg.substring(equalsPos+1);
curArg = curArg.substring(0,equalsPos);
}
} else if(curArg.length() > 2) {
for(int i=1; i<curArg.length(); i++) {
Option opt = this.options.get("-" + curArg.charAt(i));
if(opt == null) {
Option unknowOption = new BaseOption(curArg, false);
throw new UnknowOptionException(unknowOption);
}
if(!opt.isSwitch()) {
throw new OptionArgumentRequiredException(opt);
}
values.put(opt, null);
}
position++;
continue;
}
Option opt = this.options.get(curArg);
if (opt == null) {
Option unknowOption = new BaseOption(curArg, false);
throw new UnknowOptionException(unknowOption);
}
String value = null;
if (!opt.isSwitch()) {
if (valueArg == null) {
position += 1;
if (position < argv.length) {
valueArg = argv[position];
}
}
value = valueArg;
if (value == null) {
throw new OptionArgumentRequiredException(opt);
}
}
values.put(opt, value);
position += 1;
}
else {
dataArguments.add(curArg);
position += 1;
}
}
for ( ; position < argv.length; ++position ) {
dataArguments.add(argv[position]);
}
for(Option option : optionsByName.values()) {
if (option.isRequired() && !values.containsKey(option)) {
throw new RequiredOptionException(option);
}
}
}
protected boolean hasOption(String optionName) {
return this.optionsByName.containsKey(optionName) &&
values.containsKey(this.optionsByName.get(optionName));
}
protected boolean hasOption(Option option) {
return this.optionsByName.containsValue(option) &&
values.containsKey(option);
}
protected boolean getBooleanOption(String optionName) {
return hasOption(optionName) && this.optionsByName.get(optionName).isSwitch();
}
protected int getIntegerOption(String optionName, int defaultValue) {
int returnValue = defaultValue;
if (hasOption(optionName)) {
try {
returnValue = Integer.parseInt(values.get(optionsByName.get(optionName)));
} catch(NumberFormatException e) {}
}
return returnValue;
}
protected String getStringOption(String optionName, String defaultValue) {
String returnValue = defaultValue;
if (hasOption(optionName)) {
returnValue = values.get(optionsByName.get(optionName));
}
return returnValue;
}
}