/*******************************************************************************
* 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.IO.extractor;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import edu.yu.einstein.genplay.core.IO.utils.ChromosomesSelector;
import edu.yu.einstein.genplay.core.manager.project.ProjectChromosomes;
import edu.yu.einstein.genplay.core.manager.project.ProjectManager;
import edu.yu.einstein.genplay.core.multiGenome.utils.FormattedMultiGenomeName;
import edu.yu.einstein.genplay.core.multiGenome.utils.ShiftCompute;
import edu.yu.einstein.genplay.dataStructure.chromosome.Chromosome;
import edu.yu.einstein.genplay.dataStructure.enums.AlleleType;
import edu.yu.einstein.genplay.exception.exceptions.DataLineException;
import edu.yu.einstein.genplay.gui.event.invalidDataEvent.InvalidDataEventsGenerator;
import edu.yu.einstein.genplay.gui.event.invalidDataEvent.InvalidDataListener;
import edu.yu.einstein.genplay.gui.event.operationProgressEvent.OperationProgressEvent;
import edu.yu.einstein.genplay.gui.event.operationProgressEvent.OperationProgressEventsGenerator;
import edu.yu.einstein.genplay.gui.event.operationProgressEvent.OperationProgressListener;
import edu.yu.einstein.genplay.gui.statusBar.Stoppable;
/**
* This class must be extended by the file extractors
* @author Julien Lajugie
*/
public abstract class Extractor implements InvalidDataEventsGenerator, Stoppable, OperationProgressEventsGenerator {
/** Maximum number of warning that will be reported */
private final static int WARNING_LIMIT = 100;
private final List<OperationProgressListener> progressListeners; // list of progress listeners
private final ProjectChromosomes projectChromosomes; // Reference to projectChromosomes saved for fast retrieval
private final File dataFile; // file containing the data
private final List<InvalidDataListener> invalidDataListenersList; // List of invalid data listeners
private final String dataName; // name of the data
private boolean isStopped = false; // set to true if the execution of the extractor needs to be stopped
private ChromosomesSelector chromosomeSelector = null; // object that defines which chromosomes need to be extracted
private long startTime; // time when the extraction started
private long extractionDuration; // duration of the extraction in seconds
private String genomeName; // name of the genome used for the mapping of the data
private AlleleType alleleType; // type of allele to load the data (multi genome)
private int warningCount; // number of warning sent to the listeners
protected int itemExtractedCount; // number of item extracted
/**
* Constructor
* @param dataFile file containing the data
*/
public Extractor(File dataFile) {
this.dataFile = dataFile;
projectChromosomes = ProjectManager.getInstance().getProjectChromosomes();
invalidDataListenersList = new ArrayList<InvalidDataListener>();
warningCount = 0;
itemExtractedCount = 0;
dataName = retrieveDataName(dataFile);
progressListeners = new ArrayList<OperationProgressListener>();
}
@Override
public final void addInvalidDataListener(InvalidDataListener invalidDataListener) {
if (!invalidDataListenersList.contains(invalidDataListener)) {
invalidDataListenersList.add(invalidDataListener);
}
}
@Override
public void addOperationProgressListener(OperationProgressListener operationProgressListener) {
progressListeners.add(operationProgressListener);
}
/**
* Finalized the extraction (retrieves the duration of the extraction).
*/
protected void finalizeExtraction() {
extractionDuration = (System.currentTimeMillis() - startTime) / 1000l;
notifyProgressListeners(OperationProgressEvent.COMPLETE, 100d);
}
/**
* @return the {@link ChromosomesSelector} object that specifies which chromosomes are selected to be extracted
*/
public ChromosomesSelector getChromosomeSelector() {
return chromosomeSelector;
}
/**
* @return the file containing the data to extract
*/
public File getDataFile() {
return dataFile;
}
/**
* @return the name of the data
*/
public String getDataName() {
return dataName;
}
/**
* @return the duration of the extraction in seconds
*/
public long getExtractionDuration() {
return extractionDuration;
}
/**
* This method returns the position of the first base of the extractor.
* Most files are either 0-based (the first position on a chromosome is 0)
* or 1-based (the first position on a chromosome is 1).
* @return The position of the first base
*/
public abstract int getFirstBasePosition();
@Override
public InvalidDataListener[] getInvalidDataListeners() {
return (InvalidDataListener[]) invalidDataListenersList.toArray();
}
/**
* @return the number of item extracted
*/
public int getItemExtractedCount() {
return itemExtractedCount;
}
@Override
public OperationProgressListener[] getOperationProgressListeners() {
OperationProgressListener[] listeners = new OperationProgressListener[progressListeners.size()];
return progressListeners.toArray(listeners);
}
/**
* @return a reference to the {@link ProjectChromosomes}.
*/
public ProjectChromosomes getProjectChromosome() {
return projectChromosomes;
}
/**
* @param chromosome current chromosome
* @param position current position
* @return the position shifted of 1 bp if the extractor is 0 based
* and in the case of multi-genome project, the associated meta genome position
*/
protected int getRealGenomePosition(Chromosome chromosome, int position) {
if (getFirstBasePosition() != 1) {
position += 1 - getFirstBasePosition();
}
if (ProjectManager.getInstance().isMultiGenomeProject()) {
return ShiftCompute.getPosition(genomeName, alleleType, position, chromosome, FormattedMultiGenomeName.META_GENOME_NAME);
} else {
return position;
}
}
/**
* Initializes the extraction (retrieve the time at the begining of the extractio).
* @throws IOException
*/
protected void initializeExtraction() throws IOException {
startTime = System.currentTimeMillis();
}
/**
* @return true if the extraction was stopped
*/
public boolean isStopped() {
return isStopped;
}
/**
* Notifies the listener that a data event occurred
* @param e exception to send to the listeners
*/
protected void notifyDataEventListeners(DataLineException e) {
if (warningCount < WARNING_LIMIT) {
for (InvalidDataListener listeners: invalidDataListenersList) {
listeners.invalidDataExtracted(e.getFormattedMessage());
}
} else if (warningCount == WARNING_LIMIT) {
for (InvalidDataListener listeners: invalidDataListenersList) {
listeners.invalidDataExtracted("And more ...");
}
}
warningCount++;
}
/**
* Notifies the listener that a data event occurred
* @param e exception to send to the listeners
* @param lineNumber line number with a problem
* @param line line with a problem
*/
protected void notifyDataEventListeners(DataLineException e, int lineNumber, String line) {
e.setFile(dataFile);
e.setLineNumber(lineNumber);
e.setLine(line);
notifyDataEventListeners(e);
}
/**
* Notifies all the listeners that the progression of an operation changed
* @param progressState state of the progression
* @param completion completion if the state is IN_PROGRESS
*/
private void notifyProgressListeners(int progressState, double completion) {
OperationProgressEvent evt = new OperationProgressEvent(progressState, completion);
for (OperationProgressListener listener: progressListeners) {
listener.operationProgressChanged(evt);
}
}
@Override
public void removeInvalidDataListener(InvalidDataListener invalidDataListener) {
invalidDataListenersList.remove(invalidDataListener);
}
@Override
public void removeOperationProgressListener(OperationProgressListener operationProgressListener) {
progressListeners.remove(operationProgressListener);
}
/**
* @return the name of the data. The name of the data is
*/
protected abstract String retrieveDataName(File dataFile);
/**
* @param alleleType the alleleType to set
*/
public void setAlleleType(AlleleType alleleType) {
this.alleleType = alleleType;
}
/**
* @param chromosomeSelector set the {@link ChromosomesSelector} that specifies which chromosome will be extracted
*/
public void setChromosomeSelector(ChromosomesSelector chromosomeSelector) {
this.chromosomeSelector = chromosomeSelector;
}
/**
* Sets the position of the first base of the extractor.
* Most files are either 0-based (the first position on a chromosome is 0)
* or 1-based (the first position on a chromosome is 1).
* @param firstBasePosition position of the first base
*/
public abstract void setFirstBasePosition(int firstBasePosition);
/**
* @param genomeName the genomeName to set
*/
public void setGenomeName(String genomeName) {
this.genomeName = genomeName;
}
@Override
public void stop() {
isStopped = true;
}
}