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