//Written by Paul Stothard, University of Alberta, Canada
//Modified by George Waldon for combined pairwise and coloring protein alignment

function pairwiseAlignNColorProtein (theDocument) {	

	var maxInput = 2000;

var newProteinOne = "";
	var titleOne = "";

	var newProteinTwo = "";
	var titleTwo = "";
    
	// Coloring
	var theAlignment = "";
	var alignArray = new Array();
	var groupString = "GAVLI,FYW,CM,ST,KRH,DENQ,P";
	var arrayOfGroups = new Array();
	var titleArray = new Array();
	var sequenceArray = new Array();

	var longestTitle;
	var startingindex = "0,0";
    var resperline = theDocument.forms[0].elements[11].options[theDocument.forms[0].elements[11].selectedIndex].value;

    //Max lenth of sequence title shown in alignment
    var arraytitlewidth = 20;

	if (testScript() == false) {
		return false;
	}

	if ((checkFormElement (theDocument.forms[0].elements[0]) == false) || (checkSequenceLength(theDocument.forms[0].elements[0].value, maxInput) == false) || (checkFormElement (theDocument.forms[0].elements[2]) == false) || (checkSequenceLength(theDocument.forms[0].elements[2].value, maxInput) == false))	{
		return false;
	}

	var MATRIX = theDocument.forms[0].elements[7].options[theDocument.forms[0].elements[7].selectedIndex].value;
	var BEGIN_GAP_PENALTY = parseInt(theDocument.forms[0].elements[8].options[theDocument.forms[0].elements[8].selectedIndex].value);
	var GAP_PENALTY = parseInt(theDocument.forms[0].elements[9].options[theDocument.forms[0].elements[9].selectedIndex].value);
	var END_GAP_PENALTY = parseInt(theDocument.forms[0].elements[10].options[theDocument.forms[0].elements[10].selectedIndex].value);

    openWindow ("Pairwise Align Protein");
	openPre();
    outputWindow.document.write("<title>Pairwise Align Protein</title>");

	newProteinOne = getSequenceFromFasta(theDocument.forms[0].elements[0].value);
	newProteinOne = removeNonProtein(newProteinOne);
	titleOne = getTitleFromFasta(theDocument.forms[0].elements[0].value);

	newProteinTwo = getSequenceFromFasta(theDocument.forms[0].elements[2].value);
	newProteinTwo = removeNonProtein(newProteinTwo);
	titleTwo = getTitleFromFasta(theDocument.forms[0].elements[2].value);

	outputWindow.document.write(getPairwiseAlignTitle(titleOne, newProteinOne, titleTwo, newProteinTwo,parseInt(resperline)+arraytitlewidth+1));

	//change to arrays for pass by reference, so that large sequence isn't copied
	if (newProteinOne.search(/./) != -1)    {
		newProteinOne = newProteinOne.match(/./g);
	}

	if (newProteinTwo.search(/./) != -1)	{
		newProteinTwo = newProteinTwo.match(/./g);
	}
	
	theAlignment = pairwiseProtein (titleOne, newProteinOne, titleTwo, newProteinTwo, MATRIX, GAP_PENALTY, BEGIN_GAP_PENALTY, END_GAP_PENALTY);
	alignArray = theAlignment.split(/[>%]/);
	
	if (earlyCheckAlign (alignArray) == false)	{
		return false;
	}	
	
	for (var i = 1; i < alignArray.length; i++)	{
		titleArray[i-1] = alignArray[i].match(/[^\f\n\r]+[\f\n\r]/);
		titleArray[i-1] = filterFastaTitle(titleArray[i-1].toString()).replace(/[\f\n\r]/g, "");
		titleArray[i-1] = titleArray[i-1].substring(0, 20);
		if (i == 1) {
			longestTitle = titleArray[i-1].length;
		}
		else if (titleArray[i-1].length > longestTitle)	{
			longestTitle = titleArray[i-1].length;
		}
		sequenceArray[i-1] = alignArray[i].replace(/[^\f\n\r]+[\f\n\r]/,"");
		sequenceArray[i-1] = filterAlignSeq (sequenceArray[i-1]);
	}

	//make titles equal length
	var spaceString = "                    ";
	for (var i = 0; i < titleArray.length; i++)	{
		if (titleArray[i].length < longestTitle) {
	 		//add spaces
			titleArray[i] = titleArray[i] + spaceString.substring(0, (longestTitle - titleArray[i].length));
		}
	}

	if (checkAlign (titleArray, sequenceArray) == false)	{
		return false;
	}

	arrayOfGroups = groupString.split(/,/);
	if (checkGroupInput (arrayOfGroups) == false)	{
		return false;
	}

	outputWindow.document.write('<div class="proteinalign">\n');
	colorAlign (titleArray, sequenceArray, resperline, "100", arrayOfGroups, startingindex, longestTitle);
	outputWindow.document.write('</div>');

	closePre();
	closeWindow();
	return true;
}	

