//Written by Paul Stothard, University of Alberta, Canada
//Backtranslation, created from rev_trans.js file by George Waldon

function backTrans (theDocument) {	
	var newProtein = "";
	var maxInput = 20000;

	if (testScript() == false) {
		return false;
	}

	var codonTable;
	var table_to_use;
	var headtitle;
	
	var coliFrequencyTable = 
    'AmAcid  Codon      Number    /1000     Fraction   ..\n' +
 
    'Gly     GGG     50527.00     11.12      0.15\n'+
    'Gly     GGA     39036.00      8.59      0.12\n'+
    'Gly     GGT    114185.00     25.14      0.34\n'+
    'Gly     GGC    130043.00     28.63      0.39\n'+

    'Glu     GAG     83804.00     18.45      0.32\n'+
    'Glu     GAA    179460.00     39.51      0.68\n'+
    'Asp     GAT    146794.00     32.32      0.63\n'+
    'Asp     GAC     87759.00     19.32      0.37\n'+

    'Val     GTG    115687.00     25.47      0.36\n'+
    'Val     GTA     51020.00     11.23      0.16\n'+
    'Val     GTT     86572.00     19.06      0.27\n'+
    'Val     GTC     67356.00     14.83      0.21\n'+

    'Ala     GCG    146264.00     32.20      0.34\n'+
    'Ala     GCA     93390.00     20.56      0.22\n'+
    'Ala     GCT     73677.00     16.22      0.17\n'+
    'Ala     GCC    113412.00     24.97      0.27\n'+

    'Arg     AGG      7423.00      1.63      0.03\n'+
    'Arg     AGA     12345.00      2.72      0.05\n'+
    'Ser     AGT     41544.00      9.15      0.15\n'+
    'Ser     AGC     70867.00     15.60      0.26\n'+

    'Lys     AAG     51685.00     11.38      0.25\n'+
    'Lys     AAA    156169.00     34.38      0.75\n'+
    'Asn     AAT     84846.00     18.68      0.46\n'+
    'Asn     AAC     98018.00     21.58      0.54\n'+

    'Met     ATG    123604.00     27.21      1.00\n'+
    'Ile     ATA     24233.00      5.34      0.09\n'+
    'Ile     ATT    135873.00     29.92      0.50\n'+
    'Ile     ATC    111878.00     24.63      0.41\n'+

    'Thr     ACG     63696.00     14.02      0.26\n'+
    'Thr     ACA     35995.00      7.93      0.15\n'+
    'Thr     ACT     43256.00      9.52      0.18\n'+
    'Thr     ACC    103121.00     22.70      0.42\n'+

    'Trp     TGG     65630.00     14.45      1.00\n'+
    'End     TGA      4428.00      0.97      0.30\n'+
    'Cys     TGT     23461.00      5.17      0.45\n'+
    'Cys     TGC     28747.00      6.33      0.55\n'+

    'End     TAG      1172.00      0.26      0.08\n'+
    'End     TAA      9006.00      1.98      0.62\n'+
    'Tyr     TAT     75774.00     16.68      0.58\n'+
    'Tyr     TAC     55847.00     12.30      0.42\n'+

    'Leu     TTG     60322.00     13.28      0.13\n'+
    'Leu     TTA     62823.00     13.83      0.13\n'+
    'Phe     TTT    100128.00     22.05      0.57\n'+
    'Phe     TTC     74885.00     16.49      0.43\n'+

    'Ser     TCG     39546.00      8.71      0.15\n'+
    'Ser     TCA     35837.00      7.89      0.13\n'+
    'Ser     TCT     42367.00      9.33      0.16\n'+
    'Ser     TCC     40365.00      8.89      0.15\n'+

    'Arg     CGG     25751.00      5.67      0.10\n'+
    'Arg     CGA     16607.00      3.66      0.07\n'+
    'Arg     CGT     93997.00     20.70      0.37\n'+
    'Arg     CGC     96053.00     21.15      0.38\n'+

    'Gln     CAG    130898.00     28.82      0.66\n'+
    'Gln     CAA     67129.00     14.78      0.34\n'+
    'His     CAT     57585.00     12.68      0.57\n'+
    'His     CAC     43743.00      9.63      0.43\n'+

    'Leu     CTG    231373.00     50.94      0.49\n'+
    'Leu     CTA     18067.00      3.98      0.04\n'+
    'Leu     CTT     51442.00     11.33      0.11\n'+
    'Leu     CTC     48147.00     10.60      0.10\n'+

    'Pro     CCG    101467.00     22.34      0.51\n'+
    'Pro     CCA     38663.00      8.51      0.20\n'+
    'Pro     CCT     32678.00      7.19      0.17\n'+
    'Pro     CCC     24383.00      5.37      0.12\n';
	
	var colik12FrequencyTable = 
	'AmAcid  Codon      Number    /1000     Fraction   ..\n' +
 
	'Gly     GGG      44      8.59     0.12\n'+
	'Gly     GGA      47      9.18     0.13\n'+
	'Gly     GGT     109     21.28     0.29\n'+
	'Gly     GGC     171     33.39     0.46\n'+
	
	'Glu     GAG      94     18.35     0.30\n'+
	'Glu     GAA     224     43.73     0.70\n'+
	'Asp     GAT     194     37.88     0.65\n'+
	'Asp     GAC     105     20.50     0.35\n'+
	
	'Val     GTG     135     26.36     0.40\n'+
	'Val     GTA      59     11.52     0.17\n'+
	'Val     GTT      86     16.79     0.25\n'+
	'Val     GTC      60     11.71     0.18\n'+
	
	'Ala     GCG     197     38.46     0.38\n'+
	'Ala     GCA     108     21.09     0.21\n'+
	'Ala     GCT      55     10.74     0.11\n'+
	'Ala     GCC     162     31.63     0.31\n'+
	
	'Arg     AGG       8      1.56     0.03\n'+
	'Arg     AGA       7      1.37     0.02\n'+
	'Ser     AGT      37      7.22     0.14\n'+
	'Ser     AGC      85     16.60     0.33\n'+
	
	'Lys     AAG      62     12.10     0.27\n'+
	'Lys     AAA     170     33.19     0.73\n'+
	'Asn     AAT     112     21.87     0.47\n'+
	'Asn     AAC     125     24.40     0.53\n'+
	
	'Met     ATG     127     24.80     1.00\n'+
	'Ile     ATA      19      3.71     0.07\n'+
	'Ile     ATT     156     30.46     0.58\n'+
	'Ile     ATC      93     18.16     0.35\n'+
	
	'Thr     ACG      59     11.52     0.24\n'+
	'Thr     ACA      33      6.44     0.13\n'+
	'Thr     ACT      41      8.00     0.16\n'+
	'Thr     ACC     117     22.84     0.47\n'+
	
	'Trp     TGG      55     10.74     1.00\n'+
	'End     TGA       5      0.98     0.36\n'+
	'Cys     TGT      30      5.86     0.42\n'+
	'Cys     TGC      41      8.00     0.58\n'+
	
	'End     TAG       0      0.20     0.01\n'+
	'End     TAA       9      1.76     0.64\n'+
	'Tyr     TAT      86     16.79     0.53\n'+
	'Tyr     TAC      75     14.64     0.47\n'+
	
	'Leu     TTG      61     11.91     0.12\n'+
	'Leu     TTA      78     15.23     0.15\n'+
	'Phe     TTT     101     19.72     0.57\n'+
	'Phe     TTC      77     15.03     0.43\n'+
	
	'Ser     TCG      41      8.00     0.16\n'+
	'Ser     TCA      40      7.81     0.15\n'+
	'Ser     TCT      29      5.66     0.11\n'+
	'Ser     TCC      28      5.47     0.11\n'+
	
	'Arg     CGG      21      4.10     0.07\n'+
	'Arg     CGA      22      4.30     0.07\n'+
	'Arg     CGT     108     21.09     0.36\n'+
	'Arg     CGC     133     25.97     0.44\n'+
	
	'Gln     CAG     142     27.72     0.70\n'+
	'Gln     CAA      62     12.10     0.30\n'+
	'His     CAT      81     15.81     0.55\n'+
	'His     CAC      67     13.08     0.45\n'+
	
	'Leu     CTG     240     46.86     0.46\n'+
	'Leu     CTA      27      5.27     0.05\n'+
	'Leu     CTT      61     11.91     0.12\n'+
	'Leu     CTC      54     10.54     0.10\n'+
	
	'Pro     CCG     137     26.75     0.55\n'+
	'Pro     CCA      34      6.64     0.14\n'+
	'Pro     CCT      43      8.40     0.17\n'+
	'Pro     CCC      33      6.44     0.13\n';
	
	var homoFrequencyTable = 
	'AmAcid  Codon      Number    /1000     Fraction   ..\n' +
 
	'Gly     GGG      669768     16.47     0.25\n'+
	'Gly     GGA      669873     16.47     0.25\n'+
	'Gly     GGT      437126     10.75     0.16\n'+
	'Gly     GGC      903565     22.22     0.34\n'+
	
	'Glu     GAG     1609975     39.59     0.58\n'+
	'Glu     GAA     1177632     28.96     0.42\n'+
	'Asp     GAT      885429     21.78     0.46\n'+
	'Asp     GAC     1020595     25.10     0.54\n'+
	
	'Val     GTG     1143534     28.12     0.46\n'+
	'Val     GTA      287712      7.08     0.12\n'+
	'Val     GTT      448607     11.03     0.18\n'+
	'Val     GTC      588138     14.46     0.24\n'+
	
	'Ala     GCG      299495      7.37     0.11\n'+
	'Ala     GCA      643471     15.82     0.23\n'+
	'Ala     GCT      750096     18.45     0.27\n'+
	'Ala     GCC     1127679     27.73     0.40\n'+
	
	'Arg     AGG      486463     11.96     0.20\n'+
	'Arg     AGA      494682     12.17     0.21\n'+
	'Ser     AGT      493429     12.13     0.24\n'+
	'Ser     AGC      791383     19.46     0.38\n'+
	 
	'Lys     AAG     1295568     31.86     0.57\n'+
	'Lys     AAA      993621     24.44     0.43\n'+
	'Asn     AAT      689701     16.96     0.47\n'+
	'Asn     AAC      776603     19.1 0    0.53\n'+
	
	'Met     ATG      896005     22.04     1.00\n'+
	'Ile     ATA      304565      7.49     0.17\n'+
	'Ile     ATT      650473     16.00     0.36\n'+
	'Ile     ATC      846466     20.82     0.47\n'+
	
	'Thr     ACG      246105      6.05     0.11\n'+
	'Thr     ACA      614523     15.11     0.28\n'+
	'Thr     ACT      533609     13.12     0.25\n'+
	'Thr     ACC      768147     18.89     0.36\n'+
	
	'Trp     TGG      535595     13.17     1.00\n'+
	'End     TGA       63237      1.56     0.47\n'+
	'Cys     TGT      430311     10.58     0.46\n'+
	'Cys     TGC      513028     12.62     0.54\n'+
	
	'End     TAG       32109      0.79     0.24\n'+
	'End     TAA       40285      0.99     0.30\n'+
	'Tyr     TAT      495699     12.19     0.44\n'+
	'Tyr     TAC      622407     15.31     0.56\n'+
	
	'Leu     TTG      525688     12.93     0.13\n'+
	'Leu     TTA      311881      7.67     0.08\n'+
	'Phe     TTT      714298     17.57     0.46\n'+
	'Phe     TTC      824692     20.28     0.54\n'+
	
	'Ser     TCG      179419      4.41     0.09\n'+
	'Ser     TCA      496448     12.21     0.24\n'+
	'Ser     TCT      618711     15.22     0.30\n'+
	'Ser     TCC      718892     17.68     0.35\n'+
	 
	'Arg     CGG      464485     11.42     0.20\n'+
	'Arg     CGA      250760      6.17     0.11\n'+
	'Arg     CGT      184609      4.54     0.08\n'+
	'Arg     CGC      423516     10.42     0.18\n'+
	
	'Gln     CAG     1391973     34.23     0.74\n'+
	'Gln     CAA      501911     12.34     0.26\n'+
	'His     CAT      441711     10.86     0.42\n'+
	'His     CAC      613713     15.09     0.58\n'+
	
	'Leu     CTG     1611801     39.64     0.40\n'+
	'Leu     CTA      290751      7.15     0.07\n'+
	'Leu     CTT      536515     13.19     0.13\n'+
	'Leu     CTC      796638     19.59     0.20\n'+
	
	'Pro     CCG      281570      6.92     0.11\n'+
	'Pro     CCA      688038     16.92     0.28\n'+
	'Pro     CCT      713233     17.54     0.29\n'+
	'Pro     CCC      804620     19.79     0.32\n';

	if ((checkFormElement (theDocument.forms[0].elements[0]) == false) || (checkSequenceLength(theDocument.forms[0].elements[0].value, maxInput) == false))	{
		return false;
	}

	var table = theDocument.forms[0].elements[4].options[theDocument.forms[0].elements[4].selectedIndex].value;	
	if ((table.toLowerCase()== "codusagetable=1")) {
		table_to_use = colik12FrequencyTable;
		headtitle = "Back Translate using E. coli K12 codon frequencies";
	} else {
	    table_to_use = homoFrequencyTable;
		headtitle = "Back Translate using Homo sapiens codon frequencies";
	}

	codonTable = makeCodonTable(table_to_use);
	if (codonTable == false) {
		return false;
	}

	openWindow(headtitle);
	openPre();
	var arrayOfFasta = getArrayOfFasta (theDocument.forms[0].elements[0].value);

	for (var i = 0; i < arrayOfFasta.length; i++)	{
		newProtein = getSequenceFromFasta (arrayOfFasta[i]);
		var title = getTitleFromFasta (arrayOfFasta[i]);

		newProtein = removeNonProtein(newProtein);

		outputWindow.document.write(getInfoFromTitleAndSequence(title, newProtein));
		writeRevTransSeqNoDegen(newProtein, title, codonTable);
		outputWindow.document.write ("\n");
		writeRevTransSeqDegen(newProtein, title, codonTable);
		outputWindow.document.write ("\n");
		writeTranslationMap(newProtein, codonTable);
		outputWindow.document.write ('\n\n');
	}

	closePre();
	closeWindow();
	return true;
}

