/*******************************************************************************
* 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.dataStructure.list.genomeWideList.geneList;
import java.io.Serializable;
import edu.yu.einstein.genplay.core.manager.project.ProjectChromosomes;
import edu.yu.einstein.genplay.core.manager.project.ProjectManager;
import edu.yu.einstein.genplay.dataStructure.chromosome.Chromosome;
import edu.yu.einstein.genplay.dataStructure.gene.Gene;
/**
* Searches genes from gene names
* @author Julien Lajugie
*/
public final class GeneSearcher implements Serializable {
private static final long serialVersionUID = 2905806587397044885L; // generated ID
private final GeneList geneList; // GeneList where to search the genes
private String lastSearchedGeneName = null; // name of the last searched gene
private Gene lastGeneFound = null; // last found gene
private int lastFoundChromoIndex; // index of the chromosome of the last found gene
private int lastFoundGeneIndex; // index of the last found gene on the chromosome
private boolean wholeWord = false; // true for a whole word search
private boolean caseSensitive = false; // true for a case sensitive search
/**
* Creates an instance of {@link GeneSearcher}
* @param geneList {@link GeneList} where to search the genes
*/
public GeneSearcher(GeneList geneList) {
super();
this.geneList = geneList;
}
/**
* @return the chromosome of the last gene found
*/
public Chromosome getGeneChromosome() {
ProjectChromosomes projectChromosomes = ProjectManager.getInstance().getProjectChromosomes();
return projectChromosomes.get(lastFoundChromoIndex);
}
/**
* @return the lastGeneFound
*/
public Gene getLastGeneFound() {
return lastGeneFound;
}
/**
* @return the name of the last searched gene
*/
public String getLastSearchedGeneName() {
return lastSearchedGeneName;
}
/**
* @param gene a {@link Gene}
* @param geneName a name
* @return true if the Gene is a searched gene.
* The definition of a searched gene depends on the
* parameters about the case sensitivity and if only whole word are accepted
*/
private boolean isASearchedGene(Gene gene, String geneName) {
if ((gene == null) || (geneName == null) || (geneName.isEmpty())) {
return false;
}
if ((lastGeneFound != null) &&
(gene.getStart() == lastGeneFound.getStart()) &&
(gene.getStop() == lastGeneFound.getStop())) {
// case where the current gene has the same start and stop positions as the last gene
return false;
}
// case where it's a whole word search
if (wholeWord) {
if (caseSensitive) {
// case where the search is case sensitive
return gene.getName().equals(geneName);
} else {
// case where the search is not case sensitive
return gene.getName().equalsIgnoreCase(geneName);
}
} else {
// case where it's not a whole word search
if (caseSensitive) {
// case where the search is case sensitive
return gene.getName().startsWith(geneName);
} else {
// case where the search is not case sensitive
return gene.getName().toLowerCase().startsWith(geneName.toLowerCase());
}
}
}
/**
* @return true if the search is case sensitive. False otherwise
*/
public final boolean isCaseSensitive() {
return caseSensitive;
}
/**
* @param chromoIndex an index of a chromosome
* @param geneIndex an index on a chromosome
* @return true if the two parameters correspond to the indexes of the last found chromosome
*/
private boolean isLastFoundGene(int chromoIndex, int geneIndex) {
return (chromoIndex == lastFoundChromoIndex) && (geneIndex == lastFoundGeneIndex);
}
/**
* @return true if we search only the whole word matches. False otherwise
*/
public final boolean isWholeWorld() {
return wholeWord;
}
/**
* Searches the first Gene that corresponds to the specified name.
* Returns null if nothing is found
* @param geneName a gene name
* @return the first Gene that corresponds to the specified name, null if nothing is found
*/
public Gene search(String geneName) {
if ((geneName == null) || (geneName.isEmpty())) {
// if the input name is blank we return null
return null;
}
lastSearchedGeneName = geneName;
lastGeneFound = null;
int i = 0;
while ((lastGeneFound == null) && (i < geneList.size())) {
int j = 0;
while ((lastGeneFound == null) && (j < geneList.size(i))) {
if (isASearchedGene(geneList.get(i, j), geneName)) {
// case where a gene is found
lastGeneFound = geneList.get(i, j);
lastFoundChromoIndex = i;
lastFoundGeneIndex = j;
}
j++;
}
i++;
}
return lastGeneFound;
}
/**
* @return the next gene (starting from the last found gene), null is returned if nothing is found.
*/
public Gene searchNextGene() {
if (lastGeneFound == null) {
return null;
}
int i = lastFoundChromoIndex;
int j = lastFoundGeneIndex + 1;
if (j < geneList.get(i).size()) {
lastFoundChromoIndex = i;
lastFoundGeneIndex = j;
lastGeneFound = geneList.get(i, j);
}
return lastGeneFound;
}
/**
* @return the next gene (starting from the last found gene)
* that has a name that correspond to the searched name.
* Null is returned if nothing is found
*/
public Gene searchNextMatch() {
if (lastGeneFound == null) {
return null;
}
boolean found = false;
int i = lastFoundChromoIndex;
int j = lastFoundGeneIndex + 1;
while (!found && !isLastFoundGene(i, j)) {
while (!found && (j < geneList.size(i)) && !isLastFoundGene(i, j)) {
found = isASearchedGene(geneList.get(i, j), lastSearchedGeneName);
if (!found) {
j++;
}
}
if ((!found) && !isLastFoundGene(i, j)) {
i++;
if (i >= geneList.size()) {
i = 0;
}
j = 0;
}
}
if (found) {
lastFoundChromoIndex = i;
lastFoundGeneIndex = j;
lastGeneFound = geneList.get(i, j);
}
return lastGeneFound;
}
/**
* @return the previous gene (starting from the last found gene), null is returned if nothing is found.
*/
public Gene searchPreviousGene() {
if (lastGeneFound == null) {
return null;
}
int i = lastFoundChromoIndex;
int j = lastFoundGeneIndex - 1;
if (j >= 0) {
lastFoundChromoIndex = i;
lastFoundGeneIndex = j;
lastGeneFound = geneList.get(i, j);
}
return lastGeneFound;
}
/**
* @return the previous gene (starting from the last found gene)
* that has a name that correspond to the searched name
* Null is returned if nothing is found
*/
public Gene searchPreviousMatch() {
if (lastGeneFound == null) {
return null;
}
boolean found = false;
int i = lastFoundChromoIndex;
int j = lastFoundGeneIndex - 1;
while (!found && !isLastFoundGene(i, j)) {
while (!found && (j >= 0) && !isLastFoundGene(i, j)) {
found = isASearchedGene(geneList.get(i, j), lastSearchedGeneName);
if (!found) {
j--;
}
}
if ((!found) && !isLastFoundGene(i, j)) {
i--;
if (i < 0) {
i = geneList.size() - 1;
}
j = geneList.size(i) - 1;
}
}
if (found) {
lastFoundChromoIndex = i;
lastFoundGeneIndex = j;
lastGeneFound = geneList.get(i, j);
}
return lastGeneFound;
}
/**
* @param caseSensitive set to true for a case sensitive search
* @return a new result for the search with the new parameter. Null if nothing found
*/
public Gene setCaseSensitive(boolean caseSensitive) {
if (this.caseSensitive != caseSensitive) {
this.caseSensitive = caseSensitive;
if (isASearchedGene(lastGeneFound, lastSearchedGeneName)) {
return lastGeneFound;
} else {
return search(lastSearchedGeneName);
}
} else {
return lastGeneFound;
}
}
/**
* @param wholeWorld set to true for a whole word search
* @return a new result for the search with the new parameter. Null if nothing found
*/
public Gene setWholeWord(boolean wholeWorld) {
if (wholeWord != wholeWorld) {
wholeWord = wholeWorld;
if (isASearchedGene(lastGeneFound, lastSearchedGeneName)) {
return lastGeneFound;
} else {
return search(lastSearchedGeneName);
}
} else {
return lastGeneFound;
}
}
}