5cbf78d0eb9b863d29182a4052888ff6a8129f97
[jalview.git] / src / jalview / io / SimpleBlastFile.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3  * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, 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
25 /**
26  * parse a simple blast report. Attempt to cope with query anchored and pairwise
27  * alignments only.
28  * 
29  * @author Jim Procter
30  */
31
32 public class SimpleBlastFile extends AlignFile
33 {
34   /**
35    * header and footer info goes into alignment annotation.
36    */
37   StringBuffer headerLines, footerLines;
38
39   /**
40    * hold sequence ids in order of appearance in file
41    */
42   Vector seqids;
43
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           // query anchored means that we use the query sequence as the
91           // alignment ruler
92           if (line.indexOf("Query") == 0)
93           {
94             padding = -1;
95             // reset column markers for this block
96             numcol = -1;
97             aligcol = -1;
98             lastcol = -1;
99             // init or reset the column positions
100             for (int p = 5, mLen = line.length(); p < mLen; p++)
101             {
102               char c = line.charAt(p);
103               if (c >= '0' && c <= '9')
104               {
105                 if (numcol == -1)
106                 {
107                   numcol = p;
108                 }
109                 else if (aligcol != -1 && lastcol == -1)
110                 {
111                   lastcol = p;
112                 }
113               }
114               else
115               {
116                 if (c >= 'A' && c <= 'z')
117                 {
118                   if (aligcol == -1)
119                   {
120                     aligcol = p;
121                     padding = -1;
122                   }
123                 }
124                 else
125                 {
126                   if (padding == -1)
127                   {
128                     padding = p; // beginning of last stretch of whitespace
129                   }
130                 }
131               }
132             }
133             if (padding == -1)
134             {
135               padding = aligcol;
136             }
137           }
138           if (line.indexOf("Database:") > -1
139                   || (aligcol == -1 || numcol == -1 || lastcol == -1)
140                   || line.length() < lastcol)
141           {
142             inAlignments = false;
143           }
144           else
145           {
146             // now extract the alignment.
147             String sqid = line.substring(0, numcol).trim();
148             String stindx = line.substring(numcol, aligcol).trim();
149             String aligseg = line.substring(aligcol, padding);
150             String endindx = line.substring(lastcol).trim();
151             // init start/end prior to parsing
152             rstart = 1; // best guess we have
153             rend = 0; // if zero at end of parsing, then we count non-gaps
154             try
155             {
156               rstart = Long.parseLong(stindx);
157             } catch (Exception e)
158             {
159               System.err.println("Couldn't parse '" + stindx
160                       + "' as start of row");
161               // inAlignments = false;
162               // warn for this line
163             }
164             try
165             {
166               rend = Long.parseLong(endindx);
167             } catch (Exception e)
168             {
169               System.err.println("Couldn't parse '" + endindx
170                       + "' as end of row");
171               // inAlignments = false;
172
173               // warn for this line
174             }
175             Vector seqentries = (Vector) seqhash.get(sqid);
176             if (seqentries == null)
177             {
178               seqentries = new Vector();
179               seqhash.put(sqid, seqentries);
180               seqids.addElement(sqid);
181             }
182
183             Object[] seqentry = null;
184             Enumeration sqent = seqentries.elements();
185             while (seqentry == null && sqent.hasMoreElements())
186             {
187               seqentry = (Object[]) sqent.nextElement();
188               if (((long[]) seqentry[1])[1] + 1 != rstart)
189               {
190                 seqentry = null;
191               }
192             }
193             padseq = false;
194             if (seqentry == null)
195             {
196               padseq = true; // prepend gaps to new sequences in this block
197               seqentry = new Object[]
198               { new StringBuffer(), new long[]
199               { rstart, rend } };
200               seqentries.addElement(seqentry);
201               seqhash.put(sqid, seqentry);
202
203             }
204             if (sqid.equals("Query"))
205             {
206               // update current block length in case we need to pad
207               qlen = ((StringBuffer) seqentry[0]).length();
208             }
209             StringBuffer sqs = ((StringBuffer) seqentry[0]);
210             if (padseq)
211             {
212               for (long c = sqs.length(); c < qlen; c++)
213               {
214                 sqs.append(gapc);
215               }
216             }
217             sqs.append(aligseg);
218             if (rend > 0)
219             {
220               ((long[]) seqentry[1])[1] = rend;
221             }
222           }
223           // end of parsing out the sequences
224         }
225         // if we haven't parsed the line as an alignment, then
226         // add to the sequence header
227         if (!inAlignments)
228         {
229           String ln = line.trim();
230           // save any header stuff for the user
231           if (ln.length() > 0)
232           {
233             StringBuffer addto = (seqhash.size() > 0) ? footerLines
234                     : headerLines;
235             addto.append(line);
236             addto.append("\n");
237           }
238         }
239       }
240     }
241     if (seqhash.size() > 0)
242     {
243       // make the sequence vector
244       Enumeration seqid = seqids.elements();
245       while (seqid.hasMoreElements())
246       {
247         String idstring = (String) seqid.nextElement();
248         Object[] seqentry = (Object[]) seqhash.get(idstring);
249         try
250         {
251           Sequence newseq = new Sequence(idstring,
252
253           ((StringBuffer) seqentry[0]).toString(),
254                   (int) ((long[]) seqentry[1])[0],
255                   (int) ((long[]) seqentry[1])[1]);
256           if (newseq.getEnd() == 0)
257           {
258             // assume there are no deletions in the sequence.
259             newseq.setEnd(newseq.findPosition(newseq.getLength()));
260           }
261           seqs.addElement(newseq);
262         } catch (Exception e)
263         {
264           if (warningMessage == null)
265           {
266             warningMessage = "";
267           }
268           warningMessage += "Couldn't add Sequence - ID is '" + idstring
269                   + "' : Exception was " + e.toString() + "\n";
270         }
271       }
272       // add any annotation
273       if (headerLines.length() > 1)
274       {
275         setAlignmentProperty("HEADER", headerLines.toString());
276       }
277       if (footerLines.length() > 1)
278       {
279         setAlignmentProperty("FOOTER", footerLines.toString());
280       }
281     }
282   }
283
284   public String print(SequenceI[] s)
285   {
286     return new String("Not Implemented.");
287   }
288
289   public String print()
290   {
291     return print(getSeqsAsArray());
292   }
293 }