function writeRevTransSeqNoDegen(protein, title, codonTable) {
	var aminoAcid;

    //Replace stops by "z"
	protein = protein.replace(/\*/g,"z");
	
	protein = protein.replace(/(.)/g,
                    function (str, p1, offset, s) {
			aminoAcid = codonTable[p1.toString().toLowerCase()];
			return aminoAcid.mostCommonCodon;                 
                   }
                );
	outputWindow.document.write ('&gt;' + 'reverse_translation using most likely codons.\n');
	
	outputWindow.document.write (addReturns(protein));
	outputWindow.document.write ("\n");
	return true;
}

function writeRevTransSeqDegen(protein, title, codonTable) {
	var aminoAcid;

	protein = protein.replace(/\*/g,"z");

	protein = protein.replace(/(.)/g,
                    function (str, p1, offset, s) {
			aminoAcid = codonTable[p1.toString().toLowerCase()];
			return aminoAcid.degenCodon;                 
                   }
                );
	outputWindow.document.write ('&gt;' + 'reverse_translation using consensus codons.\n');
	outputWindow.document.write (addReturns(protein));
	outputWindow.document.write ("\n");
	return true;
}

function writeTranslationMap(protein, codonTable) {
	var aminoAcid;
	var proteinsequence = "";
	var baseline1 = "";
	var baseline2 = "";
	var baseline3 = "";
    var baseline4 = "";
    
	
	outputWindow.document.write ('Back Translation map:\n\n');

	protein = protein.replace(/\*/g,"z");
    proteinsequence = writeOneToThree (protein);


    baseline1 = protein.replace(/(.)/g,
        function (str, p1, offset, s) {
            aminoAcid = codonTable[p1.toString().toLowerCase()];
            return aminoAcid.nucLine1;
        }
        );
    baseline2 = protein.replace(/(.)/g,
        function (str, p1, offset, s) {
            aminoAcid = codonTable[p1.toString().toLowerCase()];
            return aminoAcid.nucLine2;
        }
        );
    baseline3 = protein.replace(/(.)/g,
        function (str, p1, offset, s) {
            aminoAcid = codonTable[p1.toString().toLowerCase()];
            return aminoAcid.nucLine3;
        }
        );
    baseline4 = protein.replace(/(.)/g,
        function (str, p1, offset, s) {
            aminoAcid = codonTable[p1.toString().toLowerCase()];
            return aminoAcid.nucLine4;
        }
        );
	writeGroupProtein (proteinsequence, "", 15, 60, 0, protein.length*3,baseline1,baseline2,baseline3,baseline4);
    return true;
}

