 
JmolHighlighterManager = Class.create({
	// Constructor.  
  	initialize: function(updateView) {
  		this.highlighters = new Array();
  		this.colorMode = "colour none;";
  		this.preConserveStateSaved = false;
  		this.drawAllExecuting = false;
  		this.drawAllArray = new Array();
  		this.updateView = updateView;
	},
	addNewHighlighter:function(highlighter) {
		if(highlighter) {
			this.highlighters.push(highlighter);
		}
	},
	drawAll:function(currentHL) {
		if(!this.drawAllExecuting) {
			this.drawAllExecuting = true;				
			var lastOne = null;
			var hlPos = $H();
			var dhlPos = $H();
			this.highlighters.each(function(highlighter){
				// for each highlighter get the de-highlight positions
				if(highlighter.getDehighlightPosition()) {
					dhlPos.set(highlighter.id, {pen:highlighter.getPen(), pos:highlighter.getDehighlightPosition()});			
				}
				
				// if find the current highliter, store it first			
				if(currentHL && highlighter.id == currentHL.id) {
					lastOne = highlighter;
				}else{
					// Add the highligh position to the hash
					hlPos.set(highlighter.id, {pen:highlighter.getPen(), pos:highlighter.getHighlightPosition()});				
				}
			});
			
			// setup method
			_drawJMol = this.drawJmol.bind(this);
			var deHLColor = this.colorMode;
			
			// DehilightAllPositions
//			dhlPos.values().each(function(item){			
//				var positions = item.pos;
//				var color = deHLColor;
//				var mode = item.pen.modeOff;			
//				_drawJMol(positions, color, mode);			
//			});				
//			
			this.updateView();
			
			// drawAll
			hlPos.values().each(function(item){
				var positions = item.pos;
				var color = item.pen.color;
				var mode = item.pen.modeOn;		
				_drawJMol(positions, color, mode);
			});
			if(lastOne != null) {
				var color = lastOne.getPen().color;
				var mode = lastOne.getPen().modeOn;		
				var positions = lastOne.getHighlightPosition();
				_drawJMol(positions, color, mode);
			}
			this.drawAllExecuting = false;			
		}else {
			// It's executing already
//			console.debug("drawAll is executing, skip it!");
		}
	},
	drawJmol:function(positions, color, mode) {
		// Following debug message will help you identify the problems, 
		// but it only works for Firefox - firebug.
		//console.log('pos[' + positions + "], color[" + color + "], mode[" + mode + "].");
		if(positions) {		
			positions.each(function(pos){	
				jmolScript("select " + pos + ";" + color);
				if(mode) {
					//console.log('jmolScript (mode): ' + mode);
					jmolScript(mode);
				}
			});
		}		
	},	
	setColorMode: function(colorMode) {
		this.colorMode = colorMode;
		this.drawAll(null);
	},
	setMode: function(mode) {
		this.highlighters.each(function(hl){
			hl.setMode(mode);
		});
	},
	clearAllHighlights:function(){
		// Stop all other execution, since the clear is called.
		this.drawAllExecuting = true;
		this.highlighters.each(function(highlighter){
			highlighter.clearAllHighlight();
		});
		// allow other highlight agagin.
		this.drawAllExecuting = false;
	}
});
var jMolHighlighterId = 0;
BhbJmolHighlighter = Class.create({
	initialize: function(manager, color, mode) {		
		this.manager = false;
		this.color = "black";
		if(color) {
			this.color = color;
		}
		this.mode = mode;
		this.id = ++jMolHighlighterId;
		if(!manager) {
			throw("Manager must be set for Highliter!");
		}
		this.setManager(manager);
		this.highlightPosition = new Array();
		this.dehighlightPosition = new Array();
	},
	setManager:function(manager) {
		this.manager = manager;
		this.manager.addNewHighlighter(this);
	},
	getPen:function(){
		if(this.mode) {
			return {color:"color " + this.color + ";", modeOn:this.mode + " on;", modeOff:this.mode + " off;"};
		}else{
			return {color:"color " + this.color + ";", modeOn:null, modeOff:null};
		}
	},
	getHighlightPosition:function(){
		return this.highlightPosition;
	},
	getDehighlightPosition:function(){
		return this.dehighlightPosition;
	},
	clearDehighlightPosition:function() {
		this.dehighlightPosition = new Array();
	},	
	setMode: function(colorMode) {
		// First clean up the current highlight
		this.manager.drawJmol(this.getHighlightPosition(), this.manager.colorMode, this.getPen().modeOff);
		// change the mode
		this.mode = colorMode;
		// Ask the manager to draw everything again.
		this.manager.drawAll(this);
	}
});
/*
*This class allows for a user to interact with the JMol Applet and higlight epitopes.
* It is based on the Prototype and scriptaculous javascript libraries
*
*/
/*
JmolEpitopesHighlighter = Class.create(BhbJmolHighlighter, {
	
	// Constructor.  Takes a closure function to load the epitopes, the data in a hash to pass to this method 
	// and the id of the div to populate with the data
  	initialize: function($super, data, div, manager, color, mode) {
		if(!color) {
			color = 'yellow';
		}  		 
		$super(manager, color, mode);
		this.data = data;
		this.divId = div;
		this.selectedEpitopes = $H();
		$('epiDiv').show();
	},
	
	
	// This class actually builds the HTML for the epitope display
	createTable : function  (hash) {
		console.log("in createTable()");
	    var items = hash.values();
		// Setup scriptaculous alias for builder
		var B = Builder;
		Builder.dump(B);
	
		var targetDiv = $(this.divId).update("");				
		// Use the first epitope to build the table header
	    var headerRowCells = [];
	    // Empty header cell for checkbox
	    headerRowCells.push(B.TH(''));
	    var firstEpiDetails = $H(items[0].details);
	    firstEpiDetails.each(function(details) {
			var label = details.key.underscore().capitalize().gsub('_', ' ');
			if(details.key == "iedbId") {
				label = 'IEDB ID ';
			} 
			if(details.key == "url") {
				return;
			}			
			headerRowCells.push(B.TH(label));
		 });	
		var headerRow = B.TR(headerRowCells);		
		var table = B.TABLE({ className: 'epitopeDetails' }, B.THEAD(headerRow));
		var tableBody = B.TBODY();
		table.appendChild(tableBody);			 
		  
		// For each epitope, create a checkbox, its details div and attatch an event to the checkbox
		// to show the collapsed div when selected
		for (var i = 0; i < items.length; i++) {
			var dId = items[i].displayId;
			var checkbox = B.INPUT({ type:'checkbox', className: 'epitopeCheckbox', value:dId});
			if(this.selectedEpitopes.keys().include(dId)) {
				checkbox.checked = true;
			}									
			Event.observe(checkbox, 'click', this.onClick.bindAsEventListener(this));	
		    var checkboxTd = B.TD();
		    checkboxTd.appendChild(checkbox);
		    var cells = [];
		    cells.push(checkboxTd);
		    				
		    var epiDetails = $H(items[i].details);	
		    epiDetails.each(function(details) {
				var data;
				if(details.key == "iedbId") {
					var link = B.A(details.value);
					link.href = items[i].details['url'];
					link.target = "_blank";
					data = B.TD();
					data.appendChild(link);
				} else {
					data = B.TD(details.value);
				}
				if(details.key == "url") {
					return;
				}
				cells.push(data);
			});
		  if(i % 2 == 0) {
		     var rowClass = 'epitopeDetailsEvenRow';
		  } else {
		     var rowClass = 'epitopeDetailsOddRow';		  
		  }
		  tableBody.appendChild(B.TR({ className: rowClass },cells));		
		}
		targetDiv.appendChild(table);	
	},
	
	// Handler to handle the selecting of an epitope
	onClick : function(event) {
		this.highlightRegion(Event.element(event)); 
	},
	
	// Handler to handle when the type of epitope has been changed
	changeEvent : function(event) {
		this._loadRegions(Event.element(event).value);
	},
	
	// Highlights the specific chain.  Parses the JSON value representing 
	// the position into a JMOL command.
	highlightRegion : function(box) {
		var ep = this.regions.get(box.value);
		var locations = ep.position.evalJSON();
		
		if (box.checked) {
			this.selectedEpitopes.set(box.value, locations);			
		} else {
			this.selectedEpitopes.unset(box.value);
			this.dehighlightPosition.push(locations);
		}
		this.highlight();
	},
	
	highlight: function() {		
		this.highlightPosition = this.getSelectedPosition();
		this.manager.drawAll(this);		
	},
	clearAllHighlight: function(event) {
		this.dehighlightPosition = this.getSelectedPosition();
		this.highlightPosition = new Array();
		this.selectedEpitopes = $H();
		this.manager.drawAll(this);
		$$('.epitopeCheckbox').each(function(box){
			box.checked = false;
		});
		$(this.select).options[0].selected = true;
		$(this.divId).hide();
	},
	getSelectedPosition:function() {
		var positions = new Array();
		this.selectedEpitopes.each(function(item) {	
			item.value.each(function(value){
				positions.push(value);
			});			
		});
		return positions;	
	}
});
*/

