/******************************************************************************* * GenPlay, Einstein Genome Analyzer * Copyright (C) 2009, 2014 Albert Einstein College of Medicine * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * Authors: Julien Lajugie <julien.lajugie@einstein.yu.edu> * Nicolas Fourel <nicolas.fourel@einstein.yu.edu> * Eric Bouhassira <eric.bouhassira@einstein.yu.edu> * * Website: <http://genplay.einstein.yu.edu> ******************************************************************************/ package edu.yu.einstein.genplay.core.multiGenome.data.display; import java.util.Iterator; import java.util.List; import edu.yu.einstein.genplay.core.multiGenome.data.display.variant.MixVariant; import edu.yu.einstein.genplay.core.multiGenome.data.display.variant.Variant; /** * The {@link VariantDisplayListIterator} iterates over a {@link VariantDisplayList} for a specific allele. * * @author Nicolas Fourel * @version 0.1 */ public class VariantDisplayListIterator implements Iterator<Variant> { private final VariantDisplayList displayList; // The list of variant display. private final List<Variant> variantList; // The list of variant. private final byte[] display; // The display policy of the variants. private boolean displayDependant; // When display dependant, the iterator does not stop on hidden variants. private int currentIndex; // The current index while iterating. /** * Constructor of {@link VariantDisplayListIterator} * @param displayList * @param alleleIndex */ public VariantDisplayListIterator (VariantDisplayList displayList, int alleleIndex) { this.displayList = displayList; variantList = displayList.getVariants().get(alleleIndex); display = displayList.getDisplay()[alleleIndex]; currentIndex = -1; displayDependant = false; } /** * @return the display policy of the current variant */ public byte getCurrentDisplay () { return getVariantDisplay(currentIndex); } /** * @return the currentIndex */ public int getCurrentIndex() { return currentIndex; } /** * @return the current meta genome position */ public int getCurrentMetaGenomePosition () { if (inBound()) { return variantList.get(currentIndex).getStart(); } return 0; } /** * @return the current {@link Variant} */ public Variant getCurrentVariant () { if (inBound() && isCurrentVariantVisible()) { return variantList.get(currentIndex); } return null; } /** * @return the displayList */ public VariantDisplayList getDisplayList() { return displayList; } /** * Recursive function. Returns the index where the value is found * or the index right after if the exact value is not found. * @param value value * @param indexStart start index (in the data array) * @param indexStop stop index (in the data array) * @return the index where the start value of the window is found or the index right after if the exact value is not found */ private int getIndex (List<Variant> list, int value, int indexStart, int indexStop) { int middle = (indexStop - indexStart) / 2; if (indexStart == indexStop) { return indexStart; } else { int start = list.get(indexStart + middle).getStart(); int stop = list.get(indexStart + middle).getStop(); if ((value >= start) && (value < stop)) { return indexStart + middle; } else if (value > start) { return getIndex(list, value, indexStart + middle + 1, indexStop); } else { return getIndex(list, value, indexStart, indexStart + middle); } } } /** * @param index the index of a variant * @return the display policy of the current variant */ private byte getVariantDisplay (int index) { Variant current = variantList.get(index); if (current instanceof MixVariant) { return VariantDisplayList.SHOW; } return display[index]; } /** * @return true if there is an element at the next position, false otherwise */ @Override public boolean hasNext() { if (displayDependant) { return hasVariantAfterPosition(getCurrentMetaGenomePosition()); } return inBound(currentIndex + 1) && isVariantVisible(currentIndex + 1); } /** * @return true if there is an element at the previous position, false otherwise */ public boolean hasPrevious() { if (displayDependant) { return hasVariantBeforePosition(getCurrentMetaGenomePosition()); } return inBound(currentIndex - 1) && isVariantVisible(currentIndex - 1); } /** * @param metaGenomePosition a position on the meta genome * @return true if there is a variant after the given meta genome position, false otherwise */ public boolean hasVariantAfterPosition (int metaGenomePosition) { boolean found = false; int index = currentIndex; while (inBound(index) && !found) { if ((variantList.get(index).getStart() > metaGenomePosition) && isVariantVisible(index)) { found = true; } index++; } return found; } /** * @param metaGenomePosition a position on the meta genome * @return true if there is a variant before the given meta genome position, false otherwise */ public boolean hasVariantBeforePosition (int metaGenomePosition) { boolean found = false; int index = currentIndex; while (inBound(index) && !found) { if ((variantList.get(index).getStart() < metaGenomePosition) && isVariantVisible(index)) { found = true; } index--; } return found; } /** * @return true if the current index is in the list bounds, false otherwise */ private boolean inBound () { return inBound(currentIndex); } /** * @param index and index * @return true if the given index is in the list bounds, false otherwise */ private boolean inBound (int index) { if ((index >= 0) && (index < variantList.size())) { return true; } return false; } /** * @return true if the current {@link Variant} is shown, false otherwise */ private boolean isCurrentVariantVisible () { return isVariantVisible(currentIndex); } /** * @param index the index of a {@link Variant} * @return true if the {@link Variant} at the given index is shown, false otherwise */ private boolean isVariantVisible (int index) { if (displayDependant) { return getVariantDisplay(index) >= 0; } return true; } /** * Move the index backward */ private void moveIndexBackward () { boolean moved = false; int index = currentIndex - 1; while (inBound(index) && !moved) { if (isVariantVisible(index)) { moved = true; currentIndex = index; } index--; } } /** * Move the index forward */ private void moveIndexForward () { boolean moved = false; int index = currentIndex + 1; while (inBound(index) && !moved) { if (isVariantVisible(index)) { moved = true; currentIndex = index; } index++; } } /** * @return the next element in the list */ @Override public Variant next() { moveIndexForward(); return getCurrentVariant(); } /** * @return the previous element in the list */ public Variant previous() { moveIndexBackward(); return getCurrentVariant(); } @Override public void remove() {} /** * @param displayDependant the displayDependant to set */ public void setDisplayDependant(boolean displayDependant) { this.displayDependant = displayDependant; } /** * Recursive function. Seeks the index of the variant for the given position in order to set the current index. * If no variant is at the position, the next variant is then selected. * @param position a position on the meta genome */ public void setIteratorPosition (int position) { int index = -1; if (variantList.size() > 0) { index = getIndex(variantList, position, 0, variantList.size() - 1); } currentIndex = index; } }