function writeGroupProtein (protein, tabIn, groupSize, basePerLine, startBase, stopBase, line1, line2, line3, line4) {

    var i = parseInt(startBase);
	var k = 0;
	var lineOfText = "";
	var nucNum = "";
    var proNum = "";
	var sepChar = " ";
    var lineText1 = "";
    var lineText2 = "";
    var lineText3 = "";
    var lineText4 = "";
    var colwidth = 0;

	groupSize = parseInt(groupSize);
	basePerLine = parseInt(basePerLine);
    colwidth = Math.LOG10E*Math.log(stopBase - startBase) +1;

	while (i < stopBase)	{
		nucNum = i + 1;

		for (var j = 1; j <= (basePerLine/groupSize); j++)	{//makes a group each loop
			while (k < groupSize)	{
				if (i + k >= stopBase) {
					break;
				}
				lineOfText = lineOfText + protein.charAt(k + i);
                lineText1 = lineText1 + line1.charAt(k + i);
                lineText2 = lineText2 + line2.charAt(k + i);
                lineText3 = lineText3 + line3.charAt(k + i);
                lineText4 = lineText4 + line4.charAt(k + i);
				k = k + 1;
			}
			lineOfText = lineOfText + sepChar;
            lineText1 = lineText1 + sepChar;
            lineText2 = lineText2 + sepChar;
            lineText3 = lineText3 + sepChar;
            lineText4 = lineText4 + sepChar;
			i = i + k;
			if (i >= stopBase) {
				break;
			}
			k = 0;
		}

        proNum = Math.round(nucNum/3) +1;
		outputWindow.document.write (rightNum(proNum,"",colwidth,tabIn) + lineOfText + "\n");
        outputWindow.document.write (rightNum(nucNum,"",colwidth,tabIn) + lineText1 + "\n");
        outputWindow.document.write (rightNum("","",colwidth,tabIn) + lineText2 + "\n");
        outputWindow.document.write (rightNum("","",colwidth,tabIn) + lineText3 + "\n");
        outputWindow.document.write (rightNum("","",colwidth,tabIn) + lineText4 + "\n\n");
        lineOfText = "";
        lineText1 = "";
        lineText2 = "";
        lineText3 = "";
        lineText4 = "";
	}
	return true;
}

