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