/**
 * Checks whether the browser is obsolete
 */
function isObsolete() {
	if(Ext.isSafari4 || Ext.isGecko || Ext.isChrome || Ext.isOpera || Ext.isIE)
		return false;
	return true
}

/**
 * Molecular weight of the amino acids. Non-coding letters have a MW=0.
 * 
 * @param {String}
 *            aa One-letter code of the amino-acid.
 * @return {float} Molecular weight of the amino-acid.
 */
function getAAWeightHydrated(aa) {
	switch (aa.toUpperCase()) {
	case 'A':
		return 89.1; // Alanine Ala
	case 'C':
		return 121.2; // Cysteine Cys
	case 'D':
		return 133.1; // Aspartic acid Asp
	case 'E':
		return 147.1; // Glutamine acid Glu
	case 'F':
		return 131.2; // Phenylalanine Phe
	case 'G':
		return 75.1; // Glycine Gly
	case 'H':
		return 155.2; // Histidine His
	case 'I':
		return 131.2; // Isoleucine Ile
	case 'K':
		return 146.2; // Lysine Lys
	case 'L':
		return 131.2; // Leucine Leu
	case 'M':
		return 149.2; // Methionine Met
	case 'N':
		return 132.1; // Asparagine Asn
	case 'P':
		return 115.1; // Proline Pro
	case 'Q':
		return 146.1; // Glutamine Gln
	case 'R':
		return 174.2; // Arginine Arg
	case 'S':
		return 105.1; // Serine Ser
	case 'T':
		return 119.1; // Threonine Thr
	case 'V':
		return 117.1; // Valine Val
	case 'W':
		return 204.2; // Tryptophan Trp
	case 'Y':
		return 181.2; // Tyrosine Tyr
	default:
		return 0.0; //
	}
};

function getAAWeight(aa) {
	switch (aa.toUpperCase()) {
	case 'A':
		return 71.09; // Alanine Ala
	case 'C':
		return 103.15; // Cysteine Cys
	case 'D':
		return 115.09; // Aspartic acid Asp
	case 'E':
		return 129.12; // Glutamine acid Glu
	case 'F':
		return 147.18; // Phenylalanine Phe
	case 'G':
		return 57.05; // Glycine Gly
	case 'H':
		return 137.14; // Histidine His
	case 'I':
		return 113.16; // Isoleucine Ile
	case 'K':
		return 128.17; // Lysine Lys
	case 'L':
		return 113.16; // Leucine Leu
	case 'M':
		return 131.19; // Methionine Met
	case 'N':
		return 114.11; // Asparagine Asn
	case 'P':
		return 97.12; // Proline Pro
	case 'Q':
		return 128.14; // Glutamine Gln
	case 'R':
		return 156.19; // Arginine Arg
	case 'S':
		return 87.08; // Serine Ser
	case 'T':
		return 101.11; // Threonine Thr
	case 'V':
		return 99.14; // Valine Val
	case 'W':
		return 186.21; // Tryptophan Trp
	case 'Y':
		return 163.18; // Tyrosine Tyr
	default:
		return 0.0; //
	}
};

/**
 * Calculates the molecular weight of a protein sequence. Does the sum of the
 * individual weights of the AA.
 * 
 * @param {String}
 *            aaSeq Amino-acid sequence
 * @return {float} The molecular weight of the amino-acid sequence.
 */
function getMolecularWeight(aaSeq) {
	var mw = 0;
	for ( var i = 0; i < aaSeq.length; i++)
		mw += getAAWeight(aaSeq.charAt(i));
	return mw;
}

/**
 * Custom renderer for the date
 * 
 * @param value
 *            date to format
 * @return Formated data
 */
function formatDate(value) {
	return value ? value.dateFormat(dateFormatString()) : '';
}

/**
 * String describing the date format
 * 
 * @return Format of the date
 */
function dateFormatString() {
	return "M d, Y";
}

/**
 * Custom renderer for the PO number
 * 
 * @param value
 *            PO # to format
 * @return Formated data
 */
function formatPO(value) {
	return value ? value.replace(';', '<br>') : '';
}

/**
 * Adds the function startsWith to all Strings
 * 
 * @param {String}
 *            prefix Prefix to check
 * @return {boolean} True if the current string starts with prefix, false
 *         otherwise
 */
String.prototype.startsWith = function(prefix) {
	return (this.match("^" + str) == str);
}

/**
 * Adds the function startsWith to all Strings
 * 
 * @param {String}
 *            prefix Prefix to check
 * @return {boolean} True if the current string starts with prefix, false
 *         otherwise
 */
String.prototype.nl2br = function() {
	 var breakTag = "<br>";
	 return (this.replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1'+ breakTag +'$2'));
}

// From http://www.tutorialspoint.com/javascript/array_foreach.htm
Array.prototype.forEach = function(fun /*, thisp*/) {
    var len = this.length;
    if (typeof fun != "function")
      throw new TypeError();

    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
      if (i in this)
        fun.call(thisp, this[i], i, this);
    }
  };