function pairwiseProtein (titleOne, newProteinOne, titleTwo, newProteinTwo, matrix, gapPenalty, beginGapPenalty, endGapPenalty)	{

	//can use one or both.
	//can compare scores (should be identical)
	var useLinearSpace = true;
	var useQuadraticSpace = false;

	//create scoringMatrix object
	var scoringMatrix;

	if (matrix == "pam30") {
		scoringMatrix = new Pam30();
	}
	else if (matrix == "pam70") {
		scoringMatrix = new Pam70();
	}
	else if (matrix == "blosum80") {
		scoringMatrix = new Blosum80();
	}
	else if (matrix == "blosum62") {
		scoringMatrix = new Blosum62();
	}
	else if (matrix == "blosum45") {
		scoringMatrix = new Blosum45();
	}

	var scoreSet = new ScoreSet();
	scoreSet.setScoreSetParam(scoringMatrix, gapPenalty, beginGapPenalty, endGapPenalty);

	var alignment;
	var alignmenttext = "";
	
	if (useLinearSpace) {

		alignment = new AlignPairLinear();
		alignment.setAlignParam(newProteinOne, newProteinTwo, scoreSet);
		alignment.align();

		alignmenttext = alignmenttext + ">" + titleOne + "\n";
		alignmenttext = alignmenttext + addReturns(alignment.getAlignedM());
		alignmenttext = alignmenttext + "\n";
		alignmenttext = alignmenttext + "\n";
		alignmenttext = alignmenttext + ">" + titleTwo + "\n";
		alignmenttext = alignmenttext + addReturns(alignment.getAlignedN());
		alignmenttext = alignmenttext + "\n\n";
		
		outputWindow.document.write("Alignment score: " + alignment.score + "\n\n");
	}

	if (useQuadraticSpace) {
	
		alignment = new AlignPairQuad();
		alignment.initializeMatrix(newProteinOne, newProteinTwo, scoreSet);
		alignment.fillMatrix();
		//alignment.dumpMatrix();
		alignment.align();	

		alignmenttext = alignmenttext + ">" + titleOne + "\n";
		alignmenttext = alignmenttext + addReturns(alignment.getAlignedM());
		alignmenttext = alignmenttext + "\n";
		alignmenttext = alignmenttext + "\n";
		alignmenttext = alignmenttext + ">" + titleTwo + "\n";
		alignmenttext = alignmenttext + addReturns(alignment.getAlignedN());
		alignmenttext = alignmenttext + "\n\n";
		
		outputWindow.document.write("Alignment score: " + alignment.score + "\n\n");
	}
	return alignmenttext;
}



//------------------------------------ ScoreSet class

//ScoreSet getScore
function getScore (r1, r2) {
	return this.scoringMatrix.scoringMatrix_getScore(r1, r2);	
}

//ScoreSet setScoreSetParam
function setScoreSetParam (scoringMatrix, gapPenalty, beginGapPenalty, endGapPenalty) {
	this.scoringMatrix = scoringMatrix;
	this.gap = gapPenalty;
	this.beginGap = beginGapPenalty;
	this.endGap = endGapPenalty;
}

//ScoreSet class
function ScoreSet () {
	this.scoringMatrix;
	this.gap;
	this.beginGap;
	this.endGap;
	this.useBeginGapTop = true;
	this.useBeginGapLeft = true;
	this.useEndGapBottom = true;
	this.useEndGapRight = true;
}

//create and throw away a prototype object
new ScoreSet();

//define object methods
ScoreSet.prototype.getScore = getScore;
ScoreSet.prototype.setScoreSetParam = setScoreSetParam;

//------------------------------------


