// JavaScript

arrayOfAminoAcids = new Array("A","B","C","D","E","F","G","H","I","K","L","M","N","P","Q","R","S","T","V","W","X","Y","Z","*","-");
arrayOfTriplets = new Array("Ala","Asx","Cys","Asp","Glu","Phe","Gly","His","Ile","Lys","Leu","Met","Asn","Pro","Gln","Arg","Ser","Thr","Val","Trp","Xaa","Tyr","Glx","Ter","Unk");
arrayOfAminoAcidWeights = new Array(71.08,114.6,103.14,115.09,129.12,147.18,57.06,137.15,113.17,128.18,113.17,131.21,114.11,97.12,128.41,156.20,87.08,101.11,99.14,186.21,119.16,163.18,128.77,0,0);

theGeneticCode = '/gc[acgtACGTURYMKSWBDHVN]/=A,/tg[ctY]/=C,/ga[ctY]/=D,/ga[agR]/=E,/tt[ctY]/=F,/gg[acgtACGTURYMKSWBDHVN]/=G,/ca[ctY]/=H,/at[actHMYW]/=I,/aa[agR]/=K,/ct[acgtACGTURYMKSWBDHVN]|[cty]t[agR]/=L,/atg/=M,/aa[ctY]/=N,/cc[acgtACGTURYMKSWBDHVN]/=P,/ca[agR]/=Q,/cg[acgtACGTURYMKSWBDHVN]|[acm]g[agR]/=R,/tc[acgtACGTURYMKSWBDHVN]|ag[ctY]/=S,/ac[acgtACGTURYMKSWBDHVN]/=T,/gt[acgtACGTURYMKSWBDHVN]/=V,/tgg/=W,/ta[ctY]/=Y,/[agr]a[ctY]/=B,/[cgs]a[agR]/=Z,/ta[agR]|t[agr]a/=*,/xxx/=-,/[ACGTURYMKSWBDHVN][ACGTURYMKSWBDHVN][ACGTURYMKSWBDHVN]/=X';

var codonAminoAcids = new Array("A", "C", "D", "E", "F", "G", "H", "I", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "V", "W", "Y", "B", "Z", "*", "-", "X"); 

var codonPatterns = new Array(/gc[acgtACGTURYMKSWBDHVN]/gi, /tg[ctY]/gi, /ga[ctY]/gi, /ga[agR]/gi, /tt[ctY]/gi, /gg[acgtACGTURYMKSWBDHVN]/gi, /ca[ctY]/gi, /at[actHMYW]/gi, /aa[agR]/gi, /ct[acgtACGTURYMKSWBDHVN]|[cty]t[agR]/gi, /atg/gi, /aa[ctY]/gi, /cc[acgtACGTURYMKSWBDHVN]/gi, /ca[agR]/gi, /cg[acgtACGTURYMKSWBDHVN]|[acm]g[agR]/gi, /tc[acgtACGTURYMKSWBDHVN]|ag[ctY]/gi, /ac[acgtACGTURYMKSWBDHVN]/gi, /gt[acgtACGTURYMKSWBDHVN]/gi, /tgg/gi, /ta[ctY]/gi, /[agr]a[ctY]/gi, /[cgs]a[agR]/gi, /ta[agR]|t[agr]a/gi, /xxx/gi, /[ACGTURYMKSWBDHVN][ACGTURYMKSWBDHVN][ACGTURYMKSWBDHVN]/gi); 


/* Only allows ACGTRYMKSWBDHVN, for most purposes
*/
function seqNormal(seq) {
    seq = seq.toUpperCase();
    var returnString = "";
	var nt_code = 'ACGTURYMKSWBDHVN';

    for (var i = 0; i < seq.length; i++) {
		if(nt_code.indexOf(seq.charAt(i)) >=0){ returnString += seq.charAt(i); }
    }
    return returnString;
}

