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