package org.xmlsh.modules.types.options;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.xmlsh.annotations.Function;
import org.xmlsh.core.AbstractBuiltinFunction;
import org.xmlsh.core.CoreException;
import org.xmlsh.core.InvalidArgumentException;
import org.xmlsh.core.Options;
import org.xmlsh.core.XClassLoader;
import org.xmlsh.core.Options.OptionDef;
import org.xmlsh.core.Options.OptionDefs;
import org.xmlsh.core.UnexpectedException;
import org.xmlsh.core.UnknownOption;
import org.xmlsh.core.XValue;
import org.xmlsh.modules.types.TypesModule;
import org.xmlsh.sh.module.ModuleConfig;
import org.xmlsh.sh.shell.Shell;
import org.xmlsh.types.TypeFamily;
import org.xmlsh.util.JavaUtils;
@org.xmlsh.annotations.Module( name="types.options")
public class OptionsModule extends TypesModule {
public OptionsModule(ModuleConfig config, XClassLoader loader) throws CoreException {
super(config,loader);
}
static Logger mLogger = LogManager.getLogger();
@Function( name="option-defs")
public static class optionDefs extends AbstractBuiltinFunction {
@Override
public XValue run(Shell shell, List<XValue> args) throws Exception
{
List<OptionDef> defs = parseDefs(args);
return XValue.newXValue(TypeFamily.JAVA, defs);
}
}
@Function( name="options")
public static class options extends AbstractBuiltinFunction {
@Override
public XValue run(Shell shell, List<XValue> args) throws UnknownOption, InvalidArgumentException, UnexpectedException
{
if( args.isEmpty()){
usage(shell, "options( option-defs [args])");
return null ;
}
requires(! args.isEmpty() , "Usage: options( option-defs [args])");
XValue xdefs = args.remove(0);
OptionDefs defs = parseDefs( xdefs ,true);
Options opts = new Options( defs );
opts.parse(args);
return XValue.newXValue(TypeFamily.JAVA,opts);
}
@Function( name="with-defaults")
public static class withDefaults extends AbstractBuiltinFunction {
@Override
public XValue run(Shell shell, List<XValue> args) throws InvalidArgumentException, UnexpectedException, UnknownOption {
requires(! args.isEmpty() , "withDefaults( options [args])");
if( args.get(0).isInstanceOf( Options.class)){
usage(shell, "with-defaults( options [args]" );
}
Options opts = args.remove(0).asInstanceOf(Options.class );
opts.withDefaultArgs( args );
return XValue.newXValue(TypeFamily.JAVA,opts);
}
}
}
protected static OptionDefs parseDefs( List<XValue> args) {
OptionDefs defs = new OptionDefs();
for( XValue arg : args )
defs.addAll( parseDefs(arg ,true) );
return defs;
}
protected static OptionDefs parseDefs(XValue args, boolean ifAbsent) {
OptionDefs defs = new OptionDefs();
for( XValue arg : args ){
if( arg.isInstanceOf( OptionDef.class ))
defs.add( arg.asInstanceOf(OptionDef.class));
else
defs.addOptionDefs( parseDefs( arg.asObject(),ifAbsent));
}
return defs;
}
protected static OptionDefs parseDefs(Object obj, boolean ifAbsent ) {
OptionDefs defs = new OptionDefs();
if( obj instanceof OptionDef )
defs.addOptionDef( (OptionDef) obj , ifAbsent );
else
if( JavaUtils.isArrayOf(obj,OptionDef.class ) )
defs.addOptionDefs(ifAbsent, (OptionDef[]) obj );
else
if( obj instanceof List )
for( Object o : (List<?>)obj )
defs.addOptionDefs( parseDefs( o ,ifAbsent) , ifAbsent );
else
defs.addOptionDefs( OptionDefs.parseDefs( obj.toString() ) , ifAbsent );
return defs;
}
@Function( name="has-opt")
public static class hasOpt extends AbstractBuiltinFunction
{
@Override
public XValue run(Shell shell, List<XValue> args) throws Exception
{
if( args.size() !=2 ||! args.get(0).isInstanceOf( Options.class)){
usage(shell, "has-opt( options option-name");
return XValue.newXValue(false);
}
Options opts = args.get(0).asInstanceOf(Options.class );
String name = args.get(1).toString();
return XValue.newXValue( opts.hasOpt(name));
}
}
@Function( name="get-opt",names={"option","flag","value" })
public static class getOpt extends AbstractBuiltinFunction
{
@Override
public XValue run(Shell shell, List<XValue> args) throws Exception
{
if( args.size() < 2 ||! args.get(0).isInstanceOf( Options.class)){
usage(shell, "options option [default]");
return XValue.nullValue();
}
Options opts = args.get(0).asInstanceOf(Options.class );
String name = args.get(1).toString();
XValue defaultValue = args.size() > 2 ? args.get(2) : null ;
OptionDef def = opts.getOptDef(name);
if( def == null )
return XValue.nullValue();
if( def.isFlag())
return
XValue.newXValue( opts.getOptFlag(name, defaultValue == null ? true : defaultValue.toBoolean() ) );
XValue v = opts.getOptValue(name);
if( v == null )
v = defaultValue ;
return v ;
}
}
@Function( name="get-args" , names={"args","remaining-args","remaining"})
public static class getArgs extends AbstractBuiltinFunction
{
@Override
public XValue run(Shell shell, List<XValue> args) throws Exception
{
if( args.size() != 1 ||! args.get(0).isInstanceOf( Options.class)){
usage(shell, "get-args(opts)");
return XValue.nullValue();
}
return XValue.newXValue(((Options) args.get(0).asInstanceOf(Options.class)).getRemainingArgs());
}
}
@Function( name="has-args" , names={"any-args"})
public static class hasArgs extends AbstractBuiltinFunction
{
@Override
public XValue run(Shell shell, List<XValue> args) throws Exception
{
if( args.size() != 1 ||! args.get(0).isInstanceOf( Options.class)){
usage(shell, "get-args(opts)");
return XValue.nullValue();
}
return XValue.newXValue(((Options) args.get(0).asInstanceOf(Options.class)).getRemainingArgs());
}
}
}