JAL-845 code/refactoring/tests related to linking DNA and protein
[jalview.git] / src / jalview / datamodel / SearchResults.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3  * Copyright (C) 2014 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.datamodel;
22
23 import java.util.ArrayList;
24 import java.util.List;
25
26 /**
27  * Holds a list of search result matches, where each match is a contiguous
28  * stretch of a single sequence.
29  * 
30  * @author gmcarstairs
31  *
32  */
33 public class SearchResults
34 {
35
36   private List<Match> matches = new ArrayList<Match>();
37
38   public class Match
39   {
40     SequenceI sequence;
41
42     int start;
43
44     int end;
45
46     public Match(SequenceI seq, int start, int end)
47     {
48       sequence = seq;
49       this.start = start;
50       this.end = end;
51     }
52
53     public SequenceI getSequence()
54     {
55       return sequence;
56     }
57
58     public int getStart()
59     {
60       return start;
61     }
62
63     public int getEnd()
64     {
65       return end;
66     }
67   }
68
69   /**
70    * This method replaces the old search results which merely held an alignment
71    * index of search matches. This broke when sequences were moved around the
72    * alignment
73    * 
74    * @param seq
75    *          Sequence
76    * @param start
77    *          int
78    * @param end
79    *          int
80    */
81   public void addResult(SequenceI seq, int start, int end)
82   {
83     matches.add(new Match(seq, start, end));
84   }
85
86   /**
87    * Quickly check if the given sequence is referred to in the search results
88    * 
89    * @param sequence
90    *          (specific alignment sequence or a dataset sequence)
91    * @return true if the results involve sequence
92    */
93   public boolean involvesSequence(SequenceI sequence)
94   {
95     SequenceI ds = sequence.getDatasetSequence();
96     for (Match m : matches)
97     {
98       if (m.sequence != null
99               && (m.sequence == sequence || m.sequence == ds))
100       {
101         return true;
102       }
103     }
104     return false;
105   }
106
107   /**
108    * This Method returns the search matches which lie between the start and end
109    * points of the sequence in question. It is optimised for returning objects
110    * for drawing on SequenceCanvas
111    */
112   public int[] getResults(SequenceI sequence, int start, int end)
113   {
114     if (matches.isEmpty())
115     {
116       return null;
117     }
118
119     int[] result = null;
120     int[] tmp = null;
121     int resultLength, matchStart = 0, matchEnd = 0;
122     boolean mfound;
123     for (Match m : matches)
124     {
125       mfound = false;
126       if (m.sequence == sequence)
127       {
128         mfound = true;
129         // locate aligned position
130         matchStart = sequence.findIndex(m.start) - 1;
131         matchEnd = sequence.findIndex(m.end) - 1;
132       }
133       else if (m.sequence == sequence.getDatasetSequence())
134       {
135         mfound = true;
136         // locate region in local context
137         matchStart = sequence.findIndex(m.start) - 1;
138         matchEnd = sequence.findIndex(m.end) - 1;
139       }
140       if (mfound)
141       {
142         if (matchStart <= end && matchEnd >= start)
143         {
144           if (matchStart < start)
145           {
146             matchStart = start;
147           }
148
149           if (matchEnd > end)
150           {
151             matchEnd = end;
152           }
153
154           if (result == null)
155           {
156             result = new int[]
157             { matchStart, matchEnd };
158           }
159           else
160           {
161             resultLength = result.length;
162             tmp = new int[resultLength + 2];
163             System.arraycopy(result, 0, tmp, 0, resultLength);
164             result = tmp;
165             result[resultLength] = matchStart;
166             result[resultLength + 1] = matchEnd;
167           }
168         }
169         else
170         {
171           // debug
172           // System.err.println("Outwith bounds!" + matchStart+">"+end +"  or "
173           // + matchEnd+"<"+start);
174         }
175       }
176     }
177     return result;
178   }
179
180   public int getSize()
181   {
182     return matches.size();
183   }
184
185   public SequenceI getResultSequence(int index)
186   {
187     return matches.get(index).sequence;
188   }
189
190   /**
191    * Returns the start position of the i'th match in the search results.
192    * 
193    * @param i
194    * @return
195    */
196   public int getResultStart(int i)
197   {
198     return matches.get(i).start;
199   }
200
201   /**
202    * Returns the end position of the i'th match in the search results.
203    * 
204    * @param i
205    * @return
206    */
207   public int getResultEnd(int i)
208   {
209     return matches.get(i).end;
210   }
211
212   /**
213    * Returns true if no search result matches are held.
214    * 
215    * @return
216    */
217   public boolean isEmpty()
218   {
219     return matches.isEmpty();
220   }
221
222   /**
223    * Returns the list of matches.
224    * 
225    * @return
226    */
227   public List<Match> getResults()
228   {
229     return matches;
230   }
231 }