update author list in license for (JAL-826)
[jalview.git] / src / jalview / io / SimpleBlastFile.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)
3  * Copyright (C) 2011 J Procter, AM Waterhouse, J Engelhardt, LM Lui, G Barton, M Clamp, S Searle
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 of the License, or (at your option) any later version.
10  * 
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.io;
19
20 import java.io.*;
21 import java.util.*;
22
23 import jalview.datamodel.*;
24 import jalview.util.*;
25
26 /**
27  * parse a simple blast report. Attempt to cope with query anchored and pairwise
28  * alignments only.
29  * 
30  * @author Jim Procter
31  */
32
33 public class SimpleBlastFile extends AlignFile
34 {
35   /**
36    * header and footer info goes into alignment annotation.
37    */
38   StringBuffer headerLines, footerLines;
39
40   /**
41    * hold sequence ids in order of appearance in file
42    */
43   Vector seqids;
44
45   public SimpleBlastFile()
46   {
47   }
48
49   public SimpleBlastFile(String inFile, String type) throws IOException
50   {
51     super(inFile, type);
52   }
53
54   public SimpleBlastFile(FileParse source) throws IOException
55   {
56     super(source);
57   }
58
59   public void initData()
60   {
61     super.initData();
62     headerLines = new StringBuffer();
63     footerLines = new StringBuffer();
64     seqids = new Vector();
65   }
66
67   public void parse() throws IOException
68   {
69     String line;
70     char gapc = ' '; // nominal gap character
71     Hashtable seqhash = new Hashtable();
72     boolean inAlignments = false;
73     int padding = -1, numcol = -1, aligcol = -1, lastcol = -1;
74     long qlen = 0, rstart, rend; // total number of query bases so far
75     boolean padseq = false;
76     while ((line = nextLine()) != null)
77     {
78       if (line.indexOf("ALIGNMENTS") == 0)
79       {
80         inAlignments = true;
81       }
82       else
83       {
84         if (inAlignments)
85         {
86           if (line.trim().length() == 0)
87           {
88             continue;
89           }
90           // parse out the sequences
91           // query anchored means that we use the query sequence as the
92           // alignment ruler
93           if (line.indexOf("Query") == 0)
94           {
95             padding = -1;
96             // reset column markers for this block
97             numcol = -1;
98             aligcol = -1;
99             lastcol = -1;
100             // init or reset the column positions
101             for (int p = 5, mLen = line.length(); p < mLen; p++)
102             {
103               char c = line.charAt(p);
104               if (c >= '0' && c <= '9')
105               {
106                 if (numcol == -1)
107                 {
108                   numcol = p;
109                 }
110                 else if (aligcol != -1 && lastcol == -1)
111                 {
112                   lastcol = p;
113                 }
114               }
115               else
116               {
117                 if (c >= 'A' && c <= 'z')
118                 {
119                   if (aligcol == -1)
120                   {
121                     aligcol = p;
122                     padding = -1;
123                   }
124                 }
125                 else
126                 {
127                   if (padding == -1)
128                   {
129                     padding = p; // beginning of last stretch of whitespace
130                   }
131                 }
132               }
133             }
134             if (padding == -1)
135             {
136               padding = aligcol;
137             }
138           }
139           if (line.indexOf("Database:") > -1
140                   || (aligcol == -1 || numcol == -1 || lastcol == -1)
141                   || line.length() < lastcol)
142           {
143             inAlignments = false;
144           }
145           else
146           {
147             // now extract the alignment.
148             String sqid = line.substring(0, numcol).trim();
149             String stindx = line.substring(numcol, aligcol).trim();
150             String aligseg = line.substring(aligcol, padding);
151             String endindx = line.substring(lastcol).trim();
152             // init start/end prior to parsing
153             rstart = 1; // best guess we have
154             rend = 0; // if zero at end of parsing, then we count non-gaps
155             try
156             {
157               rstart = Long.parseLong(stindx);
158             } catch (Exception e)
159             {
160               System.err.println("Couldn't parse '" + stindx
161                       + "' as start of row");
162               // inAlignments = false;
163               // warn for this line
164             }
165             try
166             {
167               rend = Long.parseLong(endindx);
168             } catch (Exception e)
169             {
170               System.err.println("Couldn't parse '" + endindx
171                       + "' as end of row");
172               // inAlignments = false;
173
174               // warn for this line
175             }
176             Vector seqentries = (Vector) seqhash.get(sqid);
177             if (seqentries == null)
178             {
179               seqentries = new Vector();
180               seqhash.put(sqid, seqentries);
181               seqids.addElement(sqid);
182             }
183
184             Object[] seqentry = null;
185             Enumeration sqent = seqentries.elements();
186             while (seqentry == null && sqent.hasMoreElements())
187             {
188               seqentry = (Object[]) sqent.nextElement();
189               if (((long[]) seqentry[1])[1] + 1 != rstart)
190               {
191                 seqentry = null;
192               }
193             }
194             padseq = false;
195             if (seqentry == null)
196             {
197               padseq = true; // prepend gaps to new sequences in this block
198               seqentry = new Object[]
199               { new StringBuffer(), new long[]
200               { rstart, rend } };
201               seqentries.addElement(seqentry);
202               seqhash.put(sqid, seqentry);
203
204             }
205             if (sqid.equals("Query"))
206             {
207               // update current block length in case we need to pad
208               qlen = ((StringBuffer) seqentry[0]).length();
209             }
210             StringBuffer sqs = ((StringBuffer) seqentry[0]);
211             if (padseq)
212             {
213               for (long c = sqs.length(); c < qlen; c++)
214               {
215                 sqs.append(gapc);
216               }
217             }
218             sqs.append(aligseg);
219             if (rend > 0)
220             {
221               ((long[]) seqentry[1])[1] = rend;
222             }
223           }
224           // end of parsing out the sequences
225         }
226         // if we haven't parsed the line as an alignment, then
227         // add to the sequence header
228         if (!inAlignments)
229         {
230           String ln = line.trim();
231           // save any header stuff for the user
232           if (ln.length() > 0)
233           {
234             StringBuffer addto = (seqhash.size() > 0) ? footerLines
235                     : headerLines;
236             addto.append(line);
237             addto.append("\n");
238           }
239         }
240       }
241     }
242     if (seqhash.size() > 0)
243     {
244       // make the sequence vector
245       Enumeration seqid = seqids.elements();
246       while (seqid.hasMoreElements())
247       {
248         String idstring = (String) seqid.nextElement();
249         Object[] seqentry = (Object[]) seqhash.get(idstring);
250         try
251         {
252           Sequence newseq = new Sequence(idstring,
253
254           ((StringBuffer) seqentry[0]).toString(),
255                   (int) ((long[]) seqentry[1])[0],
256                   (int) ((long[]) seqentry[1])[1]);
257           if (newseq.getEnd() == 0)
258           {
259             // assume there are no deletions in the sequence.
260             newseq.setEnd(newseq.findPosition(newseq.getLength()));
261           }
262           seqs.addElement(newseq);
263         } catch (Exception e)
264         {
265           if (warningMessage == null)
266           {
267             warningMessage = "";
268           }
269           warningMessage += "Couldn't add Sequence - ID is '" + idstring
270                   + "' : Exception was " + e.toString() + "\n";
271         }
272       }
273       // add any annotation
274       if (headerLines.length() > 1)
275       {
276         setAlignmentProperty("HEADER", headerLines.toString());
277       }
278       if (footerLines.length() > 1)
279       {
280         setAlignmentProperty("FOOTER", footerLines.toString());
281       }
282     }
283   }
284
285   public String print(SequenceI[] s)
286   {
287     return new String("Not Implemented.");
288   }
289
290   public String print()
291   {
292     return print(getSeqsAsArray());
293   }
294 }