FIDisplay = function() {
	this.filayer=null;
	// Maps uniprot accs of interactors to corresponding WireIt interactor objects
	// Used to keep track of interactors that have been drawn so the same one isn't drawn twice
	this.currentInteractors = null;
	// Map of pathway node vertex ids to array of genenames and interactor accession number pairs.
	// Used to reconstruct the 'data' parameter which is normally returned from the server when displaying
	// interactors for a single node but is read locally when displayAll is called (i.e. when switching
	// data sources).
	this.queryInteractorMappings = null;
	this.wireTip = null;
	// Keep track of WireIt container ids, mapping them from interactor uniprot
	// accession numbers.
	this.moduleIdMappings = null;
	// An array of ELV node objects which keeps track of which pathway nodes currently have FI's displayed.
	// Used when switching between interaction data sources.
	this.currentFINodes = null;
	// Indexed by vertex id of pathway nodes. For each of these, keep track of how many interactors are
	// displayed.
	this.currentlyDisplayed = null; 
	// keep track of interactor counts (total - not just those displayed) for each query protein
	this.interactorCount = null;
	this.queryRefIdAccMap = null;
	this.intactSearchUrl = null;
	this.confthreshold = null;
	this.action = null; // what to do with edges above/below threshold. Colour or hide.
						// Only colouring implemented so far.
	this.defaultColour = 'rgb(173, 216, 230)';
	
	// Default colours for interactions with confidence scores above and below set threshold.
	this.defaultBorderColour = 'rgb(0,0,255)';
	this.defaultAboveColour = 'rgb(0, 255, 0)';
	this.defaultAboveBorderColour = 'rgb(0,255,0)';
	this.defaultBelowColour = 'rgb(255, 0, 0)';
	this.defaultBelowBorderColour = 'rgb(255,0,0)';
	this.currentAboveColour = this.defaultAboveColour;
	this.currentBelowColour = this.defaultBelowColour;
	this.coordOffset = null;
	
	this.init = function(intactUrl, coordOffset){
		this.intactSearchUrl = intactUrl;
		this.filayer=null;
		this.currentFINodes = new Array();
		this.currentlyDisplayed = new Array();
		this.queryRefIdAccMap = new Array();
		this.interactorCount = new Array();
		this.idContainerMap = new Array();
		this.coordOffset = coordOffset;
	};

	/*
	 * Iterate through the queryterminals and reset the appearane to standard MI overlay.
	 * used when expression painter is closed down.
	 */
	this.resetQueryTerminals = function(){
		
	    if(this.filayer){
	    	var tipList = this.filayer.el.getElementsBySelector('div.queryTerminal');
	    	for ( var tipIndex = 0; tipIndex < tipList.length ; tipIndex++) {
	    		tipList[tipIndex].style.backgroundColor = "";
	    		tipList[tipIndex].className = tipList[tipIndex].className.replace(/expressiontips/, "proteincolour");
	    		if(tipList[tipIndex].innerHTMLOriginal){
	    			tipList[tipIndex].innerHTML = tipList[tipIndex].innerHTMLOriginal;
	    		}
	    	
	    		
	    		// reset innerhtmnl to original.
	    		// update pathwaydiagrampane displayexpresisonlevels to store innerhtml ito original
	    	}
		}
		
	};
/*
 * Main function used to display an interactor.
 * node represents the pathway node that has been clicked on and includes coordinate information.
 * data contains a list of interactors for the pathway node that will be drawn.
 * zf zoomFactor for scaling interactor sizes and locations based on diagram zoom level.
 */
this.displayFIOverlay = function(node, data, zf){
	if(data == undefined) {
		return;
	}
    try{
	var radianMultiplier = Math.PI/180;
	var nx = node.x;
	var ny = node.y;
    var nw = node.w;
    var nh = node.h;
    var cIw = 80;
    var cIh = 50;
    var iw = 50; // width of interactor boxes
    var ih = 20; // height of interactor boxes
    var IE = /*@cc_on!@*/false;
    if(IE){
    	iw = 80;
    	ih = 40;
	}
    var maxDraw = 10;
    if(zf == undefined) zf=1;
    
    nx = (nx * zf) + this.coordOffset;
    ny = (ny * zf) + this.coordOffset;
    nw = nw * zf;
    nh = nh * zf;
    
	// Use a div as a drawing canvas for fi overlay.
	var fiCanvas = $("ficanvas");
	if(fiCanvas == undefined || fiCanvas == null){
		return;
	}
	var layer = null;
	// Generate a new layer if one doesn't already exist.
	// Single layer used for all interactions in pathway.
	if(this.filayer == null){
		layer = new WireIt.Layer({parentEl:fiCanvas});
		this.filayer = layer;
		this.currentInteractors = new Array();
		// Keep a map of query interactor mappings if we already have some.
		// Layer is wiped clean when user switches zoom levels and interactors are redrawn so we need
		// to keep track of interactors for each pathway protein.
		if(this.queryInteractorMappings == undefined)
		this.queryInteractorMappings = new Array();
		this.moduleIdMappings = new Array();
	}else{
		layer = this.filayer;
	}
	
	layer.el.style.backgroundColor = "transparent";
	layer.el.style.overflow = "hidden";
	layer.el.style.zIndex = 21;
	var queryTerminal = Element.extend(document.createElement('div'));
    queryTerminal.id = "queryterminal_"+node.id;
    
	// Query node is overlayed with a new div element. This is a way to hide edges that meet in the 
	// centre if the query node.
	// Set the class name so that CSS rules will be applied to set the appearance.
	
	var innerHTML = queryTerminal.innerHTML = node.userObject.name;
	innerHTML = queryTerminal.innerHTML.replace(/\[.*/, "");
	innerHTML = queryTerminal.innerHTML.replace(/\:/g,": ");
	innerHTML = queryTerminal.innerHTML.replace(/\-/g,"- ");
	
	var expressiontip = $("expressiontip_"+node.id);
	if(expressiontip){
		queryTerminal.className = 'proteincolour queryTerminal queryComponents'+node.id + " expressiontips";
		queryTerminal.style.background = expressiontip.style.background;
		queryTerminal.innerHTML = expressiontip.innerHTML;
		queryTerminal.innerHTMLOriginal = innerHTML;
		expressiontip.style.display = "none";
		
	}else{
		queryTerminal.className = 'proteincolour queryTerminal queryComponents'+node.id;
		/*
		 * Save this in two different properties. Original keeps queryterminal text, innerHTML can change
		 * to store overlay text (like expression levels in expression painter).
		 */
		queryTerminal.innerHTML 		= innerHTML;
		queryTerminal.innerHTMLOriginal = innerHTML;
	}
	
	queryTerminal.setStyle({
			position: "absolute",
			left: nx +"px",
			top: ny + "px",
			visibility : "visible",
			
			width : nw,
			height : nh,
			zIndex : 21,
			fontSize:(12*zf) + "px"
	});
	
	layer.el.appendChild(queryTerminal);
	// If zf is 1, draw a box containing the number of interactors found for this query.
	if(zf ==1 && (data.count>0 || data.count.search(/\+/) >= 0)){
		var intCountEl = Element.extend(document.createElement('div')); // Create an element to display the
		// number of interactions for selected
		// protein.
		intCountEl.className = 'intcount queryComponents'+node.id;
		intCountEl.style.top = (ny - 5) + "px";
		intCountEl.style.left = (nx + nw -5) + "px";
		intCountEl.innerHTML = data.count;
		//this.interactorCount[node.userObject.refid] = data.count;
		$("ficanvas").appendChild(intCountEl);
		// If chembl overlay (cid stands for chebi id), make the interactors a little bit bigger to accommodate images
		if(data.interactors[0].cid){
			iw = cIw;
			ih = cIh;
		}
	}
	this.interactorCount[node.userObject.refid] = data.count;
    var rTermTopOffset = (nh/2)-15;
    var rTermLeftOffset = (nw/2)-15;
	var rInteractorContainer = layer.addContainer({
		"xtype": "WireIt.ImageContainer",
		"close" : false,
		"draggable" : false,
		"resizable" : false,
		"image" : "/icons/layer-placeholder.png",
		"terminals": [ {editable: "false", "direction": [0,1], 
			"offsetPosition": {"top": rTermTopOffset, "left": rTermLeftOffset} }],
		"position" : [nx , ny]
	});
	//rInteractorContainer.id = node.id;
	this.idContainerMap[node.id] = rInteractorContainer; 
	var queryModuleIndex = layer.containers.length-1;
	
    // Hide the terminal located at the query protein end of the edge.
	rInteractorContainer.terminals[0].el.style.visibility = "hidden";
	// Calculate slice size so we can arrange the interactors in a halo around the query.
	var sliceSize = 360/Math.min(data.interactors.length, maxDraw);
	var interactors = data.interactors;
	var newContainerCount = 0;
	for(var i = 0; i < data.interactors.length; i++){
		var displayedCount = this.currentlyDisplayed[node.id];
		if(displayedCount == undefined) displayedCount = 0;
        if(displayedCount >= maxDraw) {
        	break;
        }
		// For each interactor, check global interactor list to see if it already exists
		// indexed using accession number
		var interactor = null;
		if(data.interactors[i].cid){
			interactor = this.currentInteractors[data.interactors[i].cid];
		}else{
			interactor = this.currentInteractors[data.interactors[i].accession];
		}
		
		// if the interactors has not been created already 
		// create interactor boxes.
		if(interactor == undefined){
			var y = (zf*150)*Math.sin(((sliceSize*i)*radianMultiplier));
			var x = (zf*150)*Math.cos(((sliceSize*i)*radianMultiplier));
			var interactorWidth = (iw*zf)+ "px";
			var interactorHeight = (ih*zf) + "px";
			// Create a new WireIt container for the interactor
			var interactor = layer.addContainer({
				"xtype": "WireIt.ImageContainer",
				"resizable" : false,
				"close" : false,
				"image" : "/icons/hide-arrow.png",
				"terminals": [ {editable: "false", "direction": [0,1] }],
				"position" : [nx + x, ny+y]
			});
			 
			interactor.bodyEl.style.width = interactorWidth;
			interactor.bodyEl.style.height = interactorHeight;
			interactor.bodyEl.style.border = Math.max((zf*3),1)+ "px solid blue";
			interactor.bodyEl.style.background = "rgb(204,255,204)";
			interactor.bodyEl.style.textAlign = "center";
			interactor.bodyEl.style.verticalAlign = 'bottom';
			interactor.bodyEl.style.zIndex = 35;
			interactor.el.style.opacity=1;
			interactor.bodyEl.parentNode.style.zIndex = 35;
			interactor.bodyEl.style.overflow = "hidden";
			// If the interactors are from chembl use different text in tooltip
			if(data.interactors[i].cid){
				interactor.bodyEl.title = "Formula: " + data.interactors[i].genename
				+ ". Name: " + data.interactors[i].accession;

			}else{
				interactor.bodyEl.title = "Name: " + data.interactors[i].genename
				+ ". Uniprot Accession: " + data.interactors[i].accession;
			}
			// Below a certain zoomfactor no point displaying text in interactor nodes as they are too small
			// to read.
			if(zf>=0.5){
				if(data.interactors[i].cid){
					interactor.bodyEl.style.padding = 0;
                                        var imgDiv = document.createElement("div");
					var imghtml = "<img style=\"width:"+interactorWidth+";height:" + interactorHeight
                                                + ";\" src=\"http://www.ebi.ac.uk/chebi/displayImage.do?defaultImage=true&imageIndex=0&chebiId="
                                              + data.interactors[i].cid + "\">";
					imgDiv.innerHTML = imghtml;
					interactor.bodyEl.appendChild(imgDiv); 
				}else{
					interactor.bodyEl.innerHTML = data.interactors[i].genename;
				}
			}else{
				interactor.bodyEl.innerHTML = "";
			}
			interactor.bodyEl.accession = data.interactors[i].accession;

			if(data.interactors[i].cid){
				interactor.bodyEl.cid = data.interactors[i].cid;
			}
			// Set the position of the wire terminal so that it centered on the interactor.
			interactor.bodyEl.nextSibling.style.top = (((interactor.el.offsetHeight - interactor.terminals[0].el.offsetHeight)/2)) +"px";
			interactor.bodyEl.nextSibling.style.left = (((interactor.el.offsetWidth - interactor.terminals[0].el.offsetWidth)/2)) +"px";
			// Hide the terminal at the overlayed interactor end of the edge.
			// Otherwise WireIt terminal would be display (small node).
			interactor.terminals[0].el.style.visibility = "hidden";
			YAHOO.util.Event.addListener(interactor.bodyEl, 'dblclick', this.clickInteractor, this, true);
			// Add interactors to global list
			if(data.interactors[i].cid){
				this.currentInteractors[data.interactors[i].cid] = interactor;
				// Map uniprot accession number to container moduleid
				this.moduleIdMappings[data.interactors[i].cid] = queryModuleIndex+newContainerCount+1;
				this.idContainerMap[data.interactors[i].cid] = interactor;
			}else{
				this.currentInteractors[data.interactors[i].accession] = interactor;
				// Map uniprot accession number to container moduleid
				this.moduleIdMappings[data.interactors[i].accession] = queryModuleIndex+newContainerCount+1;
				this.idContainerMap[data.interactors[i].accession] = interactor;
			}
			newContainerCount ++;
		}else{
			interactor.bodyEl.style.display="";
		}
		// Keep track of how many interactors are displayed for this particular query protein.
		this.currentlyDisplayed[node.id]= displayedCount+1;
	}
	
	// Keep track of interactors for selected pathway node using node (Vertex) id
	this.queryInteractorMappings[node.id] = interactors;
	this.queryRefIdAccMap[node.userObject.refid] = data.query;
    var displayCount = Math.min(maxDraw,this.currentlyDisplayed[node.id]);
	
    for(var j=0; j< displayCount; j++){
    	// Get the moduleid for the interactor using its accession number
    	var currentModuleId = null;
    	if(data.interactors[j].cid){
    	   currentModuleId = this.moduleIdMappings[data.interactors[j].cid];
    	}else{
    		currentModuleId = this.moduleIdMappings[data.interactors[j].accession];
    	}
    	if(currentModuleId == undefined){
    		currentModuleId = queryModuleIndex+j+1;
    	}
    	// This is where WireIt wire is created. Needs the container ids for WireIt terminals
    	// that where created above for query protein overlay and interactor overlays.
    	// 
		var w = layer.addWire({
			src: {moduleId: queryModuleIndex, terminalId: queryModuleIndex},
		tgt: {moduleId: currentModuleId, terminalId: 0},
			drawingMethod : "straight",
			width:1
		});
    	// Create some variables to store data for use later.
		w.element.style.zIndex = 20;
		w.accession = data.interactors[j].accession;
		w.genename = data.interactors[j].genename;
		w.queryaccession = data.query;
		
		w.querygenename = node.userObject.name;
		if(data.interactors[j].conf
				&& data.interactors[j].conf.length > 0
				&& data.interactors[j].conf.search(/[0-9]*\.[0-9]*/) >= 0
				){
			w.conf = data.interactors[j].conf;
		}
		if(data.interactors[j].chemblid){
			w.chemblid = data.interactors[j].chemblid;
		}
		// Listen for the event where the user moves the mouse cursor over a wire.
		w.eventMouseIn.subscribe(this.wireIn, this, true);
    }
    // If the action is set to 'colour' then colour interactions based on confidence level of interaction.
    if(this.action == "colour"){
    	this.colourInteractions();
    }
    
    }catch(ex){
    	document.body.style.cursor = "default";
    }
 
};

/*
 * Given a pathway node, hide its interactors that don't share an interaction with another node 
 * in the pathway. 
 */
this.hideInteractors = function(node){
	var container = this.idContainerMap[node.id];
	$("ficanvas").getElementsBySelector('div.queryComponents'+node.id).invoke('remove');
	this.filayer.removeContainer(container);
	this.currentlyDisplayed[node.id] = undefined;
	this.queryInteractorMappings[node.id] = undefined;
	this.idContainerMap[node.id] = undefined;
	// Remove node from currentFINodes. 
	for(var i =0;i<this.currentFINodes.length; i++){
		if(this.currentFINodes[i].id == node.id){
			this.currentFINodes.splice(i,1);
			break;
		}
	}
	var limit = this.filayer.containers.length;
	var index=0;
	try{
	while(index<limit){
		if(this.filayer.containers[index] == undefined){
			break;
		}
		if(this.filayer.containers[index].wires && this.filayer.containers[index].wires.length == 0){
			if(this.filayer.containers[index].bodyEl.cid){
				this.currentInteractors[this.filayer.containers[index].bodyEl.cid] = undefined;
				this.idContainerMap[this.filayer.containers[index].bodyEl.cid] = undefined;
			}else{
				this.currentInteractors[this.filayer.containers[index].bodyEl.accession] = undefined;
				this.idContainerMap[this.filayer.containers[index].bodyEl.accession] = undefined;
			}
			this.filayer.removeContainer(this.filayer.containers[index]);
		}else{
			index++;
		}
	}
	var expressiontip = $("expressiontip_"+node.id);
	if(expressiontip){
		expressiontip.style.display = "block";
	}
	}catch(err){
		log("hiding error " + err.description);
	}
};
// Determines what happens when user clicks on an interactor. Currently opens up the Uniprot entry 
// for the protein. Different types (Chemicals, proteins) of interactors will need different destinations.
this.clickInteractor = function(o, u, t){
	// Some hardcoding of search urls here. Ideally server would pass search urls for each service when 
	// user first loads the elv.
	var cid=0;
    var accession=0;
	if(o.target){
	 cid = o.target.parentNode.parentNode.cid;
	accession = o.target.accession;
	if(cid == undefined) cid = o.target.cid;
	}else{ // browser is IE
		// IE doesn't seem to allow addition of new propertys to some objects at runtime (like cid and accession).
		// Need to get these from other places.
		// href property seems to be set automatically by IE, extracting href from img innerHTML set in display
		// function. Extract the chebiId from here.
	   if(o.srcElement.href){
           cid = o.srcElement.href;
           cid = cid.replace(/.*chebiId=/,"");
	   }else{
		// Extract uniprot accession number from tooltip.
		accession = o.srcElement.title;
		accession = accession.replace(/.*Accession: /,"");
		}
	}
	if(cid>0){
		/* queryBean controls limits on search, default is to search for 3 star ChEBI entries only but psicquic
		 service returns all results. stars -1 tells search engine not to limit search to 3 star entries.
		 Without this flag double clicking on some chebi interactors will result in a failed search on the 
		 ChEBI site.
		*/
		window.open("http://www.ebi.ac.uk/chebi/advancedSearchFT.do?searchString="+cid + "&queryBean.stars=-1");
	}else{
		window.open("http://www.uniprot.org/uniprot/"+accession);
	}
};

// If the user clicks on an interaction tooltip send the interactor identifiers to the relevant database
// as a search query.
// ParentObject should be an FIDisplay instance
this.wireClick = function(event, wire, parentObject){
	// dblistid is id of dropdown listing interaction data sources.
	var dblistvalue = $("dblistid").value;	
	var method = $(dblistvalue).service;
	// method 1 means a remote PSICQUIC interface
	if(method == "1"){
		var query = event.target.queryaccession + " AND " + event.target.accession; 
		var searchurl = null;
		/* Set the search urls of the different databases. When the user clicks on an interaction
		*	tip the relevant information (accession numbers, chemblid) will be submitted as part of the
		*	search url. 
		*/
		if(dblistvalue.search(/IntAct/) >=0){
			searchurl = this.intactSearchUrl.replace(/EBIINTERACTION/,query);
		}else if(dblistvalue.search(/MINT/) >=0){
			searchurl = "http://mint.bio.uniroma2.it/mint/search/search.do?ac="+event.target.queryaccession; 
		}else if(dblistvalue.search(/BioGrid/) >=0){
			searchurl = "http://www.thebiogrid.org/search.php?keywords=" + event.target.queryaccession; 
		}else if(dblistvalue.search(/MatrixDB/) >=0){
			searchurl = "http://matrixdb.ibcp.fr/cgi-bin/interactome"; 
		}else if(dblistvalue.search(/MPIDB/) >=0){
			searchurl = "http://www.jcvi.org/mpidb/interaction.php?pname="+
			event.target.queryaccession +"&species_txtbox=&species_select=&dbsource=&cvname=&confidence_structure=&confidence_method=&confidence_interologs=&confidence_purification=&confidence_evidences=&submit=Search"; 
		}else if(dblistvalue.search(/ChEMBL/) >=0){
			searchurl = "http://www.ebi.ac.uk/chembldb/index.php/compound/inspect/"+event.target.chemblid; 
		}else if(dblistvalue.search(/reactome/i) >=0){
			searchurl = "http://www.reactome.org/cgi-bin/link?SOURCE=UNIPROT&ID="+event.target.queryaccession; 
		}
		
		
		if(searchurl != null)
		window.open(searchurl);
	}
};

this.cleanUp = function(){
	this.clear();
	if(this.currentInteractors != null){
		//this.currentInteractors.length = 0;
		this.currentInteractors = new Array();
	}
	if(this.currentFINodes != null){
		this.currentFINodes = new Array();
	}
};

this.clear = function(){
	if(this.wireTip != null){
		YAHOO.util.Event.purgeElement(this.wireTip, true);
			this.wireTip.remove();
			this.wireTip = null;
		}
		if(this.filayer != null){
			this.filayer.clear();
			this.filayer= null;
		}
		if(this.queryInteractorMappings != null){
			this.queryInteractorMappings =  new Array();
		}
		if(this.queryRefidAccMap != null){
			this.queryRefIdAccMap =  new Array();
		}
		if(this.moduleIdMappings != null){
			this.moduleIdMappings = new Array();
		}
		if(this.currentlyDisplayed != null){
			this.currentlyDisplayed = new Array();
		}
		this.interactorCount = new Array();
		// Remove the div overlays for pathway proteins
		var ficanvas = $("ficanvas");
		if(ficanvas){
		$("ficanvas")
		.getElementsBySelector('div.queryTerminal')
		.invoke('remove');
		$("ficanvas")
		.getElementsBySelector(
				'div.intcount')
		.invoke('remove');
		$("ficanvas").getElementsBySelector('div.WireIt-Layer').invoke('remove');
		}
};


this.clearDisplay = function(){
	if(this.wireTip != null){
		YAHOO.util.Event.purgeElement(this.wireTip, true);
		this.wireTip.remove();
		this.wireTip = null;
	}
	if(this.filayer != null){
		this.filayer.clear();
		this.filayer = null;
		this.currentlyDisplayed = new Array();
		this.currentInteractors = new Array();
		// Remove the div overlays for pathway proteins
		$("ficanvas")
		.getElementsBySelector(
		'div.queryTerminal')
		.invoke('remove');
		$("ficanvas")
		.getElementsBySelector(
				'div.intcount')
		.invoke('remove');
	}
};
/*
 * Iterate through all nodes in pathway that have interactors displayed and redisplay.
 * Used when user changes zoom level. overlay is cleared and interactors redrawn.
 * zf - zoomfactor
 */
this.displayAll = function(zf){
	var nodeFIs = this.currentFINodes.slice();
	if(nodeFIs == null || nodeFIs.length == 0){
		return;
	}
	for(var i = 0; i < nodeFIs.length; i++){
		// Get an array of interactors for current pathway node.
		// interactor informations is genename and accession number pair.
		var nodeInteractors = this.queryInteractorMappings[nodeFIs[i].id];
		var data = new Object();
		data.interactors = nodeInteractors;
		data.query = this.queryRefIdAccMap[nodeFIs[i].userObject.refid];
		data.count = this.interactorCount[nodeFIs[i].userObject.refid];
		this.displayFIOverlay(nodeFIs[i], data, zf);
	}
	this.currentFINodes = nodeFIs;
};
/*
 * What happens when the mouse is moved a wire (interaction). Tooltip is created/displayed containing
 * gene names of interactors and confidence score if present.
 */
this.wireIn = function(eventName,wire,parentObject){
	var w = 200;
	var h = 74;
	var confidence = wire[0].conf;
	if(confidence ==undefined){
		confidence = "";
	}else{
		confidence = ". Confidence: " + confidence;
	}
	try{
		// If a wireTip does not exist create a new one, otherwise reuse the existing one.
	if(this.wireTip == null){
		// Create the tooltip that is displayed when the user mouses over a wire.
		this.wireTip = Element.extend(document.createElement('div'));
		this.wireTip.id = "wireTipId";
		this.wireTip.className = "mitip";
		this.wireTip.setStyle( {
			position : "absolute",
			top : ((wire[0].element.offsetTop + wire[1][1] - (h/2))) + "px",
			left : ((wire[0].element.offsetLeft + wire[1][0] - (w/2))) + "px",
			width : w + "px",
			height : h + "px",
			zIndex : 21,
			opacity : 0.85,		
			border : "1px solid #DCDCDC",
			background : "#DCDCDC"
		});
		this.wireTip.innerHTML = wire[0].querygenename + " interacts with " + wire[0].genename 
		+ confidence;
		this.wireTip.queryaccession = wire[0].queryaccession;
		this.wireTip.accession = wire[0].accession;
		this.wireTip.chemblid = wire[0].chemblid;
		YAHOO.util.Event.addListener(this.wireTip, 'mouseout', 
				this.wireOut, this, true);
		YAHOO.util.Event.addListener(this.wireTip, 'click', 
				this.wireClick, this, true);
		$("ficanvas").appendChild(this.wireTip);
	}else{
		this.wireTip.queryaccession = wire[0].queryaccession;
		this.wireTip.accession = wire[0].accession;
		this.wireTip.innerHTML =  wire[0].querygenename + " interacts with " + wire[0].genename
								+ confidence ;
		this.wireTip.setStyle({display:"",
			top : ((wire[0].element.offsetTop + wire[1][1] - (h/2))) + "px",
			left : ((wire[0].element.offsetLeft + wire[1][0] - (w/2))) + "px",
			visibility : "visible"
			});
	}
	}catch(err){
		alert(err);
	}
};

/*
 * Hide the tip if the mouse is moved away from the wire.
 */
this.wireOut = function(event,  parentObject){
	
	this.wireTip.setStyle({ display: "none"});
};

this.getPositionByStyle = function(obj) {
	return [ parseInt(obj.style.left),
			parseInt(obj.style.top) ];
};

this.colourInteractions = function(){
	this.confthreshold = $("confthresholdid").value;
	if(this.confthreshold.length > 0){
	this.colourInteractionsBasedOnThreshold(this.confthreshold, 
			this.currentAboveColour,
			this.currentBelowColour);
	}
};

// set colours of interactions back to default
this.resetColours = function(){
	this.action = null;
	if(this.filayer != null){
		var wires = this.filayer.wires;
		for(var i=0; i<wires.length; i++){
			wires[i].options.color = this.defaultColour;
			wires[i].options.bordercolor = this.defaultBorderColour;
			wires[i].redraw();
		}
	}
};
this.colourInteractionsBasedOnThreshold = function(confthreshold,exceedColour, belowColour){
	this.confthreshold = confthreshold;
	this.currentAboveColour = exceedColour;
	this.currentBelowColour = belowColour;

	this.action = "colour";
	var noConf = 0; // A flag to indicate if any of the interactions do not have a confidence score
	                   // These interactions will stay the default colour and user should be notified.
	if(this.filayer != null){
		// Get a list of wires (interactions) that currently exist
		var wires = this.filayer.wires;
		for(var i=0; i<wires.length; i++){
			if(wires[i].conf){
			if(wires[i].conf < confthreshold){
				wires[i].options.color = belowColour;
				wires[i].options.bordercolor = belowColour;
			}else if(wires[i].conf >= confthreshold){
				wires[i].options.color = exceedColour;
				wires[i].options.bordercolor = exceedColour;
			}
			wires[i].redraw();
			}else{
				noConf = 1;
			}
		}
		if(noConf == 1){
			alert("One or more interactions do not have a confidence score. An interaction without " +
			"a confidence score will not be coloured.");

		}
	}
};
};
