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