(JAL-1016) noted position where race condition occurs
[jalview.git] / src / org / biojava / dasobert / feature / FeatureTrackConverter.java
1 /*
2  *                  BioJava development code
3  *
4  * This code may be freely distributed and modified under the
5  * terms of the GNU Lesser General Public Licence.  This should
6  * be distributed with the code.  If you do not have a copy,
7  * see:
8  *
9  *      http://www.gnu.org/copyleft/lesser.html
10  *
11  * Copyright for this code is held jointly by the individual
12  * authors.  These should be listed in @author doc comments.
13  *
14  * For more information on the BioJava project and its aims,
15  * or to join the biojava-l mailing list, visit the home page
16  * at:
17  *
18  *      http://www.biojava.org/
19  * 
20  * Created on Dec 5, 2007
21  * 
22  */
23
24 package org.biojava.dasobert.feature;
25
26 import java.awt.Color;
27 import java.util.ArrayList;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31
32 /**
33  * converts the features from their "raw" representation as a Map into a Feature
34  * class
35  * 
36  * @author Andreas Prlic
37  * 
38  */
39 public class FeatureTrackConverter
40 {
41
42   public static final Color HELIX_COLOR = new Color(255, 51, 51);
43
44   public static final Color STRAND_COLOR = new Color(255, 204, 51);
45
46   public static final Color TURN_COLOR = new Color(204, 204, 204);
47
48   // some annotation types, for which there is a special treatment
49   public static final String DISULFID_TYPE = "DISULFID";
50
51   public static final String SECSTRUC_TYPE = "SECSTRUC";
52
53   public static final String METAL_TYPE = "METAL";
54
55   public static final String MSD_SITE_TYPE = "MSD_SITE";
56
57   String type;
58
59   public static final String TYPE_HISTOGRAM = "histogram";
60
61   public static final String TYPE_DEFAULT = "default";
62
63   // rotate between these colors
64   public static final Color[] entColors = new Color[]
65   { new Color(51, 51, 255), // blue
66       new Color(102, 255, 255), // cyan
67       new Color(153, 255, 153), // green
68       new Color(153, 255, 153), // green
69       new Color(255, 153, 153), // pink
70       new Color(255, 51, 51), // red
71       new Color(255, 51, 255) // pink
72   };
73
74   public static final String[] txtColors = new String[]
75   { "blue", "pink", "green", "yellow", "red", "cyan", "pink" };
76
77   Map[] stylesheet;
78
79   boolean isHistogram = false;
80
81   public FeatureTrackConverter()
82   {
83     type = TYPE_DEFAULT;
84     stylesheet = new Map[0];
85   }
86
87   public FeatureTrackConverter(Map[] stylesheet)
88   {
89
90     if (stylesheet == null)
91       stylesheet = new Map[0];
92
93     this.stylesheet = stylesheet;
94
95   }
96
97   public FeatureTrackConverter(Map[] stylesheet, boolean isHistogram)
98   {
99     this(stylesheet);
100     this.isHistogram = isHistogram;
101     if (isHistogram)
102       type = TYPE_HISTOGRAM;
103   }
104
105   public String getType()
106   {
107     return type;
108   }
109
110   public void setType(String type)
111   {
112     if (type.equals(TYPE_HISTOGRAM))
113       isHistogram = true;
114     this.type = type;
115   }
116
117   public boolean isHistogram()
118   {
119     return isHistogram;
120   }
121
122   public void setHistogram(boolean isHistogram)
123   {
124     this.isHistogram = isHistogram;
125   }
126
127   public FeatureTrack[] convertMap2Features(Map[] mapfeatures)
128   {
129     List features = new ArrayList();
130
131     boolean first = true;
132     boolean secstruc = false;
133     boolean isGroup = false;
134
135     FeatureTrack feat = null;
136     Segment segment = null;
137
138     int featuresCounter = 0;
139     String prevGroup = null;
140
141     for (int i = 0; i < mapfeatures.length; i++)
142     {
143
144       Map currentFeatureMap = mapfeatures[i];
145       String type = (String) currentFeatureMap.get("TYPE");
146
147       String group = (String) currentFeatureMap.get("GROUP");
148       if (group != null)
149       {
150         if (prevGroup != null)
151         {
152           if (group.equals(prevGroup))
153           {
154             feat.setName(group);
155             isGroup = true;
156           }
157           else
158           {
159             isGroup = false;
160           }
161         }
162         else
163         {
164           isGroup = false;
165         }
166       }
167       else
168       {
169         isGroup = false;
170       }
171
172       // we are skipping literature references for the moment
173       // TODO: add a display to spice for non-positional features
174       //
175       if (type.equals("reference") || type.equals("GOA"))
176       {
177         continue;
178       }
179
180       if (!first)
181       {
182         // if not first feature
183
184         if ((!secstruc) && (!isGroup))
185         {
186
187           // if not secondary structure and not in a group ...
188           features = testAddFeatures(features, feat);
189
190         }
191         else if (!(type.equals("HELIX") || type.equals("STRAND") || type
192                 .equals("TURN")))
193         {
194           // end of secondary structure
195           secstruc = false;
196           if (feat != null && (!isGroup))
197           {
198             features = testAddFeatures(features, feat);
199           }
200
201         }
202       } // end of not first
203
204       first = false;
205       if ((!secstruc) && (!isGroup))
206       {
207         featuresCounter += 1;
208         feat = getNewFeat(currentFeatureMap);
209       }
210
211       if (type.equals("STRAND"))
212       {
213         secstruc = true;
214         currentFeatureMap.put("colorTxt", "yellow");
215         feat.setName("SECSTRUC");
216         feat.setType("SECSTRUC");
217       }
218
219       else if (type.equals("HELIX"))
220       {
221         secstruc = true;
222         currentFeatureMap.put("colorTxt", "red");
223         feat.setName("SECSTRUC");
224         feat.setType("SECSTRUC");
225       }
226
227       else if (type.equals("TURN"))
228       {
229         secstruc = true;
230         currentFeatureMap.put("colorTxt", "white");
231
232         feat.setName("SECSTRUC");
233         feat.setType("SECSTRUC");
234       }
235       else
236       {
237         secstruc = false;
238         currentFeatureMap.put("colorTxt", txtColors[featuresCounter
239                 % txtColors.length]);
240         if (!isGroup)
241         {
242           try
243           {
244             feat.setName(type);
245
246           } catch (NullPointerException e)
247           {
248             // e.printStackTrace();
249             feat.setName("null");
250           }
251         }
252       }
253
254       segment = getNewSegment(currentFeatureMap);
255
256       feat.addSegment(segment);
257       prevGroup = group;
258     }
259
260     if (feat != null)
261       features = testAddFeatures(features, feat);
262
263     return (FeatureTrack[]) features.toArray(new FeatureTrack[features
264             .size()]);
265   }
266
267   /**
268    * test if this features is added as a new feature to the features list, or if
269    * it is joint with an already existing one...
270    * 
271    * @param features
272    * @param newFeature
273    * @return a List of FeatureTrack objects
274    */
275   protected List testAddFeatures(List features, FeatureTrack newFeature)
276   {
277
278     // System.out.println("testing " + newFeature + " " +
279     // newFeature.getScore());
280     Iterator iter = features.iterator();
281
282     if (isHistogramFeatureType(newFeature))
283     {
284
285       // return histogram type features
286       type = TYPE_HISTOGRAM;
287
288       Segment seg = getHistogramSegmentFromFeature(newFeature);
289
290       while (iter.hasNext())
291       {
292         FeatureTrack knownFeature = (FeatureTrack) iter.next();
293         String knownType = knownFeature.getType();
294
295         // System.out.println("found histogram style " + feat);
296         // set type of this DAS source to being HISTOGRAM style
297
298         if (knownType.equals(newFeature.getType()))
299         {
300           // convert the feature into a HistogramSegment and add to the already
301           // known feature
302
303           knownFeature.addSegment(seg);
304           // we can return now
305           return features;
306         }
307
308       }
309       // we could not link this to any existing feature
310       // convert it to a new HistogramFeature
311       HistogramFeature hfeat = new HistogramFeature();
312
313       hfeat.setLink(newFeature.getLink());
314       hfeat.setMethod(newFeature.getMethod());
315       hfeat.setName(newFeature.getName());
316       hfeat.setNote(newFeature.getNote());
317       hfeat.setScore("0");
318       hfeat.setSource(newFeature.getSource());
319       hfeat.addSegment(seg);
320       hfeat.setType(newFeature.getType());
321
322       newFeature = hfeat;
323       features.add(newFeature);
324       return features;
325     }
326
327     while (iter.hasNext())
328     {
329       FeatureTrack knownFeature = (FeatureTrack) iter.next();
330       // this only compares method source and type ...
331       boolean sameFeat = false;
332       if (knownFeature.equals(newFeature))
333         sameFeat = true;
334
335       if ((knownFeature.getSource().equals(newFeature.getSource()))
336               && (knownFeature.getMethod().equals(newFeature.getMethod()))
337               && (knownFeature.getNote().equals(newFeature.getNote()))
338               && isSecondaryStructureFeat(knownFeature)
339               && isSecondaryStructureFeat(newFeature))
340         sameFeat = true;
341
342       if (sameFeat)
343       {
344
345         // seems to be of same type, method and source, so check if the segments
346         // can be joined
347
348         List tmpsegs = knownFeature.getSegments();
349         Iterator segiter = tmpsegs.iterator();
350         List newsegs = newFeature.getSegments();
351         Iterator newsegsiter = newsegs.iterator();
352         boolean overlap = false;
353         while (newsegsiter.hasNext())
354         {
355           Segment newseg = (Segment) newsegsiter.next();
356
357           while (segiter.hasNext())
358           {
359             Segment tmpseg = (Segment) segiter.next();
360
361             if (tmpseg.overlaps(newseg))
362               overlap = true;
363           }
364         }
365
366         if (!overlap)
367         {
368           // add all new segments to old features...
369           newsegsiter = newsegs.iterator();
370           while (newsegsiter.hasNext())
371           {
372             Segment newseg = (Segment) newsegsiter.next();
373             knownFeature.addSegment(newseg);
374           }
375
376           return features;
377         }
378       }
379
380     }
381
382     // if we get here, the features could not be joint with any other one, so
383     // there is always some overlap
384     // add to the list of known features
385     features.add(newFeature);
386     return features;
387   }
388
389   private FeatureTrack getNewFeat(Map currentFeatureMap)
390   {
391     FeatureTrack feat = new FeatureTrackImpl();
392     // logger.finest(currentFeatureMap);
393     // System.out.println("DrawableDasSource " + currentFeatureMap);
394     feat.setSource((String) currentFeatureMap.get("dassource"));
395     feat.setName((String) currentFeatureMap.get("NAME"));
396     feat.setType((String) currentFeatureMap.get("TYPE"));
397     feat.setLink((String) currentFeatureMap.get("LINK"));
398     feat.setNote((String) currentFeatureMap.get("NOTE"));
399
400     String typeID = (String) currentFeatureMap.get("TYPE_ID");
401     String typeCategory = (String) currentFeatureMap.get("TYPE_CATEGORY");
402     feat.setTypeID(typeID);
403     feat.setTypeCategory(typeCategory);
404
405     String method = (String) currentFeatureMap.get("METHOD");
406     if (method == null)
407     {
408       method = "";
409     }
410     feat.setMethod(method);
411     feat.setScore((String) currentFeatureMap.get("SCORE"));
412     return feat;
413   }
414
415   private Segment getNewSegment(Map featureMap)
416   {
417     Segment s = new SegmentImpl();
418     String sstart = (String) featureMap.get("START");
419     String send = (String) featureMap.get("END");
420     int start = Integer.parseInt(sstart);
421     int end = Integer.parseInt(send);
422     s.setStart(start);
423     s.setEnd(end);
424     s.setName((String) featureMap.get("TYPE"));
425     s.setTxtColor((String) featureMap.get("colorTxt"));
426     s.setColor((Color) featureMap.get("color"));
427     s.setNote((String) featureMap.get("NOTE"));
428     return s;
429
430   }
431
432   private boolean isSecondaryStructureFeat(FeatureTrack feat)
433   {
434     String type = feat.getType();
435     if (type.equals("HELIX") || type.equals("STRAND")
436             || type.equals("TURN"))
437       return true;
438     return false;
439   }
440
441   private boolean isHistogramFeatureType(FeatureTrack feat)
442   {
443     String ftype = feat.getType();
444
445     Map[] style = stylesheet;
446
447     // System.out.println("is HistogramFeature type " + ftype + " " + style );
448
449     // todo : move this info into a config file...
450
451     if (ftype.equals("hydrophobicity"))
452     {
453       return true;
454     }
455     if (getType().equals(TYPE_HISTOGRAM))
456       return true;
457
458     if (style != null)
459     {
460
461       for (int i = 0; i < style.length; i++)
462       {
463         Map m = style[i];
464
465         // make sure the stylesheet is for this feature type
466         String styleType = (String) m.get("type");
467         if (styleType != null)
468         {
469           if (!styleType.equals(ftype))
470           {
471             continue;
472           }
473         }
474         else
475         {
476           continue;
477         }
478
479         String type = (String) m.get("style");
480         if (type != null)
481         {
482           // System.out.println("stylesheet type " + type);
483           if (type.equals("gradient") || (type.equals("lineplot"))
484                   || (type.equals("histogram")))
485           {
486
487             return true;
488           }
489         }
490       }
491     }
492
493     return false;
494   }
495
496   private HistogramSegment getHistogramSegmentFromFeature(FeatureTrack feat)
497   {
498     HistogramSegment s = new HistogramSegment();
499
500     double score = 0.0;
501
502     try
503     {
504       score = Double.parseDouble(feat.getScore());
505
506     } catch (Exception e)
507     {
508       // e.printStackTrace();
509     }
510     s.setScore(score);
511     List segments = feat.getSegments();
512     if (segments.size() > 0)
513     {
514       Segment seg = (Segment) segments.get(0);
515       s.setName(seg.getName());
516       s.setStart(seg.getStart());
517       s.setEnd(seg.getEnd());
518       s.setNote(seg.getNote());
519       s.setColor(seg.getColor());
520       s.setTxtColor(seg.getTxtColor());
521     }
522
523     return s;
524   }
525
526 }