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