function writeOneToThree (proteinSequence)	{ 
	proteinSequence = proteinSequence.toLowerCase();
	proteinSequence = proteinSequence.replace(/(.)/g, 
                    function (str, p1, offset, s) {
                      return " " + p1 + " ";
                   }
                );

	proteinSequence = proteinSequence.replace(/a/g, "ALA");
	proteinSequence = proteinSequence.replace(/c/g, "CYS");
	proteinSequence = proteinSequence.replace(/d/g, "ASP");
	proteinSequence = proteinSequence.replace(/e/g, "GLU");
	proteinSequence = proteinSequence.replace(/f/g, "PHE");
	proteinSequence = proteinSequence.replace(/g/g, "GLY");
	proteinSequence = proteinSequence.replace(/h/g, "HIS");
	proteinSequence = proteinSequence.replace(/i/g, "ILE");
	proteinSequence = proteinSequence.replace(/k/g, "LYS");
	proteinSequence = proteinSequence.replace(/l/g, "LEU");
	proteinSequence = proteinSequence.replace(/m/g, "MET");
	proteinSequence = proteinSequence.replace(/n/g, "ASN");
	proteinSequence = proteinSequence.replace(/p/g, "PRO");
	proteinSequence = proteinSequence.replace(/q/g, "GLN");
	proteinSequence = proteinSequence.replace(/r/g, "ARG");
	proteinSequence = proteinSequence.replace(/s/g, "SER");
	proteinSequence = proteinSequence.replace(/t/g, "THR");
	proteinSequence = proteinSequence.replace(/v/g, "VAL");
	proteinSequence = proteinSequence.replace(/w/g, "TRP");
	proteinSequence = proteinSequence.replace(/y/g, "TYR");
	proteinSequence = proteinSequence.replace(/\*/g, "***");
	proteinSequence = proteinSequence.replace(/z/g, "***");

	proteinSequence = proteinSequence.replace(/\s*(.)(.)(.)\s*/g,
                    function (str, p1, p2, p3, offset, s) {
                      return p1 + p2.toLowerCase() + p3.toLowerCase();
                   }
                );
    return proteinSequence;
}