/**
 * Replaces all instances of stringToFind by stringToReplace in the current
 * string
 * 
 * @param {String}
 *            stringToFind String to replace
 * @param {String}
 *            stringToReplace New string
 * @return {String} The string having the replacements made.
 */
String.prototype.replaceAll = function(stringToFind, stringToReplace) {
	var temp = this;
	var index = temp.indexOf(stringToFind);
	while (index != -1) {
		temp = temp.replace(stringToFind, stringToReplace);
		index = temp.indexOf(stringToFind);
	}
	return temp;
}

Array.prototype.contains = function(obj) {
  var i = this.length;
  while (i--) {
    if (this[i] === obj) {
      return true;
    }
  }
  return false;
}

Array.prototype.removeElement = function(element) {
	for(var i=0; i<this.length;i++ ) { 
		if(this[i]==element) {
			this.splice(i,1); 
		} 
	}
}

/**
 * Common error message to display when an error occurs on the server
 */
function alertCall(status, title, text) {
	var myIcon = Ext.MessageBox.ERROR;
	if(status>=200 && status<300)
		myIcon = Ext.MessageBox.INFO;

	if(status==0)
		myIcon = Ext.MessageBox.INFO;

	if(status==-2)
		myIcon = Ext.MessageBox.WARNING;

	if(status==403) {
		title = 'Forbidden';
		text = 'You do not have the rights to execute this command. Please contact the sysadmin for further information.';
	}
	if(status==404) {
		title = 'Not Found';
		text = 'The resource could not be found. Please try again later.';
	}
	if(status==449) {
		myIcon = Ext.MessageBox.WARNING;
	}
	if(status==503) {
		title = 'Under construction';
		text = 'The page you requested is under construction.<br>Please try again later.';
		myIcon = 'under-construction';
	}
	if(status>0)
		status = "["+status+"] ";
	else
		status = '';
	
	if(title.length<1)	title = '';
	if(text.length<1)	text = 'Your request could not be processed. Please try again later.';
	
	
	Ext.Msg.show( {
	    title: status + title,
	    msg: text,
	    buttons: Ext.Msg.OK,
	    icon: myIcon,
	    minWidth: 300
	}); // End show
}

/**
 * Alert an error using HTTP headers after an AJAX call to t he server.
 * 
 * @param responseObject XMLHttpRequest response
 */
function alertAjaxCall(responseObject) {
	var idxSplit = responseObject.statusText.indexOf(':');		                	        	
	alertCall(	responseObject.status,
				responseObject.statusText.substring(0,idxSplit),
				responseObject.statusText.substring(idxSplit+2));

}


/**
 * Pads a number
 * 
 * @param number Number to pad
 * @param length Fiexed width of the padded number
 * @param symbol Symbol to use for padding
 * @return The number after padding
 */
function pad(number, length, symbol) {	   
    var str = '' + number;
    while (str.length < length)
        str = symbol + str;    
    return str;
}

/**
 * Checks whether the given position is a valid one fin a 96-well PCR plate (from A1 to H12)
 * @param v {string} position in a 96-well PCR plate
 * @return {boolean} true is the given position is either null or valid. An error message otherwise
 */
function validatorPCRPlate96Well(v) {
	//if(v==null || v.length==0)
	//	return true;
	var re = /([abcdefghABCDEFGH])(\d{1,2})/;
	var m = re.exec(v);
	if(m != null && m[2]>0 && m[2]<13)
		return true;
	return "Well position should be between A1 and H12.";
}

/**
 * Checks whether the given value is a valid lab notebook reference
 * @param v {string} notebook reference
 * @return {boolean} true is the given position is either null or valid. An error message otherwise
 */
function validatorLabNotebookReference(v) {
	if(v==null || v.length==0)
		return true;
	re = /(\w+)[ \t]*(\d+)[ \t]*[pP][ \t]*(\d+)([ \t]*&[ \t]*[pP][ \t]*(\d+))?(.*)/;
	var m = re.exec(v);
	if(m != null && (m[6]==null || m[6].length<1))
		return true;
	return "Invalid notebook reference. Format is defined as follows:<br>* A few letters to define the user,<br>* The lab notebook number,<br>* The letter 'P' and the page number.<br>* Optionally, '&P' and a second page number.<br><br>More formally, format is <b>ABC ## P# & P#</b>";
}

/**
 * Checks whether the given value is a valid nucleotide sequence
 * @param v {string} Sequence
 * @return {boolean} true is the given sequence is either null or valid. An error message otherwise.
 */
function validatorNucleotideSequence(v) {
	if(v==null || v.length==0)
		return true;
	re = /^[ACGNTX ]*$/i;
	var m = re.exec(v);
	if(m != null) {
		return true;
	}
	return "Invalid nucleotide sequence. The sequence should contain only A, C, G, T.";
	
}

/**
 * Renderer a value by prefixing it with t he species code
 */
function speciesPrefix(val,meta,r,row,col,s) {
	return (val?r.get("species")+val:"");
}


/**
 * Changes the opacity (alpha filter) of a given section
 * @param {string} section item to switch on/off
 */
function switchLight(section) {
	if(document.getElementById(section).style.opacity>0)
		document.getElementById(section).style.opacity=0;
	else
		document.getElementById(section).style.opacity=Passport.VIRTUAL_PLATE_OPACITY;
}