/* Only allows AGCTUNI, for MW($theString), EPS($theString), oTm($theString)
*/
function seqNormal1(seq) {
    seq = seq.toUpperCase();
    var returnString = "";
	var nt_code = 'ACGTURYMKSWBDHVN';
	var nt_code1 = 'RYMWSKDHBV';
	var nt_code2 = 'AGCTUNI';

    for (var i = 0; i < seq.length; i++) {
		if(nt_code1.indexOf(seq.charAt(i)) >=0) returnString += 'N'; 
		else if(nt_code2.indexOf(seq.charAt(i)) >=0 ) returnString += seq.charAt(i);
    }
    return returnString;
}
/* Only allows ACGTN, for sequencing analysis and calculation of GC%!
*/
function seqNormal2(seq) {
    seq = seq.toUpperCase();
    var returnString = "";
	var nt_code = 'ACGTURYMKSWBDHVN';
	var nt_code1 = 'RYMWSKDHBV';
	var nt_code2 = 'AGCTN';

    for (var i = 0; i < seq.length; i++) {
		if(nt_code1.indexOf(seq.charAt(i)) >=0) returnString += 'N'; 
		else if(nt_code2.indexOf(seq.charAt(i)) >=0 ) returnString += seq.charAt(i);
    }
    return returnString;
}

function seqRev(seq) {
    seq = seq.toUpperCase();
    var returnString = "";

    for (var i = seq.length - 1; i >= 0; i--) {
		returnString += seq.charAt(i);
    }
    return returnString;
}

function seqComp(seq) {
    seq = seq.toUpperCase();
    var returnString = "";

    for (var i = 0; i < seq.length; i++) {
		if (seq.charAt(i) == "A") {	returnString += 't'; }
		else if (seq.charAt(i) == "T") {	returnString += 'a'; }
		else if (seq.charAt(i) == "G") {	returnString += 'c'; }
		else if (seq.charAt(i) == "C") {	returnString += 'g'; }
		else { returnString += seq.charAt(i); }
    }
    return returnString;
}

function seqRevComp(seq) {
    seq = seq.toUpperCase();
    var returnString = "";

    for (var i = seq.length - 1; i >= 0; i--) {
		if (seq.charAt(i) == "A") {	returnString += 't'; }
		else if (seq.charAt(i) == "T") {	returnString += 'a'; }
		else if (seq.charAt(i) == "G") {	returnString += 'c'; }
		else if (seq.charAt(i) == "C") {	returnString += 'g'; }
		else { returnString += seq.charAt(i); }
    }
    return returnString;
}

function seqTranslate(seq,startPos,strand)	{

	var proteinSeq = "";
	var codon = "";
	var proteinChar = "-";
	startPos = parseInt(startPos);
	seq = seqNormal(seq);
	if (strand == "reverse"){	seq = seqRevComp(seq);	}

	for (var i = startPos; i < (seq.length - 2); i = i + 3)	{
		codon = seq.substring(i,(i+3));
		proteinChar = "-";
		for (var j = 0; j < codonPatterns.length; j++){
			if (codon.search(codonPatterns[j]) >= 0){
				proteinChar = codonAminoAcids[j];
				break;
			}
		}
		proteinSeq = proteinSeq + proteinChar;
	}
	return proteinSeq;
}


function seqNormalProtein(seq){
    seq = seq.toUpperCase();
    var returnString = "";
	var p_code = 'ABCDEFGHIKLMNPQRSTVWXYZ*-';

    for (var i = 0; i < seq.length; i++) {
		if(p_code.indexOf(seq.charAt(i)) >=0){ returnString += seq.charAt(i); }
    }
    return returnString;
}

function seq123(seq){
	seq = seqNormalProtein(seq);
	var i, j;
	var arrayOfAminoAcids = new Array("A","B","C","D","E","F","G","H","I","K","L","M","N","P","Q","R","S","T","V","W","X","Y","Z","*","-");
	var arrayOfTriplets = new Array("Ala","Asx","Cys","Asp","Glu","Phe","Gly","His","Ile","Lys","Leu","Met","Asn","Pro","Gln","Arg","Ser","Thr","Val","Trp","Xaa","Tyr","Glx","Ter","Unk");
	var resultSeq = "";
	for (i = 0; i < seq.length; i++) {
		for (j = 0; j < arrayOfAminoAcids.length; j++){
			if (seq.charAt(i) == arrayOfAminoAcids[j]){
				resultSeq = resultSeq + arrayOfTriplets[j];
				break;
			}
		}
	}
	return resultSeq;
}

