package geneFinder;


/**
 * based on the assigned reads, assign a score to each identified gene
 * Copyright (c) 2013,
 * Franziska Zickmann, 
 * ZickmannF@rki.de, Robert Koch-Institute, Berlin, Germany
 * Distributed under the GNU Lesser General Public License, version 3.0
 *
 */

import java.util.Vector;

import types.*;

public class CalculateScores {

	public static double minScoreClust;    // necessary for the normalization later on
	public static double maxScoreClust;
	
	/*
	 * depending on the number and quality of assigned reads calculate a score for each cluster
	 * multiple and uniques are distinguished via certain weighting
	 */
	
	public static double[] assignGeneScores(boolean befOpti){
		
		minScoreClust = Double.MAX_VALUE;
		maxScoreClust = Double.MIN_VALUE;
		
		for(String contigName : GeneFinder.mappedContigs.keySet()){
			
			Contig thisContig = GeneFinder.mappedContigs.get(contigName);

			Vector<Gene> twinsAlternativeSplicing = new Vector<Gene>();
			
			for(Gene cluster : thisContig.allGenes){
				
				scoreCalculation(cluster, contigName, befOpti);
				
				if(cluster.twinNode != null){
					scoreCalculation(cluster.twinNode, contigName, befOpti);
					
					// make sure that only one of the twins is included
					
					if((cluster.twinNode.score != 0) && (cluster.score != 0)){
						// also include twin node in contig genes
						twinsAlternativeSplicing.add(cluster.twinNode);
						cluster.twinNode = null;
					} else if(cluster.twinNode.score == 0){
						cluster.twinNode = null;
					} else{
						cluster = cluster.twinNode;
						cluster.twinNode = null;
					}
				}
	
			}
			
			thisContig.allGenes.addAll(twinsAlternativeSplicing);
		}
		
		double[] minMax = {minScoreClust,maxScoreClust};
		return minMax;
	}
	
	/*
	 * does the calculation
	 */
	
	public static void scoreCalculation(Gene cluster, String contigName, boolean befOpti){

		double exonLength = 0;
		// first determine exonlength
		
		cluster.exonsOfGene.clear();
		cluster.exonLength = 0;
		FindExonsOfGene.findExonsForGene(cluster); // TODO: also check if exons are there!
		if(GeneFinder.useCPLEX){
			OptimizeAmbis.sumUpExonLengths(cluster, cluster.exonsOfGene);
		}else{
			OptimizeAmbis_GLPK.sumUpExonLengths(cluster, cluster.exonsOfGene);
		}

		exonLength = cluster.exonLength;

		if(exonLength <= 0){
			System.err.println("Exon length <= 0 for gene " + cluster.geneID);
		}
		double scoreRnaPart = 0.0;
		cluster.numOfMultis = 0;
		
		for(String rnaKey : cluster.idTOassociatedRnas.keySet()){
			
			Rna rna = ((Rna) cluster.idTOassociatedRnas.get(rnaKey)[0]);
			
			double uniqueFactor = 1.0;
			
			if(rna.isMulti != 0 || rna.isSharedBy.size() > 0){
				uniqueFactor = (1.0)/(rna.hitNum);
				if(rna.isMulti == 1){
					cluster.numOfMultis++;
					if(GeneFinder.iteration == 1 && !befOpti){
						prepareRnasForIteration(rna, cluster,contigName);
					}
				}
						
			}
			
			scoreRnaPart += (rna.quality * GeneFinder.readLength * uniqueFactor);  // * mapQual was excluded, because multi hits might have always mapQual = 0
		}
		
		cluster.score = (double) ((scoreRnaPart/(double)exonLength));
		
		if(cluster.score > 0 && cluster.score < minScoreClust){
			minScoreClust = cluster.score;
		}
		if(cluster.score > maxScoreClust ){
			maxScoreClust = cluster.score;
		}
		
	}
	
	/*
	 * calculate score for alternative isoforms, depending on their supporting reads (as fraction of all reads supporting this gene)
	 * note: will be called during output writing 
	 * Careful: its necessary to make sure that this method is only called for non-fake splice keys!!
	 */
	
	public static double calculateIsoformScore(Gene cluster, int spliceKey, int positionInVector){
		
		double score = ((double)((Vector<Vector<Rna>>)cluster.possibleIntrons.get(spliceKey)[2]).get(positionInVector).size()  * 1000.0)/((double) cluster.idTOassociatedRnas.keySet().size());  // multiply with 1000 to avoid too small numbers
		
		return score;
	}
	
	/*
	 * to initialize iteration
	 */
	
	public static void prepareRnasForIteration(Rna rna, Gene gene, String contigName){
		
		Contig thisContig = GeneFinder.mappedContigs.get(contigName);
		rna.isSharedBy.clear();

		if(rna.contigsMappedOn.size() > 1){
			
			Object[] minInfo = {Integer.MAX_VALUE,""};
			
			for(int pos = rna.contigsMappedOn.size() -1;pos>=0;pos--){
				Object[] info = rna.contigsMappedOn.get(pos);
				if(!(((Integer) info[1] > gene.startPos)  && ((Integer) info[1] < gene.stopPos) && (((Contig) info[0]).equals(thisContig)))){
					rna.contigsMappedOn.removeElementAt(pos);
				}else{
					
					if(((Integer)minInfo[0]).intValue() > (Integer) info[1]){
						String rnaInfo = "";					
						rnaInfo += rna.rnaID + "\t0\t"+ contigName + "\t" + ((Integer)info[1]) + "\t0\t" + ((String)info[2]) + "\t*\t*\t*\t*\t*\tNH:i:1\n"; 
						
						minInfo[0] = ((Integer) info[1]).intValue();
						minInfo[1] = rnaInfo;
					}

				}
			}
			
			WriteOutput.writeToOtherFile(GeneFinder.pathOut+"reassignedReads.sam",(String)minInfo[1]);
			
		}else if(rna.contigsMappedOn.size() == 1){
			String rnaInfo = "";
			Object[] info = rna.contigsMappedOn.get(0);
			rnaInfo += rna.rnaID + "\t0\t"+ contigName + "\t" + ((Integer)info[1]) + "\t0\t" + ((String)info[2]) + "\t*\t*\t*\t*\t*\tNH:i:1\n"; 
			WriteOutput.writeToOtherFile(GeneFinder.pathOut+"reassignedReads.sam",rnaInfo);
		}
	}
}
