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