//------------------------------------ ScoringMatrix Abstract Class
//ScoringMatrix getScore method
function scoringMatrix_getScore(r1, r2) {
	r1 = r1.toLowerCase();
	r2 = r2.toLowerCase();
	if (this.scoreHash[r1 + r2] == null) {
		throw "Unrecognized residue pair: " + r1 + ", " + r2 + "."; 
	}
	else {
		return this.scoreHash[r1 + r2];
	}
}

function scoringMatrix_fillHash(matrix) {
	var cols = matrix[0].split(/\s+/);
	var cells;
	//go through rows
	for (var i = 1; i < matrix.length; i++) {
		cells = matrix[i].split(/\s+/);	
		//go through cells in this row		
		for (var j = 1; j < cols.length + 1; j++) {
			this.scoreHash[cells[0].toLowerCase() + cols[j-1].toLowerCase()] = parseInt(cells[j]);
		}
	}
}

//ScoringMatrix class
function ScoringMatrix() {
	this.scoreHash = {};
}

//create and throw away a prototype object
new ScoringMatrix();

//define object methods
ScoringMatrix.prototype.scoringMatrix_getScore = scoringMatrix_getScore;
ScoringMatrix.prototype.scoringMatrix_fillHash = scoringMatrix_fillHash;

//------------------------------------ Blosum62 Class extends ScoringMatrix Class
//constructor
function Blosum62 () {
	
	var matrix = new Array (
   "A  R  N  D  C  Q  E  G  H  I  L  K  M  F  P  S  T  W  Y  V",
"A  4 -1 -2 -2  0 -1 -1  0 -2 -1 -1 -1 -1 -2 -1  1  0 -3 -2  0",
"R -1  5  0 -2 -3  1  0 -2  0 -3 -2  2 -1 -3 -2 -1 -1 -3 -2 -3",
"N -2  0  6  1 -3  0  0  0  1 -3 -3  0 -2 -3 -2  1  0 -4 -2 -3",
"D -2 -2  1  6 -3  0  2 -1 -1 -3 -4 -1 -3 -3 -1  0 -1 -4 -3 -3",
"C  0 -3 -3 -3  9 -3 -4 -3 -3 -1 -1 -3 -1 -2 -3 -1 -1 -2 -2 -1",
"Q -1  1  0  0 -3  5  2 -2  0 -3 -2  1  0 -3 -1  0 -1 -2 -1 -2",
"E -1  0  0  2 -4  2  5 -2  0 -3 -3  1 -2 -3 -1  0 -1 -3 -2 -2",
"G  0 -2  0 -1 -3 -2 -2  6 -2 -4 -4 -2 -3 -3 -2  0 -2 -2 -3 -3",
"H -2  0  1 -1 -3  0  0 -2  8 -3 -3 -1 -2 -1 -2 -1 -2 -2  2 -3",
"I -1 -3 -3 -3 -1 -3 -3 -4 -3  4  2 -3  1  0 -3 -2 -1 -3 -1  3",
"L -1 -2 -3 -4 -1 -2 -3 -4 -3  2  4 -2  2  0 -3 -2 -1 -2 -1  1",
"K -1  2  0 -1 -3  1  1 -2 -1 -3 -2  5 -1 -3 -1  0 -1 -3 -2 -2",
"M -1 -1 -2 -3 -1  0 -2 -3 -2  1  2 -1  5  0 -2 -1 -1 -1 -1  1",
"F -2 -3 -3 -3 -2 -3 -3 -3 -1  0  0 -3  0  6 -4 -2 -2  1  3 -1",
"P -1 -2 -2 -1 -3 -1 -1 -2 -2 -3 -3 -1 -2 -4  7 -1 -1 -4 -3 -2",
"S  1 -1  1  0 -1  0  0  0 -1 -2 -2  0 -1 -2 -1  4  1 -3 -2 -2",
"T  0 -1  0 -1 -1 -1 -1 -2 -2 -1 -1 -1 -1 -2 -1  1  5 -2 -2  0",
"W -3 -3 -4 -4 -2 -2 -3 -2 -2 -3 -2 -3 -1  1 -4 -3 -2 11  2 -3",
"Y -2 -2 -2 -3 -2 -1 -2 -3  2 -1 -1 -2 -1  3 -3 -2 -2  2  7 -1",
"V  0 -3 -3 -3 -1 -2 -2 -3 -3  3  1 -2  1 -1 -2 -2  0 -3 -1  4");

	this.scoringMatrix_fillHash(matrix);
}

