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