JAL-3703 fix Gff3 shared InputStream with embedded FASTA data
[jalview.git] / src / jalview / io / FastaFile.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 java.io.IOException;
24
25 import jalview.datamodel.Alignment;
26 import jalview.datamodel.AlignmentAnnotation;
27 import jalview.datamodel.Annotation;
28 import jalview.datamodel.Sequence;
29 import jalview.datamodel.SequenceI;
30
31 /**
32  * DOCUMENT ME!
33  * 
34  * @author $author$
35  * @version $Revision$
36  */
37 public class FastaFile extends AlignFile
38 {
39   /**
40    * Length of a sequence line
41    */
42   int len = 72;
43
44   StringBuffer out;
45
46   /**
47    * Creates a new FastaFile object.
48    */
49   public FastaFile()
50   {
51   }
52
53   /**
54    * Creates a new FastaFile object.
55    * 
56    * @param inFile
57    *          DOCUMENT ME!
58    * @param sourceType
59    *          DOCUMENT ME!
60    * 
61    * @throws IOException
62    *           DOCUMENT ME!
63    */
64   public FastaFile(String inFile, DataSourceType sourceType)
65           throws IOException
66   {
67     super(inFile, sourceType);
68   }
69
70   public FastaFile(FileParse source) throws IOException
71   {
72     this(source, true);
73   }
74
75   public FastaFile(FileParse source, boolean closeData) throws IOException
76   {
77     super(true, source, closeData);
78   }
79
80   public FastaFile(SequenceI[] seqs)
81   {
82     super(seqs);
83   }
84
85   /**
86    * DOCUMENT ME!
87    * 
88    * @throws IOException
89    *           DOCUMENT ME!
90    */
91   @Override
92   public void parse() throws IOException
93   {
94     StringBuffer sb = new StringBuffer();
95     boolean firstLine = true;
96
97     String line, uline;
98     Sequence seq = null;
99
100     boolean annotation = false;
101
102     while ((uline = nextLine()) != null)
103     {
104       line = uline.trim();
105       if (line.length() > 0)
106       {
107         if (line.charAt(0) == '>')
108         {
109           if (line.startsWith(">#_"))
110           {
111             if (annotation)
112             {
113               annotations.addElement(makeAnnotation(seq, sb));
114             }
115           }
116           else
117           {
118             annotation = false;
119           }
120
121           if (!firstLine)
122           {
123             seq.setSequence(sb.toString());
124
125             if (!annotation)
126             {
127               seqs.addElement(seq);
128             }
129           }
130
131           seq = parseId(line.substring(1));
132           firstLine = false;
133
134           sb = new StringBuffer();
135
136           if (line.startsWith(">#_"))
137           {
138             annotation = true;
139           }
140         }
141         else
142         {
143           sb.append(annotation ? uline : line);
144         }
145       }
146     }
147
148     if (annotation)
149     {
150       annotations.addElement(makeAnnotation(seq, sb));
151     }
152
153     else if (!firstLine)
154     {
155       seq.setSequence(sb.toString());
156       seqs.addElement(seq);
157     }
158   }
159
160   private AlignmentAnnotation makeAnnotation(SequenceI seq, StringBuffer sb)
161   {
162     Annotation[] anots = new Annotation[sb.length()];
163     char cb;
164     for (int i = 0; i < anots.length; i++)
165     {
166       char cn = sb.charAt(i);
167       if (cn != ' ')
168       {
169         anots[i] = new Annotation("" + cn, null, ' ', Float.NaN);
170       }
171     }
172     AlignmentAnnotation aa = new AlignmentAnnotation(
173             seq.getName().substring(2), seq.getDescription(), anots);
174     return aa;
175   }
176
177   /**
178    * called by AppletFormatAdapter to generate an annotated alignment, rather
179    * than bare sequences.
180    * 
181    * @param al
182    */
183   public void addAnnotations(Alignment al)
184   {
185     addProperties(al);
186     for (int i = 0; i < annotations.size(); i++)
187     {
188       AlignmentAnnotation aa = annotations.elementAt(i);
189       aa.setPadGaps(true, al.getGapCharacter());
190       al.addAnnotation(aa);
191     }
192   }
193
194   @Override
195   public String print(SequenceI[] s, boolean jvsuffix)
196   {
197     out = new StringBuffer();
198     int i = 0;
199
200     while ((i < s.length) && (s[i] != null))
201     {
202       out.append(">" + printId(s[i], jvsuffix));
203       if (s[i].getDescription() != null)
204       {
205         out.append(" " + s[i].getDescription());
206       }
207
208       out.append(newline);
209
210       int nochunks = (s[i].getLength() / len)
211               + (s[i].getLength() % len > 0 ? 1 : 0);
212
213       for (int j = 0; j < nochunks; j++)
214       {
215         int start = j * len;
216         int end = start + len;
217
218         if (end < s[i].getLength())
219         {
220           out.append(s[i].getSequenceAsString(start, end) + newline);
221         }
222         else if (start < s[i].getLength())
223         {
224           out.append(s[i].getSequenceAsString(start, s[i].getLength())
225                   + newline);
226         }
227       }
228
229       i++;
230     }
231
232     return out.toString();
233   }
234 }