/**
 * This class handle the ligands highlight
 */
LigandHighlighter = Class.create(BhbJmolHighlighter, {
	initialize:function($super, checkbox, manager, color, mode){
		//console.log("initializing ligandHighlighter");
		if(!color) {
			color = 'chartreuse';
		}		
		$super(manager, color, mode);
		this.box = checkbox;
	},
	highlightLigands:function() {
		var box = $(this.box);
		this.highlightPosition = new Array();
		this.dehighlightPosition = new Array();
		if (box.checked) {
			//console.log("highlight ligands checked.");
			this.highlightPosition.push("ligand");
		}
	},
	highlight:function(event) {
		//console.log("highlight ligands event received");
		this.highlightLigands();
		this.manager.drawAll(this);
		//console.log("after highlight ligands event.");
	},
	clearAllHighlight:function(event){
		this.highlightPosition = new Array();
		this.manager.drawAll(this);
	}
});

/**
 * This class handle the Highlight in Pink highlight
 */
PinkHighlighter = Class.create(BhbJmolHighlighter, {
	initialize:function($super, manager){	
		$super(manager, 'pink', null);
	},
 	handleHlInPink:function(event) {
	 	// hl pink 	
	  	var select = Event.element(event);		
	 	var command = select.options[select.selectedIndex].value .evalJSON();
	 	this.mode = command.mode;
	 	this.highlightPosition = new Array();
	 	this.highlightPosition.push(command.select);
 	},
	highlight:function(event) {
		this.handleHlInPink(event);
		this.manager.drawAll();
	},
	clearAllHighlight:function(event){
		this.highlightPosition = new Array();
		this.manager.drawAll();
	}
});

