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