JAL-1620 version bump and release notes
[jalview.git] / src / jalview / io / ClustalFile.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2b1)
3  * Copyright (C) 2014 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 import jalview.util.*;
28
29 public class ClustalFile extends AlignFile
30 {
31
32   public ClustalFile()
33   {
34   }
35
36   public ClustalFile(String inFile, String type) throws IOException
37   {
38     super(inFile, type);
39   }
40
41   public ClustalFile(FileParse source) throws IOException
42   {
43     super(source);
44   }
45
46   public void initData()
47   {
48     super.initData();
49   }
50
51   public void parse() throws IOException
52   {
53     int i = 0;
54     boolean flag = false;
55     boolean rna = false;
56     boolean top = false;
57     StringBuffer pssecstr = new StringBuffer(), consstr = new StringBuffer();
58     Vector headers = new Vector();
59     Hashtable seqhash = new Hashtable();
60     StringBuffer tempseq;
61     String line, id;
62     StringTokenizer str;
63
64     try
65     {
66       while ((line = nextLine()) != null)
67       {
68         if (line.length() == 0)
69         {
70           top = true;
71         }
72         if (line.indexOf(" ") != 0)
73         {
74           str = new StringTokenizer(line, " ");
75
76           if (str.hasMoreTokens())
77           {
78             id = str.nextToken();
79
80             if (id.equalsIgnoreCase("CLUSTAL"))
81             {
82               flag = true;
83             }
84             else
85             {
86               if (flag)
87               {
88                 if (seqhash.containsKey(id))
89                 {
90                   tempseq = (StringBuffer) seqhash.get(id);
91                 }
92                 else
93                 {
94                   tempseq = new StringBuffer();
95                   seqhash.put(id, tempseq);
96                 }
97
98                 if (!(headers.contains(id)))
99                 {
100                   headers.addElement(id);
101                 }
102
103                 if (str.hasMoreTokens())
104                 {
105                   tempseq.append(str.nextToken());
106                 }
107                 top = false;
108               }
109             }
110           }
111           else
112           {
113             flag = true;
114           }
115         }
116         else
117         {
118           if (line.matches("\\s+(-|\\.|\\(|\\[|\\]|\\))+"))
119           {
120             if (top)
121             {
122               pssecstr.append(line.trim());
123             }
124             else
125             {
126               consstr.append(line.trim());
127             }
128           }
129         }
130       }
131     } catch (IOException e)
132     {
133       System.err.println("Exception parsing clustal file " + e);
134       e.printStackTrace();
135     }
136
137     if (flag)
138     {
139       this.noSeqs = headers.size();
140
141       // Add sequences to the hash
142       for (i = 0; i < headers.size(); i++)
143       {
144         if (seqhash.get(headers.elementAt(i)) != null)
145         {
146           if (maxLength < seqhash.get(headers.elementAt(i)).toString()
147                   .length())
148           {
149             maxLength = seqhash.get(headers.elementAt(i)).toString()
150                     .length();
151           }
152
153           Sequence newSeq = parseId(headers.elementAt(i).toString());
154           newSeq.setSequence(seqhash.get(headers.elementAt(i).toString())
155                   .toString());
156
157           seqs.addElement(newSeq);
158         }
159         else
160         {
161           System.err
162                   .println("Clustal File Reader: Can't find sequence for "
163                           + headers.elementAt(i));
164         }
165       }
166       AlignmentAnnotation lastssa = null;
167       if (pssecstr.length() == maxLength)
168       {
169         Vector ss = new Vector();
170         AlignmentAnnotation ssa = lastssa = StockholmFile
171                 .parseAnnotationRow(ss, "secondary structure",
172                         pssecstr.toString());
173         ssa.label = "Secondary Structure";
174         annotations.addElement(ssa);
175       }
176       if (consstr.length() == maxLength)
177       {
178         Vector ss = new Vector();
179         AlignmentAnnotation ssa = StockholmFile.parseAnnotationRow(ss,
180                 "secondary structure", consstr.toString());
181         ssa.label = "Consensus Secondary Structure";
182         if (lastssa == null
183                 || !lastssa.getRNAStruc().equals(
184                         ssa.getRNAStruc().replace('-', '.')))
185         {
186           annotations.addElement(ssa);
187         }
188       }
189     }
190   }
191
192   public String print()
193   {
194     return print(getSeqsAsArray());
195     // TODO: locaRNA style aln output
196   }
197
198   public String print(SequenceI[] s)
199   {
200     StringBuffer out = new StringBuffer("CLUSTAL" + newline + newline);
201
202     int max = 0;
203     int maxid = 0;
204
205     int i = 0;
206
207     while ((i < s.length) && (s[i] != null))
208     {
209       String tmp = printId(s[i]);
210
211       if (s[i].getSequence().length > max)
212       {
213         max = s[i].getSequence().length;
214       }
215
216       if (tmp.length() > maxid)
217       {
218         maxid = tmp.length();
219       }
220
221       i++;
222     }
223
224     if (maxid < 15)
225     {
226       maxid = 15;
227     }
228
229     maxid++;
230
231     int len = 60;
232     int nochunks = (max / len) + 1;
233
234     for (i = 0; i < nochunks; i++)
235     {
236       int j = 0;
237
238       while ((j < s.length) && (s[j] != null))
239       {
240         out.append(new Format("%-" + maxid + "s").form(printId(s[j]) + " "));
241
242         int start = i * len;
243         int end = start + len;
244
245         if ((end < s[j].getSequence().length)
246                 && (start < s[j].getSequence().length))
247         {
248           out.append(s[j].getSequenceAsString(start, end));
249         }
250         else
251         {
252           if (start < s[j].getSequence().length)
253           {
254             out.append(s[j].getSequenceAsString().substring(start));
255           }
256         }
257
258         out.append(newline);
259         j++;
260       }
261
262       out.append(newline);
263     }
264
265     return out.toString();
266   }
267 }