content: package aliview.primer;
  
  import java.text.DecimalFormat;
  import java.util.ArrayList;
  
  import org.apache.commons.lang.StringUtils;
  import org.apache.log4j.Logger;
  
  import aliview.NucleotideUtilities;
  
  public class Primer implements Comparable<Primer> {
  	private static final Logger logger = Logger.getLogger(Primer.class);
  	private static final String LF = System.getProperty("line.separator");
  	DecimalFormat DEC_FORMAT = new DecimalFormat("#.#");
  	String sequence;
  	private int position;
  
  	public Primer(String sequence, int position) {
  		super();
  		this.sequence = sequence;
  		this.position = position;
  	}
  
  	public long getScore(){
  		long score = 0;
  
  		long foldVal = getDegenerateFold();
  
  		score = foldVal;
  
  		return score;
  	}
  
  	public long getDegenerateFold(){
  
  		long foldVal = 1;
  		for(int n = 0; n < sequence.length(); n++){
  			foldVal = foldVal * NucleotideUtilities.degenFoldFromChar(sequence.charAt(n));
  		}
  
  		return foldVal;
  	}
  
  	public String getBaseStackingAvgTmAsString(){
  		double tm = getBaseStackingAvgTm();
  		String tmString = "";
  		tmString += DEC_FORMAT.format(tm) + "°C";
  		return tmString;
  	}
  
  	public double getBaseStackingAvgTm(){
  		double conc_primer = 200;// nM 
  		double conc_salt = 50; //mM
  		double conc_mg = 0; //mM
  
  		// expand all primers
  		ArrayList<String> regenerated = NucleotideUtilities.regenerateDegenerated(sequence);
  
  		// loop through and get max and min tm
  		double minTM = Double.MAX_VALUE;
  		double maxTM = Double.MIN_VALUE;
  		for(String thisSeq: regenerated){
  			double tm = OligoCalc.getBaseStackingTM(thisSeq, conc_primer, conc_salt, conc_mg);
  			minTM = Math.min(tm, minTM);
  			maxTM = Math.max(tm, maxTM);
  		}
  
  		return (minTM/2+maxTM/2);
  	}
  
  	public String getBaseStackingTmAsString(){
  		double conc_primer = 200;// nM 
  		double conc_salt = 50; //mM
  		double conc_mg = 0; //mM
  
  		// expand all primers
  		ArrayList<String> regenerated = NucleotideUtilities.regenerateDegenerated(sequence);
  
  		// loop through and get max and min tm
  		double minTM = Double.MAX_VALUE;
  		double maxTM = Double.MIN_VALUE;
  		for(String thisSeq: regenerated){
  			double tm = OligoCalc.getBaseStackingTM(thisSeq, conc_primer, conc_salt, conc_mg);
  			//logger.info("tm=" + tm);
  			minTM = Math.min(tm, minTM);
  			maxTM = Math.max(tm, maxTM);
  		}
  
  		String tmString = "";
  		if(minTM == maxTM){
  			tmString = DEC_FORMAT.format(minTM) + "°C"; 
  		}
  		else{
  			tmString += DEC_FORMAT.format(minTM) + "°C to " + DEC_FORMAT.format(maxTM) + "°C"; 
  		}
  
  		return tmString;
  	}
  
  	public String getTmAsString(){
  		double conc_primer = 200;// nM 
  		double conc_salt = 50; //mM
  		double conc_mg = 0; //mM
  
  		// expand all primers
  		ArrayList<String> regenerated = NucleotideUtilities.regenerateDegenerated(sequence);
  
  		// loop through and get max and min tm
  		double minTM = Double.MAX_VALUE;
  		double maxTM = Double.MIN_VALUE;
  		for(String thisSeq: regenerated){
  			double tm = OligoCalc.getBaseStackingTM(thisSeq, conc_primer, conc_salt, conc_mg);
  			//logger.info("tm=" + tm);
  			minTM = Math.min(tm, minTM);
  			maxTM = Math.max(tm, maxTM);
  		}
  
  		String tmString = "baseStack ";
  		if(minTM == maxTM){
  			tmString = DEC_FORMAT.format(minTM) + "°C"; 
  		}
  		else{
  			tmString += "avg=" + DEC_FORMAT.format(minTM/2+maxTM/2) + "°C " +  
  					DEC_FORMAT.format(minTM) + "°C to " + DEC_FORMAT.format(maxTM) + "°C"; 
  		}
  
  		return tmString;
  	}
  
  	public int compareTo(Primer o) {
  
  		if(this.getScore() == o.getScore()){
  			return 0;
  		}
  
  		if(this.getScore() > o.getScore()){
  			return 1;
  		}
  		else{
  			return -1;
  		}
  
  	}
  
  	public String getSequence() {
  		return this.sequence;
  	}
  
  	public int getPosition() {
  		return this.position;
  	}
  
  	public double getGCcontent() {
  		double ng = StringUtils.countMatches(this.getSequence(), "G");
  		double nc = StringUtils.countMatches(this.getSequence(), "C");
  		double gc_contents = (ng+nc)/this.getSequence().length();
  		return gc_contents;
  	}
  
  	public int getLength() {
  		return this.getSequence().length();
  	}
  
  	public int get3EndDimerMaxLength() {
  		Dimer d = new Dimer(this.getSequence(), NucleotideUtilities.revComp(this.getSequence()));
  		return d.get3EndDimerMaxLength();
  	}
  
  
  	public int getDimerMaxLength() {
  		Dimer d = new Dimer(this.getSequence(), NucleotideUtilities.revComp(this.getSequence()));
  		return d.getDimerMaxLength();
  	}
  	public ArrayList<String> getAllDimersAsText() {
  		Dimer d = new Dimer(this.getSequence(), NucleotideUtilities.revComp(this.getSequence()));
  		return d.getAllDimersAsText();
  	}
  
  	public String getPrimerDetailsAsText() {
  		String data="";
  		data += ">" + this.getPosition() + LF;
  		data += "" + this.getSequence() + LF;
  		data += "revcomp:" + aliview.NucleotideUtilities.revComp(this.getSequence()) + LF;
  		data += "position:" + this.getPosition() + LF;
  		data += "length:" + this.getSequence().length() + LF;
  		data += "degenerate-fold:" + this.getScore() + LF;
  
  
  		boolean isFirstLine = true;
  		for(String line: NucleotideUtilities.seqToDeUPACStringArray(this.getSequence())){
  			if(isFirstLine){
  				data += "degenerate-view: " + line + LF;
  				isFirstLine = false;
  			}else{
  				data += "                 " + line + LF;
  			}
  		}
  
  		data += "Tm(base-stacking):" + this.getBaseStackingTmAsString() + " (avg=" + getBaseStackingAvgTmAsString() + ")" +  LF;
  		data += "gc-content:" + this.getGCcontent() + LF;
  		data += "max 3\"-end-dimer:" + this.get3EndDimerMaxLength() + LF;
  		data += "max dimer length:" + this.getDimerMaxLength() +  LF;
  		data += "below are all dimers above threshold length (" + this.getDimerLengthThreashold() + "):" + LF;
  		data += LF;
  		for(String line: this.getAllDimersAsText()){
  			data += line + LF;
  		}
  		return data;
  	}
  
  	private int getDimerLengthThreashold() {
  		return Dimer.getDimerLengthThreashold();
  	}
  
  }
  