package net.sourceforge.javautil.ui.cli;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import net.sourceforge.javautil.common.ReflectionUtil;
import net.sourceforge.javautil.common.reflection.cache.ClassCache;
import net.sourceforge.javautil.common.reflection.cache.ClassDescriptor;
import net.sourceforge.javautil.common.reflection.cache.ClassMethod;
import net.sourceforge.javautil.common.reflection.cache.ClassProperty;
import net.sourceforge.javautil.ui.cli.CommandLineCommand.CommandLineArgument;
import net.sourceforge.javautil.ui.command.UICommand;
import net.sourceforge.javautil.ui.command.UICommandArguments;
import net.sourceforge.javautil.ui.command.UICommand.CommandFlag;
import net.sourceforge.javautil.ui.command.UICommand.CommandOption;
import net.sourceforge.javautil.ui.command.UICommandArguments.PassedArgument;
/**
* Utility that will parse arguments and allow them to be interpreted
* according to standard rules.
*
* @author elponderador
* @author $Author: ponderator $
* @version $Id: CommandLineArgumentsStandard.java 1512 2009-11-28 03:06:04Z ponderator $
*/
public class CommandLineArgumentsStandard implements UICommandArguments<CommandLineArgument, CommandOption, CommandFlag> {
/**
* Unparsed argument list
*/
protected final String[] arguments;
protected final Map<String, CommandLineArgumentOption> options = new LinkedHashMap<String, CommandLineArgumentOption>();
protected final List<String> flags = new ArrayList<String>();
protected final List<String> other = new ArrayList<String>();
protected Logger log = Logger.getLogger(CommandLineArgumentsStandard.class.getName());
/**
* @param arguments The {@link #arguments}
*/
public CommandLineArgumentsStandard (String... arguments) {
this.arguments = arguments;
this.parse();
}
/**
* @return The amount of arguments passed to {@link #CommandLineArguments(String...)}
*/
public int getRawArgumentCount () { return arguments.length; }
/**
* @param idx The index of the raw argument
* @return The raw argument value, or null if the index is invalid
*/
public String getRawArgument (int idx) { return idx >= 0 && idx < arguments.length ? arguments[idx] : null; }
/**
* @return A map of options, the key is the option with out prefix and the value is a composite option information object.
*/
public Map<String, PassedOption> getOptions () { return new LinkedHashMap<String, PassedOption>(options); }
/**
* @return The boolean flags, if the flag name is in the list it implies true, otherwise false.
*/
public List<String> getFlags () { return new ArrayList<String>(flags); }
/**
* @return Command specific arguments
*/
public List<PassedArgument> getArguments () {
List<PassedArgument> arguments = new ArrayList<PassedArgument>();
for (int o=0; o<other.size(); o++) {
arguments.add(new PassedArgument(o, other.get(o)));
}
return arguments;
}
/**
* @param idx The index of the argument
* @return The argument, or null if it was not specified
*/
public PassedArgument getArgument(int idx) {
return idx >= 0 && idx < other.size() ? new PassedArgument(idx, other.get(idx)) : null;
}
/**
* @param name The name of the option
* @return The option if preset, otherwise null
*/
public PassedOption getOption (String name) { return this.options.get(name); }
/**
* @param name The name of the option
* @param defaultValue The value to return if the option is not present
* @return The options value or the default value
*/
public String getOptionValue (String name, String defaultValue) {
return this.options.containsKey(name) ?
String.valueOf( this.options.get(name).getValue() ) : defaultValue;
}
/**
* @param flag The name of the flag
* @return True if the flag was present, otherwise false
*/
public boolean isEnabled (String flag) { return this.flags.contains(flag); }
/**
* This will search for arguments that start with - or -- and expect corresponding values
* either with = or with a following argument. Arguments with a / prefix will be considered
* boolean flags. All other arguments will be placed in a separate list.
*
* @throws IllegalArgumentException
*/
private void parse () {
for (int a=0; a<arguments.length; a++) {
String argument = arguments[a];
String name = null;
String value = null;
String prefix = null;
if (argument.startsWith("-")) {
if (argument.startsWith("--") && argument.length() > 2) { prefix = "--"; argument = argument.substring(2); }
else if (argument.length() > 1) { prefix = "-"; argument = argument.substring(1); }
if (argument.startsWith("-"))
throw new IllegalArgumentException("Could not understand: " + argument);
if (argument.contains("=")) {
String[] parts = argument.split("=");
name = parts[0];
if (parts.length > 1) value = parts[1];
} else {
name = argument;
}
} else if (argument.startsWith("/")) {
if (argument.length() > 1) argument = argument.substring(1);
if (argument.startsWith("/")) {
other.add(arguments[a]);
continue;
} else {
prefix = "/";
name = argument;
}
} else {
other.add(argument);
continue;
}
if (other.size() > 0)
log.info("Arguments found before options/flags: " + argument + " before + " + other);
if (value == null) {
if ("/".equals(prefix)) {
this.flags.add(name);
} else {
if (a + 1 == arguments.length) {
other.add(arguments[a]);
} else
this.options.put(name, new CommandLineArgumentOption(prefix, name, arguments[++a]));
}
} else {
this.options.put(name, new CommandLineArgumentOption(prefix, name, value));
}
}
}
/**
* This wraps an option that has a corresponding value.
*
* @author elponderador
* @author $Author: ponderator $
* @version $Id: CommandLineArgumentsStandard.java 1512 2009-11-28 03:06:04Z ponderator $
*/
public class CommandLineArgumentOption extends PassedOption {
protected String prefix;
public CommandLineArgumentOption(String prefix, String name, String value) {
super(name, value);
this.prefix = prefix;
}
public String getPrefix() { return prefix; }
}
}