Blosum62.prototype = new ScoringMatrix();


//------------------------------------ Blosum45 Class extends ScoringMatrix Class
//constructor
function Blosum45 () {
	
	var matrix = new Array (
   "A  R  N  D  C  Q  E  G  H  I  L  K  M  F  P  S  T  W  Y  V",
"A  5 -2 -1 -2 -1 -1 -1  0 -2 -1 -1 -1 -1 -2 -1  1  0 -2 -2  0",
"R -2  7  0 -1 -3  1  0 -2  0 -3 -2  3 -1 -2 -2 -1 -1 -2 -1 -2",
"N -1  0  6  2 -2  0  0  0  1 -2 -3  0 -2 -2 -2  1  0 -4 -2 -3", 
"D -2 -1  2  7 -3  0  2 -1  0 -4 -3  0 -3 -4 -1  0 -1 -4 -2 -3",
"C -1 -3 -2 -3 12 -3 -3 -3 -3 -3 -2 -3 -2 -2 -4 -1 -1 -5 -3 -1",
"Q -1  1  0  0 -3  6  2 -2  1 -2 -2  1  0 -4 -1  0 -1 -2 -1 -3",
"E -1  0  0  2 -3  2  6 -2  0 -3 -2  1 -2 -3  0  0 -1 -3 -2 -3",
"G  0 -2  0 -1 -3 -2 -2  7 -2 -4 -3 -2 -2 -3 -2  0 -2 -2 -3 -3",
"H -2  0  1  0 -3  1  0 -2 10 -3 -2 -1  0 -2 -2 -1 -2 -3  2 -3",
"I -1 -3 -2 -4 -3 -2 -3 -4 -3  5  2 -3  2  0 -2 -2 -1 -2  0  3",
"L -1 -2 -3 -3 -2 -2 -2 -3 -2  2  5 -3  2  1 -3 -3 -1 -2  0  1",
"K -1  3  0  0 -3  1  1 -2 -1 -3 -3  5 -1 -3 -1 -1 -1 -2 -1 -2",
"M -1 -1 -2 -3 -2  0 -2 -2  0  2  2 -1  6  0 -2 -2 -1 -2  0  1",
"F -2 -2 -2 -4 -2 -4 -3 -3 -2  0  1 -3  0  8 -3 -2 -1  1  3  0",
"P -1 -2 -2 -1 -4 -1  0 -2 -2 -2 -3 -1 -2 -3  9 -1 -1 -3 -3 -3",
"S  1 -1  1  0 -1  0  0  0 -1 -2 -3 -1 -2 -2 -1  4  2 -4 -2 -1",
"T  0 -1  0 -1 -1 -1 -1 -2 -2 -1 -1 -1 -1 -1 -1  2  5 -3 -1  0",
"W -2 -2 -4 -4 -5 -2 -3 -2 -3 -2 -2 -2 -2  1 -3 -4 -3 15  3 -3",
"Y -2 -1 -2 -2 -3 -1 -2 -3  2  0  0 -1  0  3 -3 -2 -1  3  8 -1",
"V  0 -2 -3 -3 -1 -3 -3 -3 -3  3  1 -2  1  0 -3 -1  0 -3 -1  5");

	this.scoringMatrix_fillHash(matrix);	
}

Blosum45.prototype = new ScoringMatrix();


