JAL-1432 updated copyright notices
[jalview.git] / src / jalview / io / SequenceAnnotationReport.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.0b1)
3  * Copyright (C) 2014 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 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  * The Jalview Authors are detailed in the 'AUTHORS' file.
18  */
19 package jalview.io;
20
21 import java.util.ArrayList;
22 import java.util.Hashtable;
23 import java.util.Vector;
24
25 import jalview.datamodel.DBRefEntry;
26 import jalview.datamodel.SequenceFeature;
27 import jalview.datamodel.SequenceI;
28 import jalview.util.UrlLink;
29
30 /**
31  * generate HTML reports for a sequence
32  * 
33  * @author jimp
34  */
35 public class SequenceAnnotationReport
36 {
37   final String linkImageURL;
38
39   public SequenceAnnotationReport(String linkImageURL)
40   {
41     this.linkImageURL = linkImageURL;
42   }
43
44   /**
45    * appends the features at rpos to the given stringbuffer ready for display in
46    * a tooltip
47    * 
48    * @param tooltipText2
49    * @param linkImageURL
50    * @param rpos
51    * @param features
52    *          TODO refactor to Jalview 'utilities' somehow.
53    */
54   public void appendFeatures(final StringBuffer tooltipText2, int rpos,
55           SequenceFeature[] features)
56   {
57     appendFeatures(tooltipText2, rpos, features, null);
58   }
59
60   public void appendFeatures(final StringBuffer tooltipText2, int rpos,
61           SequenceFeature[] features, Hashtable minmax)
62   {
63     String tmpString;
64     if (features != null)
65     {
66       for (int i = 0; i < features.length; i++)
67       {
68         if (features[i].getType().equals("disulfide bond"))
69         {
70           if (features[i].getBegin() == rpos
71                   || features[i].getEnd() == rpos)
72           {
73             if (tooltipText2.length() > 6)
74             {
75               tooltipText2.append("<br>");
76             }
77             tooltipText2.append("disulfide bond " + features[i].getBegin()
78                     + ":" + features[i].getEnd());
79           }
80         }
81         else
82         {
83           if (tooltipText2.length() > 6)
84           {
85             tooltipText2.append("<br>");
86           }
87           // TODO: remove this hack to display link only features
88           boolean linkOnly = features[i].getValue("linkonly") != null;
89           if (!linkOnly)
90           {
91             tooltipText2.append(features[i].getType() + " ");
92             if (rpos != 0)
93             {
94               // we are marking a positional feature
95               tooltipText2.append(features[i].begin);
96             }
97             if (features[i].begin != features[i].end)
98             {
99               tooltipText2.append(" " + features[i].end);
100             }
101
102             if (features[i].getDescription() != null
103                     && !features[i].description.equals(features[i]
104                             .getType()))
105             {
106               tmpString = features[i].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 (features[i].getScore() != Float.NaN)
152             {
153               float[][] rng = (minmax == null) ? null : ((float[][]) minmax
154                       .get(features[i].getType()));
155               if (rng != null && rng[0] != null && rng[0][0] != rng[0][1])
156               {
157                 tooltipText2.append(" Score=" + features[i].getScore());
158               }
159             }
160             if (features[i].getValue("status") != null)
161             {
162               String status = features[i].getValue("status").toString();
163               if (status.length() > 0)
164               {
165                 tooltipText2.append("; (" + features[i].getValue("status")
166                         + ")");
167               }
168             }
169           }
170         }
171         if (features[i].links != null)
172         {
173           if (linkImageURL != null)
174           {
175             tooltipText2.append(" <img src=\"" + linkImageURL + "\">");
176           }
177           else
178           {
179             for (String urlstring : (Vector<String>) features[i].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[]
235               { target });
236       // collect id string too
237       String id = seq.getName();
238       String descr = seq.getDescription();
239       if (descr != null && descr.length() < 1)
240       {
241         descr = null;
242       }
243       if (dbr != null)
244       {
245         for (int r = 0; r < dbr.length; r++)
246         {
247           if (id != null && dbr[r].getAccessionId().equals(id))
248           {
249             // suppress duplicate link creation for the bare sequence ID
250             // string with this link
251             id = null;
252           }
253           // create Bare ID link for this RUL
254           String[] urls = urlLink.makeUrls(dbr[r].getAccessionId(), true);
255           if (urls != null)
256           {
257             for (int u = 0; u < urls.length; u += 2)
258             {
259               String unq = urls[u] + "|" + urls[u + 1];
260               if (!uniques.contains(unq))
261               {
262                 urlSets.add(new String[]
263                 { target, label, urls[u], urls[u + 1] });
264                 uniques.add(unq);
265               }
266             }
267           }
268         }
269       }
270       if (id != null)
271       {
272         // create Bare ID link for this RUL
273         String[] urls = urlLink.makeUrls(id, true);
274         if (urls != null)
275         {
276           for (int u = 0; u < urls.length; u += 2)
277           {
278             String unq = urls[u] + "|" + urls[u + 1];
279             if (!uniques.contains(unq))
280             {
281               urlSets.add(new String[]
282               { target, label, urls[u], urls[u + 1] });
283               uniques.add(unq);
284             }
285           }
286         }
287       }
288       if (descr != null && urlLink.getRegexReplace() != null)
289       {
290         // create link for this URL from description only if regex matches
291         String[] urls = urlLink.makeUrls(descr, true);
292         if (urls != null)
293         {
294           for (int u = 0; u < urls.length; u += 2)
295           {
296             String unq = urls[u] + "|" + urls[u + 1];
297             if (!uniques.contains(unq))
298             {
299               urlSets.add(new String[]
300               { target, label, urls[u], urls[u + 1] });
301               uniques.add(unq);
302             }
303           }
304         }
305       }
306
307     }
308     else
309     {
310       String unq = label + "|" + urlLink.getUrl_prefix();
311       if (!uniques.contains(unq))
312       {
313         uniques.add(unq);
314         // Add a non-dynamic link
315         urlSets.add(new String[]
316         { target, label, null, urlLink.getUrl_prefix() });
317       }
318     }
319
320     return urlSets.toArray(new String[][]
321     {});
322   }
323
324   public void createSequenceAnnotationReport(final StringBuffer tip,
325           SequenceI sequence, boolean showDbRefs, boolean showNpFeats,
326           Hashtable minmax)
327   {
328     createSequenceAnnotationReport(tip, sequence, showDbRefs, showNpFeats,
329             true, minmax);
330   }
331
332   public void createSequenceAnnotationReport(final StringBuffer tip,
333           SequenceI sequence, boolean showDbRefs, boolean showNpFeats,
334           boolean tableWrap, Hashtable minmax)
335   {
336     String tmp;
337     tip.append("<i>");
338
339     int maxWidth = 0;
340     if (sequence.getDescription() != null)
341     {
342       tmp = sequence.getDescription();
343       tip.append("<br>" + tmp);
344       maxWidth = Math.max(maxWidth, tmp.length());
345     }
346     SequenceI ds = sequence;
347     while (ds.getDatasetSequence() != null)
348     {
349       ds = ds.getDatasetSequence();
350     }
351     DBRefEntry[] dbrefs = ds.getDBRef();
352     if (showDbRefs && dbrefs != null)
353     {
354       for (int i = 0; i < dbrefs.length; i++)
355       {
356         tip.append("<br>");
357         tmp = dbrefs[i].getSource() + " " + dbrefs[i].getAccessionId();
358         tip.append(tmp);
359         maxWidth = Math.max(maxWidth, tmp.length());
360       }
361     }
362
363     // ADD NON POSITIONAL SEQUENCE INFO
364     SequenceFeature[] features = ds.getSequenceFeatures();
365     SequenceFeature[] tfeat = new SequenceFeature[1];
366     if (showNpFeats && features != null)
367     {
368       for (int i = 0; i < features.length; i++)
369       {
370         if (features[i].begin == 0 && features[i].end == 0)
371         {
372           int sz = -tip.length();
373           tfeat[0] = features[i];
374           appendFeatures(tip, 0, tfeat, minmax);
375           sz += tip.length();
376           maxWidth = Math.max(maxWidth, sz);
377         }
378       }
379     }
380
381     if (tableWrap && maxWidth > 60)
382     {
383       tip.insert(0, "<table width=350 border=0><tr><td><i>");
384       tip.append("</i></td></tr></table>");
385     }
386
387   }
388 }