function makeCodonTable(gcgTable) {
	gcgTable = gcgTable.replace(/[^\.]*\.\./,"");
	var tableArray = gcgTable.split(/[\f\n\r]/);
	var re = /(\w+)\s+(\w+)\s+(\S+)\s+(\S+)\s+(\S+)/g;
	var matchArray;
	var codonTable = new CodonTable();
	
	for (var i = 0; i < tableArray.length; i++)	{
		while (matchArray = re.exec(tableArray[i])) {
			
			try {
				codonTable[matchArray[1].toLowerCase()].addCodon(new Codon(matchArray[2], parseFloat(matchArray[3]), parseFloat(matchArray[4]), parseFloat(matchArray[5])));

				}
			catch(e) {
				
				alert ("There is a problem with a line of the codon table: " + matchArray[1] + " " + matchArray[2] + " " + matchArray[3] + " " + matchArray[4] + " " + matchArray[4]);
				return false;
			}		
		}
	}

	codonTable.a.determineBaseFreq();
	codonTable.c.determineBaseFreq();
	codonTable.d.determineBaseFreq();
	codonTable.e.determineBaseFreq();
	codonTable.f.determineBaseFreq();
	codonTable.g.determineBaseFreq();
	codonTable.h.determineBaseFreq();
	codonTable.i.determineBaseFreq();
	codonTable.k.determineBaseFreq();
	codonTable.l.determineBaseFreq();
	codonTable.m.determineBaseFreq();
	codonTable.n.determineBaseFreq();
	codonTable.p.determineBaseFreq();
	codonTable.q.determineBaseFreq();
	codonTable.r.determineBaseFreq();
	codonTable.s.determineBaseFreq();
	codonTable.t.determineBaseFreq();
	codonTable.v.determineBaseFreq();
	codonTable.w.determineBaseFreq();
	codonTable.y.determineBaseFreq();
	codonTable.z.determineBaseFreq();
	
	codonTable.a.fillRuler();
	codonTable.c.fillRuler();
	codonTable.d.fillRuler();
	codonTable.e.fillRuler();
	codonTable.f.fillRuler();
	codonTable.g.fillRuler();
	codonTable.h.fillRuler();
	codonTable.i.fillRuler();
	codonTable.k.fillRuler();
	codonTable.l.fillRuler();
	codonTable.m.fillRuler();
	codonTable.n.fillRuler();
	codonTable.p.fillRuler();
	codonTable.q.fillRuler();
	codonTable.r.fillRuler();
	codonTable.s.fillRuler();
	codonTable.t.fillRuler();
	codonTable.v.fillRuler();
	codonTable.w.fillRuler();
	codonTable.y.fillRuler();
	codonTable.z.fillRuler();	

	return codonTable;	
}

