Merge branch 'patch/JAL-4195_cli_eps_export_npe' into develop
[jalview.git] / src / jalview / bin / argparser / ArgParser.java
index 6d1251c..907b1fa 100644 (file)
@@ -48,79 +48,117 @@ public class ArgParser
 
   protected static final String DOUBLEDASH = "--";
 
-  protected static final char EQUALS = '=';
+  public static final char EQUALS = '=';
 
   protected static final String NEGATESTRING = "no";
 
-  // the default linked id prefix used for no id (not even square braces)
+  /**
+   * the default linked id prefix used for no id (ie when not even square braces
+   * are provided)
+   */
   protected static final String DEFAULTLINKEDIDPREFIX = "JALVIEW:";
 
-  // the linkedId string used to match all linkedIds seen so far
+  /**
+   * the linkedId string used to match all linkedIds seen so far
+   */
   protected static final String MATCHALLLINKEDIDS = "*";
 
-  // the linkedId string used to match all of the last --open'ed linkedIds
+  /**
+   * the linkedId string used to match all of the last --open'ed linkedIds
+   */
   protected static final String MATCHOPENEDLINKEDIDS = "open*";
 
-  // the counter added to the default linked id prefix
+  /**
+   * the counter added to the default linked id prefix
+   */
   private int defaultLinkedIdCounter = 0;
 
-  // the substitution string used to use the defaultLinkedIdCounter
+  /**
+   * the substitution string used to use the defaultLinkedIdCounter
+   */
   private static final String DEFAULTLINKEDIDCOUNTER = "{}";
 
-  // the counter added to the default linked id prefix. NOW using
-  // linkedIdAutoCounter
-  // private int openLinkedIdCounter = 0;
-
-  // the linked id prefix used for --open files. NOW the same as DEFAULT
+  /**
+   * the linked id prefix used for --open files. NOW the same as DEFAULT
+   */
   protected static final String OPENLINKEDIDPREFIX = DEFAULTLINKEDIDPREFIX;
 
-  // the counter used for {n} substitutions
+  /**
+   * the counter used for {n} substitutions
+   */
   private int linkedIdAutoCounter = 0;
 
-  // the linked id substitution string used to increment the idCounter (and use
-  // the incremented value)
+  /**
+   * the linked id substitution string used to increment the idCounter (and use
+   * the incremented value)
+   */
   private static final String INCREMENTLINKEDIDAUTOCOUNTER = "{++n}";
 
-  // the linked id substitution string used to use the idCounter
+  /**
+   * the linked id substitution string used to use the idCounter
+   */
   private static final String LINKEDIDAUTOCOUNTER = "{n}";
 
-  // the linked id substitution string used to use the filename extension of
-  // --append
-  // or --open
+  /**
+   * the linked id substitution string used to use the filename extension of
+   * --append or --open
+   */
   private static final String LINKEDIDEXTENSION = "{extension}";
 
-  // the linked id substitution string used to use the base filename of --append
-  // or --open
+  /**
+   * the linked id substitution string used to use the base filename of --append
+   */
+  /** or --open */
   private static final String LINKEDIDBASENAME = "{basename}";
 
-  // the linked id substitution string used to use the dir path of --append
-  // or --open
+  /**
+   * the linked id substitution string used to use the dir path of --append or
+   * --open
+   */
   private static final String LINKEDIDDIRNAME = "{dirname}";
 
-  // the current argfile
+  /**
+   * the current argfile
+   */
   private String argFile = null;
 
-  // the linked id substitution string used to use the dir path of the latest
-  // --argfile name
+  /**
+   * the linked id substitution string used to use the dir path of the latest
+   */
+  /** --argfile name */
   private static final String ARGFILEBASENAME = "{argfilebasename}";
 
-  // the linked id substitution string used to use the dir path of the latest
-  // --argfile name
+  /**
+   * the linked id substitution string used to use the dir path of the latest
+   * --argfile name
+   */
   private static final String ARGFILEDIRNAME = "{argfiledirname}";
 
-  // flag to say whether {n} subtitutions in output filenames should be made.
-  // Turn on and off with --substitutions and --nosubstitutions
-  // Start with it on
+  /**
+   * flag to say whether {n} subtitutions in output filenames should be made.
+   * Turn on and off with --substitutions and --nosubstitutions Start with it on
+   */
   private boolean substitutions = true;
 