function seq321(seq){
	var arrayOfAminoAcids = new Array("A","B","C","D","E","F","G","H","I","K","L","M","N","P","Q","R","S","T","V","W","X","Y","Z","*","-");
	var arrayOfTriplets = new Array("Ala","Asx","Cys","Asp","Glu","Phe","Gly","His","Ile","Lys","Leu","Met","Asn","Pro","Gln","Arg","Ser","Thr","Val","Trp","Xaa","Tyr","Glx","Ter","Unk");
	var resultSeq = "";
	var triplet = "";
	for (var i = 0; i < seq.length - 2; i = i + 3) {
		triplet = seq.substring(i,i+3)
		for (var j = 0; j < arrayOfTriplets.length; j++)	{
			if (triplet.toUpperCase() == arrayOfTriplets[j].toUpperCase())	{
				resultSeq = resultSeq + arrayOfAminoAcids[j];
				break;
			}
		}
	}
	return resultSeq;
}

function protMW(seq){
	var arrayOfAminoAcids = new Array("A","B","C","D","E","F","G","H","I","K","L","M","N","P","Q","R","S","T","V","W","X","Y","Z","*","-");
	var arrayOfAminoAcidWeights = new Array(71.08,114.6,103.14,115.09,129.12,147.18,57.06,137.15,113.17,128.18,113.17,131.21,114.11,97.12,128.41,156.20,87.08,101.11,99.14,186.21,119.16,163.18,128.77,0,0);
	seq = seqNormalProtein(seq);
	var result = 0;
	for (var i = 0; i < seq.length; i++)	{
		for (var j = 0; j < arrayOfAminoAcids.length; j++)	{
			if (seq.charAt(i) == arrayOfAminoAcids[j])	{
				result = result + arrayOfAminoAcidWeights[j];
				break;
			}
		}
	}
	if (result == 0)	{
		return result;
	}
	else	{
		result = result + 18.02; //add the weight of water for the ends of the protein.
		result = result/1000;	//convert to kilodaltons.
		result = Math.round(result*100)/100;	//round to hundredths
		return result;
	}
}


function Eps() {
	this["A"] = 15.4;
	this["C"] = 7.4;
	this["G"] = 11.5;
	this["I"] = 7.2;
	this["N"] = 10.7;
	this["T"] = 8.7;
	this["U"] = 8.7 ;
	this["AA"] = 13.7;
	this["AC"] = 10.6;
	this["AG"] = 12.5;
	this["AI"] = 9.3;
	this["AN"] = 12;
	this["AT"] = 11.4;
	this["AU"] = 11.4;
	this["CA"] = 10.6;
	this["CC"] = 7.3;
	this["CG"] = 9;
	this["CI"] = 7.2;
	this["CN"] = 8.6;
	this["CT"] = 7.6;
	this["CU"] = 7.6;
	this["GA"] = 12.6;
	this["GC"] = 8.8;
	this["GG"] = 10.8;
	this["GI"] = 8.8;
	this["GN"] = 10.5;
	this["GT"] = 10;
	this["GU"] = 10.5;
	this["IA"] = 9.3;
	this["IC"] = 7.1;
	this["IG"] = 8.8;
	this["II"] = 6.8;
	this["IN"] = 8.4;
	this["IT"] = 8.4;
	this["IU"] = 8.4;
	this["NA"] = 12.1;
	this["NC"] = 8.7;
	this["NG"] = 9.4;
	this["NI"] = 8.7;
	this["NN"] = 9.9;
	this["NT"] = 9.4;
	this["NU"] = 9.4;
	this["TA"] = 11.7;
	this["TC"] = 8.1;
	this["TG"] = 9.5;
	this["TI"] = 8.1;
	this["TN"] = 9.4;
	this["TT"] = 9.4;
	this["TU"] = 9.4;
	this["UA"] = 11.7;
	this["UC"] = 8.1;
	this["UG"] = 9.5;
	this["UI"] = 8.1;
	this["UN"] = 9.4;
	this["UT"] = 9.4;
	this["UU"] = 9.4;
}

