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 boolean containsArg(Arg a)
230 if (m == null || !m.containsKey(a))
232 return a.hasOption(Opt.STRING) ? getArgValue(a) != null : true;
235 public boolean hasValue(Arg a, String val)
237 if (m == null || !m.containsKey(a))
239 for (ArgValue av : getArgValueList(a))
241 String avVal = av.getValue();
242 if ((val == null && avVal == null)
243 || (val != null && val.equals(avVal)))
251 public boolean getBoolean(Arg a)
253 ArgValues av = getArgValues(a);
254 return av == null ? false : av.getBoolean();
257 public Set<Arg> getArgKeys()
262 public ArgValue getArgValueOfArgWithSubValKey(Arg a, String svKey)
264 return getArgValueOfArgWithSubValKey(a, svKey, false);
267 public ArgValue getArgValueOfArgWithSubValKey(Arg a, String svKey,
270 ArgValues avs = this.getArgValues(a);
275 List<ArgValue> compareAvs = avs.getArgValueList();
276 for (int i = 0; i < compareAvs.size(); i++)
278 int index = last ? compareAvs.size() - 1 - i : i;
279 ArgValue av = compareAvs.get(index);
280 SubVals sv = av.getSubVals();
281 if (sv.has(svKey) && !sv.get(svKey).equals("false"))
289 public ArgValue getClosestPreviousArgValueOfArg(ArgValue thisAv, Arg a)
291 ArgValue closestAv = null;
292 int thisArgIndex = thisAv.getArgIndex();
293 ArgValues compareAvs = this.getArgValues(a);
294 int closestPreviousIndex = -1;
295 for (ArgValue av : compareAvs.getArgValueList())
297 int argIndex = av.getArgIndex();
298 if (argIndex < thisArgIndex && argIndex > closestPreviousIndex)
300 closestPreviousIndex = argIndex;
307 public ArgValue getClosestNextArgValueOfArg(ArgValue thisAv, Arg a,
310 // this looks for the *next* arg that *might* be referring back to
311 // a thisAv. Such an arg would have no subValues (if it does it should
312 // specify an id in the subValues so wouldn't need to be guessed).
313 ArgValue closestAv = null;
314 int thisArgIndex = thisAv.getArgIndex();
317 ArgValues compareAvs = this.getArgValues(a);
318 int closestNextIndex = Integer.MAX_VALUE;
319 for (ArgValue av : compareAvs.getArgValueList())
321 int argIndex = av.getArgIndex();
322 if (argIndex > thisArgIndex && argIndex < closestNextIndex)
324 closestNextIndex = argIndex;
329 // check if withinType this closestAv doesn't belong to the next primary arg
330 // of this type. Checking for *any* shared type.
331 if (withinTypes && closestAv != null)
333 int nextPrimaryArgOfSameTypeIndex = Integer.MAX_VALUE;
334 for (Arg tmpA : this.getArgKeys())
336 // interested in Opt.PRIMARY args of the same type
337 if (tmpA.sharesType(a) && tmpA.hasOption(Opt.PRIMARY))
339 for (ArgValue tmpAv : getArgValueList(tmpA))
341 int tmpArgIndex = tmpAv.getArgIndex();
342 if (tmpArgIndex > thisArgIndex
343 && tmpArgIndex < nextPrimaryArgOfSameTypeIndex)
345 nextPrimaryArgOfSameTypeIndex = tmpArgIndex;
350 if (nextPrimaryArgOfSameTypeIndex < closestAv.getArgIndex())
352 // looks like closestAv actually belongs to a different primary Arg
360 // TODO this is incomplete and currently unused (fortunately)
361 public ArgValue[] getArgValuesReferringTo(String key, String value, Arg a)
363 // this looks for the *next* arg that *might* be referring back to
364 // a thisAv. Such an arg would have no subValues (if it does it should
365 // specify an id in the subValues so wouldn't need to be guessed).
366 List<ArgValue> avList = new ArrayList<>();
367 Arg[] args = a == null ? (Arg[]) this.getMap().keySet().toArray()
370 for (Arg keyArg : args)
372 for (ArgValue av : this.getArgValueList(keyArg))
377 return (ArgValue[]) avList.toArray();
380 public boolean hasId(Arg a, String id)
382 ArgValues avs = this.getArgValues(a);
383 return avs == null ? false : avs.hasId(id);
386 public ArgValue getId(Arg a, String id)
388 ArgValues avs = this.getArgValues(a);
389 return avs == null ? null : avs.getId(id);
393 * This method returns the basename of the first --append or --open value.
394 * Used primarily for substitutions in output filenames.
396 public String getBasename()
398 return getDirBasenameOrExtension(false, false, false);
402 * This method returns the basename of the first --append or --open value.
403 * Used primarily for substitutions in output filenames.
405 public String getExtension()
407 return getDirBasenameOrExtension(false, true, false);
411 * This method returns the dirname of the first --append or --open value.
412 * Used primarily for substitutions in output filenames.
414 public String getDirname()
416 return getDirBasenameOrExtension(true, false, false);
419 public String getDirBasenameOrExtension(boolean dirname,
420 boolean extension, boolean absoluteDirname)
422 String filename = null;
423 String appendVal = getValue(Arg.APPEND);
424 String openVal = getValue(Arg.OPEN);
425 if (appendVal != null)
426 filename = appendVal;
427 if (filename == null && openVal != null)
429 if (filename == null)
432 File file = new File(filename);
435 return FileUtils.getDirname(file);
437 return extension ? FileUtils.getExtension(file)
438 : FileUtils.getBasename(file);
442 * Checks if there is an Arg with Opt
444 public boolean hasArgWithOption(Opt o)
446 for (Arg a : getArgKeys())
455 * ArgInfo is a more straightforward list of arguments and their info
458 public void addArgInfo(Arg arg, String value, SubVals subVals,
461 argInfoList.add(new ArgInfo(arg, value, subVals, argIndex));
464 public List<ArgInfo> getArgInfoList()
466 Collections.sort(argInfoList);
471 * get from following Arg of type a or subval of same name (lowercase)
473 public String getValueFromSubValOrArg(ArgValue av, Arg a, SubVals sv)
475 return getFromSubValArgOrPref(av, a, sv, null, null, null);
479 * get from following Arg of type a or subval key or preference pref or
482 public String getFromSubValArgOrPref(ArgValue av, Arg a, SubVals sv,
483 String key, String pref, String def)
485 return getFromSubValArgOrPref(a, Position.AFTER, av, sv, key, pref,
490 * get from following(AFTER), first occurence of (FIRST) or previous (BEFORE)
491 * Arg of type a or subval key or preference pref or default def
493 public String getFromSubValArgOrPref(Arg a, Position pos, ArgValue av,
494 SubVals sv, String key, String pref, String def)
496 return getFromSubValArgOrPrefWithSubstitutions(null, a, pos, av, sv,
500 public String getFromSubValArgOrPrefWithSubstitutions(ArgParser ap, Arg a,
501 Position pos, ArgValue av, SubVals sv, String key, String pref,
504 return getFromSubValArgOrPrefWithSubstitutionsWithinTypes(ap, a, pos,
505 av, sv, key, pref, def, true);
508 public String getFromSubValArgOrPrefWithSubstitutionsWithinTypes(
509 ArgParser ap, Arg a, Position pos, ArgValue av, SubVals sv,
510 String key, String pref, String def, boolean withinTypes)
515 if (sv != null && sv.has(key) && sv.get(key) != null)
517 value = ap == null ? sv.get(key)
518 : sv.getWithSubstitutions(ap, getLinkedId(), key);
520 else if (containsArg(a))
522 if (pos == ArgValuesMap.Position.FIRST && getValue(a) != null)
524 else if (pos == ArgValuesMap.Position.BEFORE
525 && getClosestPreviousArgValueOfArg(av, a) != null)
526 value = getClosestPreviousArgValueOfArg(av, a).getValue();
527 else if (pos == ArgValuesMap.Position.AFTER
528 && getClosestNextArgValueOfArg(av, a, withinTypes) != null)
529 value = getClosestNextArgValueOfArg(av, a, withinTypes).getValue();
531 // look for allstructures subval for Type.STRUCTURE
532 Arg arg = av.getArg();
533 if (value == null && arg.hasOption(Opt.PRIMARY)
534 && arg.hasType(Type.STRUCTURE) && !a.hasOption(Opt.PRIMARY)
535 && (a.getFirstType() == Type.STRUCTURE
536 // || a.getType() == Type.STRUCTUREIMAGE))
539 ArgValue av2 = getArgValueOfArgWithSubValKey(a,
540 Arg.ALLSTRUCTURES.getName());
543 value = av2.getValue();
549 // look for --all --a occurrences
550 for (ArgValue tmpAv : this.getArgValueList(a))
552 if (tmpAv.setByWildcardLinkedId())
554 value = tmpAv.getValue();
561 value = pref != null ? Cache.getDefault(pref, def) : def;
566 public boolean getBoolFromSubValOrArg(Arg a, SubVals sv)
568 return getFromSubValArgOrPref(a, sv, null, null, false);
571 public boolean getFromSubValArgOrPref(Arg a, SubVals sv, String key,
572 String pref, boolean def)
574 return getFromSubValArgOrPref(a, sv, key, pref, def, false);
577 public boolean getFromSubValArgOrPref(Arg a, SubVals sv, String key,
578 String pref, boolean def, boolean invertPref)
580 if ((key == null && a == null) || (sv == null && a == null))
583 boolean usingArgKey = false;
590 String nokey = ArgParser.NEGATESTRING + key;
592 // look for key or nokey in subvals first (if using Arg check options)
595 // check for true boolean
596 if (sv.has(key) && sv.get(key) != null)
600 if (!(a.hasOption(Opt.BOOLEAN) || a.hasOption(Opt.UNARY)))
603 "Looking for boolean in subval from non-boolean/non-unary Arg "
608 return sv.get(key).toLowerCase(Locale.ROOT).equals("true");
611 // check for negative boolean (subval "no..." will be "true")
612 if (sv.has(nokey) && sv.get(nokey) != null)
616 if (!(a.hasOption(Opt.BOOLEAN)))
619 "Looking for negative boolean in subval from non-boolean Arg "
624 return !sv.get(nokey).toLowerCase(Locale.ROOT).equals("true");
630 return getBoolean(a);
632 // return preference or default
633 boolean prefVal = pref != null ? Cache.getDefault(pref, def) : false;
634 return pref != null ? (invertPref ? !prefVal : prefVal) : def;
637 public class ArgInfo implements Comparable<ArgInfo>
641 private String value;
643 private SubVals subVals;
645 private int argIndex;
647 public ArgInfo(Arg arg, String value, SubVals subVals, int argIndex)
651 this.subVals = subVals;
652 this.argIndex = argIndex;
660 public String value()
665 public SubVals subVals()
670 public int argIndex()
676 public int compareTo(ArgInfo ai2)
678 return Integer.compare(this.argIndex(), ai2.argIndex());
682 public static enum Position