package org.genedb.web.gui;
import org.genedb.db.domain.objects.BasicGene;
import org.genedb.db.domain.objects.CompoundLocatedFeature;
import org.genedb.db.domain.objects.LocatedFeature;
import org.apache.log4j.Logger;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
public abstract class TrackedDiagram {
private static final Logger logger = Logger.getLogger(TrackedDiagram.class);
protected AllocatedCompoundFeature.Mode packSubfeatures = AllocatedCompoundFeature.Mode.UNPACKED;
/**
* The number of blank tracks to leave above (or,
* for negative tracks, below) each compound feature.
*/
protected int numberOfBlankTracksAboveCompoundFeature = 0;
private int start, end;
private int numberOfPositiveTracks = 0, numberOfNegativeTracks = 0;
public int numberOfPositiveTracks() {
return numberOfPositiveTracks;
}
public int numberOfNegativeTracks() {
return numberOfNegativeTracks;
}
public int numberOfTracks() {
return numberOfPositiveTracks() + numberOfNegativeTracks();
}
private SortedSet<AllocatedCompoundFeature> allocatedCompoundFeatures = new TreeSet<AllocatedCompoundFeature>();
private List<LocatedFeature> globalFeatures = new ArrayList<LocatedFeature>();
public SortedSet<AllocatedCompoundFeature> getAllocatedCompoundFeatures() {
return allocatedCompoundFeatures;
}
/**
* Get the global features of this diagram.
* @return a list of the global features, in left-to-right order.
*/
public List<LocatedFeature> getGlobalFeatures() {
return globalFeatures;
}
/**
* Add a compound feature to this diagram
* @param feature the feature to add
* @param track the track number
*/
private void addFeature(AllocatedCompoundFeature feature, int track) {
feature.setTrack(track);
allocatedCompoundFeatures.add(feature);
int numberOfSubtracks = feature.getSubtracks().size();
if (track + numberOfSubtracks - 1 + numberOfBlankTracksAboveCompoundFeature > numberOfPositiveTracks) {
numberOfPositiveTracks = track + numberOfSubtracks - 1 + numberOfBlankTracksAboveCompoundFeature;
} else if (-track + numberOfSubtracks - 1 + numberOfBlankTracksAboveCompoundFeature > numberOfNegativeTracks) {
numberOfNegativeTracks = -track + numberOfSubtracks - 1 + numberOfBlankTracksAboveCompoundFeature;
}
}
/**
* Add a global feature. A global feature does not belong to a track,
* it's a feature of an entire region of the diagram. The obvious example
* is a gap in a sequence.
*
* Global features should be added in left-to-right order.
*/
protected void addGlobalFeature(LocatedFeature feature) {
globalFeatures.add(feature);
}
/**
* The track number should be between -1 and
* <code>-numberOfNegativeTracks()</code> inclusive, to retrieve a
* negative track; or between 1 and <code>numberOfPositiveTracks()</code>
* inclusive, to retrieve a negative track.
*
* @param track
* @return a list of Transcripts, or null if there are none
*/
@Deprecated
public List<LocatedFeature> getTrack(int track) {
List<LocatedFeature> ret = new ArrayList<LocatedFeature>();
if (track == 0)
return getGlobalFeatures();
if (track > numberOfPositiveTracks() || track < -numberOfNegativeTracks())
return null;
for (AllocatedCompoundFeature f: allocatedCompoundFeatures) {
ret.addAll(f.forTrack(track));
}
return ret;
}
public TrackedDiagram(int start, int end) {
this.start = start;
this.end = end;
}
/**
* Get the location (interbase coordinates) of the start of the diagram.
*
* @return the start location
*/
public int getStart() {
return start;
}
/**
* Get the location (interbase coordinates) of the end of the diagram.
*
* @return the end location
*/
public int getEnd() {
return end;
}
/**
* Get the size of the diagram in bases, equivalent to
* <code>(getEnd() - getStart())</code>.
*
* @return the size of the diagram
*/
public int getSize() {
return end - start;
}
/**
* Allocates each transcript to a track in the appropriate way, grouping
* together the different subfeatures of each compound feature.
*
* @param boundaries
* @param negativeHalf <code>true</code> for the negative
* @return the diagram Half
*/
protected void allocateTracks(Iterable<? extends CompoundLocatedFeature> compoundFeatures, boolean negativeHalf) {
DiagramLayout layout = new DiagramLayout();
for (CompoundLocatedFeature compoundFeature : compoundFeatures) {
AllocatedCompoundFeature allocatedCompoundFeature
= new AllocatedCompoundFeature(compoundFeature, 0, packSubfeatures);
int numSubtracks = allocatedCompoundFeature.getSubtracks().size();
if (numSubtracks == 0) {
/*
* Give a more comprehensible error message if this is a gene.
*/
if (compoundFeature instanceof BasicGene)
logger.error(String.format("The gene '%s' has no transcripts!", compoundFeature
.getUniqueName()));
else
logger.error(String.format("The compound feature '%s' has no subfeatures!", compoundFeature
.getUniqueName()));
continue;
}
int track = layout.addBlock(compoundFeature.getFmin(), compoundFeature.getFmax(),
numSubtracks + numberOfBlankTracksAboveCompoundFeature);
addFeature(allocatedCompoundFeature, negativeHalf ? -track : track);
}
}
}