Merge branch 'develop' into feature/JAL-3416_update_to_flatlaf_3.1.1_with_unpacked_na...
[jalview.git] / src / jalview / bin / argparser / SubVals.java
1 package jalview.bin.argparser;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.List;
6 import java.util.Map;
7
8 import jalview.bin.Console;
9
10 /**
11  * A helper class to parse a string of the possible forms "content"
12  * "[index]content", "[keyName=keyValue]content" and return the integer index,
13  * the strings keyName and keyValue, and the content after the square brackets
14  * (if present). Values not set `will be -1 or null.
15  */
16 public class SubVals
17 {
18   public static int NOTSET = -1;
19
20   private int index = NOTSET;
21
22   private Map<String, String> subValMap;
23
24   private static char SEPARATOR = ',';
25
26   private static char EQUALS = '=';
27
28   private String content = null;
29
30   protected SubVals(SubVals sv, String c)
31   {
32     this(sv, c, true);
33   }
34
35   protected SubVals(SubVals sv, String c, boolean merge)
36   {
37     SubVals subvals;
38     if (merge)
39     {
40       SubVals vsv = new SubVals(c);
41       if (sv != null && sv.getSubValMap() != null)
42       {
43         for (String key : sv.getSubValMap().keySet())
44         {
45           vsv.put(key, sv.get(key));
46         }
47       }
48       if (sv != null && sv.getIndex() > 0)
49       {
50         vsv.index = sv.getIndex();
51       }
52       subvals = vsv;
53     }
54     else
55     {
56       // replace
57       subvals = sv;
58     }
59     if (subvals == null)
60     {
61       this.subValMap = new HashMap<>();
62     }
63     else
64     {
65       this.subValMap = subvals == null ? new HashMap<>()
66               : subvals.getSubValMap();
67       this.index = subvals.getIndex();
68     }
69     this.content = c;
70   }
71
72   protected SubVals(String item)
73   {
74     if (subValMap == null)
75       subValMap = new HashMap<>();
76     this.parseVals(item);
77   }
78
79   public void parseVals(String item)
80   {
81     if (item == null)
82       return;
83     if (item.indexOf('[') == 0 && item.indexOf(']') > 1)
84     {
85       int openBracket = 0;
86       int closeBracket = item.indexOf(']');
87       String subvalsString = item.substring(openBracket + 1, closeBracket);
88       this.content = item.substring(closeBracket + 1);
89       boolean setIndex = false;
90       for (String subvalString : subvalsString
91               .split(Character.toString(SEPARATOR)))
92       {
93         int equals = subvalString.indexOf(EQUALS);
94         if (equals > -1)
95         {
96           this.put(subvalString.substring(0, equals),
97                   subvalString.substring(equals + 1));
98         }
99         else
100         {
101           try
102           {
103             this.index = Integer.parseInt(subvalString);
104             setIndex = true;
105           } catch (NumberFormatException e)
106           {
107             // store this non-numeric key as a "true" value
108             this.put(subvalString, "true");
109           }
110         }
111       }
112       if (!setIndex)
113         this.index = NOTSET;
114       else
115         Console.debug("SubVals from '" + subvalsString + "' has index "
116                 + this.index + " set");
117     }
118     else
119     {
120       this.content = item;
121     }
122   }
123
124   protected void put(String key, String val)
125   {
126     subValMap.put(key, val);
127   }
128
129   public boolean notSet()
130   {
131     // notSet is true if content present but nonsensical
132     return index == NOTSET && (subValMap == null || subValMap.size() == 0);
133   }
134
135   public String getWithSubstitutions(ArgParser ap, String id, String key)
136   {
137     return ap.makeSubstitutions(subValMap.get(key), id);
138   }
139
140   public String get(String key)
141   {
142     return subValMap.get(key);
143   }
144
145   public boolean has(String key)
146   {
147     return subValMap.containsKey(key);
148   }
149
150   public int getIndex()
151   {
152     return index;
153   }
154
155   public String getContent()
156   {
157     return content;
158   }
159
160   protected Map<String, String> getSubValMap()
161   {
162     return subValMap;
163   }
164
165   public String toString()
166   {
167     if (subValMap == null && getIndex() == NOTSET)
168       return "";
169
170     StringBuilder sb = new StringBuilder();
171     List<String> entries = new ArrayList<>();
172     subValMap.entrySet().stream().forEachOrdered(
173             m -> entries.add(m.getValue().equals("true") ? m.getKey()
174                     : new StringBuilder().append(m.getKey()).append(EQUALS)
175                             .append(m.getValue()).toString()));
176     if (getIndex() != NOTSET)
177       entries.add(Integer.toString(getIndex()));
178     sb.append('[');
179     sb.append(String.join(Character.toString(SEPARATOR), entries));
180     sb.append(']');
181     return sb.toString();
182   }
183 }