+ return args;
+ }
+
+ public static enum Position
+ {
+ FIRST, BEFORE, AFTER
+ }
+
+ /**
+ * get from following Arg of type a or subval of same name (lowercase)
+ */
+ public static String getValueFromSubValOrArg(ArgValuesMap avm,
+ ArgValue av, Arg a, SubVals sv)
+ {
+ return getFromSubValArgOrPref(avm, av, a, sv, null, null, null);
+ }
+
+ /**
+ * get from following Arg of type a or subval key or preference pref or
+ * default def
+ */
+ public static String getFromSubValArgOrPref(ArgValuesMap avm, ArgValue av,
+ Arg a, SubVals sv, String key, String pref, String def)
+ {
+ return getFromSubValArgOrPref(avm, a, Position.AFTER, av, sv, key, pref,
+ def);
+ }
+
+ /**
+ * get from following(AFTER), first occurence of (FIRST) or previous (BEFORE)
+ * Arg of type a or subval key or preference pref or default def
+ */
+ public static String getFromSubValArgOrPref(ArgValuesMap avm, Arg a,
+ Position pos, ArgValue av, SubVals sv, String key, String pref,
+ String def)
+ {
+ return getFromSubValArgOrPrefWithSubstitutions(null, avm, a, pos, av,
+ sv, key, pref, def);
+ }
+
+ public static String getFromSubValArgOrPrefWithSubstitutions(ArgParser ap,
+ ArgValuesMap avm, Arg a, Position pos, ArgValue av, SubVals sv,
+ String key, String pref, String def)
+ {
+ if (key == null)
+ key = a.getName();
+ String value = null;
+ if (sv != null && sv.has(key) && sv.get(key) != null)
+ {
+ value = ap == null ? sv.get(key)
+ : sv.getWithSubstitutions(ap, avm.getLinkedId(), key);
+ }
+ else if (avm != null && avm.containsArg(a))
+ {
+ if (pos == Position.FIRST && avm.getValue(a) != null)
+ value = avm.getValue(a);
+ else if (pos == Position.BEFORE
+ && avm.getClosestPreviousArgValueOfArg(av, a) != null)
+ value = avm.getClosestPreviousArgValueOfArg(av, a).getValue();
+ else if (pos == Position.AFTER
+ && avm.getClosestNextArgValueOfArg(av, a) != null)
+ value = avm.getClosestNextArgValueOfArg(av, a).getValue();
+
+ // look for allstructures subval for Type.STRUCTURE*
+ Arg arg = av.getArg();
+ if (value == null && arg.hasOption(Opt.PRIMARY)
+ && arg.getType() == Type.STRUCTURE
+ && !a.hasOption(Opt.PRIMARY) && (a.getType() == Type.STRUCTURE
+ || a.getType() == Type.STRUCTUREIMAGE))
+ {
+ ArgValue av2 = avm.getArgValueOfArgWithSubValKey(a,
+ Arg.ALLSTRUCTURES.getName());
+ if (av2 != null)
+ {
+ value = av2.getValue();
+ }
+ }
+ }
+ if (value == null)
+ {
+ value = pref != null ? Cache.getDefault(pref, def) : def;
+ }
+ return value;
+ }
+
+ public static boolean getBoolFromSubValOrArg(ArgValuesMap avm, Arg a,
+ SubVals sv)
+ {
+ return getFromSubValArgOrPref(avm, a, sv, null, null, false);
+ }
+
+ public static boolean getFromSubValArgOrPref(ArgValuesMap avm, Arg a,
+ SubVals sv, String key, String pref, boolean def)
+ {
+ return getFromSubValArgOrPref(avm, a, sv, key, pref, def, false);
+ }
+
+ public static boolean getFromSubValArgOrPref(ArgValuesMap avm, Arg a,
+ SubVals sv, String key, String pref, boolean def,
+ boolean invertPref)
+ {
+ if ((key == null && a == null) || (sv == null && a == null))
+ return false;
+
+ boolean usingArgKey = false;
+ if (key == null)
+ {
+ key = a.getName();
+ usingArgKey = true;
+ }
+
+ String nokey = ArgParser.NEGATESTRING + key;
+
+ // look for key or nokey in subvals first (if using Arg check options)
+ if (sv != null)
+ {
+ // check for true boolean
+ if (sv.has(key) && sv.get(key) != null)
+ {
+ if (usingArgKey)
+ {
+ if (!(a.hasOption(Opt.BOOLEAN) || a.hasOption(Opt.UNARY)))
+ {
+ Console.debug(
+ "Looking for boolean in subval from non-boolean/non-unary Arg "
+ + a.getName());
+ return false;
+ }
+ }
+ return sv.get(key).toLowerCase(Locale.ROOT).equals("true");
+ }
+
+ // check for negative boolean (subval "no..." will be "true")
+ if (sv.has(nokey) && sv.get(nokey) != null)
+ {
+ if (usingArgKey)
+ {
+ if (!(a.hasOption(Opt.BOOLEAN)))
+ {
+ Console.debug(
+ "Looking for negative boolean in subval from non-boolean Arg "
+ + a.getName());
+ return false;
+ }
+ }
+ return !sv.get(nokey).toLowerCase(Locale.ROOT).equals("true");
+ }
+ }
+
+ // check argvalues
+ if (avm != null && avm.containsArg(a))
+ return avm.getBoolean(a);
+
+ // return preference or default
+ boolean prefVal = pref != null ? Cache.getDefault(pref, def) : false;
+ return pref != null ? (invertPref ? !prefVal : prefVal) : def;
+ }
+
+ // the following methods look for the "*" linkedId and add the argvalue to all
+ // linkedId ArgValues if it does.
+ /**
+ * This version inserts the subvals sv into all created values
+ */
+ private void addValue(String linkedId, Type type, ArgValues avs,
+ SubVals sv, String v, int argIndex, boolean doSubs)
+ {
+ this.argValueOperation(Op.ADDVALUE, linkedId, type, avs, sv, v, false,
+ argIndex, doSubs);
+ }
+
+ private void addValue(String linkedId, Type type, ArgValues avs, String v,
+ int argIndex, boolean doSubs)
+ {
+ this.argValueOperation(Op.ADDVALUE, linkedId, type, avs, null, v, false,
+ argIndex, doSubs);
+ }
+
+ private void setBoolean(String linkedId, Type type, ArgValues avs,
+ boolean b, int argIndex)
+ {
+ this.argValueOperation(Op.SETBOOLEAN, linkedId, type, avs, null, null,
+ b, argIndex, false);
+ }
+
+ private void setNegated(String linkedId, ArgValues avs, boolean b)
+ {
+ this.argValueOperation(Op.SETNEGATED, linkedId, null, avs, null, null,
+ b, 0, false);
+ }
+
+ private void incrementCount(String linkedId, ArgValues avs)
+ {
+ this.argValueOperation(Op.INCREMENTCOUNT, linkedId, null, avs, null,
+ null, false, 0, false);
+ }
+
+ private enum Op
+ {
+ ADDVALUE, SETBOOLEAN, SETNEGATED, INCREMENTCOUNT
+ }
+
+ private void argValueOperation(Op op, String linkedId, Type type,
+ ArgValues avs, SubVals sv, String v, boolean b, int argIndex,
+ boolean doSubs)
+ {
+ // default to merge subvals if subvals are provided
+ argValueOperation(op, linkedId, type, avs, sv, true, v, b, argIndex,
+ doSubs);
+ }
+
+ /**
+ * The following operations look for the "*" and "open*" linkedIds and add the
+ * argvalue to all appropriate linkedId ArgValues if it does. If subvals are
+ * supplied, they are inserted into all new set values.
+ *
+ * @param op
+ * The ArgParser.Op operation
+ * @param linkedId
+ * The String linkedId from the ArgValuesMap
+ * @param type
+ * The Arg.Type to attach to this ArgValue
+ * @param avs
+ * The ArgValues for this linkedId
+ * @param sv
+ * Use these SubVals on the ArgValue
+ * @param merge
+ * Merge the SubVals with any existing on the value. False will
+ * replace unless sv is null
+ * @param v
+ * The value of the ArgValue (may contain subvals).
+ * @param b
+ * The boolean value of the ArgValue.
+ * @param argIndex
+ * The argIndex for the ArgValue.
+ * @param doSubs
+ * Whether to perform substitutions on the subvals and value.
+ */
+ private void argValueOperation(Op op, String linkedId, Type type,
+ ArgValues avs, SubVals sv, boolean merge, String v, boolean b,
+ int argIndex, boolean doSubs)
+ {
+ Arg a = avs.arg();
+
+ List<String> wildcardLinkedIds = null;
+ if (a.hasOption(Opt.ALLOWALL))
+ {
+ switch (linkedId)
+ {
+ case MATCHALLLINKEDIDS:
+ wildcardLinkedIds = getLinkedIds();
+ break;
+ case MATCHOPENEDLINKEDIDS:
+ wildcardLinkedIds = this.storedLinkedIds;
+ break;
+ }
+ }
+
+ // if we're not a wildcard linkedId and the arg is marked to be stored, add
+ // to storedLinkedIds
+ if (linkedId != null && wildcardLinkedIds == null
+ && a.hasOption(Opt.STORED)
+ && !storedLinkedIds.contains(linkedId))
+ {
+ storedLinkedIds.add(linkedId);
+ }
+
+ // if we are a wildcard linkedId, apply the arg and value to all appropriate
+ // linkedIds
+ if (wildcardLinkedIds != null)
+ {
+ for (String id : wildcardLinkedIds)
+ {
+ // skip incorrectly stored wildcard ids!
+ if (id == null || MATCHALLLINKEDIDS.equals(id)
+ || MATCHOPENEDLINKEDIDS.equals(id))
+ continue;
+ ArgValuesMap avm = linkedArgs.get(id);
+ // don't set an output if there isn't an input
+ if (a.hasOption(Opt.REQUIREINPUT)
+ && !avm.hasArgWithOption(Opt.INPUT))
+ continue;
+
+ ArgValues tavs = avm.getOrCreateArgValues(a);
+ switch (op)
+ {
+
+ case ADDVALUE:
+ String val = v;
+ if (sv != null)
+ {
+ if (doSubs)
+ {
+ sv = new SubVals(sv, val, merge);
+ val = makeSubstitutions(sv.getContent(), id);
+ }
+ tavs.addValue(sv, type, val, argIndex, true);
+ }
+ else
+ {
+ if (doSubs)
+ {
+ val = makeSubstitutions(v, id);
+ }
+ tavs.addValue(type, val, argIndex, true);
+ }
+ finaliseStoringArgValue(id, tavs);
+ break;
+
+ case SETBOOLEAN:
+ tavs.setBoolean(type, b, argIndex, true);
+ finaliseStoringArgValue(id, tavs);
+ break;
+
+ case SETNEGATED:
+ tavs.setNegated(b, true);
+ break;
+
+ case INCREMENTCOUNT:
+ tavs.incrementCount();
+ break;
+
+ default:
+ break;
+
+ }
+
+ }
+ }
+ else // no wildcard linkedId -- do it simpler
+ {
+ switch (op)
+ {
+ case ADDVALUE:
+ String val = v;
+ if (sv != null)
+ {
+ if (doSubs)
+ {
+ val = makeSubstitutions(v, linkedId);
+ sv = new SubVals(sv, val);
+ }
+ avs.addValue(sv, type, val, argIndex, false);
+ }
+ else
+ {
+ if (doSubs)
+ {
+ val = makeSubstitutions(v, linkedId);
+ }
+ avs.addValue(type, val, argIndex, false);
+ }
+ finaliseStoringArgValue(linkedId, avs);
+ break;
+
+ case SETBOOLEAN:
+ avs.setBoolean(type, b, argIndex, false);
+ finaliseStoringArgValue(linkedId, avs);
+ break;
+
+ case SETNEGATED:
+ avs.setNegated(b, false);
+ break;
+
+ case INCREMENTCOUNT:
+ avs.incrementCount();
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ private ArgValuesMap getOrCreateLinkedArgValuesMap(String linkedId)
+ {
+ if (linkedArgs.containsKey(linkedId)
+ && linkedArgs.get(linkedId) != null)
+ return linkedArgs.get(linkedId);
+
+ linkedArgs.put(linkedId, new ArgValuesMap(linkedId));
+ return linkedArgs.get(linkedId);