package nl.tudelft.lifetiles.graph.model; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import nl.tudelft.lifetiles.core.util.SetUtils; import nl.tudelft.lifetiles.sequence.Mutation; import nl.tudelft.lifetiles.sequence.model.Sequence; import nl.tudelft.lifetiles.sequence.model.SequenceSegment; /** * Container including the stacks with the mutation quantity used for drawing * the stacked mutation quantity diagram. * * @author Jos * */ public class StackedMutationContainer { /** * Mapping value of the insertion mutation. */ private static final Integer INSERTION_MAP = 1; /** * Mapping value of the deletion mutation. */ private static final Integer DELETION_MAP = 2; /** * Mapping value of the polymorphism mutation. */ private static final Integer POLYMORPHISM_MAP = 3; /** * The number of values being counted by the stacked mutation container. */ private static final int NUMBER_OF_VALUES = 4; /** * List with the stacked quantity of mutations. * <dl> * <dt>[0]</dt> * <dd>total bases.</dd> * <dt>[1]</dt> * <dd>insertion bases.</dd> * <dt>[2]</dt> * <dd>deletion bases.</dd> * <dt>[3]</dt> * <dd>polymorphism bases.</dd> * </dl> */ private List<List<Long>> stackedMutations; /** * Child StackedMutationContainer, one level below this stacked mutation * container. */ private StackedMutationContainer child; /** * Zoom/layer level of this stacked mutation container. Level corresponds to * number of columns inversed. */ private int level; /** * Public constructor for stacked mutation container. Will construct the * stacked mutation container by calculating the level in comparison with * the bucketCache. * * @param buckets * BucketCache to be used to generate the stacked mutation * container. * @param visibleSequences * The visible sequences in the graph controller. */ public StackedMutationContainer(final BucketCache buckets, final Set<Sequence> visibleSequences) { this.level = (int) Math.round(Math.log(buckets.getNumberBuckets()) / Math.log(2) + 1); fillStackedMutationContainer(this.level, buckets, visibleSequences); } /** * Private constructor for stacked mutation container. Will construct the * stacked mutation container based on the given level by the parent stacked * mutation container. * * @param level * The level of this stacked mutation container. * @param buckets * The bucketCache to insert into this stackedMutationContainer. * @param visibleSequences * The visible sequences in the graph controller. */ private StackedMutationContainer(final int level, final BucketCache buckets, final Set<Sequence> visibleSequences) { this.level = level; fillStackedMutationContainer(this.level, buckets, visibleSequences); } /** * Fills this stacked mutation container with the bucketCache or the child * stacked mutation container based on the level given. * * @param level * Level of this stacked mutation container. * @param buckets * BucketCache to be inserted into this stacked mutation * container. * @param visibleSequences * The visible sequences in the graph. */ private void fillStackedMutationContainer(final int level, final BucketCache buckets, final Set<Sequence> visibleSequences) { this.level = level; stackedMutations = new ArrayList<>(); if (this.level <= 1) { child = null; insertBuckets(buckets, visibleSequences); } else { child = new StackedMutationContainer(level - 1, buckets, visibleSequences); insertStackedMutationContainers(child); } } /** * Insert the child stacked Mutation Container. Merges the layer of the * child. * * @param containers * The child stacked mutation container. */ private void insertStackedMutationContainers( final StackedMutationContainer containers) { for (int index = 0; index < containers.getStack().size() / 2; index++) { stackedMutations.add(insertStackedContainer(containers.getStack() .get(2 * index), containers.getStack().get(2 * index + 1))); } } /** * Insert two sections of the child stacked Mutation Container into one * section of the stacked Mutation Container. * * @param left * Left section of the child stacked mutation container. * @param right * Right section of the child stacked mutation container. * @return merged section for this stacked mutation container. */ private List<Long> insertStackedContainer(final List<Long> left, final List<Long> right) { List<Long> stack = new ArrayList<>(left.size()); for (int index = 0; index < left.size(); index++) { stack.add(left.get(index) + right.get(index)); } return stack; } /** * Returns all columns in the stacked mutation diagram. * * @return all columns in the stacked mutation diagram. */ public List<List<Long>> getStack() { return stackedMutations; } /** * Insert the buckets into the mutation quantity list. * * @param buckets * BucketCache which needs to be added to the stacked mutation * container. * @param visibleSequences * The visible sequences in the graph. */ private void insertBuckets(final BucketCache buckets, final Set<Sequence> visibleSequences) { for (Set<SequenceSegment> bucket : buckets.getBuckets()) { stackedMutations.add(insertBucket(bucket, visibleSequences)); } } /** * Insert the bucket into the mutation quantity list. * * @param bucket * Bucket from bucketCache which needs to be added to the stacked * mutation container. * @param visibleSequences * The visible sequences in the graph. * @return stacked mutation quantity list for this bucket. */ private List<Long> insertBucket(final Set<SequenceSegment> bucket, final Set<Sequence> visibleSequences) { List<Long> list = new ArrayList<>(NUMBER_OF_VALUES); for (int index = 0; index < NUMBER_OF_VALUES; index++) { list.add((long) 0); } Map<Mutation, Integer> mutations = new HashMap<>( Mutation.values().length); mutations.put(Mutation.INSERTION, INSERTION_MAP); mutations.put(Mutation.DELETION, DELETION_MAP); mutations.put(Mutation.POLYMORPHISM, POLYMORPHISM_MAP); for (SequenceSegment segment : bucket) { int sourceSize; if (visibleSequences == null) { sourceSize = segment.getSources().size(); } else { sourceSize = SetUtils.intersectionSize(segment.getSources(), visibleSequences); } long size = segment.getContent().getLength() * sourceSize; if (mutations.containsKey(segment.getMutation())) { int index = mutations.get(segment.getMutation()); list.set(index, list.get(index) + size); } list.set(0, list.get(0) + size); } return list; } /** * Return the maximum number of mutations in one of the stacks. * * @return the maximum number of mutations in one of the stacks. */ public Long getMaxMutations() { long max = 0; for (List<Long> stack : stackedMutations) { max = Math.max( max, stack.get(INSERTION_MAP) + stack.get(DELETION_MAP) + stack.get(POLYMORPHISM_MAP)); } return max; } /** * Returns a map from level to stacked container. * * @return map from level to stacked container. */ public Map<Integer, StackedMutationContainer> mapLevelStackedMutation() { Map<Integer, StackedMutationContainer> map; if (child == null) { map = new HashMap<>(); } else { map = child.mapLevelStackedMutation(); } map.put(getLevel(), this); return map; } /** * @return the level */ public int getLevel() { return level; } }