find incrementally searches ID then subsequence matches.
[jalview.git] / src / jalview / analysis / Finder.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Development Version 2.4.1)
3  * Copyright (C) 2009 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.analysis;
20
21 import java.util.*;
22
23 import jalview.datamodel.*;
24
25 public class Finder
26 {
27   /**
28    * Implements the search algorithms for the Find dialog box.
29    */
30   SearchResults searchResults;
31
32   AlignmentI alignment;
33
34   jalview.datamodel.SequenceGroup selection = null;
35
36   Vector idMatch = null;
37
38   boolean caseSensitive = false;
39
40   boolean findAll = false;
41
42   com.stevesoft.pat.Regex regex = null;
43
44   /**
45    * hold's last-searched position between calles to find(false)
46    */
47   int seqIndex = 0, resIndex = -1;
48
49   public Finder(AlignmentI alignment, SequenceGroup selection)
50   {
51     this.alignment = alignment;
52     this.selection = selection;
53   }
54
55   /**
56    * restart search at given sequence and residue on alignment and (optionally) contained in selection
57    * @param alignment
58    * @param selectionGroup
59    * @param seqIndex
60    * @param resIndex
61    */
62   public Finder(AlignmentI alignment, SequenceGroup selectionGroup,
63           int seqIndex, int resIndex)
64   {
65     this(alignment, selectionGroup);
66     this.seqIndex = seqIndex;
67     this.resIndex = resIndex;
68   }
69
70   public boolean find(String searchString)
71   {
72     boolean hasResults = false;
73     if (!caseSensitive)
74     {
75       searchString = searchString.toUpperCase();
76     }
77     regex = new com.stevesoft.pat.Regex(searchString);
78     regex.setIgnoreCase(!caseSensitive);
79     searchResults = new SearchResults();
80     idMatch = new Vector();
81     Sequence seq;
82     String item = null;
83     boolean found = false;
84
85     // //// is the searchString a residue number?
86     try
87     {
88       int res = Integer.parseInt(searchString);
89       found = true;
90       if (selection == null || selection.getSize() < 1)
91       {
92         seq = (Sequence) alignment.getSequenceAt(0);
93       }
94       else
95       {
96         seq = (Sequence) (selection.getSequenceAt(0));
97       }
98
99       searchResults.addResult(seq, res, res);
100       hasResults = true;
101     } catch (NumberFormatException ex)
102     {
103     }
104
105     // /////////////////////////////////////////////
106
107     int end = alignment.getHeight();
108
109     if (selection != null)
110     {
111       if ((selection.getSize() < 1)
112               || ((selection.getEndRes() - selection.getStartRes()) < 2))
113       {
114         selection = null;
115       }
116     }
117
118     while (!found && (seqIndex < end))
119     {
120       seq = (Sequence) alignment.getSequenceAt(seqIndex);
121
122       if ((selection != null && selection.getSize()>0)
123               && !selection.getSequences(null).contains(seq))
124       {
125         seqIndex++;
126         resIndex = -1;
127
128         continue;
129       }
130       if (resIndex<0) {
131         resIndex=0;
132         if (regex.search(seq.getName()))
133         {
134           idMatch.addElement(seq);
135           hasResults = true;
136           if (!findAll)
137           {
138             // stop and return the match
139             found=true;
140             break;
141           }
142         }
143       }
144       item = seq.getSequenceAsString();
145
146       if ((selection != null)
147               && (selection.getEndRes() < alignment.getWidth() - 1))
148       {
149         item = item.substring(0, selection.getEndRes() + 1);
150       }
151
152       // /Shall we ignore gaps???? - JBPNote: Add Flag for forcing this or not
153       StringBuffer noGapsSB = new StringBuffer();
154       int insertCount = 0;
155       Vector spaces = new Vector();
156
157       for (int j = 0; j < item.length(); j++)
158       {
159         if (!jalview.util.Comparison.isGap(item.charAt(j)))
160         {
161           noGapsSB.append(item.charAt(j));
162           spaces.addElement(new Integer(insertCount));
163         }
164         else
165         {
166           insertCount++;
167         }
168       }
169
170       String noGaps = noGapsSB.toString();
171
172       for (int r = resIndex; r < noGaps.length(); r++)
173       {
174
175         if (regex.searchFrom(noGaps, r))
176         {
177           resIndex = regex.matchedFrom();
178
179           if ((selection != null && selection.getSize()>0)
180                   && ((resIndex + Integer.parseInt(spaces.elementAt(
181                           resIndex).toString())) < selection.getStartRes()))
182           {
183             continue;
184           }
185
186           int sres = seq
187                   .findPosition(resIndex
188                           + Integer.parseInt(spaces.elementAt(resIndex)
189                                   .toString()));
190           int eres = seq.findPosition(regex.matchedTo()
191                   - 1
192                   + Integer.parseInt(spaces
193                           .elementAt(regex.matchedTo() - 1).toString()));
194
195           searchResults.addResult(seq, sres, eres);
196           hasResults = true;
197           if (!findAll)
198           {
199             // thats enough, break and display the result
200             found = true;
201             resIndex++;
202
203             break;
204           }
205
206           r = resIndex;
207         }
208         else
209         {
210           break;
211         }
212       }
213
214       if (!found)
215       {
216         seqIndex++;
217         resIndex = -1;
218       }
219     }
220
221     /**
222      * We now search the Id string in the main search loop.
223      * for (int id = 0; id < alignment.getHeight(); id++)
224     {
225       if (regex.search(alignment.getSequenceAt(id).getName()))
226       {
227         idMatch.addElement(alignment.getSequenceAt(id));
228         hasResults = true;
229       }
230     } */
231     return hasResults;
232   }
233
234   /**
235    * @return the alignment
236    */
237   public AlignmentI getAlignment()
238   {
239     return alignment;
240   }
241
242   /**
243    * @param alignment
244    *                the alignment to set
245    */
246   public void setAlignment(AlignmentI alignment)
247   {
248     this.alignment = alignment;
249   }
250
251   /**
252    * @return the caseSensitive
253    */
254   public boolean isCaseSensitive()
255   {
256     return caseSensitive;
257   }
258
259   /**
260    * @param caseSensitive
261    *                the caseSensitive to set
262    */
263   public void setCaseSensitive(boolean caseSensitive)
264   {
265     this.caseSensitive = caseSensitive;
266   }
267
268   /**
269    * @return the findAll
270    */
271   public boolean isFindAll()
272   {
273     return findAll;
274   }
275
276   /**
277    * @param findAll
278    *                the findAll to set
279    */
280   public void setFindAll(boolean findAll)
281   {
282     this.findAll = findAll;
283   }
284
285   /**
286    * @return the selection
287    */
288   public jalview.datamodel.SequenceGroup getSelection()
289   {
290     return selection;
291   }
292
293   /**
294    * @param selection
295    *                the selection to set
296    */
297   public void setSelection(jalview.datamodel.SequenceGroup selection)
298   {
299     this.selection = selection;
300   }
301
302   /**
303    * @return the idMatch
304    */
305   public Vector getIdMatch()
306   {
307     return idMatch;
308   }
309
310   /**
311    * @return the regex
312    */
313   public com.stevesoft.pat.Regex getRegex()
314   {
315     return regex;
316   }
317
318   /**
319    * @return the searchResults
320    */
321   public SearchResults getSearchResults()
322   {
323     return searchResults;
324   }
325
326   /**
327    * @return the resIndex
328    */
329   public int getResIndex()
330   {
331     return resIndex;
332   }
333
334   /**
335    * @param resIndex
336    *                the resIndex to set
337    */
338   public void setResIndex(int resIndex)
339   {
340     this.resIndex = resIndex;
341   }
342
343   /**
344    * @return the seqIndex
345    */
346   public int getSeqIndex()
347   {
348     return seqIndex;
349   }
350
351   /**
352    * @param seqIndex
353    *                the seqIndex to set
354    */
355   public void setSeqIndex(int seqIndex)
356   {
357     this.seqIndex = seqIndex;
358   }
359 }