file format enum wip changes
[jalview.git] / src / jalview / io / SimpleBlastFile.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ 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, DataSourceType sourceType)
55           throws IOException
56   {
57     super(inFile, sourceType);
58   }
59
60   public SimpleBlastFile(FileParse source) throws IOException
61   {
62     super(source);
63   }
64
65   @Override
66   public void initData()
67   {
68     super.initData();
69     headerLines = new StringBuffer();
70     footerLines = new StringBuffer();
71     seqids = new Vector();
72   }
73
74   @Override
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[] { new StringBuffer(),
207                   new long[] { rstart, rend } };
208               seqentries.addElement(seqentry);
209               seqhash.put(sqid, seqentry);
210
211             }
212             if (sqid.equals("Query"))
213             {
214               // update current block length in case we need to pad
215               qlen = ((StringBuffer) seqentry[0]).length();
216             }
217             StringBuffer sqs = ((StringBuffer) seqentry[0]);
218             if (padseq)
219             {
220               for (long c = sqs.length(); c < qlen; c++)
221               {
222                 sqs.append(gapc);
223               }
224             }
225             sqs.append(aligseg);
226             if (rend > 0)
227             {
228               ((long[]) seqentry[1])[1] = rend;
229             }
230           }
231           // end of parsing out the sequences
232         }
233         // if we haven't parsed the line as an alignment, then
234         // add to the sequence header
235         if (!inAlignments)
236         {
237           String ln = line.trim();
238           // save any header stuff for the user
239           if (ln.length() > 0)
240           {
241             StringBuffer addto = (seqhash.size() > 0) ? footerLines
242                     : headerLines;
243             addto.append(line);
244             addto.append("\n");
245           }
246         }
247       }
248     }
249     if (seqhash.size() > 0)
250     {
251       // make the sequence vector
252       Enumeration seqid = seqids.elements();
253       while (seqid.hasMoreElements())
254       {
255         String idstring = (String) seqid.nextElement();
256         Object[] seqentry = (Object[]) seqhash.get(idstring);
257         try
258         {
259           Sequence newseq = new Sequence(idstring,
260
261           ((StringBuffer) seqentry[0]).toString(),
262                   (int) ((long[]) seqentry[1])[0],
263                   (int) ((long[]) seqentry[1])[1]);
264           if (newseq.getEnd() == 0)
265           {
266             // assume there are no deletions in the sequence.
267             newseq.setEnd(newseq.findPosition(newseq.getLength()));
268           }
269           seqs.addElement(newseq);
270         } catch (Exception e)
271         {
272           if (warningMessage == null)
273           {
274             warningMessage = "";
275           }
276           warningMessage += "Couldn't add Sequence - ID is '" + idstring
277                   + "' : Exception was " + e.toString() + "\n";
278         }
279       }
280       // add any annotation
281       if (headerLines.length() > 1)
282       {
283         setAlignmentProperty("HEADER", headerLines.toString());
284       }
285       if (footerLines.length() > 1)
286       {
287         setAlignmentProperty("FOOTER", footerLines.toString());
288       }
289     }
290   }
291
292   public String print(SequenceI[] s)
293   {
294     return new String("Not Implemented.");
295   }
296
297   @Override
298   public String print()
299   {
300     return print(getSeqsAsArray());
301   }
302 }