-  // flag to say whether the default linkedId is the current default linked id
-  // or ALL linkedIds
+  /**
+   * flag to say whether the default linkedId is the current default linked id
+   *
+   * or ALL linkedIds
+   */
   private boolean allLinkedIds = false;
 
-  // flag to say whether the default linkedId is the current default linked id
-  // or OPENED linkedIds
+  /**
+   * flag to say whether the default linkedId is the current default linked id
+   * or OPENED linkedIds
+   */
   private boolean openedLinkedIds = false;
 
+  /**
+   * flag to say whether the structure arguments should be applied to all
+   * structures with this linked id
+   */
+  private boolean allStructures = false;
+
   protected static final Map<String, Arg> argMap;
 
   protected Map<String, ArgValuesMap> linkedArgs = new HashMap<>();
@@ -298,12 +336,34 @@ public class ArgParser
         Arg a = argMap.get(argName);
         // check for boolean prepended by "no" e.g. --nowrap
         boolean negated = false;
-        if (a == null && argName.startsWith(NEGATESTRING) && argMap
-                .containsKey(argName.substring(NEGATESTRING.length())))
+        if (a == null)
         {
-          argName = argName.substring(NEGATESTRING.length());
-          a = argMap.get(argName);
-          negated = true;
+          if (argName.startsWith(NEGATESTRING) && argMap
+                  .containsKey(argName.substring(NEGATESTRING.length())))
+          {
+            argName = argName.substring(NEGATESTRING.length());
+            a = argMap.get(argName);
+            negated = true;
+          }
+          else
+          {
+            // after all other args, look for Opt.PREFIXKEV args if still not
+            // found
+            for (Arg potentialArg : EnumSet.allOf(Arg.class))
+            {
+              if (potentialArg.hasOption(Opt.PREFIXKEV) && argName != null
+                      && argName.startsWith(potentialArg.getName())
+                      && equalPos > -1)
+              {
+                val = argName.substring(potentialArg.getName().length())
+                        + EQUALS + val;
+                argName = argName.substring(0,
+                        potentialArg.getName().length());
+                a = potentialArg;
+                break;
+              }
+            }
+          }
         }
 
         // check for config errors
@@ -424,6 +484,10 @@ public class ArgParser
           openedLinkedIds = !negated;
           allLinkedIds = false;
         }