//class CodonTable
function CodonTable() {
	this.a = new AminoAcid();
	this.c = new AminoAcid();
	this.d = new AminoAcid();
	this.e = new AminoAcid();
	this.f = new AminoAcid();
	this.g = new AminoAcid();
	this.h = new AminoAcid();
	this.i = new AminoAcid();
	this.k = new AminoAcid();
	this.l = new AminoAcid();
	this.m = new AminoAcid();
	this.n = new AminoAcid();
	this.p = new AminoAcid();
	this.q = new AminoAcid();
	this.r = new AminoAcid();
	this.s = new AminoAcid();
	this.t = new AminoAcid();
	this.v = new AminoAcid();
	this.w = new AminoAcid();
	this.y = new AminoAcid();
	this.z = new AminoAcid();

	this.ala = this.a;
	this.cys = this.c;
	this.asp = this.d;
	this.glu = this.e;
	this.phe = this.f;
	this.gly = this.g;
	this.his = this.h;
	this.ile = this.i;
	this.lys = this.k;
	this.leu = this.l;
	this.met = this.m;
	this.asn = this.n;
	this.pro = this.p;
	this.gln = this.q;
	this.arg = this.r;
	this.ser = this.s;
	this.thr = this.t;
	this.val = this.v;
	this.trp = this.w;
	this.tyr = this.y;
	this.end = this.z;
}

