d241308b7142ec69fa7bf8d3c5ba12a10c66a305
[jalview.git] / src / jalview / io / FormatAdapter.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.api.AlignViewportI;
24 import jalview.datamodel.Alignment;
25 import jalview.datamodel.AlignmentAnnotation;
26 import jalview.datamodel.AlignmentI;
27 import jalview.datamodel.ColumnSelection;
28 import jalview.datamodel.Sequence;
29 import jalview.datamodel.SequenceGroup;
30 import jalview.datamodel.SequenceI;
31
32 /**
33  * Additional formatting methods used by the application in a number of places.
34  * 
35  * @author $author$
36  * @version $Revision$
37  */
38 public class FormatAdapter extends AppletFormatAdapter
39 {
40   public FormatAdapter(AlignViewportI viewport)
41   {
42     super(viewport);
43     init();
44   }
45
46   public FormatAdapter()
47   {
48     super();
49     init();
50   }
51
52   private void init()
53   {
54     if (jalview.bin.Cache.getDefault("STRUCT_FROM_PDB", true))
55     {
56       annotFromStructure = jalview.bin.Cache.getDefault("ADD_TEMPFACT_ANN",
57               true);
58       localSecondaryStruct = jalview.bin.Cache.getDefault("ADD_SS_ANN",
59             true);
60     serviceSecondaryStruct = jalview.bin.Cache.getDefault("USE_RNAVIEW",
61             true);
62     }
63     else
64     {
65       // disable all PDB annotation options
66       annotFromStructure = false;
67       localSecondaryStruct = false;
68       serviceSecondaryStruct = false;
69     }
70   }
71
72   public String formatSequences(String format, SequenceI[] seqs,
73           String[] omitHiddenColumns, int[] exportRange)
74   {
75
76     return formatSequences(format,
77             replaceStrings(seqs, omitHiddenColumns, exportRange));
78   }
79
80   /**
81    * create sequences with each sequence string replaced with the one given in
82    * omitHiddenCOlumns
83    * 
84    * @param seqs
85    * @param omitHiddenColumns
86    * @return new sequences
87    */
88   public SequenceI[] replaceStrings(SequenceI[] seqs,
89           String[] omitHiddenColumns, int[] startEnd)
90   {
91     if (omitHiddenColumns != null)
92     {
93       SequenceI[] tmp = new SequenceI[seqs.length];
94
95       int startRes;
96       int endRes;
97       int startIndex;
98       int endIndex;
99       for (int i = 0; i < seqs.length; i++)
100       {
101         startRes = seqs[i].getStart();
102         endRes = seqs[i].getEnd();
103
104         startIndex = startEnd[0];
105         endIndex = startEnd[1];
106
107         if (startEnd != null)
108         {
109           // get first non-gaped residue start position
110           while (jalview.util.Comparison.isGap(seqs[i]
111                   .getCharAt(startIndex)) && startIndex < endIndex)
112           {
113             startIndex++;
114           }
115
116           // get last non-gaped residue end position
117           while (jalview.util.Comparison.isGap(seqs[i].getCharAt(endIndex))
118                   && endIndex > startIndex)
119           {
120             endIndex--;
121           }
122
123           startRes = seqs[i].findPosition(startIndex);
124           startRes = seqs[i].getStart() > 1 ? startRes - seqs[i].getStart()
125                   : startRes;
126           endRes = seqs[i].findPosition(endIndex) - seqs[i].getStart();
127         }
128
129         tmp[i] = new Sequence(seqs[i].getName(), omitHiddenColumns[i],
130                 startRes, endRes);
131         tmp[i].setDescription(seqs[i].getDescription());
132       }
133       seqs = tmp;
134     }
135     return seqs;
136   }
137
138   /**
139    * Format a vector of sequences as a flat alignment file. TODO: allow caller
140    * to detect errors and warnings encountered when generating output
141    * 
142    * 
143    * @param format
144    *          Format string as givien in the AppletFormatAdaptor list (exact
145    *          match to name of class implementing file io for that format)
146    * @param seqs
147    *          vector of sequences to write
148    * 
149    * @return String containing sequences in desired format
150    */
151   public String formatSequences(String format, SequenceI[] seqs)
152   {
153
154     try
155     {
156       AlignFile afile = null;
157
158       if (format.equalsIgnoreCase("FASTA"))
159       {
160         afile = new FastaFile();
161         afile.addJVSuffix(jalview.bin.Cache.getDefault("FASTA_JVSUFFIX",
162                 true));
163       }
164       else if (format.equalsIgnoreCase("MSF"))
165       {
166         afile = new MSFfile();
167         afile.addJVSuffix(jalview.bin.Cache
168                 .getDefault("MSF_JVSUFFIX", true));
169       }
170       else if (format.equalsIgnoreCase("PileUp"))
171       {
172         afile = new PileUpfile();
173         afile.addJVSuffix(jalview.bin.Cache.getDefault("PILEUP_JVSUFFIX",
174                 true));
175       }
176       else if (format.equalsIgnoreCase("CLUSTAL"))
177       {
178         afile = new ClustalFile();
179         afile.addJVSuffix(jalview.bin.Cache.getDefault("CLUSTAL_JVSUFFIX",
180                 true));
181       }
182       else if (format.equalsIgnoreCase("BLC"))
183       {
184         afile = new BLCFile();
185         afile.addJVSuffix(jalview.bin.Cache
186                 .getDefault("BLC_JVSUFFIX", true));
187       }
188       else if (format.equalsIgnoreCase("PIR"))
189       {
190         afile = new PIRFile();
191         afile.addJVSuffix(jalview.bin.Cache
192                 .getDefault("PIR_JVSUFFIX", true));
193       }
194       else if (format.equalsIgnoreCase("PFAM"))
195       {
196         afile = new PfamFile();
197         afile.addJVSuffix(jalview.bin.Cache.getDefault("PFAM_JVSUFFIX",
198                 true));
199       }
200       /*
201        * amsa is not supported by this function - it requires an alignment
202        * rather than a sequence vector else if (format.equalsIgnoreCase("AMSA"))
203        * { afile = new AMSAFile(); afile.addJVSuffix(
204        * jalview.bin.Cache.getDefault("AMSA_JVSUFFIX", true)); }
205        */
206
207       afile.setSeqs(seqs);
208       String afileresp = afile.print();
209       if (afile.hasWarningMessage())
210       {
211         System.err.println("Warning raised when writing as " + format
212                 + " : " + afile.getWarningMessage());
213       }
214       return afileresp;
215     } catch (Exception e)
216     {
217       System.err.println("Failed to write alignment as a '" + format
218               + "' file\n");
219       e.printStackTrace();
220     }
221
222     return null;
223   }
224
225   public boolean getCacheSuffixDefault(String format)
226   {
227     if (isValidFormat(format))
228     {
229       return jalview.bin.Cache.getDefault(format.toUpperCase()
230               + "_JVSUFFIX", true);
231     }
232     return false;
233   }
234
235   public String formatSequences(String format, AlignmentI alignment,
236           String[] omitHidden, int[] exportRange, ColumnSelection colSel)
237   {
238     return formatSequences(format, alignment, omitHidden, exportRange,
239             getCacheSuffixDefault(format), colSel, null);
240   }
241
242   public String formatSequences(String format, AlignmentI alignment,
243           String[] omitHidden, int[] exportRange, ColumnSelection colSel,
244           SequenceGroup sgp)
245   {
246     return formatSequences(format, alignment, omitHidden, exportRange,
247             getCacheSuffixDefault(format), colSel, sgp);
248   }
249
250   /**
251    * hack function to replace seuqences with visible sequence strings before
252    * generating a string of the alignment in the given format.
253    * 
254    * @param format
255    * @param alignment
256    * @param omitHidden
257    *          sequence strings to write out in order of sequences in alignment
258    * @param colSel
259    *          defines hidden columns that are edited out of annotation
260    * @return string representation of the alignment formatted as format
261    */
262   public String formatSequences(String format, AlignmentI alignment,
263           String[] omitHidden, int[] exportRange, boolean suffix,
264           ColumnSelection colSel)
265   {
266     return formatSequences(format, alignment, omitHidden, exportRange,
267             suffix, colSel,
268             null);
269   }
270
271   public String formatSequences(String format, AlignmentI alignment,
272           String[] omitHidden, int[] exportRange, boolean suffix,
273           ColumnSelection colSel,
274           jalview.datamodel.SequenceGroup selgp)
275   {
276     if (omitHidden != null)
277     {
278       // TODO consider using AlignmentView to prune to visible region
279       // TODO prune sequence annotation and groups to visible region
280       // TODO: JAL-1486 - set start and end for output correctly. basically,
281       // AlignmentView.getVisibleContigs does this.
282       Alignment alv = new Alignment(replaceStrings(
283               alignment.getSequencesArray(), omitHidden, exportRange));
284       AlignmentAnnotation[] ala = alignment.getAlignmentAnnotation();
285       if (ala != null)
286       {
287         for (int i = 0; i < ala.length; i++)
288         {
289           AlignmentAnnotation na = new AlignmentAnnotation(ala[i]);
290           if (selgp != null)
291           {
292             colSel.makeVisibleAnnotation(selgp.getStartRes(),
293                     selgp.getEndRes(), na);
294           }
295           else
296           {
297             colSel.makeVisibleAnnotation(na);
298           }
299           alv.addAnnotation(na);
300         }
301       }
302       return this.formatSequences(format, alv, suffix);
303     }
304     return this.formatSequences(format, alignment, suffix);
305   }
306
307   public Alignment readFile(String inFile, String type, String format)
308           throws java.io.IOException
309   {
310     Alignment al = super.readFile(inFile, type, format);
311     return al;
312   }
313
314   public AlignmentI readFromFile(FileParse source, String format)
315           throws java.io.IOException
316   {
317     Alignment al = (Alignment) super.readFromFile(source, format);
318     return al;
319   }
320
321   /**
322    * validate format is valid for IO in Application. This is basically the
323    * AppletFormatAdapter.isValidFormat call with additional checks for
324    * Application only formats like 'Jalview'.
325    * 
326    * @param format
327    *          a format string to be compared with list of readable or writable
328    *          formats (READABLE_FORMATS or WRITABLE_FORMATS)
329    * @param forwriting
330    *          when true, format is checked against list of writable formats.
331    * @return true if format is valid
332    */
333   public static final boolean isValidIOFormat(String format,
334           boolean forwriting)
335   {
336     if (format.equalsIgnoreCase("jalview"))
337     {
338       return true;
339     }
340     return AppletFormatAdapter.isValidFormat(format, forwriting);
341   }
342
343   /**
344    * Create a flat file representation of a given view or selected region of a view
345    * @param format
346    * @param av
347    * @return String containing flat file
348    */
349   public String formatSequences(String format, AlignViewportI av, boolean selectedOnly)
350   {
351     return formatSequences(format, getCacheSuffixDefault(format), av, selectedOnly);
352   }
353
354
355 }