//------------------------------------ Blosum80 Class extends ScoringMatrix Class
//constructor
function Blosum80 () {
	
	var matrix = new Array (
   "A  R  N  D  C  Q  E  G  H  I  L  K  M  F  P  S  T  W  Y  V",
"A  5 -2 -2 -2 -1 -1 -1  0 -2 -2 -2 -1 -1 -3 -1  1  0 -3 -2  0",
"R -2  6 -1 -2 -4  1 -1 -3  0 -3 -3  2 -2 -4 -2 -1 -1 -4 -3 -3",
"N -2 -1  6  1 -3  0 -1 -1  0 -4 -4  0 -3 -4 -3  0  0 -4 -3 -4",
"D -2 -2  1  6 -4 -1  1 -2 -2 -4 -5 -1 -4 -4 -2 -1 -1 -6 -4 -4",
"C -1 -4 -3 -4  9 -4 -5 -4 -4 -2 -2 -4 -2 -3 -4 -2 -1 -3 -3 -1",
"Q -1  1  0 -1 -4  6  2 -2  1 -3 -3  1  0 -4 -2  0 -1 -3 -2 -3",
"E -1 -1 -1  1 -5  2  6 -3  0 -4 -4  1 -2 -4 -2  0 -1 -4 -3 -3",
"G  0 -3 -1 -2 -4 -2 -3  6 -3 -5 -4 -2 -4 -4 -3 -1 -2 -4 -4 -4",
"H -2  0  0 -2 -4  1  0 -3  8 -4 -3 -1 -2 -2 -3 -1 -2 -3  2 -4",
"I -2 -3 -4 -4 -2 -3 -4 -5 -4  5  1 -3  1 -1 -4 -3 -1 -3 -2  3",
"L -2 -3 -4 -5 -2 -3 -4 -4 -3  1  4 -3  2  0 -3 -3 -2 -2 -2  1",
"K -1  2  0 -1 -4  1  1 -2 -1 -3 -3  5 -2 -4 -1 -1 -1 -4 -3 -3",
"M -1 -2 -3 -4 -2  0 -2 -4 -2  1  2 -2  6  0 -3 -2 -1 -2 -2  1",
"F -3 -4 -4 -4 -3 -4 -4 -4 -2 -1  0 -4  0  6 -4 -3 -2  0  3 -1",
"P -1 -2 -3 -2 -4 -2 -2 -3 -3 -4 -3 -1 -3 -4  8 -1 -2 -5 -4 -3",
"S  1 -1  0 -1 -2  0  0 -1 -1 -3 -3 -1 -2 -3 -1  5  1 -4 -2 -2",
"T  0 -1  0 -1 -1 -1 -1 -2 -2 -1 -2 -1 -1 -2 -2  1  5 -4 -2  0",
"W -3 -4 -4 -6 -3 -3 -4 -4 -3 -3 -2 -4 -2  0 -5 -4 -4 11  2 -3",
"Y -2 -3 -3 -4 -3 -2 -3 -4  2 -2 -2 -3 -2  3 -4 -2 -2  2  7 -2",
"V  0 -3 -4 -4 -1 -3 -3 -4 -4  3  1 -3  1 -1 -3 -2  0 -3 -2  4");

	this.scoringMatrix_fillHash(matrix);	
}

Blosum80.prototype = new ScoringMatrix();


//------------------------------------ Pam70 Class extends ScoringMatrix Class
//constructor
function Pam70 () {
	
	var matrix = new Array (
    "A   R   N   D   C   Q   E   G   H   I   L   K   M   F   P   S   T   W   Y   V",
"A   5  -4  -2  -1  -4  -2  -1   0  -4  -2  -4  -4  -3  -6   0   1   1  -9  -5  -1",
"R  -4   8  -3  -6  -5   0  -5  -6   0  -3  -6   2  -2  -7  -2  -1  -4   0  -7  -5",
"N  -2  -3   6   3  -7  -1   0  -1   1  -3  -5   0  -5  -6  -3   1   0  -6  -3  -5",
"D  -1  -6   3   6  -9   0   3  -1  -1  -5  -8  -2  -7 -10  -4  -1  -2 -10  -7  -5",
"C  -4  -5  -7  -9   9  -9  -9  -6  -5  -4 -10  -9  -9  -8  -5  -1  -5 -11  -2  -4",
"Q  -2   0  -1   0  -9   7   2  -4   2  -5  -3  -1  -2  -9  -1  -3  -3  -8  -8  -4",
"E  -1  -5   0   3  -9   2   6  -2  -2  -4  -6  -2  -4  -9  -3  -2  -3 -11  -6  -4",
"G   0  -6  -1  -1  -6  -4  -2   6  -6  -6  -7  -5  -6  -7  -3   0  -3 -10  -9  -3",
"H  -4   0   1  -1  -5   2  -2  -6   8  -6  -4  -3  -6  -4  -2  -3  -4  -5  -1  -4",
"I  -2  -3  -3  -5  -4  -5  -4  -6  -6   7   1  -4   1   0  -5  -4  -1  -9  -4   3",
"L  -4  -6  -5  -8 -10  -3  -6  -7  -4   1   6  -5   2  -1  -5  -6  -4  -4  -4   0",
"K  -4   2   0  -2  -9  -1  -2  -5  -3  -4  -5   6   0  -9  -4  -2  -1  -7  -7  -6",
"M  -3  -2  -5  -7  -9  -2  -4  -6  -6   1   2   0  10  -2  -5  -3  -2  -8  -7   0",
"F  -6  -7  -6 -10  -8  -9  -9  -7  -4   0  -1  -9  -2   8  -7  -4  -6  -2   4  -5",
"P   0  -2  -3  -4  -5  -1  -3  -3  -2  -5  -5  -4  -5  -7   7   0  -2  -9  -9  -3",
"S   1  -1   1  -1  -1  -3  -2   0  -3  -4  -6  -2  -3  -4   0   5   2  -3  -5  -3",
"T   1  -4   0  -2  -5  -3  -3  -3  -4  -1  -4  -1  -2  -6  -2   2   6  -8  -4  -1",
"W  -9   0  -6 -10 -11  -8 -11 -10  -5  -9  -4  -7  -8  -2  -9  -3  -8  13  -3 -10",
"Y  -5  -7  -3  -7  -2  -8  -6  -9  -1  -4  -4  -7  -7   4  -9  -5  -4  -3   9  -5",
"V  -1  -5  -5  -5  -4  -4  -4  -3  -4   3   0  -6   0  -5  -3  -3  -1 -10  -5   6");
	
	this.scoringMatrix_fillHash(matrix);
}