//class AminoAcid method fillRuler()
function fillRuler() {

	//calculate some other values
	this.setMostCommonCodon();
	this.setDegenCodon();
    this.setNucLines();
}

//class AminoAcid method addCodon()
function addCodon(codon) {
	this.codons.push(codon);	
}

//class AminoAcid method determineBaseFreq()
function determineBaseFreq() {
	this.fixFraction();
	for (var i = 0; i < this.codons.length; i++) {
	    if (this.codons[i].sequence.charAt(0) == "g") {
		    this.baseFreqPosOne[0] = this.baseFreqPosOne[0] + this.codons[i].fraction;
	    }
	    else if (this.codons[i].sequence.charAt(0) == "a") {
		    this.baseFreqPosOne[1] = this.baseFreqPosOne[1] + this.codons[i].fraction;
	    }
	    else if (this.codons[i].sequence.charAt(0) == "t") {
		    this.baseFreqPosOne[2] = this.baseFreqPosOne[2] + this.codons[i].fraction;
	    }
	    else if (this.codons[i].sequence.charAt(0) == "c") {
		    this.baseFreqPosOne[3] = this.baseFreqPosOne[3] + this.codons[i].fraction;
	    }

	    if (this.codons[i].sequence.charAt(1) == "g") {
		    this.baseFreqPosTwo[0] = this.baseFreqPosTwo[0] + this.codons[i].fraction;
	    }
	    else if (this.codons[i].sequence.charAt(1) == "a") {
		    this.baseFreqPosTwo[1] = this.baseFreqPosTwo[1] + this.codons[i].fraction;
	    }
	    else if (this.codons[i].sequence.charAt(1) == "t") {
		    this.baseFreqPosTwo[2] = this.baseFreqPosTwo[2] + this.codons[i].fraction;
	    }
	    else if (this.codons[i].sequence.charAt(1) == "c") {
		    this.baseFreqPosTwo[3] = this.baseFreqPosTwo[3] + this.codons[i].fraction;
	    }

	    if (this.codons[i].sequence.charAt(2) == "g") {
		    this.baseFreqPosThree[0] = this.baseFreqPosThree[0] + this.codons[i].fraction;
	    }
	    else if (this.codons[i].sequence.charAt(2) == "a") {
		    this.baseFreqPosThree[1] = this.baseFreqPosThree[1] + this.codons[i].fraction;
	    }
	    else if (this.codons[i].sequence.charAt(2) == "t") {
		    this.baseFreqPosThree[2] = this.baseFreqPosThree[2] + this.codons[i].fraction;
	    }
	    else if (this.codons[i].sequence.charAt(2) == "c") {
		    this.baseFreqPosThree[3] = this.baseFreqPosThree[3] + this.codons[i].fraction;
	    }
	}
	return true;
}

//class AminoAcid method fixFraction()
//added to address bug in http://www.kazusa.or.jp/codon/ that causes fraction values to all be given as 0.
function fixFraction() {
	var perThouTotal = 0;
	for (var i = 0; i < this.codons.length; i++) {
		perThouTotal = perThouTotal + this.codons[i].perThou;
	}

	if (perThouTotal == 0) {
		return false;
	}

	for (var i = 0; i < this.codons.length; i++) {
		this.codons[i].fraction = this.codons[i].perThou / perThouTotal;
	}
	return true;	
}

