performed javacscript:fix and worked on documentation
[taxeditor.git] / taxeditor-store / src / main / java / eu / etaxonomy / taxeditor / parser / ParseHandler.java
1 /**
2 *
3 */
4 package eu.etaxonomy.taxeditor.parser;
5
6 import java.lang.reflect.Method;
7 import java.util.ArrayList;
8 import java.util.List;
9
10 import org.eclipse.swt.widgets.Control;
11
12 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
13 import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
14 import eu.etaxonomy.cdm.model.name.NonViralName;
15 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
16 import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;
17 import eu.etaxonomy.cdm.model.reference.ReferenceBase;
18 import eu.etaxonomy.cdm.strategy.match.MatchException;
19 import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
20 import eu.etaxonomy.taxeditor.preference.PreferencesUtil;
21 import eu.etaxonomy.taxeditor.store.CdmStore;
22 import eu.etaxonomy.taxeditor.store.StoreUtil;
23
24 /**
25 * <p>ParseHandler class.</p>
26 *
27 * @author n.hoffmann
28 * @version $Id: $
29 */
30 public class ParseHandler{
31
32 private TaxonNameBase taxonNameBase;
33
34 private List<INomenclaturalReference> duplicateReferences;
35 private List<INomenclaturalReference> duplicateInReferences;
36
37 private List<TaxonNameBase> duplicateNames;
38
39 private List<TeamOrPersonBase> duplicateCombinationAuthorTeams;
40 private List<TeamOrPersonBase> duplicateExCombinationAuthorTeams;
41 private List<TeamOrPersonBase> duplicateBasionymAuthorTeams;
42 private List<TeamOrPersonBase> duplicateExBasionymAuthorTeams;
43
44 private static NonViralNameParserImpl nonViralNameParser = NonViralNameParserImpl.NewInstance();
45
46 /**
47 * The name that should get parsed
48 */
49 private NonViralName name;
50
51 /**
52 * The widget, the name got entered in
53 */
54 private Control textWidget;
55
56 private boolean doResolveInReferences;
57
58 /**
59 * Creates a new instance
60 *
61 * @param textWidget
62 * @param name
63 */
64 private ParseHandler(Control textWidget, TaxonNameBase name){
65 if(textWidget != null){
66 this.textWidget = textWidget;
67 checkControlHasText();
68 }else{
69 throw new IllegalArgumentException("text widget must not be null");
70 }
71
72 if(name == null){
73 this.name = nonViralNameParser.getNonViralNameInstance("", PreferencesUtil.getPreferredNomenclaturalCode());
74 }else{
75 this.name = (NonViralName) HibernateProxyHelper.deproxy(name);
76 }
77 }
78
79 /**
80 * Factory method to create a new instance of the this class
81 *
82 * @param textWidget The text widget where the NonViralName may be entered into
83 * @param name An initial NonViralName or null when creating a new name
84 * @return An instance of this class
85 */
86 public static ParseHandler NewInstance(Control textWidget, TaxonNameBase name){
87 return new ParseHandler(textWidget, name);
88
89 }
90
91 /**
92 * Parses a given string and returns a <code>TaxonNameBase</code> instance with the
93 * reuslts of the parsing.
94 *
95 * This method should be used to quickly create a new name from a string.
96 * Wherever the string will be parsed again in subsequent editing, an instance
97 * of <code>ParseHandler</code> should be attached to the text widget.
98 *
99 * @param unparsedNameString a {@link java.lang.String} object.
100 * @return a {@link eu.etaxonomy.cdm.model.name.TaxonNameBase} object.
101 */
102 public static TaxonNameBase quickParse(String unparsedNameString){
103 TaxonNameBase name = nonViralNameParser.parseReferencedName(unparsedNameString,
104 PreferencesUtil.getPreferredNomenclaturalCode(), null);
105
106 // if (name.hasProblem()) {
107 // name.setFullTitleCache(unparsedNameString);
108 // }
109
110 return name;
111 }
112
113 /**
114 * Creates an empty <code>TaxonNameBase</code> instance with the nomenclatural code
115 * currently set in preferences.
116 *
117 * @return a {@link eu.etaxonomy.cdm.model.name.TaxonNameBase} object.
118 */
119 public static TaxonNameBase createEmptyName(){
120 return nonViralNameParser.getNonViralNameInstance("", PreferencesUtil.getPreferredNomenclaturalCode());
121 }
122
123 /**
124 * Check if the given control has a getText() method
125 */
126 private void checkControlHasText(){
127 Class clazz = textWidget.getClass();
128
129 try {
130 clazz.getDeclaredMethod("getText", null);
131 } catch (SecurityException e) {
132 } catch (NoSuchMethodException e) {
133 throw new IllegalArgumentException("Given composite does not have a getText method");
134 }
135 }
136
137 /**
138 * Parses the string that was entered into the text widget and returns a
139 * NonViralName object that resulted from the parsing process.
140 *
141 * @return The parsed NonViralName object
142 */
143 public NonViralName parse(){
144
145
146 String unparsedNameString = "";
147 try {
148 Method getText;
149 getText = textWidget.getClass().getDeclaredMethod("getText", null);
150 unparsedNameString = (String) getText.invoke(textWidget, null);
151 } catch (Exception e) {
152 // we should never get here
153 StoreUtil.error(this.getClass(), "Error trying to invoke getText method", e);
154 }
155
156
157 nonViralNameParser.parseReferencedName(name, unparsedNameString,
158 name.getRank(), true);
159
160 // if (name.hasProblem()) {
161 // name.setFullTitleCache(unparsedNameString);
162 // }
163
164 return name;
165 }
166
167 /**
168 * Parses the string that was entered into the text widget and returns a
169 * NonViralName object that resulted from the parsing process.
170 *
171 * The atomized fields (scientific name, author and reference) will be matched
172 * against the database to find possible duplicates. If duplicates were found
173 * the respective parts of the NonViralName will be replaced with the found
174 * objects.
175 *
176 * @return The parsed NonViralName object
177 */
178 public NonViralName parseAndResolveDuplicates(){
179
180 parse();
181
182 findMatches(name);
183
184 resolveDuplicates(name);
185
186 return name;
187 }
188
189
190
191
192 /**
193 * @param name The name to resolve duplicates for.
194 */
195 private void resolveDuplicates(NonViralName name) {
196 resolveDuplicateNames(name);
197
198 resolveAllDuplicateAuthors(name);
199
200 resolveDuplicateReferences(name);
201
202 if(duplicateInReferences != null)
203 resolveDuplicateInReferences(name);
204 }
205
206
207 /**
208 * @param name The name to resolve duplicates for.
209 */
210 private void resolveDuplicateNames(NonViralName name) {
211
212 if (duplicateNames.size() == 1){
213 name = (NonViralName) duplicateNames.iterator().next();
214 }else if(duplicateNames.size() > 1){
215 // FIXME TODO resolve multiple duplications. Use first match for a start
216 name = (NonViralName) duplicateNames.iterator().next();
217 }
218 }
219
220 /**
221 * @param name The name to resolve duplicates for.
222 */
223 private void resolveDuplicateReferences(NonViralName name) {
224 if(duplicateReferences.size() == 1){
225 // exactly one match. We assume that the user wants this reference
226 INomenclaturalReference duplicate = duplicateReferences.iterator().next();
227 name.setNomenclaturalReference(duplicate);
228 }else if(duplicateReferences.size() > 1){
229 // FIXME TODO resolve multiple duplications. Use first match for a start
230 INomenclaturalReference duplicate = duplicateReferences.iterator().next();
231 name.setNomenclaturalReference(duplicate);
232 }
233 }
234
235 /**
236 * @param name The name to resolve duplicates for.
237 */
238 private void resolveDuplicateInReferences(NonViralName name) {
239 ReferenceBase reference = (ReferenceBase) HibernateProxyHelper.deproxy(name.getNomenclaturalReference());
240
241 if(duplicateInReferences.size() > 0){
242 ReferenceBase inReference = (ReferenceBase) duplicateInReferences.iterator().next();
243 reference.setInReference(inReference);
244 StoreUtil.warn(this.getClass(), reference.generateTitle());
245 // FIXME TODO resolve multiple duplications. We use first match for a start
246 StoreUtil.warn(this.getClass(), reference.getTitleCache());
247 }
248 }
249
250
251 /**
252 * @param name The name to resolve duplicates for.
253 */
254 private void resolveAllDuplicateAuthors(NonViralName name) {
255
256 if(duplicateCombinationAuthorTeams.size() > 0){
257 name.setCombinationAuthorTeam(duplicateCombinationAuthorTeams.iterator().next());
258 ReferenceBase reference = (ReferenceBase) name.getNomenclaturalReference();
259 if(reference != null){
260 reference.setAuthorTeam(duplicateCombinationAuthorTeams.iterator().next());
261 }
262 // FIXME TODO resolve multiple duplications. We use first match for a start.
263 }
264
265 if(duplicateExCombinationAuthorTeams.size() > 0){
266 name.setExCombinationAuthorTeam(duplicateExCombinationAuthorTeams.iterator().next());
267 // FIXME TODO resolve multiple duplications. We use first match for a start.
268 }
269
270 if(duplicateBasionymAuthorTeams.size() > 0){
271 name.setBasionymAuthorTeam(duplicateBasionymAuthorTeams.iterator().next());
272 // FIXME TODO resolve multiple duplications. We use first match for a start.
273 }
274
275 if(duplicateExBasionymAuthorTeams.size() > 0){
276 name.setExBasionymAuthorTeam(duplicateExBasionymAuthorTeams.iterator().next());
277 // FIXME TODO resolve multiple duplications. We use first match for a start.
278 }
279 }
280
281 /**
282 * Splits a NonViralName into its parts and calls methods to find matches for these
283 * parts in the database.
284 *
285 * @param name The NonViralName to find matches for.
286 */
287 private void findMatches(NonViralName name){
288
289 duplicateNames = findMatchingLatinNames(name);
290
291 duplicateCombinationAuthorTeams = findMatchingAuthors((TeamOrPersonBase) name.getCombinationAuthorTeam());
292 duplicateExCombinationAuthorTeams = findMatchingAuthors((TeamOrPersonBase) name.getExCombinationAuthorTeam());
293 duplicateBasionymAuthorTeams = findMatchingAuthors((TeamOrPersonBase) name.getBasionymAuthorTeam());
294 duplicateExBasionymAuthorTeams = findMatchingAuthors((TeamOrPersonBase) name.getExBasionymAuthorTeam());
295
296 INomenclaturalReference nomenclaturalReference = name.getNomenclaturalReference();
297
298 // check if the reference has an inreference and also check if the inReference already exists
299 if(nomenclaturalReference != null){
300 ReferenceBase inReference = ((ReferenceBase)nomenclaturalReference).getInReference();
301 if(inReference != null){
302 doResolveInReferences = true;
303 duplicateInReferences = findMatchingNomenclaturalReference(inReference);
304 }
305 }
306
307 duplicateReferences = findMatchingNomenclaturalReference(nomenclaturalReference);
308 }
309
310 /**
311 * @param nomenclaturalReference The NomenclaturalReference to find matches for.
312 * @return A <code>List</code> of possibly matching NomenclaturalReference's.
313 */
314 private List<INomenclaturalReference> findMatchingNomenclaturalReference(INomenclaturalReference nomenclaturalReference) {
315 if(nomenclaturalReference == null) return new ArrayList<INomenclaturalReference>();
316 try{
317 return CdmStore.getCommonService().findMatching(nomenclaturalReference, MatchStrategyConfigurator.ReferenceMatchStrategy());
318 }catch (MatchException e) {
319 StoreUtil.error(this.getClass(), "Error finding matching references", e);
320 }
321 return null;
322 }
323
324 /**
325 * @param authorTeam The TeamOrPersonBase to find matches for.
326 * @return A <code>List</code> of possibly matching TeamOrPersonBase's.
327 */
328 private List<TeamOrPersonBase> findMatchingAuthors(TeamOrPersonBase authorTeam) {
329
330 if(authorTeam == null){
331 return new ArrayList<TeamOrPersonBase>();
332 }
333
334 try{
335 return CdmStore.getCommonService().findMatching(authorTeam, MatchStrategyConfigurator.TeamOrPersonMatchStrategy());
336 }catch (MatchException e) {
337 StoreUtil.error(this.getClass(), "Error finding matching authors", e);
338 }
339 return null;
340 }
341
342 /**
343 * @param taxonNameBase The TaxonNameBase to find matches for.
344 * @return A <code>List</code> of possibly matching TaxonNameBase's.
345 */
346 private List<TaxonNameBase> findMatchingLatinNames(TaxonNameBase taxonNameBase) {
347
348 try {
349 return CdmStore.getCommonService().findMatching(taxonNameBase, MatchStrategyConfigurator.NonViralNameMatchStrategy());
350
351 } catch (MatchException e) {
352 StoreUtil.error(this.getClass(), "Error finding matching names", e);
353 }
354 return null;
355 }
356
357 /**
358 * <p>Getter for the field <code>textWidget</code>.</p>
359 *
360 * @return The Control this ParseHandler is attached to.
361 */
362 public Control getTextWidget() {
363 return textWidget;
364 }
365
366 /**
367 * <p>Setter for the field <code>textWidget</code>.</p>
368 *
369 * @param textWidget The textWidget to set
370 */
371 public void setTextWidget(Control textWidget) {
372 this.textWidget = textWidget;
373 checkControlHasText();
374 }
375 }