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