JAL-1641 Further refactoring of JSON export option, introduction of Viewport to the...
[jalview.git] / src / jalview / io / JSONFile.java
1 package jalview.io;
2
3 import jalview.api.AlignViewportI;
4 import jalview.api.FeatureRenderer;
5 import jalview.api.FeaturesDisplayedI;
6 import jalview.datamodel.AlignmentAnnotation;
7 import jalview.datamodel.Annotation;
8 import jalview.datamodel.Sequence;
9 import jalview.datamodel.SequenceFeature;
10 import jalview.datamodel.SequenceGroup;
11 import jalview.datamodel.SequenceI;
12 import jalview.gui.AlignFrame;
13 import jalview.json.binding.v1.AlignmentAnnotationPojo;
14 import jalview.json.binding.v1.AlignmentPojo;
15 import jalview.json.binding.v1.AnnotationPojo;
16 import jalview.json.binding.v1.JalviewSettingsPojo;
17 import jalview.json.binding.v1.JalviewSettingsPojo.JalviewBioJsColorSchemeMapper;
18 import jalview.json.binding.v1.SequenceFeaturesPojo;
19 import jalview.json.binding.v1.SequenceGrpPojo;
20 import jalview.json.binding.v1.SequencePojo;
21 import jalview.schemes.ColourSchemeI;
22 import jalview.schemes.ColourSchemeProperty;
23
24 import java.awt.Color;
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.Hashtable;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Vector;
31
32 import org.json.simple.JSONArray;
33 import org.json.simple.JSONObject;
34 import org.json.simple.parser.JSONParser;
35
36 public class JSONFile extends AlignFile
37 {
38   private ColourSchemeI colourScheme;
39
40   // private static boolean seqFeaturesEnabled;
41
42   private String jalviewVersion;
43
44   private String webStartLaunchServletUrl;
45
46   public static final String FILE_EXT = "json";
47
48   public static final String FILE_DESC = "JSON";
49
50   private String globalColorScheme;
51
52   private boolean showSeqFeatures;
53
54   private Hashtable<String, Sequence> seqMap;
55
56   private FeaturesDisplayedI displayedFeatures;
57
58   // private AlignViewportI viewport;
59
60   private FeatureRenderer fr;
61
62   private JSONExportSettings jsonExportSettings;
63
64   public JSONFile()
65   {
66     super();
67   }
68
69   public JSONFile(FileParse source) throws IOException
70   {
71     super(source);
72   }
73
74   public JSONFile(String inFile, String type) throws IOException
75   {
76     super(inFile, type);
77   }
78
79   @Override
80   public void parse() throws IOException
81   {
82     StringBuilder jsonStringBuilder = new StringBuilder();
83     String currentLine;
84     while ((currentLine = nextLine()) != null)
85     {
86       jsonStringBuilder.append(currentLine);
87     }
88     parse(jsonStringBuilder.toString());
89
90   }
91
92   @Override
93   public String print()
94   {
95     try
96     {
97       if (getJsonExportSettings() == null)
98       {
99         jsonExportSettings = new JSONExportSettings();
100         jsonExportSettings.setExportAnnotations(true);
101         jsonExportSettings.setExportGroups(true);
102         jsonExportSettings.setExportJalviewSettings(true);
103         jsonExportSettings.setExportSequenceFeatures(true);
104       }
105
106       AlignmentPojo jsonAlignmentPojo = new AlignmentPojo();
107       if (getViewport() != null)
108       {
109         globalColorScheme = ColourSchemeProperty
110                 .getColourName(getViewport()
111                 .getGlobalColourScheme());
112         setDisplayedFeatures(getViewport().getFeaturesDisplayed());
113         showSeqFeatures = getViewport().isShowSequenceFeatures();
114         fr = getViewport().getFeatureRenderer();
115         // setSeqFeaturesEnabled(viewport.isShowSequenceFeatures());
116       }
117
118       int count = 0;
119       for (SequenceI seq : seqs)
120       {
121         StringBuilder name = new StringBuilder();
122         name.append(seq.getName()).append("/").append(seq.getStart())
123                 .append("-").append(seq.getEnd());
124         SequencePojo jsonSeqPojo = new SequencePojo();
125         jsonSeqPojo.setId(seq.getName() + "_" + seq.hashCode());
126         jsonSeqPojo.setOrder(++count);
127         jsonSeqPojo.setEnd(seq.getEnd());
128         jsonSeqPojo.setStart(seq.getStart());
129         jsonSeqPojo.setName(name.toString());
130         jsonSeqPojo.setSeq(seq.getSequenceAsString());
131         jsonAlignmentPojo.getSeqs().add(jsonSeqPojo);
132       }
133
134       if (jsonExportSettings.isExportJalviewSettings())
135       {
136         jalviewVersion = jalview.bin.Cache.getProperty("VERSION");
137         webStartLaunchServletUrl = jalview.bin.Cache.getDefault(
138                 "www.jalview.org", "http://www.jalview.org")
139                 + "/services/launchApp";
140
141         JalviewSettingsPojo jvSettings = new JalviewSettingsPojo();
142         jvSettings.setGlobalColorScheme(globalColorScheme);
143         jvSettings.setJalviewVersion(jalviewVersion);
144         jvSettings.setWebStartUrl(webStartLaunchServletUrl);
145         jvSettings.setShowSeqFeatures(showSeqFeatures);
146         jsonAlignmentPojo.setJalviewSettings(jvSettings);
147       }
148
149       if (jsonExportSettings.isExportAnnotations())
150       {
151         jsonAlignmentPojo
152                 .setAlignAnnotation(annotationToJsonPojo(annotations));
153       }
154
155       if (jsonExportSettings.isExportSequenceFeatures())
156       {
157         jsonAlignmentPojo
158                 .setSeqFeatures(sequenceFeatureToJsonPojo(seqs, fr));
159       }
160
161       if (jsonExportSettings.isExportGroups() && seqGroups != null
162               && seqGroups.size() > 0)
163       {
164         for (SequenceGroup seqGrp : seqGroups)
165         {
166           SequenceGrpPojo seqGrpPojo = new SequenceGrpPojo();
167           seqGrpPojo.setGroupName(seqGrp.getName());
168           seqGrpPojo.setColourScheme(ColourSchemeProperty
169                   .getColourName(seqGrp.cs));
170           seqGrpPojo.setColourText(seqGrp.getColourText());
171           seqGrpPojo.setDescription(seqGrp.getDescription());
172           seqGrpPojo.setDisplayBoxes(seqGrp.getDisplayBoxes());
173           seqGrpPojo.setDisplayText(seqGrp.getDisplayText());
174           seqGrpPojo.setEndRes(seqGrp.getEndRes());
175           seqGrpPojo.setStartRes(seqGrp.getStartRes());
176           seqGrpPojo.setShowNonconserved(seqGrp.getShowNonconserved());
177           for (SequenceI seq : seqGrp.getSequences())
178           {
179             seqGrpPojo.getSeqsHash().add(
180                     seq.getName() + "_" + seq.hashCode());
181           }
182           jsonAlignmentPojo.getSeqGroups().add(seqGrpPojo);
183         }
184       }
185       com.json.JSONObject generatedJSon = new com.json.JSONObject(
186               jsonAlignmentPojo);
187       String jsonOutput = generatedJSon.toString();
188       return jsonOutput.replaceAll("xstart", "xStart").replaceAll("xend",
189               "xEnd");
190     } catch (Exception e)
191     {
192       e.printStackTrace();
193       throw e;
194     }
195   }
196
197   public static List<SequenceFeaturesPojo> sequenceFeatureToJsonPojo(
198           List<SequenceI> seqs, FeatureRenderer fr)
199   {
200     FeaturesDisplayedI displayedFeatures = (fr == null) ? null : fr
201             .getFeaturesDisplayed();
202     List<SequenceFeaturesPojo> sequenceFeaturesPojo = new ArrayList<SequenceFeaturesPojo>();
203     for (SequenceI seq : seqs)
204     {
205       SequenceI dataSetSequence = seq.getDatasetSequence();
206       SequenceFeature[] seqFeatures = (dataSetSequence == null) ? null
207               : seq.getDatasetSequence().getSequenceFeatures();
208
209       if (seqFeatures == null)
210       {
211         continue;
212       }
213
214       for (SequenceFeature sf : seqFeatures)
215       {
216         if (displayedFeatures != null
217                 && displayedFeatures.isVisible(sf.getType()))
218         {
219           SequenceFeaturesPojo jsonFeature = new SequenceFeaturesPojo(
220                   seq.getName() + "_" + seq.hashCode());
221           String featureColour = (fr == null) ? null : jalview.util.Format
222                   .getHexString(fr
223                   .findFeatureColour(Color.white, seq,
224                           seq.findIndex(sf.getBegin())));
225           jsonFeature.setXstart(seq.findIndex(sf.getBegin()) - 1);
226           jsonFeature.setXend(seq.findIndex(sf.getEnd()));
227           jsonFeature.setType(sf.getType());
228           jsonFeature.setDescription(sf.getDescription());
229           jsonFeature.setLinks(sf.links);
230           jsonFeature.setOtherDetails(sf.otherDetails);
231           jsonFeature.setScore(sf.getScore());
232           jsonFeature.setFillColor(featureColour);
233           jsonFeature.setFeatureGroup(sf.getFeatureGroup());
234           sequenceFeaturesPojo.add(jsonFeature);
235         }
236       }
237     }
238     return sequenceFeaturesPojo;
239   }
240
241   public static List<AlignmentAnnotationPojo> annotationToJsonPojo(
242           Vector<AlignmentAnnotation> annotations)
243   {
244     List<AlignmentAnnotationPojo> jsonAnnotations = new ArrayList<AlignmentAnnotationPojo>();
245     if (annotations == null)
246     {
247       return jsonAnnotations;
248     }
249     for (AlignmentAnnotation annot : annotations)
250     {
251       AlignmentAnnotationPojo alignAnnotPojo = new AlignmentAnnotationPojo();
252       alignAnnotPojo.setDescription(annot.description);
253       alignAnnotPojo.setLabel(annot.label);
254       for (Annotation annotation : annot.annotations)
255       {
256         AnnotationPojo annotationPojo = new AnnotationPojo();
257         if (annotation != null)
258         {
259           annotationPojo.setDescription(annotation.description);
260           annotationPojo.setValue(annotation.value);
261           annotationPojo
262                   .setSecondaryStructure(annotation.secondaryStructure);
263           annotationPojo.setDisplayCharacter(annotation.displayCharacter);
264           alignAnnotPojo.getAnnotations().add(annotationPojo);
265         }
266         else
267         {
268           alignAnnotPojo.getAnnotations().add(annotationPojo);
269         }
270       }
271       jsonAnnotations.add(alignAnnotPojo);
272     }
273     return jsonAnnotations;
274   }
275
276   @SuppressWarnings("unchecked")
277   public JSONFile parse(String jsonAlignmentString)
278   {
279     try
280     {
281       JSONParser jsonParser = new JSONParser();
282       JSONObject alignmentJsonObj = (JSONObject) jsonParser
283               .parse(jsonAlignmentString);
284       JSONArray seqJsonArray = (JSONArray) alignmentJsonObj.get("seqs");
285       JSONArray alAnnotJsonArray = (JSONArray) alignmentJsonObj
286               .get("alignAnnotation");
287       JSONArray jsonSeqArray = (JSONArray) alignmentJsonObj
288               .get("seqFeatures");
289       JSONArray seqGrpJsonArray = (JSONArray) alignmentJsonObj
290               .get("seqGroups");
291       JSONObject jvSettingsJsonObj = (JSONObject) alignmentJsonObj
292               .get("jalviewSettings");
293
294       if (jvSettingsJsonObj != null)
295       {
296         String jsColourScheme = (String) jvSettingsJsonObj
297                 .get("globalColorScheme");
298         Boolean showFeatures = Boolean.valueOf(jvSettingsJsonObj.get(
299                 "showSeqFeatures").toString());
300         setColourScheme(getJalviewColorScheme(jsColourScheme));
301         // JSONFile.setSeqFeaturesEnabled(showFeatures);
302         setShowSeqFeatures(showFeatures);
303       }
304
305       seqMap = new Hashtable<String, Sequence>();
306       for (Iterator<JSONObject> sequenceIter = seqJsonArray.iterator(); sequenceIter
307               .hasNext();)
308       {
309         JSONObject sequence = sequenceIter.next();
310         String sequcenceString = sequence.get("seq").toString();
311         String sequenceName = sequence.get("name").toString();
312         String seqUniqueId = sequence.get("id").toString();
313         int start = Integer.valueOf(sequence.get("start").toString());
314         int end = Integer.valueOf(sequence.get("end").toString());
315         Sequence seq = new Sequence(sequenceName, sequcenceString, start,
316                 end);
317         seqs.add(seq);
318         seqMap.put(seqUniqueId, seq);
319       }
320       parseFeatures(jsonSeqArray);
321
322       for (Iterator<JSONObject> seqGrpIter = seqGrpJsonArray.iterator(); seqGrpIter
323               .hasNext();)
324       {
325         JSONObject seqGrpObj = seqGrpIter.next();
326         String grpName = seqGrpObj.get("groupName").toString();
327         String colourScheme = seqGrpObj.get("colourScheme").toString();
328         String description = (seqGrpObj.get("description") == null) ? null
329                 : seqGrpObj.get("description").toString();
330         boolean displayBoxes = Boolean.valueOf(seqGrpObj
331                 .get("displayBoxes").toString());
332         boolean displayText = Boolean.valueOf(seqGrpObj.get("displayText")
333                 .toString());
334         boolean colourText = Boolean.valueOf(seqGrpObj.get("colourText")
335                 .toString());
336         boolean showNonconserved = Boolean.valueOf(seqGrpObj.get(
337                 "showNonconserved").toString());
338         int startRes = Integer
339                 .valueOf(seqGrpObj.get("startRes").toString());
340         int endRes = Integer.valueOf(seqGrpObj.get("endRes").toString());
341         JSONArray seqsHashArray = (JSONArray) seqGrpObj.get("seqsHash");
342
343         ArrayList<SequenceI> grpSeqs = new ArrayList<SequenceI>();
344         if (seqsHashArray.size() > 0)
345         {
346           Iterator<String> seqHashIter = seqsHashArray.iterator();
347           while (seqHashIter.hasNext())
348           {
349             String seqHash = seqHashIter.next();
350             Sequence sequence = seqMap.get(seqHash);
351             if (sequence != null)
352             {
353               grpSeqs.add(sequence);
354             }
355           }
356         }
357         ColourSchemeI scheme = getJalviewColorScheme(colourScheme);
358         SequenceGroup seqGrp = new SequenceGroup(grpSeqs, grpName, scheme,
359                 displayBoxes, displayText, colourText, startRes, endRes);
360         seqGrp.setShowNonconserved(showNonconserved);
361         seqGrp.setDescription(description);
362         this.seqGroups.add(seqGrp);
363
364       }
365
366       for (Iterator<JSONObject> alAnnotIter = alAnnotJsonArray.iterator(); alAnnotIter
367               .hasNext();)
368       {
369         JSONObject alAnnot = alAnnotIter.next();
370         JSONArray annotJsonArray = (JSONArray) alAnnot.get("annotations");
371         Annotation[] annotations = new Annotation[annotJsonArray.size()];
372         int count = 0;
373         for (Iterator<JSONObject> annotIter = annotJsonArray.iterator(); annotIter
374                 .hasNext();)
375         {
376           JSONObject annot = annotIter.next();
377           if (annot == null)
378           {
379             annotations[count] = null;
380           }
381           else
382           {
383             float val = annot.get("value") == null ? null : Float
384                     .valueOf(annot.get("value").toString());
385             String desc = annot.get("description") == null ? null : annot
386                     .get("description").toString();
387
388             char ss = annot.get("secondaryStructure") == null ? null
389                     : annot.get("secondaryStructure").toString().charAt(0);
390             String displayChar = annot.get("displayCharacter").toString();
391
392             annotations[count] = new Annotation(displayChar, desc, ss, val);
393           }
394           ++count;
395         }
396
397         AlignmentAnnotation alignAnnot = new AlignmentAnnotation(alAnnot
398                 .get("label").toString(), alAnnot.get("description")
399                 .toString(), annotations);
400         this.annotations.add(alignAnnot);
401       }
402
403     } catch (Exception e)
404     {
405       e.printStackTrace();
406     }
407     return this;
408   }
409
410
411   @SuppressWarnings("unchecked")
412   private void parseFeatures(JSONArray jsonSeqFeatures)
413   {
414     if (jsonSeqFeatures != null)
415     {
416       for (Iterator<JSONObject> seqFeatureItr = jsonSeqFeatures.iterator(); seqFeatureItr
417               .hasNext();)
418       {
419         JSONObject jsonFeature = seqFeatureItr.next();
420         Long begin = (Long) jsonFeature.get("xStart");
421         Long end = (Long) jsonFeature.get("xEnd");
422         String type = (String) jsonFeature.get("type");
423         String featureGrp = (String) jsonFeature.get("featureGroup");
424         String descripiton = (String) jsonFeature.get("description");
425         String seqRef = (String) jsonFeature.get("sequenceRef");
426         Float score = Float.valueOf(jsonFeature.get("score").toString());
427         // Hashtable otherDetails = (Hashtable) jsonFeature
428         // .get("otherDetails");
429         // sequenceFeature.otherDetails = otherDetails;
430
431         Sequence seq = seqMap.get(seqRef);
432         SequenceFeature sequenceFeature = new SequenceFeature();
433         JSONArray linksJsonArray = (JSONArray) jsonFeature.get("links");
434         if (linksJsonArray != null && linksJsonArray.size() > 0)
435         {
436           Iterator<String> linkList = linksJsonArray.iterator();
437           while (linkList.hasNext())
438           {
439             String link = linkList.next();
440             sequenceFeature.addLink(link);
441           }
442         }
443         sequenceFeature.setFeatureGroup(featureGrp);
444         sequenceFeature.setScore(score);
445         sequenceFeature.setDescription(descripiton);
446         sequenceFeature.setType(type);
447         sequenceFeature.setBegin(seq.findPosition(begin.intValue()));
448         sequenceFeature.setEnd(seq.findPosition(end.intValue()) - 1);
449         seq.addSequenceFeature(sequenceFeature);
450       }
451     }
452   }
453
454   public static ColourSchemeI getJalviewColorScheme(
455           String bioJsColourSchemeName)
456   {
457     ColourSchemeI jalviewColor = null;
458     for (JalviewBioJsColorSchemeMapper cs : JalviewBioJsColorSchemeMapper
459             .values())
460     {
461       if (cs.getBioJsName().equalsIgnoreCase(bioJsColourSchemeName))
462       {
463         jalviewColor = cs.getJvColourScheme();
464         break;
465       }
466     }
467     return jalviewColor;
468   }
469
470   public void LoadAlignmentFeatures(AlignFrame af)
471   {
472     af.setShowSeqFeatures(isShowSeqFeatures());
473     af.changeColour(getColourScheme());
474     af.setMenusForViewport();
475   }
476
477   public String getGlobalColorScheme()
478   {
479     return globalColorScheme;
480   }
481
482   public void setGlobalColorScheme(String globalColorScheme)
483   {
484     this.globalColorScheme = globalColorScheme;
485   }
486
487   public ColourSchemeI getColourScheme()
488   {
489     return colourScheme;
490   }
491
492   public void setColourScheme(ColourSchemeI colourScheme)
493   {
494     this.colourScheme = colourScheme;
495   }
496
497   public FeaturesDisplayedI getDisplayedFeatures()
498   {
499     return displayedFeatures;
500   }
501
502   public void setDisplayedFeatures(FeaturesDisplayedI displayedFeatures)
503   {
504     this.displayedFeatures = displayedFeatures;
505   }
506
507   public JSONExportSettings getJsonExportSettings()
508   {
509     return jsonExportSettings;
510   }
511
512   public void setJsonExportSettings(JSONExportSettings jsonExportSettings)
513   {
514     this.jsonExportSettings = jsonExportSettings;
515   }
516
517   public static String getJSONData(AlignViewportI av)
518   {
519     JSONFile jsonFile = new JSONFile();
520     jsonFile.setViewport(av);
521     jsonFile.seqGroups = av.getAlignment().getGroups();
522     jsonFile.setDisplayedFeatures(av.getFeaturesDisplayed());
523
524     for (SequenceI seq : av.getAlignment().getSequences())
525     {
526       jsonFile.seqs.add(seq);
527     }
528   
529     // Add non auto calculated annotation to AlignFile
530     for (AlignmentAnnotation annot : av.getAlignment()
531             .getAlignmentAnnotation())
532     {
533       if (annot != null && !annot.autoCalculated)
534       {
535         if (annot.label.equals("PDB.CATempFactor"))
536         {
537           continue;
538         }
539         jsonFile.annotations.add(annot);
540       }
541     }
542     String jsonString = jsonFile.print();
543     return jsonString;
544   }
545
546   public boolean isShowSeqFeatures()
547   {
548     return showSeqFeatures;
549   }
550
551   public void setShowSeqFeatures(boolean showSeqFeatures)
552   {
553     this.showSeqFeatures = showSeqFeatures;
554   }
555
556   public class JSONExportSettings
557   {
558     private boolean exportSequence;
559
560     private boolean exportSequenceFeatures;
561
562     private boolean exportAnnotations;
563
564     private boolean exportGroups;
565
566     private boolean exportJalviewSettings;
567
568     public boolean isExportSequence()
569     {
570       return exportSequence;
571     }
572
573     public void setExportSequence(boolean exportSequence)
574     {
575       this.exportSequence = exportSequence;
576     }
577
578     public boolean isExportSequenceFeatures()
579     {
580       return exportSequenceFeatures;
581     }
582
583     public void setExportSequenceFeatures(boolean exportSequenceFeatures)
584     {
585       this.exportSequenceFeatures = exportSequenceFeatures;
586     }
587
588     public boolean isExportAnnotations()
589     {
590       return exportAnnotations;
591     }
592
593     public void setExportAnnotations(boolean exportAnnotations)
594     {
595       this.exportAnnotations = exportAnnotations;
596     }
597
598     public boolean isExportGroups()
599     {
600       return exportGroups;
601     }
602
603     public void setExportGroups(boolean exportGroups)
604     {
605       this.exportGroups = exportGroups;
606     }
607
608     public boolean isExportJalviewSettings()
609     {
610       return exportJalviewSettings;
611     }
612
613     public void setExportJalviewSettings(boolean exportJalviewSettings)
614     {
615       this.exportJalviewSettings = exportJalviewSettings;
616     }
617   }
618 }