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