497e4c920df0b04fef00bf0f84fb0a5ab5540437
[jalview.git] / src / jalview / io / SequenceAnnotationReport.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3  * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
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  */
18 package jalview.io;
19
20 import java.util.ArrayList;
21 import java.util.Hashtable;
22 import java.util.Vector;
23
24 import jalview.datamodel.DBRefEntry;
25 import jalview.datamodel.SequenceFeature;
26 import jalview.datamodel.SequenceI;
27 import jalview.util.UrlLink;
28
29 /**
30  * generate HTML reports for a sequence
31  * 
32  * @author jimp
33  */
34 public class SequenceAnnotationReport
35 {
36   final String linkImageURL;
37
38   public SequenceAnnotationReport(String linkImageURL)
39   {
40     this.linkImageURL = linkImageURL;
41   }
42
43   /**
44    * appends the features at rpos to the given stringbuffer ready for display in
45    * a tooltip
46    * 
47    * @param tooltipText2
48    * @param linkImageURL
49    * @param rpos
50    * @param features
51    *          TODO refactor to Jalview 'utilities' somehow.
52    */
53   public void appendFeatures(final StringBuffer tooltipText2, int rpos,
54           SequenceFeature[] features)
55   {
56     appendFeatures(tooltipText2, rpos, features, null);
57   }
58
59   public void appendFeatures(final StringBuffer tooltipText2, int rpos,
60           SequenceFeature[] features, Hashtable minmax)
61   {
62     String tmpString;
63     if (features != null)
64     {
65       for (int i = 0; i < features.length; i++)
66       {
67         if (features[i].getType().equals("disulfide bond"))
68         {
69           if (features[i].getBegin() == rpos
70                   || features[i].getEnd() == rpos)
71           {
72             if (tooltipText2.length() > 6)
73             {
74               tooltipText2.append("<br>");
75             }
76             tooltipText2.append("disulfide bond " + features[i].getBegin()
77                     + ":" + features[i].getEnd());
78           }
79         }
80         else
81         {
82           if (tooltipText2.length() > 6)
83           {
84             tooltipText2.append("<br>");
85           }
86           // TODO: remove this hack to display link only features
87           boolean linkOnly = features[i].getValue("linkonly") != null;
88           if (!linkOnly)
89           {
90             tooltipText2.append(features[i].getType() + " ");
91             if (rpos != 0)
92             {
93               // we are marking a positional feature
94               tooltipText2.append(features[i].begin);
95             }
96             if (features[i].begin != features[i].end)
97             {
98               tooltipText2.append(" " + features[i].end);
99             }
100
101             if (features[i].getDescription() != null
102                     && !features[i].description.equals(features[i]
103                             .getType()))
104             {
105               tmpString = features[i].getDescription();
106               String tmp2up = tmpString.toUpperCase();
107               int startTag = tmp2up.indexOf("<HTML>");
108               if (startTag > -1)
109               {
110                 tmpString = tmpString.substring(startTag + 6);
111                 tmp2up = tmp2up.substring(startTag + 6);
112               }
113               int endTag = tmp2up.indexOf("</BODY>");
114               if (endTag > -1)
115               {
116                 tmpString = tmpString.substring(0, endTag);
117                 tmp2up = tmp2up.substring(0, endTag);
118               }
119               endTag = tmp2up.indexOf("</HTML>");
120               if (endTag > -1)
121               {
122                 tmpString = tmpString.substring(0, endTag);
123               }
124
125               if (startTag > -1)
126               {
127                 tooltipText2.append("; " + tmpString);
128               }
129               else
130               {
131                 if (tmpString.indexOf("<") > -1
132                         || tmpString.indexOf(">") > -1)
133                 {
134                   // The description does not specify html is to
135                   // be used, so we must remove < > symbols
136                   tmpString = tmpString.replaceAll("<", "&lt;");
137                   tmpString = tmpString.replaceAll(">", "&gt;");
138
139                   tooltipText2.append("; ");
140                   tooltipText2.append(tmpString);
141
142                 }
143                 else
144                 {
145                   tooltipText2.append("; " + tmpString);
146                 }
147               }
148             }
149             // check score should be shown
150             if (features[i].getScore() != Float.NaN)
151             {
152               float[][] rng = (minmax == null) ? null : ((float[][]) minmax
153                       .get(features[i].getType()));
154               if (rng != null && rng[0] != null && rng[0][0] != rng[0][1])
155               {
156                 tooltipText2.append(" Score=" + features[i].getScore());
157               }
158             }
159             if (features[i].getValue("status") != null)
160             {
161               String status = features[i].getValue("status").toString();
162               if (status.length() > 0)
163               {
164                 tooltipText2.append("; (" + features[i].getValue("status")
165                         + ")");
166               }
167             }
168           }
169         }
170         if (features[i].links != null)
171         {
172           if (linkImageURL != null)
173           {
174             tooltipText2.append(" <img src=\"" + linkImageURL + "\">");
175           }
176           else
177           {
178             for (String urlstring : (Vector<String>) features[i].links)
179             {
180               try
181               {
182                 for (String[] urllink : createLinksFrom(null, urlstring))
183                 {
184                   tooltipText2.append("<br/> <a href=\""
185                           + urllink[3]
186                           + "\" target=\""
187                           + urllink[0]
188                           + "\">"
189                           + (urllink[0].toLowerCase().equals(
190                                   urllink[1].toLowerCase()) ? urllink[0]
191                                   : (urllink[0] + ":" + urllink[1]))
192                           + "</a></br>");
193                 }
194               } catch (Exception x)
195               {
196                 System.err.println("problem when creating links from "
197                         + urlstring);
198                 x.printStackTrace();
199               }
200             }
201           }
202
203         }
204       }
205     }
206   }
207
208   /**
209    * 
210    * @param seq
211    * @param link
212    * @return String[][] { String[] { link target, link label, dynamic component
213    *         inserted (if any), url }}
214    */
215   public String[][] createLinksFrom(SequenceI seq, String link)
216   {
217     ArrayList<String[]> urlSets = new ArrayList<String[]>();
218     ArrayList<String> uniques = new ArrayList<String>();
219     UrlLink urlLink = new UrlLink(link);
220     if (!urlLink.isValid())
221     {
222       System.err.println(urlLink.getInvalidMessage());
223       return null;
224     }
225     final String target = urlLink.getTarget(); // link.substring(0,
226     // link.indexOf("|"));
227     final String label = urlLink.getLabel();
228     if (seq != null && urlLink.isDynamic())
229     {
230
231       // collect matching db-refs
232       DBRefEntry[] dbr = jalview.util.DBRefUtils.selectRefs(seq.getDBRef(),
233               new String[]
234               { 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[]
262                 { target, label, urls[u], 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[]
281               { target, label, urls[u], 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[]
299               { target, label, urls[u], 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[]
315         { target, label, null, urlLink.getUrl_prefix() });
316       }
317     }
318
319     return urlSets.toArray(new String[][]
320     {});
321   }
322
323   public void createSequenceAnnotationReport(final StringBuffer tip,
324           SequenceI sequence, boolean showDbRefs, boolean showNpFeats,
325           Hashtable minmax)
326   {
327     createSequenceAnnotationReport(tip, sequence, showDbRefs, showNpFeats,
328             true, minmax);
329   }
330
331   public void createSequenceAnnotationReport(final StringBuffer tip,
332           SequenceI sequence, boolean showDbRefs, boolean showNpFeats,
333           boolean tableWrap, Hashtable minmax)
334   {
335     String tmp;
336     tip.append("<i>");
337
338     int maxWidth = 0;
339     if (sequence.getDescription() != null)
340     {
341       tmp = sequence.getDescription();
342       tip.append("<br>" + tmp);
343       maxWidth = Math.max(maxWidth, tmp.length());
344     }
345     SequenceI ds = sequence;
346     while (ds.getDatasetSequence() != null)
347     {
348       ds = ds.getDatasetSequence();
349     }
350     DBRefEntry[] dbrefs = ds.getDBRef();
351     if (showDbRefs && dbrefs != null)
352     {
353       for (int i = 0; i < dbrefs.length; i++)
354       {
355         tip.append("<br>");
356         tmp = dbrefs[i].getSource() + " " + dbrefs[i].getAccessionId();
357         tip.append(tmp);
358         maxWidth = Math.max(maxWidth, tmp.length());
359       }
360     }
361
362     // ADD NON POSITIONAL SEQUENCE INFO
363     SequenceFeature[] features = ds.getSequenceFeatures();
364     SequenceFeature[] tfeat = new SequenceFeature[1];
365     if (showNpFeats && features != null)
366     {
367       for (int i = 0; i < features.length; i++)
368       {
369         if (features[i].begin == 0 && features[i].end == 0)
370         {
371           int sz = -tip.length();
372           tfeat[0] = features[i];
373           appendFeatures(tip, 0, tfeat, minmax);
374           sz += tip.length();
375           maxWidth = Math.max(maxWidth, sz);
376         }
377       }
378     }
379
380     if (tableWrap && maxWidth > 60)
381     {
382       tip.insert(0, "<table width=350 border=0><tr><td><i>");
383       tip.append("</i></td></tr></table>");
384     }
385
386   }
387 }