72f804409a0596a87e4c803c9be31ea41be58734
[jalview.git] / src / jalview / io / SequenceAnnotationReport.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.DBRefEntry;
24 import jalview.datamodel.SequenceFeature;
25 import jalview.datamodel.SequenceI;
26 import jalview.util.UrlLink;
27
28 import java.util.ArrayList;
29 import java.util.Hashtable;
30 import java.util.List;
31
32 /**
33  * generate HTML reports for a sequence
34  * 
35  * @author jimp
36  */
37 public class SequenceAnnotationReport
38 {
39   final String linkImageURL;
40
41   public SequenceAnnotationReport(String linkImageURL)
42   {
43     this.linkImageURL = linkImageURL;
44   }
45
46   /**
47    * appends the features at rpos to the given stringbuffer ready for display in
48    * a tooltip
49    * 
50    * @param tooltipText2
51    * @param linkImageURL
52    * @param rpos
53    * @param features
54    *          TODO refactor to Jalview 'utilities' somehow.
55    */
56   public void appendFeatures(final StringBuffer tooltipText2, int rpos,
57           List<SequenceFeature> features)
58   {
59     appendFeatures(tooltipText2, rpos, features, null);
60   }
61
62   public void appendFeatures(final StringBuffer tooltipText2, int rpos,
63           List<SequenceFeature> features, Hashtable minmax)
64   {
65     String tmpString;
66     if (features != null)
67     {
68       for (SequenceFeature feature : features)
69       {
70         if (feature.getType().equals("disulfide bond"))
71         {
72           if (feature.getBegin() == rpos || feature.getEnd() == rpos)
73           {
74             if (tooltipText2.length() > 6)
75             {
76               tooltipText2.append("<br>");
77             }
78             tooltipText2.append("disulfide bond " + feature.getBegin()
79                     + ":" + feature.getEnd());
80           }
81         }
82         else
83         {
84           if (tooltipText2.length() > 6)
85           {
86             tooltipText2.append("<br>");
87           }
88           // TODO: remove this hack to display link only features
89           boolean linkOnly = feature.getValue("linkonly") != null;
90           if (!linkOnly)
91           {
92             tooltipText2.append(feature.getType() + " ");
93             if (rpos != 0)
94             {
95               // we are marking a positional feature
96               tooltipText2.append(feature.begin);
97             }
98             if (feature.begin != feature.end)
99             {
100               tooltipText2.append(" " + feature.end);
101             }
102
103             if (feature.getDescription() != null
104                     && !feature.description.equals(feature.getType()))
105             {
106               tmpString = feature.getDescription();
107               String tmp2up = tmpString.toUpperCase();
108               int startTag = tmp2up.indexOf("<HTML>");
109               if (startTag > -1)
110               {
111                 tmpString = tmpString.substring(startTag + 6);
112                 tmp2up = tmp2up.substring(startTag + 6);
113               }
114               int endTag = tmp2up.indexOf("</BODY>");
115               if (endTag > -1)
116               {
117                 tmpString = tmpString.substring(0, endTag);
118                 tmp2up = tmp2up.substring(0, endTag);
119               }
120               endTag = tmp2up.indexOf("</HTML>");
121               if (endTag > -1)
122               {
123                 tmpString = tmpString.substring(0, endTag);
124               }
125
126               if (startTag > -1)
127               {
128                 tooltipText2.append("; " + tmpString);
129               }
130               else
131               {
132                 if (tmpString.indexOf("<") > -1
133                         || tmpString.indexOf(">") > -1)
134                 {
135                   // The description does not specify html is to
136                   // be used, so we must remove < > symbols
137                   tmpString = tmpString.replaceAll("<", "&lt;");
138                   tmpString = tmpString.replaceAll(">", "&gt;");
139
140                   tooltipText2.append("; ");
141                   tooltipText2.append(tmpString);
142
143                 }
144                 else
145                 {
146                   tooltipText2.append("; " + tmpString);
147                 }
148               }
149             }
150             // check score should be shown
151             if (!Float.isNaN(feature.getScore()))
152             {
153               float[][] rng = (minmax == null) ? null : ((float[][]) minmax
154                       .get(feature.getType()));
155               if (rng != null && rng[0] != null && rng[0][0] != rng[0][1])
156               {
157                 tooltipText2.append(" Score=" + feature.getScore());
158               }
159             }
160             if (feature.getValue("status") != null)
161             {
162               String status = feature.getValue("status").toString();
163               if (status.length() > 0)
164               {
165                 tooltipText2.append("; (" + feature.getValue("status")
166                         + ")");
167               }
168             }
169           }
170         }
171         if (feature.links != null)
172         {
173           if (linkImageURL != null)
174           {
175             tooltipText2.append(" <img src=\"" + linkImageURL + "\">");
176           }
177           else
178           {
179             for (String urlstring : feature.links)
180             {
181               try
182               {
183                 for (String[] urllink : createLinksFrom(null, urlstring))
184                 {
185                   tooltipText2.append("<br/> <a href=\""
186                           + urllink[3]
187                           + "\" target=\""
188                           + urllink[0]
189                           + "\">"
190                           + (urllink[0].toLowerCase().equals(
191                                   urllink[1].toLowerCase()) ? urllink[0]
192                                   : (urllink[0] + ":" + urllink[1]))
193                           + "</a></br>");
194                 }
195               } catch (Exception x)
196               {
197                 System.err.println("problem when creating links from "
198                         + urlstring);
199                 x.printStackTrace();
200               }
201             }
202           }
203
204         }
205       }
206     }
207   }
208
209   /**
210    * 
211    * @param seq
212    * @param link
213    * @return String[][] { String[] { link target, link label, dynamic component
214    *         inserted (if any), url }}
215    */
216   public String[][] createLinksFrom(SequenceI seq, String link)
217   {
218     ArrayList<String[]> urlSets = new ArrayList<String[]>();
219     ArrayList<String> uniques = new ArrayList<String>();
220     UrlLink urlLink = new UrlLink(link);
221     if (!urlLink.isValid())
222     {
223       System.err.println(urlLink.getInvalidMessage());
224       return null;
225     }
226     final String target = urlLink.getTarget(); // link.substring(0,
227     // link.indexOf("|"));
228     final String label = urlLink.getLabel();
229     if (seq != null && urlLink.isDynamic())
230     {
231
232       // collect matching db-refs
233       DBRefEntry[] dbr = jalview.util.DBRefUtils.selectRefs(seq.getDBRef(),
234               new String[] { target });
235       // collect id string too
236       String id = seq.getName();
237       String descr = seq.getDescription();
238       if (descr != null && descr.length() < 1)
239       {
240         descr = null;
241       }
242       if (dbr != null)
243       {
244         for (int r = 0; r < dbr.length; r++)
245         {
246           if (id != null && dbr[r].getAccessionId().equals(id))
247           {
248             // suppress duplicate link creation for the bare sequence ID
249             // string with this link
250             id = null;
251           }
252           // create Bare ID link for this RUL
253           String[] urls = urlLink.makeUrls(dbr[r].getAccessionId(), true);
254           if (urls != null)
255           {
256             for (int u = 0; u < urls.length; u += 2)
257             {
258               String unq = urls[u] + "|" + urls[u + 1];
259               if (!uniques.contains(unq))
260               {
261                 urlSets.add(new String[] { target, label, urls[u],
262                     urls[u + 1] });
263                 uniques.add(unq);
264               }
265             }
266           }
267         }
268       }
269       if (id != null)
270       {
271         // create Bare ID link for this RUL
272         String[] urls = urlLink.makeUrls(id, true);
273         if (urls != null)
274         {
275           for (int u = 0; u < urls.length; u += 2)
276           {
277             String unq = urls[u] + "|" + urls[u + 1];
278             if (!uniques.contains(unq))
279             {
280               urlSets.add(new String[] { target, label, urls[u],
281                   urls[u + 1] });
282               uniques.add(unq);
283             }
284           }
285         }
286       }
287       if (descr != null && urlLink.getRegexReplace() != null)
288       {
289         // create link for this URL from description only if regex matches
290         String[] urls = urlLink.makeUrls(descr, true);
291         if (urls != null)
292         {
293           for (int u = 0; u < urls.length; u += 2)
294           {
295             String unq = urls[u] + "|" + urls[u + 1];
296             if (!uniques.contains(unq))
297             {
298               urlSets.add(new String[] { target, label, urls[u],
299                   urls[u + 1] });
300               uniques.add(unq);
301             }
302           }
303         }
304       }
305
306     }
307     else
308     {
309       String unq = label + "|" + urlLink.getUrl_prefix();
310       if (!uniques.contains(unq))
311       {
312         uniques.add(unq);
313         // Add a non-dynamic link
314         urlSets.add(new String[] { target, label, null,
315             urlLink.getUrl_prefix() });
316       }
317     }
318
319     return urlSets.toArray(new String[][] {});
320   }
321
322   public void createSequenceAnnotationReport(final StringBuffer tip,
323           SequenceI sequence, boolean showDbRefs, boolean showNpFeats,
324           Hashtable minmax)
325   {
326     createSequenceAnnotationReport(tip, sequence, showDbRefs, showNpFeats,
327             true, minmax);
328   }
329
330   public void createSequenceAnnotationReport(final StringBuffer tip,
331           SequenceI sequence, boolean showDbRefs, boolean showNpFeats,
332           boolean tableWrap, Hashtable minmax)
333   {
334     String tmp;
335     tip.append("<i>");
336
337     int maxWidth = 0;
338     if (sequence.getDescription() != null)
339     {
340       tmp = sequence.getDescription();
341       tip.append("<br>" + tmp);
342       maxWidth = Math.max(maxWidth, tmp.length());
343     }
344     SequenceI ds = sequence;
345     while (ds.getDatasetSequence() != null)
346     {
347       ds = ds.getDatasetSequence();
348     }
349     DBRefEntry[] dbrefs = ds.getDBRef();
350     if (showDbRefs && dbrefs != null)
351     {
352       for (int i = 0; i < dbrefs.length; i++)
353       {
354         tip.append("<br>");
355         tmp = dbrefs[i].getSource() + " " + dbrefs[i].getAccessionId();
356         tip.append(tmp);
357         maxWidth = Math.max(maxWidth, tmp.length());
358       }
359     }
360
361     // ADD NON POSITIONAL SEQUENCE INFO
362     SequenceFeature[] features = sequence.getSequenceFeatures();
363     if (showNpFeats && features != null)
364     {
365       for (int i = 0; i < features.length; i++)
366       {
367         if (features[i].begin == 0 && features[i].end == 0)
368         {
369           int sz = -tip.length();
370           List<SequenceFeature> tfeat = new ArrayList<SequenceFeature>();
371           tfeat.add(features[i]);
372           appendFeatures(tip, 0, tfeat, minmax);
373           sz += tip.length();
374           maxWidth = Math.max(maxWidth, sz);
375         }
376       }
377     }
378
379     if (tableWrap && maxWidth > 60)
380     {
381       tip.insert(0, "<table width=350 border=0><tr><td><i>");
382       tip.append("</i></td></tr></table>");
383     }
384
385   }
386 }