//class AminoAcid method getMostCommonCodon()
function setMostCommonCodon() {
	var highestFraction = 0;
	var highestCodon = "nnn";
	for (var i = 0; i < this.codons.length; i++)	{
		if (this.codons[i].fraction > highestFraction) {
			highestFraction = this.codons[i].fraction;
			highestCodon = this.codons[i].sequence;
		}
	}
	this.mostCommonCodon =  highestCodon;
}

//class AminoAcid method getDegenCodon()
function setDegenCodon() {
	this.degenCodon = getConsensusBase(this.baseFreqPosOne) + getConsensusBase(this.baseFreqPosTwo) + getConsensusBase(this.baseFreqPosThree);
}

function getBase(pos, baseFreq) {
    var basecount = 0;
    var i = 0;
    for(i = 0; i<4; i++) {
        if (baseFreq[i] > 0) {
            basecount++;
        }
        if(basecount==pos)
            break;
    }
    if (i==0) {
		return "G";
	}
	if (i==1) {
		return "A";
	}
	if (i==2) {
		return "T";
	}
	if (i==3) {
		return "C";
	}
    return " ";
}

//class AminoAcid method setNucLines()
function setNucLines() {
    this.nucLine1 = getBase(1,this.baseFreqPosOne) + getBase(1,this.baseFreqPosTwo) + getBase(1,this.baseFreqPosThree);
    this.nucLine2 = getBase(2,this.baseFreqPosOne) + getBase(2,this.baseFreqPosTwo) + getBase(2,this.baseFreqPosThree);
    this.nucLine3 = getBase(3,this.baseFreqPosOne) + getBase(3,this.baseFreqPosTwo) + getBase(3,this.baseFreqPosThree);
    this.nucLine4 = getBase(4,this.baseFreqPosOne) + getBase(4,this.baseFreqPosTwo) + getBase(4,this.baseFreqPosThree);
}

//class AminoAcid method getConsensusBase()
function getConsensusBase(baseFreq) {
	var g;
	var a;
	var t;
	var c;
	if (baseFreq[0] > 0) {
		g = true;
	}
	if (baseFreq[1] > 0) {
		a = true;
	}
	if (baseFreq[2] > 0) {
		t = true;
	}
	if (baseFreq[3] > 0) {
		c = true;
	}
	if (!g && !a && !c && !t) {
		return "n";	
	}
	if (g && a && c && t) {
		return "n";
	}
	else if (a && c && t) {
		return "h";
	}
	else if (a && g && t) {
		return "d";
	}
	else if (c && g && t) {
		return "b";
	}
	else if (a && c) {
		return "m";
	}
	else if (g && t) {
		return "k";
	}
	else if (a && t) {
		return "w";
	}
	else if (g && c) {
		return "s";
	}
	else if (c && t) {
		return "y";
	}
	else if (a && g) {
		return "r";
	}
	else if (t) {
		return "t";
	}
	else if (g) {
		return "g";
	}
	else if (c) {
		return "c";
	}
	else if (a) {
		return "a";
	}
	return true;
}

//class AminoAcid
function AminoAcid() {
	this.codons = new Array();
	//g, a, t, c
	this.baseFreqPosOne = new Array (0, 0, 0, 0);
	this.baseFreqPosTwo = new Array (0, 0, 0, 0);
	this.baseFreqPosThree = new Array (0, 0, 0, 0);
	this.mostComonCodon;
	this.degenCodon;
    this.nucLine1;
    this.nucLine2;
    this.nucLine3;
    this.nucLine4;
}

//create and throw away a prototype object
new AminoAcid();

// define object methods
AminoAcid.prototype.fillRuler = fillRuler;
AminoAcid.prototype.addCodon = addCodon;
AminoAcid.prototype.determineBaseFreq = determineBaseFreq;
AminoAcid.prototype.fixFraction = fixFraction;
AminoAcid.prototype.setMostCommonCodon = setMostCommonCodon;
AminoAcid.prototype.setDegenCodon = setDegenCodon;
AminoAcid.prototype.getConsensusBase = getConsensusBase;
AminoAcid.prototype.setNucLines = setNucLines;


//class Codon
function Codon(sequence, number, perThou, fraction) {
	this.sequence = sequence.toLowerCase();
	this.number = number;
	this.perThou = perThou;
	this.fraction = fraction;
}