/**
 * This class handle the Activesite highlight
 */
/*
ActiveSiteHighlighter = Class.create(BhbJmolHighlighter, {
	initialize:function($super, checkboxclass, manager, color, mode){
		if(!color) {
			color = 'orange';
		}		
		$super(manager, color, mode);
		this.checkboxclass = checkboxclass;
	},
	highlightActiveSites:function() {
		var hlPositions = new Array();
		var dhPositions = new Array();
		$$('.' + this.checkboxclass).each(function(box){
			var data = box.readAttribute('data').evalJSON();
			if (box.checked) {
				if(data.hasChain == "Y") {
					hlPositions.push(data.residue + ":" + data.chain);
				} else {
					hlPositions.push(data.residue);
				}
			} else {
				if(data.hasChain == "Y") {
					dhPositions.push(data.residue + ":" + data.chain);
				} else {
					dhPositions.push(data.residue);
				}				
			}
		});
		this.dehighlightPosition = $A(dhPositions);
		this.highlightPosition = $A(hlPositions);
	},
	highlight:function(event) {
		this.highlightActiveSites();
		this.manager.drawAll(this);
	},
	clearAllHighlight:function(event){
		var positions = new Array();
		$$('.'+this.checkboxclass).each(function(box){			
			if (box.checked) {
				var data = box.readAttribute('data').evalJSON();
				if(data.hasChain == "Y") {
					positions.push(data.residue + ":" + data.chain);
				} else {
					positions.push(data.residue);
				}	
				box.checked = false;
			}
		});
		this.dehighlightPosition = $A(positions);
		this.highlightPosition = new Array();
		this.manager.drawAll(this);
	}
});
*/
JmolActiveSiteHighlighter = Class.create(BhbJmolHighlighter, {
	initialize: function($super, data, div, manager, color, mode) {
		if(!color) {
			color = 'orange';
		}
		if(!mode) {
			mode = 'halos ON';
		}
		$super(manager, color, mode);
		this.data = data;
		this.mode = mode;
		this.divId = div;
		this.selectedActiveSites = $H();
		this.createActiveSiteTable();
	},
	createActiveSiteTable:function() {
		var theData = this.data;
		var tbd = $(this.divId);
		var row = document.createElement("tr");
		tbd.appendChild(row);
		var h0 = document.createElement("th")
		h0.setAttribute("width","3")
		row.appendChild(h0); //An empty th element for the checkboxes in the table below
		var h1 = document.createElement("th");
		h1.setAttribute("align","left");
		h1.setAttribute("width","5");
		var t1 = document.createTextNode("Residue");
		h1.appendChild(t1);
		row.appendChild(h1);
		var h2 = document.createElement("th");
		h2.setAttribute("width","5");
		h2.setAttribute("align","left");
		var t2 = document.createTextNode("Chain");
		h2.appendChild(t2);
		row.appendChild(h2);
		var h3 = document.createElement("th");
		var t3 = document.createTextNode("Peptide");
		h3.setAttribute("width","5");
		h3.setAttribute("align","left");
		h3.appendChild(t3);
		row.appendChild(h3);
		for(var i = 0; i < theData.length; i++) {
			var datum = theData[i]
			var rox = document.createElement("tr");
			tbd.appendChild(rox);
			var ckbox_cell= document.createElement("td");
			rox.appendChild(ckbox_cell);
			var checkbox = document.createElement("input");
			checkbox.setAttribute("type","checkbox");
			checkbox.setAttribute("class", "aschex");
			checkbox.setAttribute("id", "aschex_" + i);
			checkbox.setAttribute("value",datum.residue + ":" + datum.chain);
			ckbox_cell.appendChild(checkbox);
			var residueCell = document.createElement("td");
			var residue = document.createTextNode(datum.residue);
			residueCell.appendChild(residue);
			rox.appendChild(residueCell);
			var chainCell = document.createElement("td");
			var chain = document.createTextNode(datum.chain);
			chainCell.appendChild(chain);
			rox.appendChild(chainCell);
			var peptideCell = document.createElement("td");
			var peptide = document.createTextNode(datum.peptide);
			peptideCell.appendChild(peptide);
			rox.appendChild(peptideCell);
		}
	},
	changeEvent : function(event) {
		
		var box = Event.element(event);

		if(box.checked) {
			this.selectedActiveSites.set(box.id, box.value );
		}
		else {
			this.selectedActiveSites.unset(box.id);
			this.dehighlightPosition.push(box.value);
		}
		this.highlight();
	},
	highlight: function() {		
		this.highlightPosition = this.getSelectedPosition();
		this.manager.drawAll(this);		
	},
	getSelectedPosition:function() {
		var positions = new Array();
		this.selectedActiveSites.each(function(item) {	
			positions.push(item[1]);
		});
		return positions;	
	},
	clearAllHighlight:function(event){
		this.dehighlightPosition = this.getSelectedPosition();
		this.highlightPosition = new Array();
		this.selectedActiveSites = $H();
		this.manager.drawAll(this);
		$$('.aschex').each(function(box){
			box.checked = false;
		});
	}
	
});	

