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