JAL-2788 possible adjustments to sequence accesses
[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(),
65             consstr = new StringBuffer();
66     Vector headers = new Vector();
67     Hashtable seqhash = new Hashtable();
68     StringBuffer tempseq;
69     String line, id;
70     StringTokenizer str;
71
72     try
73     {
74       while ((line = nextLine()) != null)
75       {
76         if (line.length() == 0)
77         {
78           top = true;
79         }
80         if (line.indexOf(" ") != 0)
81         {
82           str = new StringTokenizer(line, " ");
83
84           if (str.hasMoreTokens())
85           {
86             id = str.nextToken();
87
88             if (id.equalsIgnoreCase("CLUSTAL"))
89             {
90               flag = true;
91             }
92             else
93             {
94               if (flag)
95               {
96                 if (seqhash.containsKey(id))
97                 {
98                   tempseq = (StringBuffer) seqhash.get(id);
99                 }
100                 else
101                 {
102                   tempseq = new StringBuffer();
103                   seqhash.put(id, tempseq);
104                 }
105
106                 if (!(headers.contains(id)))
107                 {
108                   headers.addElement(id);
109                 }
110
111                 if (str.hasMoreTokens())
112                 {
113                   tempseq.append(str.nextToken());
114                 }
115                 top = false;
116               }
117             }
118           }
119           else
120           {
121             flag = true;
122           }
123         }
124         else
125         {
126           if (line.matches("\\s+(-|\\.|\\(|\\[|\\]|\\))+"))
127           {
128             if (top)
129             {
130               pssecstr.append(line.trim());
131             }
132             else
133             {
134               consstr.append(line.trim());
135             }
136           }
137         }
138       }
139     } catch (IOException e)
140     {
141       System.err.println("Exception parsing clustal file " + e);
142       e.printStackTrace();
143     }
144
145     if (flag)
146     {
147       this.noSeqs = headers.size();
148
149       // Add sequences to the hash
150       for (i = 0; i < headers.size(); i++)
151       {
152         if (seqhash.get(headers.elementAt(i)) != null)
153         {
154           if (maxLength < seqhash.get(headers.elementAt(i)).toString()
155                   .length())
156           {
157             maxLength = seqhash.get(headers.elementAt(i)).toString()
158                     .length();
159           }
160
161           Sequence newSeq = parseId(headers.elementAt(i).toString());
162           newSeq.setSequence(
163                   seqhash.get(headers.elementAt(i).toString()).toString());
164
165           seqs.addElement(newSeq);
166         }
167         else
168         {
169           System.err.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 || !lastssa.getRNAStruc()
190                 .equals(ssa.getRNAStruc().replace('-', '.')))
191         {
192           annotations.addElement(ssa);
193         }
194       }
195     }
196   }
197
198   @Override
199   public String print(SequenceI[] s, boolean jvsuffix)
200   {
201     StringBuffer out = new StringBuffer("CLUSTAL" + newline + newline);
202
203     int max = 0;
204     int maxid = 0;
205
206     int i = 0;
207
208     while ((i < s.length) && (s[i] != null))
209     {
210       String tmp = printId(s[i], jvsuffix);
211
212       max = Math.max(max, s[i].getLength());
213
214       if (tmp.length() > maxid)
215       {
216         maxid = tmp.length();
217       }
218
219       i++;
220     }
221
222     if (maxid < 15)
223     {
224       maxid = 15;
225     }
226
227     maxid++;
228
229     int len = 60;
230     int nochunks = (max / len) + (max % len > 0 ? 1 : 0);
231
232     for (i = 0; i < nochunks; i++)
233     {
234       int j = 0;
235
236       while ((j < s.length) && (s[j] != null))
237       {
238         out.append(new Format("%-" + maxid + "s")
239                 .form(printId(s[j], jvsuffix) + " "));
240
241         int start = i * len;
242         int end = start + len;
243
244         int length = s[j].getLength();
245         if ((end < length) && (start < length))
246         {
247           out.append(s[j].getSequenceAsString(start, end));
248         }
249         else
250         {
251           if (start < length)
252           {
253             out.append(s[j].getSequenceAsString().substring(start));
254           }
255         }
256
257         out.append(newline);
258         j++;
259       }
260
261       out.append(newline);
262     }
263
264     return out.toString();
265   }
266 }