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.Collections;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Locale;
32 import jalview.bin.Cache;
33 import jalview.bin.Console;
34 import jalview.bin.argparser.Arg.Opt;
35 import jalview.bin.argparser.Arg.Type;
36 import jalview.util.FileUtils;
39 * Helper class to allow easy extraction of information about specific argument
40 * values (without having to check for null etc all the time)
42 public class ArgValuesMap
44 private List<ArgInfo> argInfoList = new ArrayList<>();
46 protected Map<Arg, ArgValues> m;
48 private String linkedId;
50 protected ArgValuesMap(String linkedId)
52 this.linkedId = linkedId;
56 protected ArgValuesMap(String linkedId, Map<Arg, ArgValues> map)
58 this.linkedId = linkedId;
62 public String getLinkedId()
67 private Map<Arg, ArgValues> getMap()
74 m = new HashMap<Arg, ArgValues>();
77 private void newArg(Arg a)
82 m.put(a, new ArgValues(a));
85 public ArgValues getArgValues(Arg a)
87 return m == null ? null : m.get(a);
90 public ArgValues getOrCreateArgValues(Arg a)
92 ArgValues avs = m.get(a);
95 return getArgValues(a);
98 public List<ArgValue> getArgValueList(Arg a)
100 ArgValues avs = getArgValues(a);
101 return avs == null ? new ArrayList<>() : avs.getArgValueList();
104 public ArgValue getArgValue(Arg a)
106 List<ArgValue> vals = getArgValueList(a);
107 return (vals == null || vals.size() == 0) ? null : vals.get(0);
110 public String getValue(Arg a)
112 ArgValue av = getArgValue(a);
113 return av == null ? null : av.getValue();
116 public boolean containsArg(Arg a)
118 if (m == null || !m.containsKey(a))
120 return a.hasOption(Opt.STRING) ? getArgValue(a) != null : true;
123 public boolean hasValue(Arg a, String val)
125 if (m == null || !m.containsKey(a))
127 for (ArgValue av : getArgValueList(a))
129 String avVal = av.getValue();
130 if ((val == null && avVal == null)
131 || (val != null && val.equals(avVal)))
139 public boolean getBoolean(Arg a)
141 ArgValues av = getArgValues(a);
142 return av == null ? false : av.getBoolean();
145 public Set<Arg> getArgKeys()
150 public ArgValue getArgValueOfArgWithSubValKey(Arg a, String svKey)
152 return getArgValueOfArgWithSubValKey(a, svKey, false);
155 public ArgValue getArgValueOfArgWithSubValKey(Arg a, String svKey,
158 ArgValues avs = this.getArgValues(a);
163 List<ArgValue> compareAvs = avs.getArgValueList();
164 for (int i = 0; i < compareAvs.size(); i++)
166 int index = last ? compareAvs.size() - 1 - i : i;
167 ArgValue av = compareAvs.get(index);
168 SubVals sv = av.getSubVals();
169 if (sv.has(svKey) && !sv.get(svKey).equals("false"))
177 public ArgValue getClosestPreviousArgValueOfArg(ArgValue thisAv, Arg a)
179 ArgValue closestAv = null;
180 int thisArgIndex = thisAv.getArgIndex();
181 ArgValues compareAvs = this.getArgValues(a);
182 int closestPreviousIndex = -1;
183 for (ArgValue av : compareAvs.getArgValueList())
185 int argIndex = av.getArgIndex();
186 if (argIndex < thisArgIndex && argIndex > closestPreviousIndex)
188 closestPreviousIndex = argIndex;
195 public ArgValue getClosestNextArgValueOfArg(ArgValue thisAv, Arg a,
198 // this looks for the *next* arg that *might* be referring back to
199 // a thisAv. Such an arg would have no subValues (if it does it should
200 // specify an id in the subValues so wouldn't need to be guessed).
201 ArgValue closestAv = null;
202 int thisArgIndex = thisAv.getArgIndex();
205 ArgValues compareAvs = this.getArgValues(a);
206 int closestNextIndex = Integer.MAX_VALUE;
207 for (ArgValue av : compareAvs.getArgValueList())
209 int argIndex = av.getArgIndex();
210 if (argIndex > thisArgIndex && argIndex < closestNextIndex)
212 closestNextIndex = argIndex;
217 // check if withinType this closestAv doesn't belong to the next primary arg
219 if (withinType && closestAv != null)
221 int nextPrimaryArgOfSameTypeIndex = Integer.MAX_VALUE;
222 for (Arg tmpA : this.getArgKeys())
224 // interested in Opt.PRIMARY args of the same type
225 if (tmpA.getType() == a.getType() && tmpA.hasOption(Opt.PRIMARY))
227 for (ArgValue tmpAv : getArgValueList(tmpA))
229 int tmpArgIndex = tmpAv.getArgIndex();
230 if (tmpArgIndex > thisArgIndex
231 && tmpArgIndex < nextPrimaryArgOfSameTypeIndex)
233 nextPrimaryArgOfSameTypeIndex = tmpArgIndex;
238 if (nextPrimaryArgOfSameTypeIndex < closestAv.getArgIndex())
240 // looks licke closestAv actually belongs to a different primary Arg
248 // TODO this is incomplete and currently unused (fortunately)
249 public ArgValue[] getArgValuesReferringTo(String key, String value, Arg a)
251 // this looks for the *next* arg that *might* be referring back to
252 // a thisAv. Such an arg would have no subValues (if it does it should
253 // specify an id in the subValues so wouldn't need to be guessed).
254 List<ArgValue> avList = new ArrayList<>();
255 Arg[] args = a == null ? (Arg[]) this.getMap().keySet().toArray()
258 for (Arg keyArg : args)
260 for (ArgValue av : this.getArgValueList(keyArg))
265 return (ArgValue[]) avList.toArray();
268 public boolean hasId(Arg a, String id)
270 ArgValues avs = this.getArgValues(a);
271 return avs == null ? false : avs.hasId(id);
274 public ArgValue getId(Arg a, String id)
276 ArgValues avs = this.getArgValues(a);
277 return avs == null ? null : avs.getId(id);
281 * This method returns the basename of the first --append or --open value.
282 * Used primarily for substitutions in output filenames.
284 public String getBasename()
286 return getDirBasenameOrExtension(false, false, false);
290 * This method returns the basename of the first --append or --open value.
291 * Used primarily for substitutions in output filenames.
293 public String getExtension()
295 return getDirBasenameOrExtension(false, true, false);
299 * This method returns the dirname of the first --append or --open value.
300 * Used primarily for substitutions in output filenames.
302 public String getDirname()
304 return getDirBasenameOrExtension(true, false, false);
307 public String getDirBasenameOrExtension(boolean dirname,
308 boolean extension, boolean absoluteDirname)
310 String filename = null;
311 String appendVal = getValue(Arg.APPEND);
312 String openVal = getValue(Arg.OPEN);
313 if (appendVal != null)
314 filename = appendVal;
315 if (filename == null && openVal != null)
317 if (filename == null)
320 File file = new File(filename);
323 return FileUtils.getDirname(file);
325 return extension ? FileUtils.getExtension(file)
326 : FileUtils.getBasename(file);
330 * Checks if there is an Arg with Opt
332 public boolean hasArgWithOption(Opt o)
334 for (Arg a : getArgKeys())
343 * ArgInfo is a more straightforward list of arguments and their info
346 public void addArgInfo(Arg arg, String value, SubVals subVals,
349 argInfoList.add(new ArgInfo(arg, value, subVals, argIndex));
352 public List<ArgInfo> getArgInfoList()
354 Collections.sort(argInfoList);
359 * get from following Arg of type a or subval of same name (lowercase)
361 public String getValueFromSubValOrArg(ArgValue av, Arg a, SubVals sv)
363 return getFromSubValArgOrPref(av, a, sv, null, null, null);
367 * get from following Arg of type a or subval key or preference pref or
370 public String getFromSubValArgOrPref(ArgValue av, Arg a, SubVals sv,
371 String key, String pref, String def)
373 return getFromSubValArgOrPref(a, ArgValuesMap.Position.AFTER, av, sv,
378 * get from following(AFTER), first occurence of (FIRST) or previous (BEFORE)
379 * Arg of type a or subval key or preference pref or default def
381 public String getFromSubValArgOrPref(Arg a, ArgValuesMap.Position pos,
382 ArgValue av, SubVals sv, String key, String pref, String def)
384 return getFromSubValArgOrPrefWithSubstitutions(null, a, pos, av, sv,
388 public String getFromSubValArgOrPrefWithSubstitutions(ArgParser ap, Arg a,
389 ArgValuesMap.Position pos, ArgValue av, SubVals sv, String key,
390 String pref, String def)
392 return getFromSubValArgOrPrefWithSubstitutionsWithinType(ap, a, pos, av,
393 sv, key, pref, def, true);
396 public String getFromSubValArgOrPrefWithSubstitutionsWithinType(
397 ArgParser ap, Arg a, ArgValuesMap.Position pos, ArgValue av,
398 SubVals sv, String key, String pref, String def,
404 if (sv != null && sv.has(key) && sv.get(key) != null)
406 value = ap == null ? sv.get(key)
407 : sv.getWithSubstitutions(ap, getLinkedId(), key);
409 else if (containsArg(a))
411 if (pos == ArgValuesMap.Position.FIRST && getValue(a) != null)
413 else if (pos == ArgValuesMap.Position.BEFORE
414 && getClosestPreviousArgValueOfArg(av, a) != null)
415 value = getClosestPreviousArgValueOfArg(av, a).getValue();
416 else if (pos == ArgValuesMap.Position.AFTER
417 && getClosestNextArgValueOfArg(av, a, withinType) != null)
418 value = getClosestNextArgValueOfArg(av, a, withinType).getValue();
420 // look for allstructures subval for Type.STRUCTURE
421 Arg arg = av.getArg();
422 if (value == null && arg.hasOption(Opt.PRIMARY)
423 && arg.getType() == Type.STRUCTURE
424 && !a.hasOption(Opt.PRIMARY) && (a.getType() == Type.STRUCTURE
425 // || a.getType() == Type.STRUCTUREIMAGE))
428 ArgValue av2 = getArgValueOfArgWithSubValKey(a,
429 Arg.ALLSTRUCTURES.getName());
432 value = av2.getValue();
438 value = pref != null ? Cache.getDefault(pref, def) : def;
443 public boolean getBoolFromSubValOrArg(Arg a, SubVals sv)
445 return getFromSubValArgOrPref(a, sv, null, null, false);
448 public boolean getFromSubValArgOrPref(Arg a, SubVals sv, String key,
449 String pref, boolean def)
451 return getFromSubValArgOrPref(a, sv, key, pref, def, false);
454 public boolean getFromSubValArgOrPref(Arg a, SubVals sv, String key,
455 String pref, boolean def, boolean invertPref)
457 if ((key == null && a == null) || (sv == null && a == null))
460 boolean usingArgKey = false;
467 String nokey = ArgParser.NEGATESTRING + key;
469 // look for key or nokey in subvals first (if using Arg check options)
472 // check for true boolean
473 if (sv.has(key) && sv.get(key) != null)
477 if (!(a.hasOption(Opt.BOOLEAN) || a.hasOption(Opt.UNARY)))
480 "Looking for boolean in subval from non-boolean/non-unary Arg "
485 return sv.get(key).toLowerCase(Locale.ROOT).equals("true");
488 // check for negative boolean (subval "no..." will be "true")
489 if (sv.has(nokey) && sv.get(nokey) != null)
493 if (!(a.hasOption(Opt.BOOLEAN)))
496 "Looking for negative boolean in subval from non-boolean Arg "
501 return !sv.get(nokey).toLowerCase(Locale.ROOT).equals("true");
507 return getBoolean(a);
509 // return preference or default
510 boolean prefVal = pref != null ? Cache.getDefault(pref, def) : false;
511 return pref != null ? (invertPref ? !prefVal : prefVal) : def;
514 public class ArgInfo implements Comparable<ArgInfo>
518 private String value;
520 private SubVals subVals;
522 private int argIndex;
524 public ArgInfo(Arg arg, String value, SubVals subVals, int argIndex)
528 this.subVals = subVals;
529 this.argIndex = argIndex;
537 public String value()
542 public SubVals subVals()
547 public int argIndex()
553 public int compareTo(ArgInfo ai2)
555 return Integer.compare(this.argIndex(), ai2.argIndex());
559 public static enum Position