JAL-1355
[jalview.git] / src / jalview / io / AlignFile.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
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 jalview.datamodel.Alignment;
24 import jalview.datamodel.AlignmentAnnotation;
25 import jalview.datamodel.Sequence;
26 import jalview.datamodel.SequenceI;
27 import jalview.util.MessageManager;
28
29 import java.io.IOException;
30 import java.util.Enumeration;
31 import java.util.Hashtable;
32 import java.util.Vector;
33
34 /**
35  * DOCUMENT ME!
36  * 
37  * @author $author$
38  * @version $Revision$
39  */
40 public abstract class AlignFile extends FileParse
41 {
42   int noSeqs = 0;
43
44   int maxLength = 0;
45
46   /**
47    * Sequences to be added to form a new alignment.
48    */
49   protected Vector<SequenceI> seqs;
50
51   /**
52    * annotation to be added to generated alignment object
53    */
54   protected Vector annotations;
55
56   /**
57    * Properties to be added to generated alignment object
58    */
59   protected Hashtable properties;
60
61   long start;
62
63   long end;
64
65   boolean jvSuffix = true;
66
67   /**
68    * Creates a new AlignFile object.
69    */
70   public AlignFile()
71   {
72     // Shouldn't we init data structures (JBPNote: not sure - initData is for
73     // initialising the structures used for reading from a datasource, and the
74     // bare constructor hasn't got any datasource)
75     initData();
76   }
77
78   /**
79    * Constructor which parses the data from a file of some specified type.
80    * 
81    * @param inFile
82    *          Filename to read from.
83    * @param type
84    *          What type of file to read from (File, URL)
85    */
86   public AlignFile(String inFile, String type) throws IOException
87   {
88     super(inFile, type);
89     initData();
90     parse();
91     // sets the index of each sequence in the alignment
92     for (int i = 0, c = seqs.size(); i < c; i++)
93     {
94       seqs.get(i).setIndex(i);
95     }
96   }
97
98   /**
99    * Attempt to read from the position where some other parsing process left
100    * off.
101    * 
102    * @param source
103    * @throws IOException
104    */
105   public AlignFile(FileParse source) throws IOException
106   {
107     super(source);
108     initData();
109     parse();
110     // sets the index of each sequence in the alignment
111     for (int i = 0, c = seqs.size(); i < c; i++)
112     {
113       seqs.get(i).setIndex(i);
114     }
115   }
116
117   /**
118    * Return the seqs Vector
119    */
120   public Vector<SequenceI> getSeqs()
121   {
122     return seqs;
123   }
124
125   /**
126    * Return the Sequences in the seqs Vector as an array of Sequences
127    */
128   public SequenceI[] getSeqsAsArray()
129   {
130     SequenceI[] s = new SequenceI[seqs.size()];
131
132     for (int i = 0; i < seqs.size(); i++)
133     {
134       s[i] = (SequenceI) seqs.elementAt(i);
135     }
136
137     return s;
138   }
139
140   /**
141    * called by AppletFormatAdapter to generate an annotated alignment, rather
142    * than bare sequences.
143    * 
144    * @param al
145    */
146   public void addAnnotations(Alignment al)
147   {
148     addProperties(al);
149     for (int i = 0; i < annotations.size(); i++)
150     {
151       // detect if annotations.elementAt(i) rna secondary structure
152       // if so then do:
153       /*
154        * SequenceFeature[] pairArray =
155        * Rna.GetBasePairsFromAlignmentAnnotation(annotations.elementAt(i));
156        * Rna.HelixMap(pairArray);
157        */
158       AlignmentAnnotation an = (AlignmentAnnotation) annotations
159               .elementAt(i);
160       an.validateRangeAndDisplay();
161       al.addAnnotation(an);
162     }
163
164   }
165
166   /**
167    * Add any additional information extracted from the file to the alignment
168    * properties.
169    * 
170    * @note implicitly called by addAnnotations()
171    * @param al
172    */
173   public void addProperties(Alignment al)
174   {
175     if (properties != null && properties.size() > 0)
176     {
177       Enumeration keys = properties.keys();
178       Enumeration vals = properties.elements();
179       while (keys.hasMoreElements())
180       {
181         al.setProperty(keys.nextElement(), vals.nextElement());
182       }
183     }
184   }
185
186   /**
187    * Store a non-null key-value pair in a hashtable used to set alignment
188    * properties note: null keys will raise an error, null values will result in
189    * the key/value pair being silently ignored.
190    * 
191    * @param key
192    *          - non-null key object
193    * @param value
194    *          - non-null value
195    */
196   protected void setAlignmentProperty(Object key, Object value)
197   {
198     if (key == null)
199     {
200       throw new Error(MessageManager.getString("error.implementation_error_cannot_have_null_alignment"));
201     }
202     if (value == null)
203     {
204       return; // null properties are ignored.
205     }
206     if (properties == null)
207     {
208       properties = new Hashtable();
209     }
210     properties.put(key, value);
211   }
212
213   protected Object getAlignmentProperty(Object key)
214   {
215     if (properties != null && key != null)
216     {
217       return properties.get(key);
218     }
219     return null;
220   }
221
222   /**
223    * Initialise objects to store sequence data in.
224    */
225   protected void initData()
226   {
227     seqs = new Vector();
228     annotations = new Vector();
229   }
230
231   /**
232    * DOCUMENT ME!
233    * 
234    * @param s
235    *          DOCUMENT ME!
236    */
237   protected void setSeqs(SequenceI[] s)
238   {
239     seqs = new Vector();
240
241     for (int i = 0; i < s.length; i++)
242     {
243       seqs.addElement(s[i]);
244     }
245   }
246
247   /**
248    * This method must be implemented to parse the contents of the file.
249    */
250   public abstract void parse() throws IOException;
251
252   /**
253    * Print out in alignment file format the Sequences in the seqs Vector.
254    */
255   public abstract String print();
256
257   public void addJVSuffix(boolean b)
258   {
259     jvSuffix = b;
260   }
261
262   /**
263    * A general parser for ids.
264    * 
265    * @String id Id to be parsed
266    */
267   Sequence parseId(String id)
268   {
269     Sequence seq = null;
270     id = id.trim();
271     int space = id.indexOf(" ");
272     if (space > -1)
273     {
274       seq = new Sequence(id.substring(0, space), "");
275       seq.setDescription(id.substring(space + 1));
276     }
277     else
278     {
279       seq = new Sequence(id, "");
280     }
281
282     return seq;
283   }
284
285   /**
286    * Creates the output id. Adds prefix Uniprot format source|id And suffix
287    * Jalview /start-end
288    * 
289    * @String id Id to be parsed
290    */
291   String printId(SequenceI seq)
292   {
293     return seq.getDisplayId(jvSuffix);
294   }
295
296   /**
297    * vector of String[] treeName, newickString pairs
298    */
299   Vector newickStrings = null;
300
301   protected void addNewickTree(String treeName, String newickString)
302   {
303     if (newickStrings == null)
304     {
305       newickStrings = new Vector();
306     }
307     newickStrings.addElement(new String[]
308     { treeName, newickString });
309   }
310
311   protected int getTreeCount()
312   {
313     if (newickStrings == null)
314     {
315       return 0;
316     }
317     return newickStrings.size();
318   }
319
320 }