/*
*This class allows for a user to interact with the JMol Applet and higlight epitopes.
* It is no longer based on the Prototype and scriptaculous javascript libraries
* See above for BHB's version.  
*
*/
JmolEpitopesHighlighter = Class.create(BhbJmolHighlighter, {
	// Constructor.  Takes data in the form of a JSON string that is a list of Maps, one map per epitope
	// and the id of the div to populate with the data
  	initialize: function($super, data, div, manager, color) {
		var mode = 'halos OFF';
		if(!color) {
			color = 'yellow';
		}
		$super(manager, color, mode);
		this.data = data;
		this.divId = div;
		this.selectedEpitopes = $H();
		this.createEpitopeTable();
	},
	createEpitopeTable:function() {
		var theData = this.data;
		var tbd = $(this.divId);
		var row = document.createElement("tr");
		tbd.appendChild(row);
		row.appendChild(document.createElement("th"));//for the checkbox
		var h1 = document.createElement("th");
		var t1 = document.createTextNode("Range");
		h1.appendChild(t1);
		row.appendChild(h1);
		var h3 = document.createElement("th");
		h3.setAttribute("align","left");
		var t3 = document.createTextNode("Sequence");
		h3.appendChild(t3);
		row.appendChild(h3);
		for(var i = 0; i < theData.length; i++) {
			var datum = theData[i]
			var rox = document.createElement("tr")
			tbd.appendChild(rox);
			var ckbox_cell= document.createElement("td");
			rox.appendChild(ckbox_cell);
			var checkbox = document.createElement("input");
			checkbox.setAttribute("type","checkbox");
			checkbox.setAttribute("class", "epichex");
			checkbox.setAttribute("id", "epichex_" + i);
			checkbox.setAttribute("value",datum['range']);
			ckbox_cell.appendChild(checkbox);
			var rangeCell = document.createElement("td");
			rox.appendChild(rangeCell);
			var range = document.createTextNode(datum['range']);
			rangeCell.appendChild(range);
			var seqCell = document.createElement("td");
			rox.appendChild(seqCell);
			var sequence = document.createTextNode(datum['sequence']);
			seqCell.appendChild(sequence);
		}
	},
	changeEvent : function(event) {
		var color = "color yellow;";
		var chains = ["A","B","C","D","E","F","G","H","I","J"];
		var chainInfo = jmolGetPropertyAsArray("chainInfo");
		var numChains = chainInfo.models[0].chains.length;
		
		var box = Event.element(event);
		
		for(var i = 0; i < numChains; i++) {
			if(box.checked) {
				this.selectedEpitopes.set(box.id + ":" + chains[i] , box.value + ":" +  chains[i]);
			}
			else {
				this.selectedEpitopes.unset(box.id + ":" + chains[i]);
				this.dehighlightPosition.push(box.value + ":" + chains[i]);
			}
		}
		this.highlight();
	},
	highlight: function() {		
		this.highlightPosition = this.getSelectedPosition();
		this.manager.drawAll(this);		
	},
	getSelectedPosition:function() {
		var positions = new Array();
		this.selectedEpitopes.each(function(item) {	
			positions.push(item[1]);
		});
		return positions;	
	},
	clearAllHighlight:function(event){
		this.dehighlightPosition = this.getSelectedPosition();
		this.highlightPosition = new Array();
		this.selectedEpitopes = $H();
		this.manager.drawAll(this);
		$$('.epichex').each(function(box){
			box.checked = false;
		});
	}
});	