function dS() {
	this["AA"] = 24;
	this["AC"] = 17.3;
	this["AG"] = 20.8;
	this["AI"] = 23.9;
	this["AN"] = 23.9;
	this["AT"] = 23.9;
	this["AU"] = 23.9;
	this["CA"] = 12.9;
	this["CC"] = 26.6;
	this["CG"] = 27.8;
	this["CI"] = 20.8;
	this["CN"] = 20.8;
	this["CT"] = 20.8;
	this["CU"] = 20.8;
	this["GA"] = 13.5;
	this["GC"] = 26.7;
	this["GG"] = 26.6;
	this["GI"] = 17.3;
	this["GN"] = 17.3;
	this["GT"] = 17.3;
	this["GU"] = 17.3;
	this["IA"] = 16.9;
	this["IC"] = 13.5;
	this["IG"] = 12.9;
	this["II"] = 24;
	this["IN"] = 24;
	this["IT"] = 24;
	this["IU"] = 24;
	this["NA"] = 16.9;
	this["NC"] = 13.5;
	this["NG"] = 12.9;
	this["NI"] = 24;
	this["NN"] = 24;
	this["NT"] = 24;
	this["NU"] = 24;
	this["TA"] = 16.9;
	this["TC"] = 13.5;
	this["TG"] = 12.9;
	this["TI"] = 24;
	this["TN"] = 24;
	this["TT"] = 24;
	this["TU"] = 24;
	this["UA"] = 16.9;
	this["UC"] = 13.5;
	this["UG"] = 12.9;
	this["UI"] = 24;
	this["UN"] = 24;
	this["UT"] = 24;
	this["UU"] = 24;
}

function dH() {
	this["AA"] = 9.1;
	this["AC"] = 6.5;
	this["AG"] = 7.8;
	this["AI"] = 8.6;
	this["AN"] = 8.6;
	this["AT"] = 8.6;
	this["AU"] = 8.6;
	this["CA"] = 5.8;
	this["CC"] = 11;
	this["CG"] = 11.9;
	this["CI"] = 7.8;
	this["CN"] = 7.8;
	this["CT"] = 7.8;
	this["CU"] = 7.8;
	this["GA"] = 5.6;
	this["GC"] = 11.1;
	this["GG"] = 11;
	this["GI"] = 6.5;
	this["GN"] = 6.5;
	this["GT"] = 6.5;
	this["GU"] = 6.5;
	this["IA"] = 6;
	this["IC"] = 5.6;
	this["IG"] = 5.8;
	this["II"] = 9.1;
	this["IN"] = 9.1;
	this["IT"] = 9.1;
	this["IU"] = 9.1;
	this["NA"] = 6;
	this["NC"] = 5.6;
	this["NG"] = 5.8;
	this["NI"] = 9.1;
	this["NN"] = 9.1;
	this["NT"] = 9.1;
	this["NU"] = 9.1;
	this["TA"] = 6;
	this["TC"] = 5.6;
	this["TG"] = 5.8;
	this["TI"] = 9.1;
	this["TN"] = 9.1;
	this["TT"] = 9.1;
	this["TU"] = 9.1;
	this["UA"] = 6;
	this["UC"] = 5.6;
	this["UG"] = 5.8;
	this["UI"] = 9.1;
	this["UN"] = 9.1;
	this["UT"] = 9.1;
	this["UU"] = 9.1;
}


function charCount(theChar, theString) {
    theChar = theChar.toUpperCase();
    theString = theString.toUpperCase();
	var count = 0;
    for (var i = 0; i < theString.length; i++) { if (theString.charAt(i) == theChar) count++; }
    return count;
}

function GC(theString){
	theString = seqNormal2(theString);
    if(theString.length > 0)
		return Math.round(100 * ( charCount('g', theString) + charCount('c', theString) + charCount('n', theString) / 2) / theString.length );
    else {	return 0;  }
}

