JAL-1807 Bob's JalviewJS prototype first commit
[jalviewjs.git] / src / jalview / analysis / Finder.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.analysis;
22
23 import jalview.datamodel.AlignmentI;
24 import jalview.datamodel.SearchResults;
25 import jalview.datamodel.Sequence;
26 import jalview.datamodel.SequenceGroup;
27 import jalview.jsdev.RegExp;
28 import jalview.jsdev.api.RegExpInterface;
29 import jalview.util.Comparison;
30
31 import java.util.Vector;
32
33 //import com.stevesoft.pat.Regex;
34
35 public class Finder
36 {
37   /**
38    * Implements the search algorithms for the Find dialog box.
39    */
40   SearchResults searchResults;
41
42   AlignmentI alignment;
43
44   SequenceGroup selection = null;
45
46   Vector idMatch = null;
47
48   boolean caseSensitive = false;
49
50   private boolean includeDescription = false;
51
52   boolean findAll = false;
53
54   RegExpInterface regex = null;
55
56   /**
57    * hold's last-searched position between calles to find(false)
58    */
59   int seqIndex = 0, resIndex = -1;
60
61   public Finder(AlignmentI alignment, SequenceGroup selection)
62   {
63     this.alignment = alignment;
64     this.selection = selection;
65   }
66
67   /**
68    * restart search at given sequence and residue on alignment and (optionally)
69    * contained in selection
70    * 
71    * @param alignment
72    * @param selectionGroup
73    * @param seqIndex
74    * @param resIndex
75    */
76   public Finder(AlignmentI alignment, SequenceGroup selectionGroup,
77           int seqIndex, int resIndex)
78   {
79     this(alignment, selectionGroup);
80     this.seqIndex = seqIndex;
81     this.resIndex = resIndex;
82   }
83
84   public boolean find(String searchString)
85   {
86     boolean hasResults = false;
87     if (!caseSensitive)
88     {
89       searchString = searchString.toUpperCase();
90     }
91     regex = RegExp.newRegex(searchString);
92     regex.setIgnoreCase(!caseSensitive);
93     searchResults = new SearchResults();
94     idMatch = new Vector();
95     Sequence seq;
96     String item = null;
97     boolean found = false;
98     int end = alignment.getHeight();
99
100     // /////////////////////////////////////////////
101
102     if (selection != null)
103     {
104       if ((selection.getSize() < 1)
105               || ((selection.getEndRes() - selection.getStartRes()) < 2))
106       {
107         selection = null;
108       }
109     }
110
111     while (!found && (seqIndex < end))
112     {
113       seq = (Sequence) alignment.getSequenceAt(seqIndex);
114
115       if ((selection != null && selection.getSize() > 0)
116               && !selection.getSequences(null).contains(seq))
117       {
118         seqIndex++;
119         resIndex = -1;
120
121         continue;
122       }
123       if (resIndex < 0)
124       {
125         resIndex = 0;
126         // test for one off matches - sequence position and sequence ID
127         // //// is the searchString a residue number?
128         try
129         {
130           int res = Integer.parseInt(searchString);
131           // possibly a residue number - check if valid for seq
132           if (seq.getEnd() >= res)
133           {
134             searchResults.addResult(seq, res, res);
135             hasResults = true;
136             // resIndex=seq.getLength();
137             // seqIndex++;
138             if (!findAll)
139             {
140               found = true;
141               break;
142             }
143           }
144         } catch (NumberFormatException ex)
145         {
146         }
147
148         if (regex.search(seq.getName()))
149         {
150           idMatch.addElement(seq);
151           hasResults = true;
152           if (!findAll)
153           {
154             // stop and return the match
155             found = true;
156             break;
157           }
158         }
159
160         if (isIncludeDescription() && seq.getDescription() != null
161                 && regex.search(seq.getDescription()))
162         {
163           idMatch.addElement(seq);
164           hasResults = true;
165           if (!findAll)
166           {
167             // stop and return the match
168             found = true;
169             break;
170           }
171         }
172       }
173       item = seq.getSequenceAsString();
174
175       if ((selection != null)
176               && (selection.getEndRes() < alignment.getWidth() - 1))
177       {
178         item = item.substring(0, selection.getEndRes() + 1);
179       }
180
181       // /Shall we ignore gaps???? - JBPNote: Add Flag for forcing this or not
182       StringBuffer noGapsSB = new StringBuffer();
183       int insertCount = 0;
184       Vector spaces = new Vector();
185
186       for (int j = 0; j < item.length(); j++)
187       {
188         if (!Comparison.isGap(item.charAt(j)))
189         {
190           noGapsSB.append(item.charAt(j));
191           spaces.addElement(new Integer(insertCount));
192         }
193         else
194         {
195           insertCount++;
196         }
197       }
198
199       String noGaps = noGapsSB.toString();
200
201       for (int r = resIndex; r < noGaps.length(); r++)
202       {
203
204         if (regex.searchFrom(noGaps, r))
205         {
206           resIndex = regex.matchedFrom();
207
208           if ((selection != null && selection.getSize() > 0)
209                   && ((resIndex + Integer.parseInt(spaces.elementAt(
210                           resIndex).toString())) < selection.getStartRes()))
211           {
212             continue;
213           }
214 // if invalid string used, then regex has no matched to/from
215           int sres = seq
216                   .findPosition(resIndex
217                           + Integer.parseInt(spaces.elementAt(resIndex)
218                                   .toString()));
219           int eres = seq.findPosition(regex.matchedTo()
220                   - 1
221                   + Integer.parseInt(spaces
222                           .elementAt(regex.matchedTo() - 1).toString()));
223
224           searchResults.addResult(seq, sres, eres);
225           hasResults = true;
226           if (!findAll)
227           {
228             // thats enough, break and display the result
229             found = true;
230             resIndex++;
231
232             break;
233           }
234
235           r = resIndex;
236         }
237         else
238         {
239           break;
240         }
241       }
242
243       if (!found)
244       {
245         seqIndex++;
246         resIndex = -1;
247       }
248     }
249
250     /**
251      * We now search the Id string in the main search loop. for (int id = 0; id
252      * < alignment.getHeight(); id++) { if
253      * (regex.search(alignment.getSequenceAt(id).getName())) {
254      * idMatch.addElement(alignment.getSequenceAt(id)); hasResults = true; } }
255      */
256     return hasResults;
257   }
258
259   /**
260    * @return the alignment
261    */
262   public AlignmentI getAlignment()
263   {
264     return alignment;
265   }
266
267   /**
268    * @param alignment
269    *          the alignment to set
270    */
271   public void setAlignment(AlignmentI alignment)
272   {
273     this.alignment = alignment;
274   }
275
276   /**
277    * @return the caseSensitive
278    */
279   public boolean isCaseSensitive()
280   {
281     return caseSensitive;
282   }
283
284   /**
285    * @param caseSensitive
286    *          the caseSensitive to set
287    */
288   public void setCaseSensitive(boolean caseSensitive)
289   {
290     this.caseSensitive = caseSensitive;
291   }
292
293   /**
294    * @return the findAll
295    */
296   public boolean isFindAll()
297   {
298     return findAll;
299   }
300
301   /**
302    * @param findAll
303    *          the findAll to set
304    */
305   public void setFindAll(boolean findAll)
306   {
307     this.findAll = findAll;
308   }
309
310   /**
311    * @return the selection
312    */
313   public SequenceGroup getSelection()
314   {
315     return selection;
316   }
317
318   /**
319    * @param selection
320    *          the selection to set
321    */
322   public void setSelection(SequenceGroup selection)
323   {
324     this.selection = selection;
325   }
326
327   /**
328    * @return the idMatch
329    */
330   public Vector getIdMatch()
331   {
332     return idMatch;
333   }
334
335   /**
336    * @return the regex
337    */
338   public RegExpInterface getRegex()
339   {
340     return regex;
341   }
342
343   /**
344    * @return the searchResults
345    */
346   public SearchResults getSearchResults()
347   {
348     return searchResults;
349   }
350
351   /**
352    * @return the resIndex
353    */
354   public int getResIndex()
355   {
356     return resIndex;
357   }
358
359   /**
360    * @param resIndex
361    *          the resIndex to set
362    */
363   public void setResIndex(int resIndex)
364   {
365     this.resIndex = resIndex;
366   }
367
368   /**
369    * @return the seqIndex
370    */
371   public int getSeqIndex()
372   {
373     return seqIndex;
374   }
375
376   /**
377    * @param seqIndex
378    *          the seqIndex to set
379    */
380   public void setSeqIndex(int seqIndex)
381   {
382     this.seqIndex = seqIndex;
383   }
384
385   public boolean isIncludeDescription()
386   {
387     return includeDescription;
388   }
389
390   public void setIncludeDescription(boolean includeDescription)
391   {
392     this.includeDescription = includeDescription;
393   }
394 }