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