Pam70.prototype = new ScoringMatrix();

//------------------------------------ Pam30 Class extends ScoringMatrix Class
//constructor
function Pam30 () {
	
	var matrix = new Array (
    "A   R   N   D   C   Q   E   G   H   I   L   K   M   F   P   S   T   W   Y   V",
"A   6  -7  -4  -3  -6  -4  -2  -2  -7  -5  -6  -7  -5  -8  -2   0  -1 -13  -8  -2",
"R  -7   8  -6 -10  -8  -2  -9  -9  -2  -5  -8   0  -4  -9  -4  -3  -6  -2 -10  -8",
"N  -4  -6   8   2 -11  -3  -2  -3   0  -5  -7  -1  -9  -9  -6   0  -2  -8  -4  -8",
"D  -3 -10   2   8 -14  -2   2  -3  -4  -7 -12  -4 -11 -15  -8  -4  -5 -15 -11  -8",
"C  -6  -8 -11 -14  10 -14 -14  -9  -7  -6 -15 -14 -13 -13  -8  -3  -8 -15  -4  -6",
"Q  -4  -2  -3  -2 -14   8   1  -7   1  -8  -5  -3  -4 -13  -3  -5  -5 -13 -12  -7",
"E  -2  -9  -2   2 -14   1   8  -4  -5  -5  -9  -4  -7 -14  -5  -4  -6 -17  -8  -6",
"G  -2  -9  -3  -3  -9  -7  -4   6  -9 -11 -10  -7  -8  -9  -6  -2  -6 -15 -14  -5",
"H  -7  -2   0  -4  -7   1  -5  -9   9  -9  -6  -6 -10  -6  -4  -6  -7  -7  -3  -6",
"I  -5  -5  -5  -7  -6  -8  -5 -11  -9   8  -1  -6  -1  -2  -8  -7  -2 -14  -6   2",
"L  -6  -8  -7 -12 -15  -5  -9 -10  -6  -1   7  -8   1  -3  -7  -8  -7  -6  -7  -2",
"K  -7   0  -1  -4 -14  -3  -4  -7  -6  -6  -8   7  -2 -14  -6  -4  -3 -12  -9  -9",
"M  -5  -4  -9 -11 -13  -4  -7  -8 -10  -1   1  -2  11  -4  -8  -5  -4 -13 -11  -1",
"F  -8  -9  -9 -15 -13 -13 -14  -9  -6  -2  -3 -14  -4   9 -10  -6  -9  -4   2  -8",
"P  -2  -4  -6  -8  -8  -3  -5  -6  -4  -8  -7  -6  -8 -10   8  -2  -4 -14 -13  -6",
"S   0  -3   0  -4  -3  -5  -4  -2  -6  -7  -8  -4  -5  -6  -2   6   0  -5  -7  -6",
"T  -1  -6  -2  -5  -8  -5  -6  -6  -7  -2  -7  -3  -4  -9  -4   0   7 -13  -6  -3",
"W -13  -2  -8 -15 -15 -13 -17 -15  -7 -14  -6 -12 -13  -4 -14  -5 -13  13  -5 -15",
"Y  -8 -10  -4 -11  -4 -12  -8 -14  -3  -6  -7  -9 -11   2 -13  -7  -6  -5  10  -7",
"V  -2  -8  -8  -8  -6  -7  -6  -5  -6   2  -2  -9  -1  -8  -6  -6  -3 -15  -7   7");

	this.scoringMatrix_fillHash(matrix);	
}