function Tm(theString) {
	theString = seqNormal1(theString);
	
	DeltaH = new dH();
	DeltaS = new dS();

  if (theString.length > 0){

	if (theString.length <= 20){
	    return(2 * (charCount('a', theString) + charCount('t', theString) + charCount('i', theString) + charCount('u', theString)) +
		   4 * (charCount('g', theString) + charCount('c', theString)) +
		   3 * charCount('n', theString));
	}
    else {

	    var sigma_dH = 0
	    var sigma_dS = 0

	    for (var i = 0; i < (theString.length - 1); i++) {
			sigma_dH += DeltaH[theString.substring(i, i + 2)]
			sigma_dS += DeltaS[theString.substring(i, i + 2)]
	    }

	    return Math.round(-1000 * sigma_dH / (-10.8 - sigma_dS + 1.987 * -23.5) -273.15 + 16.6 * -1.3);
	}
  }
  else { return 0;  }
}

function MW(theString){
    if (theString.length > 0){
		return Math.round(252 * charCount('a', theString) +
			  228 * charCount('c', theString) +
			  268 * charCount('g', theString) +
			  243 * charCount('t', theString) +
			  243 * charCount('u', theString) +
			  253 * charCount('i', theString) +
			  248 * charCount('n', theString) +
			  61 * (theString.length - 1));
    }
    else { return 0; }
}

function epsilon(theString) {
	Epsilon = new Eps();

    var eps_seq = 0
    if (theString.length > 0) {
	  for (var i = 0; i < theString.length - 1; i++) {
	    eps_seq += 2 * Epsilon[theString.substring(i, i + 2)] - Epsilon[theString.substring(i + 1, i + 2)];
	  }
	  eps_seq += Epsilon[theString.substring(theString.length - 1, theString.length)];
	  return eps_seq;
    }
    else { return 0; }
}



function seqFormat(seq) {
    var retSeq = "";

	var n = 0;
	var w = 60;
	var b = 10;
	var i, j, s, seq1, seq2, num1, num2;
	for(i=1; i<seq.length; i+=w){
		s = seq.substr(i-1,w);
		seq1 = '';
		for(j=0; j<w; j++){   
			if(j%b == 0) seq1 += ' ' + s.charAt(j);
			else seq1 += s.charAt(j);
		}
		num1 = (w*n+1).toString();
		while(num1.length < 9) num1 = ' ' + num1;
/*		
		s = seqComp(seq.substr(i-1,w));
		seq2 = '';
		for(j=0; j<w; j++){   
			if(j%b == 0) seq2 += ' ' + s.charAt(j);
			else seq2 += s.charAt(j);
		}
		num2 = (seq.length-n*w).toString();
		while(num2.length < 6) num2 = ' ' + num2;
*/		
		if(n==0) retSeq += num1 + seq1;
		else retSeq += '\n' + num1 + seq1;
		
//		retSeq += '\n' + num2 + seq2 + '\n';

		n++; 
	}
    return retSeq;
}

function seqFormat2(seq) {
    var retSeq = "";

	var n = 0;
	var w = 60;
	var b = 10;
	var i, j, s, seq1, seq2, num1, num2;
	for(i=1; i<seq.length; i+=w){
		s = seq.substr(i-1,w);
		seq1 = '';
		for(j=0; j<w; j++){   
			if(j%b == 0) seq1 += ' ' + s.charAt(j);
			else seq1 += s.charAt(j);
		}
		num1 = (w*n+1).toString();
		while(num1.length < 9) num1 = ' ' + num1;
		
		s = seqComp(seq.substr(i-1,w));
		seq2 = '';
		for(j=0; j<w; j++){   
			if(j%b == 0) seq2 += ' ' + s.charAt(j);
			else seq2 += s.charAt(j);
		}
		num2 = (seq.length-n*w).toString();
		while(num2.length < 9) num2 = ' ' + num2;
		
		if(n==0) retSeq += num1 + seq1;
		else retSeq += '\n' + num1 + seq1;
		
		retSeq += '\n' + num2 + seq2 + '\n';

		n++; 
	}
    return retSeq;
}