+        else if (a == Arg.ALLSTRUCTURES)
+        {
+          allStructures = !negated;
+        }
 
         if (a.hasOption(Opt.STORED))
         {
@@ -445,7 +509,7 @@ public class ArgParser
         {
           if (linkedId == null)
           {
-            if (a.hasOption(Opt.OUTPUT) && a.hasOption(Opt.ALLOWALL)
+            if (a.hasOption(Opt.OUTPUTFILE) && a.hasOption(Opt.ALLOWALL)
                     && val.startsWith(MATCHALLLINKEDIDS))
             {
               // --output=*.ext is shorthand for --all --output {basename}.ext
@@ -456,7 +520,8 @@ public class ArgParser
               val = LINKEDIDDIRNAME + File.separator + LINKEDIDBASENAME
                       + val.substring(MATCHALLLINKEDIDS.length());
             }
-            else if (a.hasOption(Opt.OUTPUT) && a.hasOption(Opt.ALLOWALL)
+            else if (a.hasOption(Opt.OUTPUTFILE)
+                    && a.hasOption(Opt.ALLOWALL)
                     && val.startsWith(MATCHOPENEDLINKEDIDS))
             {
               // --output=open*.ext is shorthand for --opened --output
@@ -485,23 +550,26 @@ public class ArgParser
                       + arg);
             }
           }
-          else if (linkedId.contains(LINKEDIDAUTOCOUNTER))
-          {
-            // turn {n} to the autoCounter
-            autoCounterString = Integer.toString(linkedIdAutoCounter);
-            linkedId = linkedId.replace(LINKEDIDAUTOCOUNTER,
-                    autoCounterString);
-            Console.debug(
-                    "Changing linkedId to '" + linkedId + "' from " + arg);
-          }
-          else if (linkedId.contains(INCREMENTLINKEDIDAUTOCOUNTER))
+          else
           {
-            // turn {++n} to the incremented autoCounter
-            autoCounterString = Integer.toString(++linkedIdAutoCounter);
-            linkedId = linkedId.replace(INCREMENTLINKEDIDAUTOCOUNTER,
-                    autoCounterString);
-            Console.debug(
-                    "Changing linkedId to '" + linkedId + "' from " + arg);
+            if (linkedId.contains(LINKEDIDAUTOCOUNTER))
+            {
+              // turn {n} to the autoCounter
+              autoCounterString = Integer.toString(linkedIdAutoCounter);
+              linkedId = linkedId.replace(LINKEDIDAUTOCOUNTER,
+                      autoCounterString);
+              Console.debug("Changing linkedId to '" + linkedId + "' from "
+                      + arg);
+            }
+            if (linkedId.contains(INCREMENTLINKEDIDAUTOCOUNTER))
+            {
+              // turn {++n} to the incremented autoCounter
+              autoCounterString = Integer.toString(++linkedIdAutoCounter);
+              linkedId = linkedId.replace(INCREMENTLINKEDIDAUTOCOUNTER,
+                      autoCounterString);
+              Console.debug("Changing linkedId to '" + linkedId + "' from "
+                      + arg);
+            }
           }
         }
 
@@ -521,8 +589,9 @@ public class ArgParser
         }
 
         // check for unique id
-        SubVals idsv = new SubVals(val);
-        String id = idsv.get(ArgValues.ID);
+        SubVals subvals = new SubVals(val);
+        boolean addNewSubVals = false;
+        String id = subvals.get(ArgValues.ID);
         if (id != null && avm.hasId(a, id))
         {
           Console.error("Argument '" + a.argString()
@@ -530,10 +599,21 @@ public class ArgParser
           continue;
         }
 
-        /* TODO
-         * Change all avs.addValue() avs.setBoolean avs.setNegated() avs.incrementCount calls to checkfor linkedId == "*"
-         * DONE, need to check
-         */
+        // set allstructures to all non-primary structure options in this linked
+        // id if --allstructures has been set
+        if (allStructures
+                && (a.getType() == Type.STRUCTURE
+                        || a.getType() == Type.STRUCTUREIMAGE)
+                && !a.hasOption(Opt.PRIMARY))
+        {
+          if (!subvals.has(Arg.ALLSTRUCTURES.getName()))
+          // && !subvals.has("structureid"))
+          {
+            subvals.put(Arg.ALLSTRUCTURES.getName(), "true");
+            addNewSubVals = true;
+          }
+        }
+
         ArgValues avs = avm.getOrCreateArgValues(a);
 
         // store appropriate String value(s)
@@ -563,7 +643,9 @@ public class ArgParser
           }
           else
           {
-            addValue(linkedId, type, avs, val, argIndex, true);
+            // addValue(linkedId, type, avs, val, argIndex, true);
+            addValue(linkedId, type, avs, addNewSubVals ? subvals : null,
+                    val, argIndex, true);
           }
         }
         else if (a.hasOption(Opt.BOOLEAN))
@@ -877,15 +959,19 @@ public class ArgParser
     FIRST, BEFORE, AFTER
   }
 
-  // get from following Arg of type a or subval of same name (lowercase)
+  /**
+   * 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
+  /**
+   * 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)
   {
@@ -893,8 +979,10 @@ public class ArgParser
             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
+  /**
+   * 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)
@@ -925,8 +1013,23 @@ public class ArgParser
       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();
+        }
+      }
     }
-    else
+    if (value == null)
     {
       value = pref != null ? Cache.getDefault(pref, def) : def;
     }
@@ -942,6 +1045,13 @@ public class ArgParser
   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;
 
@@ -995,12 +1105,15 @@ public class ArgParser
       return avm.getBoolean(a);
 
     // return preference or default
-    return pref != null ? Cache.getDefault(pref, def) : def;
+    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
+  /**
+   * 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)
   {
@@ -1039,13 +1152,46 @@ public class ArgParser
     ADDVALUE, SETBOOLEAN, SETNEGATED, INCREMENTCOUNT
   }
 
-  // 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.
   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;
@@ -1097,8 +1243,8 @@ public class ArgParser
           {
             if (doSubs)
             {
-              val = makeSubstitutions(v, id);
-              sv = new SubVals(sv, val);
+              sv = new SubVals(sv, val, merge);
+              val = makeSubstitutions(sv.getContent(), id);
             }
             tavs.addValue(sv, type, val, argIndex, true);
           }