/**
 * Changes the bulb states when switching light
 * @param {string} ID of the bulb to switch on/off
 */
function switchSwitcher(section) {
	if(document.getElementById(section).src.indexOf('off')!=-1)
		document.getElementById(section).src='images/icons/lightbulb.png';
	else
		document.getElementById(section).src='images/icons/lightbulb_off.png';
}


/**
 * (un)Select wells in a plate
 * @param {string} ID of the well to switch on/off
 */
function switchPlateWell(plate1,plate2,position,column) {
	if(Passport.spreadsheet_store.getAt(Passport.selectedRow).get(column).length>1) {
		var list = Passport.spreadsheet_store.getAt(Passport.selectedRow).get(column).split(/[;, ]+/);
	} else {
		var list = new Array();
	}
	if(list == null || list.length<1) { // list is empty
		Passport.spreadsheet_store.getAt(Passport.selectedRow).set(column,position);		
		document.getElementById(plate1).style.backgroundImage='url(images/icons/tick.png)';
		document.getElementById(plate2).style.backgroundImage='url(images/icons/tick.png)';
	} else {
		if(list.contains(position)) {		
			list.removeElement(position);			
			document.getElementById(plate1).style.backgroundImage='url(images/icons/bullet_black.png)';
			document.getElementById(plate2).style.backgroundImage='url(images/icons/bullet_black.png)';
		} else {
			list.push(position);
			document.getElementById(plate1).style.backgroundImage='url(images/icons/tick.png)';
			document.getElementById(plate2).style.backgroundImage='url(images/icons/tick.png)';
		}
		Passport.spreadsheet_store.getAt(Passport.selectedRow).set(column,list.sort().toString());
	}
	if(Passport.spreadsheet_store.getAt(Passport.selectedRow).get(column).length>1) {
		Passport.spreadsheet_store.getAt(Passport.selectedRow).set('activity',true);
	} else {
		Passport.spreadsheet_store.getAt(Passport.selectedRow).set('activity',false);
	}
	
}

function padLeft(s,len,c){
	s+= "";
	c=c || ' ';
	while(s.length< len) s= c+s;
	return s;
}

/**
 * Get the id of a well position in a 96-well plate 
 * @param {string} position A1-H12
 * @return {int} 1 for A1, 2 for A2,..., 96 for H12
 */
function wellPositionToID(position) {
	var rowLabel = 'ABCDEFGH';
	var row = position.substring(0,1);
	var col = 1*position.substring(1);
	return 12*rowLabel.indexOf(row)+col;	
}

function isNumeric(sText) {
   var ValidChars = "0123456789.-";
   for (i = 0; i < sText.length; i++) { 
      if (ValidChars.indexOf(sText.charAt(i)) == -1) 
         return false;
	}
	return true;
}
function isInteger(sText) {
   var ValidChars = "0123456789";
   for (i = 0; i < sText.length; i++) { 
      if (ValidChars.indexOf(sText.charAt(i)) == -1) 
         return false;
	}
	return true;
}

/**
 * Sets the given ExtJS EditorGrid as read-only.
 * @param {Ext.grid.EditorGridPanel} spreadsheet_panel
 */
function setSpreadsheetReadOnly(spreadsheet_panel) {
	Passport.menuTip_panel.hide();
	for(i=0;i<spreadsheet_panel.getColumnModel().getColumnCount();i++)
		spreadsheet_panel.getColumnModel().setEditable(i,false);
	spreadsheet_panel.getTopToolbar().disable();
	spreadsheet_panel.getTopToolbar().hide();
	spreadsheet_panel.setTitle(spreadsheet_panel.header.dom.textContent.trim() + " (read-only)");
}

function showTip(text) {
    Ext.getDom('tipContent').innerHTML = (text==null?Passport.KEYMAP:text);
	Passport.menuTip_panel.expand();
}
function showHelp(text) {
    Ext.getDom('helpContent').innerHTML = (text==null?Passport.KEYMAP:text);
	Passport.helpWindow.show();
	Passport.helpWindow.center();
}


// querystring to POST JavaScript
// copyright 15th October 2007 by Stephen Chapman
// permission to use this Javascript on your web page is granted
// provided that all of the code in this script (including these
// comments) is used without any alteration


function toPost(getString) {
    var parms = getString.split('?');
    var newF = document.createElement("form");
    newF.action = parms[0];
    newF.method = 'POST';
    var parms = parms[1].split('&');
    for (var i = 0; i < parms.length; i++) {
        var pos = parms[i].indexOf('=');
        if (pos > 0) {
            var key = parms[i].substring(0, pos);
            var val = parms[i].substring(pos + 1); /*@cc_on @if (@_jscript)  var newH = document.createElement("<input name='"+key+"'>");  @else */
            var newH = document.createElement("input");
            newH.name = key; /* @end @*/
            newH.type = 'hidden';
            newH.value = val;
            newF.appendChild(newH);
        }
    }
    document.getElementsByTagName('body')[0].appendChild(newF);
    newF.submit();
}
