2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.bin.argparser;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Locale;
34 import jalview.bin.Cache;
35 import jalview.bin.Console;
36 import jalview.bin.argparser.Arg.Opt;
37 import jalview.bin.argparser.Arg.Type;
38 import jalview.util.FileUtils;
41 * Helper class to allow easy extraction of information about specific argument
42 * values (without having to check for null etc all the time)
44 public class ArgValuesMap
46 private List<ArgInfo> argInfoList = new ArrayList<>();
48 protected Map<Arg, ArgValues> m;
50 private String linkedId;
52 protected ArgValuesMap(String linkedId)
54 this.linkedId = linkedId;
58 protected ArgValuesMap(String linkedId, Map<Arg, ArgValues> map)
60 this.linkedId = linkedId;
64 public String getLinkedId()
69 private Map<Arg, ArgValues> getMap()
76 m = new HashMap<Arg, ArgValues>();
79 private void newArg(Arg a)
87 m.put(a, new ArgValues(a, this));
91 public ArgValues getArgValues(Arg a)
93 return m == null ? null : m.get(a);
96 public ArgValues getOrCreateArgValues(Arg a)
98 ArgValues avs = m.get(a);
101 return getArgValues(a);
104 public List<ArgValue> getArgValueList(Arg a)
106 ArgValues avs = getArgValues(a);
107 return avs == null ? new ArrayList<>() : avs.getArgValueList();
110 public List<ArgValue> getArgValueListFromSubValOrArg(ArgValue av, Arg a,
113 return getArgValueListFromSubValArgOrPrefWithSubstitutionsWithinTypes(
114 null, a, Position.AFTER, av, sv, null, null, null, true, null);
117 public List<ArgValue> getArgValueListFromSubValArgOrPrefWithSubstitutionsWithinTypes(
118 ArgParser ap, Arg a, ArgValuesMap.Position pos, ArgValue av,
119 SubVals sv, String key, String pref, String def,
120 boolean withinTypes, Type type)
126 Set<Type> types = new HashSet<>();
129 types.addAll(Arrays.asList(av.getArg().getTypes()));
135 List<ArgValue> avList = new ArrayList<>();
136 if (sv != null && sv.has(key) && sv.get(key) != null)
138 String value = ap == null ? sv.get(key)
139 : sv.getWithSubstitutions(ap, getLinkedId(), key);
140 // protected ArgValue(Arg a, SubVals sv, Type type, String content, int
143 ArgValue svav = new ArgValue(a, null, null, value, av.getArgIndex(),
144 false, null, this.getLinkedId());
147 else if (containsArg(a))
149 if (pos == ArgValuesMap.Position.FIRST && getValue(a) != null)
150 avList.add(getArgValue(a));
151 else if (pos == ArgValuesMap.Position.BEFORE
152 && getClosestPreviousArgValueOfArg(av, a) != null)
154 for (ArgValue tmpAv : getArgValues(a).getArgValueList())
156 if (tmpAv.getArgIndex() >= av.getArgIndex())
163 else if (pos == ArgValuesMap.Position.AFTER
164 && getClosestNextArgValueOfArg(av, a, withinTypes) != null)
166 for (ArgValue tmpAv : getArgValues(a).getArgValueList())
168 if (tmpAv.getArgIndex() <= av.getArgIndex())
177 // check if withinType the avs don't belong to the next primary arg
178 // of this type. Checking for *any* shared type.
179 if (withinTypes && !avList.isEmpty())
181 int nextPrimaryArgOfSameTypeIndex = Integer.MAX_VALUE;
182 // run through every Arg used in this ArgValuesMap
183 for (Arg tmpA : this.getArgKeys())
185 // only interested in looking up to next Opt.PRIMARY args of the same
186 // type as av (or provided type)
187 if (tmpA.hasType(types) && tmpA.hasOption(Opt.PRIMARY))
189 for (ArgValue tmpAv : getArgValueList(tmpA))
191 int tmpArgIndex = tmpAv.getArgIndex();
192 if (tmpArgIndex > av.getArgIndex()
193 && tmpArgIndex < nextPrimaryArgOfSameTypeIndex)
195 nextPrimaryArgOfSameTypeIndex = tmpArgIndex;
200 List<ArgValue> tmpList = new ArrayList<>();
201 for (ArgValue tmpAv : avList)
203 int tmpAvIndex = tmpAv.getArgIndex();
204 if (av.getArgIndex() < tmpAvIndex
205 && tmpAvIndex < nextPrimaryArgOfSameTypeIndex)
216 public ArgValue getArgValue(Arg a)
218 List<ArgValue> vals = getArgValueList(a);
219 return (vals == null || vals.size() == 0) ? null : vals.get(0);
222 public String getValue(Arg a)
224 ArgValue av = getArgValue(a);
225 return av == null ? null : av.getValue();
228 public List<String> getValues(Arg a)
230 return toValues(getArgValueList(a));
233 public static List<String> toValues(List<ArgValue> avl)
239 List<String> vl = new ArrayList<>();
240 for (ArgValue av : avl)
242 vl.add(av.getValue());
247 public boolean containsArg(Arg a)
249 if (m == null || !m.containsKey(a))
251 return a.hasOption(Opt.STRING) ? getArgValue(a) != null : true;
254 public boolean hasValue(Arg a, String val)
256 if (m == null || !m.containsKey(a))
258 for (ArgValue av : getArgValueList(a))
260 String avVal = av.getValue();
261 if ((val == null && avVal == null)
262 || (val != null && val.equals(avVal)))
270 public boolean getBoolean(Arg a)
272 ArgValues av = getArgValues(a);
273 return av == null ? false : av.getBoolean();
276 public Set<Arg> getArgKeys()
281 public ArgValue getArgValueOfArgWithSubValKey(Arg a, String svKey)
283 return getArgValueOfArgWithSubValKey(a, svKey, false);
286 public ArgValue getArgValueOfArgWithSubValKey(Arg a, String svKey,
289 ArgValues avs = this.getArgValues(a);
294 List<ArgValue> compareAvs = avs.getArgValueList();
295 for (int i = 0; i < compareAvs.size(); i++)
297 int index = last ? compareAvs.size() - 1 - i : i;
298 ArgValue av = compareAvs.get(index);
299 SubVals sv = av.getSubVals();
300 if (sv.has(svKey) && !sv.get(svKey).equals("false"))
308 public ArgValue getClosestPreviousArgValueOfArg(ArgValue thisAv, Arg a)
310 ArgValue closestAv = null;
311 int thisArgIndex = thisAv.getArgIndex();
312 ArgValues compareAvs = this.getArgValues(a);
313 int closestPreviousIndex = -1;
314 for (ArgValue av : compareAvs.getArgValueList())
316 int argIndex = av.getArgIndex();
317 if (argIndex < thisArgIndex && argIndex > closestPreviousIndex)
319 closestPreviousIndex = argIndex;
326 public ArgValue getClosestNextArgValueOfArg(ArgValue thisAv, Arg a,
329 // this looks for the *next* arg that *might* be referring back to
330 // a thisAv. Such an arg would have no subValues (if it does it should
331 // specify an id in the subValues so wouldn't need to be guessed).
332 ArgValue closestAv = null;
333 int thisArgIndex = thisAv.getArgIndex();
336 ArgValues compareAvs = this.getArgValues(a);
337 int closestNextIndex = Integer.MAX_VALUE;
338 for (ArgValue av : compareAvs.getArgValueList())
340 int argIndex = av.getArgIndex();
341 if (argIndex > thisArgIndex && argIndex < closestNextIndex)
343 closestNextIndex = argIndex;
348 // check if withinType this closestAv doesn't belong to the next primary arg
349 // of this type. Checking for *any* shared type.
350 if (withinTypes && closestAv != null)
352 int nextPrimaryArgOfSameTypeIndex = Integer.MAX_VALUE;
353 for (Arg tmpA : this.getArgKeys())
355 // interested in Opt.PRIMARY args of the same type
356 if (tmpA.sharesType(a) && tmpA.hasOption(Opt.PRIMARY))
358 for (ArgValue tmpAv : getArgValueList(tmpA))
360 int tmpArgIndex = tmpAv.getArgIndex();
361 if (tmpArgIndex > thisArgIndex
362 && tmpArgIndex < nextPrimaryArgOfSameTypeIndex)
364 nextPrimaryArgOfSameTypeIndex = tmpArgIndex;
369 if (nextPrimaryArgOfSameTypeIndex < closestAv.getArgIndex())
371 // looks like closestAv actually belongs to a different primary Arg
379 // TODO this is incomplete and currently unused (fortunately)
380 public ArgValue[] getArgValuesReferringTo(String key, String value, Arg a)
382 // this looks for the *next* arg that *might* be referring back to
383 // a thisAv. Such an arg would have no subValues (if it does it should
384 // specify an id in the subValues so wouldn't need to be guessed).
385 List<ArgValue> avList = new ArrayList<>();
386 Arg[] args = a == null ? (Arg[]) this.getMap().keySet().toArray()
389 for (Arg keyArg : args)
391 for (ArgValue av : this.getArgValueList(keyArg))
396 return (ArgValue[]) avList.toArray();
399 public boolean hasId(Arg a, String id)
401 ArgValues avs = this.getArgValues(a);
402 return avs == null ? false : avs.hasId(id);
405 public ArgValue getId(Arg a, String id)
407 ArgValues avs = this.getArgValues(a);
408 return avs == null ? null : avs.getId(id);
412 * This method returns the basename of the first --append or --open value.
413 * Used primarily for substitutions in output filenames.
415 public String getBasename()
417 return getDirBasenameOrExtension(false, false, false);
421 * This method returns the basename of the first --append or --open value.
422 * Used primarily for substitutions in output filenames.
424 public String getExtension()
426 return getDirBasenameOrExtension(false, true, false);
430 * This method returns the dirname of the first --append or --open value.
431 * Used primarily for substitutions in output filenames.
433 public String getDirname()
435 return getDirBasenameOrExtension(true, false, false);
438 public String getDirBasenameOrExtension(boolean dirname,
439 boolean extension, boolean absoluteDirname)
441 String filename = null;
442 String appendVal = getValue(Arg.APPEND);
443 String openVal = getValue(Arg.OPEN);
444 if (appendVal != null)
445 filename = appendVal;
446 if (filename == null && openVal != null)
448 if (filename == null)
451 File file = new File(filename);
454 return FileUtils.getDirname(file);
456 return extension ? FileUtils.getExtension(file)
457 : FileUtils.getBasename(file);
461 * Checks if there is an Arg with Opt
463 public boolean hasArgWithOption(Opt o)
465 for (Arg a : getArgKeys())
474 * ArgInfo is a more straightforward list of arguments and their info
477 public void addArgInfo(Arg arg, String value, SubVals subVals,
480 argInfoList.add(new ArgInfo(arg, value, subVals, argIndex));
483 public List<ArgInfo> getArgInfoList()
485 Collections.sort(argInfoList);
490 * get from following Arg of type a or subval of same name (lowercase)
492 public String getValueFromSubValOrArg(ArgValue av, Arg a, SubVals sv)
494 return getFromSubValArgOrPref(av, a, sv, null, null, null);
498 * get from following Arg of type a or subval key or preference pref or
501 public String getFromSubValArgOrPref(ArgValue av, Arg a, SubVals sv,
502 String key, String pref, String def)
504 return getFromSubValArgOrPref(a, Position.AFTER, av, sv, key, pref,
509 * get from following(AFTER), first occurence of (FIRST) or previous (BEFORE)
510 * Arg of type a or subval key or preference pref or default def
512 public String getFromSubValArgOrPref(Arg a, Position pos, ArgValue av,
513 SubVals sv, String key, String pref, String def)
515 return getFromSubValArgOrPrefWithSubstitutions(null, a, pos, av, sv,
519 public String getFromSubValArgOrPrefWithSubstitutions(ArgParser ap, Arg a,
520 Position pos, ArgValue av, SubVals sv, String key, String pref,
523 return getFromSubValArgOrPrefWithSubstitutionsWithinTypes(ap, a, pos,
524 av, sv, key, pref, def, true);
527 public String getFromSubValArgOrPrefWithSubstitutionsWithinTypes(
528 ArgParser ap, Arg a, Position pos, ArgValue av, SubVals sv,
529 String key, String pref, String def, boolean withinTypes)
534 if (sv != null && sv.has(key) && sv.get(key) != null)
536 value = ap == null ? sv.get(key)
537 : sv.getWithSubstitutions(ap, getLinkedId(), key);
539 else if (containsArg(a))
541 if (pos == ArgValuesMap.Position.FIRST && getValue(a) != null)
543 else if (pos == ArgValuesMap.Position.BEFORE
544 && getClosestPreviousArgValueOfArg(av, a) != null)
545 value = getClosestPreviousArgValueOfArg(av, a).getValue();
546 else if (pos == ArgValuesMap.Position.AFTER
547 && getClosestNextArgValueOfArg(av, a, withinTypes) != null)
548 value = getClosestNextArgValueOfArg(av, a, withinTypes).getValue();
550 // look for allstructures subval for Type.STRUCTURE
551 Arg arg = av.getArg();
552 if (value == null && arg.hasOption(Opt.PRIMARY)
553 && arg.hasType(Type.STRUCTURE) && !a.hasOption(Opt.PRIMARY)
554 && (a.getFirstType() == Type.STRUCTURE
555 // || a.getType() == Type.STRUCTUREIMAGE))
558 ArgValue av2 = getArgValueOfArgWithSubValKey(a,
559 Arg.ALLSTRUCTURES.getName());
562 value = av2.getValue();
568 // look for --all --a occurrences
569 for (ArgValue tmpAv : this.getArgValueList(a))
571 if (tmpAv.setByWildcardLinkedId())
573 value = tmpAv.getValue();
580 value = pref != null ? Cache.getDefault(pref, def) : def;
585 public boolean getBoolFromSubValOrArg(Arg a, SubVals sv)
587 return getFromSubValArgOrPref(a, sv, null, null, false);
590 public boolean getFromSubValArgOrPref(Arg a, SubVals sv, String key,
591 String pref, boolean def)
593 return getFromSubValArgOrPref(a, sv, key, pref, def, false);
596 public boolean getFromSubValArgOrPref(Arg a, SubVals sv, String key,
597 String pref, boolean def, boolean invertPref)
599 if ((key == null && a == null) || (sv == null && a == null))
602 boolean usingArgKey = false;
609 String nokey = ArgParser.NEGATESTRING + key;
611 // look for key or nokey in subvals first (if using Arg check options)
614 // check for true boolean
615 if (sv.has(key) && sv.get(key) != null)
619 if (!(a.hasOption(Opt.BOOLEAN) || a.hasOption(Opt.UNARY)))
622 "Looking for boolean in subval from non-boolean/non-unary Arg "
627 return sv.get(key).toLowerCase(Locale.ROOT).equals("true");
630 // check for negative boolean (subval "no..." will be "true")
631 if (sv.has(nokey) && sv.get(nokey) != null)
635 if (!(a.hasOption(Opt.BOOLEAN)))
638 "Looking for negative boolean in subval from non-boolean Arg "
643 return !sv.get(nokey).toLowerCase(Locale.ROOT).equals("true");
649 return getBoolean(a);
651 // return preference or default
652 boolean prefVal = pref != null ? Cache.getDefault(pref, def) : false;
653 return pref != null ? (invertPref ? !prefVal : prefVal) : def;
657 public String toString()
659 StringBuilder sb = new StringBuilder();
660 for (Arg a : this.getArgKeys())
662 sb.append(a.argString());
664 for (ArgValue av : this.getArgValueList(a))
667 sb.append(av.getValue());
671 return sb.toString();
674 public class ArgInfo implements Comparable<ArgInfo>
678 private String value;
680 private SubVals subVals;
682 private int argIndex;
684 public ArgInfo(Arg arg, String value, SubVals subVals, int argIndex)
688 this.subVals = subVals;
689 this.argIndex = argIndex;
697 public String value()
702 public SubVals subVals()
707 public int argIndex()
713 public int compareTo(ArgInfo ai2)
715 return Integer.compare(this.argIndex(), ai2.argIndex());
719 public static enum Position