/*
*This class allows for a user to interact with the JMol Applet and higlight epitopes.
* It is based on the Prototype and scriptaculous javascript libraries
*
*/
JmolSnpHighlighter = Class.create(BhbJmolHighlighter, {
	
	// Constructor.  Takes data in the form of a JSON string that is a list of Maps, one map per polymorphism
	// and the id of the div to populate with the data
  	initialize: function($super, data, div, manager, color, mode) {
		if(!color) {
			color = 'red';
		}
		$super(manager, color, mode);
		this.data = data;
		this.divId = div;
		this.selectedSnps = $H();
		this.createSnpTable();
	},
	createSnpTable:function() {
		var theData = this.data;
		var tbd = $(this.divId);
		var row = document.createElement("tr");
		tbd.appendChild(row);
		row.appendChild(document.createElement("th"));
		var h1 = document.createElement("th");
		var t1 = document.createTextNode("Start");
		h1.appendChild(t1);
		row.appendChild(h1);
		var h2 = document.createElement("th");
		var t2 = document.createTextNode("End");
		h2.appendChild(t2);
		row.appendChild(h2);
		var h3 = document.createElement("th");
		var t3 = document.createTextNode("Type");
		h3.appendChild(t3);
		row.appendChild(h3);
		var h4 = document.createElement("th");
		var t4 = document.createTextNode("Strain Name");
		h4.appendChild(t4);
		row.appendChild(h4);
		var h5 = document.createElement("th");
		var t5 = document.createTextNode("Ref NT");
		h5.appendChild(t5);
		row.appendChild(h5);
		var h6 = document.createElement("th");
		var t6 = document.createTextNode("Delta NT");
		h6.appendChild(t6);
		row.appendChild(h6);
		var h7 = document.createElement("th");
		var t7 = document.createTextNode("Delta AA");
		h7.appendChild(t7);
		row.appendChild(h7);
		var last;
		for(var i = 0; i < theData.length; i++) {
			var datum = theData[i];
			var pos =  datum[0] + "-" + datum[1] ;
			var rox = document.createElement("tr")
			tbd.appendChild(rox);
			var ckbox_cell= document.createElement("td");
			ckbox_cell.setAttribute("valign","center");
			rox.appendChild(ckbox_cell);
			if(last == undefined || last != pos) {
				last = pos;
				var checkbox = document.createElement("input");
				checkbox.setAttribute("type","checkbox");
				checkbox.setAttribute("class", "snpchex");
				checkbox.setAttribute("id", "snpchex_" + i);
				checkbox.setAttribute("value",pos);
				ckbox_cell.appendChild(checkbox);
			}
			for(var j = 0; j < datum.length; j++) {
				var td = document.createElement("td");
				var txt = document.createTextNode(datum[j]);
				td.appendChild(txt);
				rox.appendChild(td);
			}
		}
	},
	changeEvent : function(event) {
		var color = "color yellow;";
		var chains = ["A","B","C","D","E","F","G","H","I","J"];
		var chainInfo = jmolGetPropertyAsArray("chainInfo");
		var numChains = chainInfo.models[0].chains.length;
		
		var box = Event.element(event);
		
		for(var i = 0; i < numChains; i++) {
			if(box.checked) {
				this.selectedSnps.set(box.id + ":" + chains[i] , box.value + ":" +  chains[i]);
			}
			else {
				this.selectedSnps.unset(box.id + ":" + chains[i]);
				this.dehighlightPosition.push(box.value + ":" + chains[i]);
			}
		}
		this.highlight();
	},
	highlight: function() {		
		this.highlightPosition = this.getSelectedPosition();
		this.manager.drawAll(this);		
	},
	getSelectedPosition:function() {
		var positions = new Array();
		this.selectedSnps.each(function(item) {	
			positions.push(item[1]);
		});
		return positions;	
	}

});