Pam30.prototype = new ScoringMatrix();

//---------------------------------- Coloring

function colorAlign (arrayOfTitles, arrayOfSequences, basePerLine, consensus, arrayOfGroups, definedStarts, longestTitle)	{
	var positions = new Array (arrayOfSequences.length);
	if (definedStarts.search(/\S/) == -1)	{
		definedStarts = "0,0";
	}
	var definedStartsArray = definedStarts.split(/,/);
	for (var i = 0; i < positions.length; i++)	{
		if (i >= definedStartsArray.length)	{
			positions[i] = 0;
		}
		else	{
			if (definedStartsArray[i].search(/\d/) != -1)	{
				positions[i] = parseInt(definedStartsArray[i].replace(/\D/g, ""));
			}
			else	{
				alert('An incorrect starting position was encountered. It was set to 0.');
				outputWindow.focus();
				positions[i] = 0;
			}
		}
	}
	var totalBasesShown = 0; 
	consensus = (parseInt(consensus)) / 100;
	basePerLine = parseInt(basePerLine);
	var columnCount = 0;
 	var arrayOfColumns = new Array(basePerLine);
	for (var i=0; i < arrayOfColumns.length; i++) {
   		arrayOfColumns[i] = new Array(arrayOfSequences.length);
	}

	var i = 0;
	var columnSeq;
	var re;
	var result;
	var output = "";

	while (totalBasesShown < arrayOfSequences[0].length)	{
		for (var jj = 0; jj < arrayOfSequences.length; jj++)	{		
			output = output + arrayOfTitles[jj] + ' ';
			while ((i < (totalBasesShown + basePerLine)) && (i < arrayOfSequences[0].length))	{
				if (jj == 0) {
					//fill the column
					for (var k = 0; k < arrayOfSequences.length; k++)	{
						arrayOfColumns[columnCount][k] = arrayOfSequences[k].charAt(i);
						
					}
				}
				if ( (arrayOfSequences[jj].charAt(i) == ".") || (arrayOfSequences[jj].charAt(i) == "-") ) {
					output = output + "<span class=\"diff\">" + arrayOfSequences[jj].charAt(i) + "</span>";
					i = i + 1;
					columnCount++;
					continue;
				}

				columnSeq = arrayOfColumns[columnCount].join(",");
				re = new RegExp (arrayOfSequences[jj].charAt(i),"gi");
				
				//GW Intentionally color by similarity
				if ((columnSeq.match(re)).length / arrayOfSequences.length >= consensus)	{
					output = output + "<span class=\"ident\">" + arrayOfSequences[jj].charAt(i) + "</span>";
					i = i + 1;
					columnCount++;
					continue;
				}

				result = 1;
				for (var m = 0; m < arrayOfGroups.length; m++)	{
					if (arrayOfGroups[m].search(re) != -1)	{
						var re = new RegExp ("[" + arrayOfGroups[m] + "]","gi");
						result = (columnSeq.match(re)).length;
						break;
					}
				}

				if (result / arrayOfSequences.length >= consensus)	{
                                   	output = output + "<span class=\"sim\">" + arrayOfSequences[jj].charAt(i) + "</span>";
					i = i + 1;
					columnCount++;
					continue;
				}
									
				output = output + "<span class=\"diff\">" + arrayOfSequences[jj].charAt(i) + "</span>";
				i = i + 1;
				columnCount++;
			}
			positions[jj] = positions[jj] + ((arrayOfSequences[jj].substring(totalBasesShown,i)).replace(/\.|\-/g,"")).length;
			output = output + ' ' + positions[jj] + '\n';
			outputWindow.document.write(output);
			output = "";
			i = totalBasesShown;
			columnCount = 0;
		}
		totalBasesShown = totalBasesShown + basePerLine;
		i = totalBasesShown;
		outputWindow.document.write('\n');
	}
	return true;
}
