/*
Control panel which contains functionality for the funtional interaction overlay.
Could be extended to be tabbed and provide functionality for expression painter.
*/

ControlPanel = function(){
this.controlPanel = null;
this.uploadFIFileDialog = null;
this.colourPickerDialog = null;
this.newPsicquicServiceDialog = null;
this.exceedColour = "rgb(0,255,0)";
this.belowColour = "rgb(255,0,0)";
this.width = "400px"; // move into stylesheet
this.topOffset = 40; // amount to shift the location of the control panel up by when displayed
this.fiDisplay = null;
this.interactorsDisplayedColour = "rgb(236,246,252)";
this.displayControlWidth = 25;


this.init = function(fiDisplay){
	this.fiDisplay = fiDisplay;
	this.uploadFIFileDialog = new UploadFIFileDialog();
	this.uploadFIFileDialog.init();
	this.newPsicquicServiceDialog = new NewPsicquicServiceDialog();
	this.newPsicquicServiceDialog.init();
	YAHOO.util.Event.addListener($("displaycontrolpanelbutton"), 'click', 
			this.displayControlDialog, this, true);
	YAHOO.util.Event.addListener($("dblistid"), 'change', 
			this.serviceChanged, this, true);
	YAHOO.util.Event.addListener($("clearoverlayid"), 'click', 
			this.onClearOverlayClick, this, true);
	YAHOO.util.Event.addListener($("uploadfileid"), 'click', 
			this.onUploadInteractionDataClick, this, true);
	YAHOO.util.Event.addListener($("newpsicquicid"), 'click', 
			this.onSubmitNewPsicquicClick, this, true);
	YAHOO.util.Event.addListener($("exceedthresholdbuttonid"), 'click', 
			this.onSetThresholdExceededColourClick, this, true);
	YAHOO.util.Event.addListener($("belowthresholdbuttonid"), 'click', 
			this.onSetBelowThresholdColourClick, this, true);
	YAHOO.util.Event.addListener($("colourapplicationbuttonid"), 'click', 
			this.onApplyColoursButtonClick, this, true);
	YAHOO.util.Event.addListener($("resetcoloursbuttonid"), 'click', 
			this.onResetColoursButtonClick, this, true);
	YAHOO.util.Event.addListener($("pathwayinteractorsbuttonid"), 'click', 
			this.onShowPathwayInteractionsButtonClick, this, true);
	YAHOO.util.Event.addListener($("pathwayinteractorsexportbuttonid"), 'click', 
			this.onPathwayInteractionsExportButtonClick, this, true);

	this.tableBuiltEvent = new YAHOO.util.CustomEvent("InteractionTableBuiltEvent");
	this.rowClickedEvent = new YAHOO.util.CustomEvent("RowClickedEvent");
	this.displayInteractorsButtonClickedEvent = new YAHOO.util.CustomEvent("displayInteractorsButtonClickedEvent");
    // Retrieve a list of active psicquic services and populate dblistid dropdown.
	this.populatePsicquicList();
	this.colourPickerDialog = YAHOO.example.colorpicker.inDialog;
	this.colourPickerDialog.colourChangedEvent.subscribe(this.onChangedEdgeColour.bind(this), this);
};

/*
 * Query the PSICQUICProxyServlet for servicenames and indexes to populate the drop down of
 * psicquic services. 
 */
this.populatePsicquicList = function(){
	var callback = {
			scope: this,
			customevents: {
				onSuccess: function(eventType, args) {
					if(args[0].responseText.length == 0){
						alert("No PSICQUIC services found!");
						return;
					}
					var data = eval("(" + args[0].responseText + ")");
					var services = data.services;
					var serviceList = $("dblistid");
					var defaultIndex = 0;
					for(var i=0; i<services.length;i++){
						 var o = services[i];
						 var elOptNew = document.createElement('option');
						 elOptNew.text = services[i].name;
						 elOptNew.value =  services[i].name + "Option";
						 elOptNew.id = services[i].name + "Option";
						 if(services[i].service){
							 elOptNew.service = "3";
						 }else{
							 // 1 indicates to PsicquicProxyServlet that query is submitted using REST.
							 // User submitted data added to drop down will have label of 3 instead
							 //elOptNew.label = "1";
							 elOptNew.service = "1";
						 }
						 elOptNew.text = services[i].name;
						 elOptNew.si = services[i].index; // Store the service index
					         try{
						 serviceList.add(elOptNew, null);
						}catch(ex){
							serviceList.add(elOptNew);
						}
						 // Default service is IntAct
						 if(services[i].name == "IntAct"){
							 serviceList.selectedIndex=i;
						 }
					}
				}, 
				onFailure: function(eventType, args) {
				},
				onComplete: function(eventType, args) {
				}
			}
		};
	YAHOO.util.Connect
	.asyncRequest(
				'POST',
				"/ReactomeGWT/entrypoint/elv/PSICQUICProxyServlet",
				callback,
						"action=reg"
					);
};

this.cleanUp = function(){
	// Purge removes all event listeners from element.
	YAHOO.util.Event.purgeElement($("displaycontrolpanelbutton"), true);
	YAHOO.util.Event.purgeElement($("dblistid"), true);
	YAHOO.util.Event.purgeElement($("clearoverlayid"), true);
	YAHOO.util.Event.purgeElement($("uploadfileid"), true);
	YAHOO.util.Event.purgeElement($("exceedthresholdbuttonid"), true);
	YAHOO.util.Event.purgeElement($("belowthresholdbuttonid"), true);
	YAHOO.util.Event.purgeElement($("colourapplicationbuttonid"), true);
	YAHOO.util.Event.purgeElement($("resetcoloursbuttonid"), true);
	YAHOO.util.Event.purgeElement($("pathwayinteractorsbuttonid"), true);
};

this.displayControlDialog = function(){
	$("controlpaneldialog").style.display="block";
   try{	   
   if(this.controlPanel == null){
	var dialog1 = new YAHOO.widget.Dialog("controlpaneldialog",  
				            { width : this.width, 
				              fixedcenter : true, 
				              visible : false,  
				              constraintoviewport : true, 
				              draggable: true,
				              close: false,
				              buttons : [  
				                          { text:"Close", handler:this.handleCancel, isDefault:true } ] 
				             } );
	dialog1.callback = { 
			success: this.handleSuccess,
		     failure: this.handleFailure 
		     };
	
	// Render the Dialog
	dialog1.render();
	// Shift the control panel up a bit so that if user displays table the bottom of the panel will be
	// displayed on screen.
	dialog1.element.style.top = (dialog1.element.offsetTop - this.topOffset)+"px";
	dialog1.element.style.visibility = "visible";
	this.controlPanel = dialog1;
   }else{
	   this.controlPanel.render();
	   this.controlPanel.element.style.visibility = "visible";
	   $("controlpaneldialog").style.display="block";
   }
   }catch(err){
	   alert("ERROR: " + err);
   }
};

// Define various event handlers for Dialog
this.handleSubmit = function() {
	this.submit();
};

this.hideTable = function(){
	var button = $("pathwayinteractorsbuttonid");
	button.innerHTML = "Display table of all interactors for pathway";
	button.tableaction = 1;
	var intsDiv = $("interactionstableid");
	intsDiv.style.display = "none";
	return;
};
this.processInteractionTable = function(toggle){
	var button = $("pathwayinteractorsbuttonid");
	if(toggle){
		var hide = /hide/i; // Check if current text in table button is 'Hide ...'
		// Toggle message on table button.
		if(button.innerHTML.search(hide)>=0){
			this.hideTable();
			return;
		}
	}
    var intsDiv = $("interactionstableid");
    var tableObject = $("interactortableid");
    // if the table of interactions already exists, overlay a time indicator on it.
    if(tableObject){
    	// Get rid of the scroll bars in the div wrapping the interaction table.
    	intsDiv.style.overflow="hidden";
    	
    	overlapElementWithTimeIndicator(intsDiv);
    }
	var t = this;
	var callback = {
			success: function(response){
			    var intsDiv = $("interactionstableid");
			    var width = intsDiv.clientWidth;
			    var cellWidth = width/2;
			    var intsTable = "<table id=\"interactortableid\" style=\"table-layout:fixed;width=\"100%\";\" border=\"1\">" +
			    					"<tr><td class =\"th\" width=\""+t.displayControlWidth+"\" ><div style=\"width:" 
			    				+ t.displayControlWidth 
			    				+";display:block;visibility:hidden;\"> </div></td><td class=\"th\" style=\"white-space: nowrap;\"\">Proteins in Pathway</td><td class=\"th\"\">Interactors Found</td></tr>";
			    if(response.responseText.length ==0){
			    	t.hideTable();
			    	alert("No interactors returned from interaction database.");
			    	var ol = $("olid");
					if(ol){
						ol.parentNode.removeChild(ol);
					}
					if(intsDiv.style.display==""){
						intsTable += "</table>";
						intsDiv.innerHTML = intsTable;
					}
			    	// Set the mouse pointer back to standard
					document.body.style.cursor = "default";
			    	return;
			    }
			    var data = eval("(" + response.responseText + ")");
                var results = data.queryresults;
                var maxStringLength = 25;
                // Read through interaction data and build the table HTML.
                for(var i=0; i<results.length; i++){
                	var result = results[i];
                	var interactors = result.interactors;
                	for(var j=0; j<interactors.length; j++){
                		var genenamefragment = interactors[j].genename;
                		if(genenamefragment.length > maxStringLength){
                			genenamefragment = genenamefragment.substring(0, maxStringLength);
                			genenamefragment += "...";
                		}
                		var querynode = pba.pathwayDiagramPane.nodes[pba.pathwayDiagramPane.refdbnodes[result.refid]];
                		if(querynode){
                			var querynamefragment = querynode.userObject.name;
                			if(querynamefragment == undefined){
                			
                			}else{
                				if(querynamefragment.length > maxStringLength){
                					querynamefragment = querynamefragment.substring(0,maxStringLength);
                					querynamefragment += "...";
                				}
                				var pid = querynode.userObject.id;
                				intsTable += 
                					"<tr class=\"queryrow_"+pid +"\" style=\"background:blue;\"><td onClick=\"pba.pathwayDiagramPane.controlPanel.onClickDisplayHandler("
                					+pid +"," + querynode.id + ")\" align=\"center\" title=\"Click to display or hide interactors\"  style=\"cursor:pointer;background:white;width:"
                					+ t.displayControlWidth +";\"><div class=\"th\" style=\"width:12;height:12;\"/></td><td onClick=\"pba.pathwayDiagramPane.controlPanel.onClickHandler("
                					+pid +"," + querynode.id + ")\" title=\"Click to move view to protein\"  style=\"cursor:pointer;background:white;"
                					+"white-space:nowrap;\">" 
                					+ querynamefragment 
                					+ "</td><td style=\"background:white;overflow:hidden;white-space: nowrap;\">" 
                					+  genenamefragment + "</td></tr>";
                			}
                		}
                	}
                	// colour rows here
                }
                intsTable += "</table>";
                // Set the HTML of the div wrapping the table to the table html.
                intsDiv.innerHTML = intsTable;
                t.tableBuiltEvent.fire();
			},
			failure: function(response){
				document.body.style.cursor = "default";
			}
	};
	// Redrawing might not be instantaneous. Set the cursor to the wait pointer.
	document.body.style.cursor = "wait";
    // dblistid is the id of the dropdown containing the list of interaction data sources.
	var id = $("dblistid").value;	
	var method = $(id).service;
	var label = id.replace(/Option/,"");
	var selectedIndex = $(id).si; // The index for service(interaction database).
								 // Servlet uses this to retrieve the url of the new
								// service.

	YAHOO.util.Connect
	.asyncRequest(
				'POST',
				"/ReactomeGWT/entrypoint/elv/PSICQUICProxyServlet",
				callback,
						'label='
						+ label
						+ '&retrievalmethod='+ method
						+ '&pdbid=' + pba.focus_pathway_id
						+ '&si=' + selectedIndex
						+ '&action=pi'
					);
};

this.showTable = function(){
	try{
		var button = $("pathwayinteractorsbuttonid"); // Get a handle to the button the user presses
		// to display/hide table of interactions.
		button.innerHTML = "Hide table of all interactors for pathway";

		var intsDiv = $("interactionstableid");
		intsDiv.style.display = ""; // a blank display value causes the element to be displayed.
		intsDiv.style.overflow="auto";
		// Set the mouse pointer back to standard
	
		var ol = $("olid");
		if(ol){
			ol.parentNode.removeChild(ol);
		}
	}catch(err){
		alert("There was a problem displaying table of interactions: " + err.description);
	}
	document.body.style.cursor = "default";
}
this.onShowPathwayInteractionsButtonClick = function(toggle, arg2, arg3){
	this.processInteractionTable("toggle");
};

this.onPathwayInteractionsExportButtonClick = function(){
    // dblistid is the id of the dropdown containing the list of interaction data sources.
	var id = $("dblistid").value;	
	var selectedIndex = $(id).si; // The index for service(interaction database).
								 // Servlet uses this to retrieve the url of the new
							// service.
	window.open("/ReactomeGWT/entrypoint/elv/PSICQUICProxyServlet?action=ex&pdbid="
			+pba.focus_pathway_id
			+"&si="+selectedIndex);
};

this.colourRows=function(pid, vid, colour){
	var queryrowList = $("interactionstableid").getElementsBySelector(".queryrow_"+pid);
	if(colour == undefined){
	 colour = this.interactorsDisplayedColour;
	}
	
	for(var i=0;i<queryrowList.length; i++){
		var tdList = queryrowList[i].childNodes;
		for(var j=0;j<tdList.length;j++){
			tdList[j].style.backgroundColor = colour;
		}
	}
};

this.onClickHandler = function(pid,vid){
	this.rowClickedEvent.fire(pid, vid);
};

this.onClickDisplayHandler = function(pid,vid){
	this.displayInteractorsButtonClickedEvent.fire(pid, vid);
};

this.onSubmitNewPsicquicClick = function(){
	var newpsicquiccontainer = $("submitnewpsicquiccontainer");
	var x = this.controlPanel.element.offsetLeft;
	var y = this.controlPanel.element.offsetTop;	
	this.newPsicquicServiceDialog.displayNewPsicquicServiceDialog(x-50,y-20);
};

this.handleCancel = function() {
	$("controlpaneldialog").style.display="none";
};
this.handleSuccess = function(o) {
	var response = o.responseText;
	response = response.split("<!")[0];
	document.getElementById("resp").innerHTML = response;
};
this.handleFailure = function(o) {
	alert("Submission failed: " + o.status);
};

/*
 * Event handler called when interaction service changed.
 */
this.serviceChanged = function(){
	var fiCanvas = $("ficanvas");
	
	// if fiCanvas exists remove wires(interactions) from previous service
	if(fiCanvas){
		fiCanvas.getElementsBySelector('div.WireIt-Layer').invoke('remove');
	}
	var t = this;
	pba.pathwayDiagramPane.filayer= null;
	var callback = {
			success: function(response){
				// Take a copy of the current nodes before clearing the FI slate.
				// Interactions for these nodes will be retrieved from new service and drawn
				// where they exist.
				var nodeFIs = pba.getCurrentFINodes().slice();
				pba.pathwayDiagramPane.fiDisplay.clear();
				if(response.responseText.length == 0){
					document.body.style.cursor = "default";
					// Only display warning if user has selected at least one query protein.
					if(nodeFIs.length > 0){
						t.hideTable();
						alert("No interaction data returned from PSICQUIC service.");
					}
					return;
				}
				
				var data = eval("(" + response.responseText +")");
				if(data.queryresults.length==0){
					document.body.style.cursor = "default";
					// Only display warning if user has selected at least one query protein.
					if(nodeFIs.length > 0){
						alert("No interaction data returned from PSICQUIC service.");
					}
				}
				for(var i = 0; i < nodeFIs.length; i++){
					for(var j=0; j<data.queryresults.length; j++){
						// If the current queryresult matches a node in the pathway that is displaying
						// interactions from previous interaction source then dispay interactions from 
						// newly selected inertaction source.
						if(data.queryresults[j].refid == nodeFIs[i].userObject.refid){
							pba.displayFIOverlay(nodeFIs[i], data.queryresults[j]);
						}
					}
				}
				// Set the mouse pointer back to standard
				document.body.style.cursor = "default";
			},
			failure: function(response){
				document.body.style.cursor = "default";
				alert("Failure when switching PSICQUIC services.")
			}
	};
	// Redrawing might not be instantaneous. Set the cursor to the wait pointer.
	document.body.style.cursor = "wait";
    // dblistid is the id of the dropdown containing the list of interaction data sources.
	var id = $("dblistid").value;	
	var method = $(id).service;
	var label = id.replace(/Option/,"");
	var selectedIndex = $(id).si; // The index for new service.
													// Servlet uses this to retrieve the url of the new
													// service.
	var nodeFIs = pba.getCurrentFINodes();
	var refidList ="";
	// The ELV keeps track of which nodes the user has displayed interactors for. When the service is
	// changed the refids for these nodes are submitted to PsicquicProxyServlet so that interactions can
	// be retrieved from the new service.
	for(var i = 0; i < nodeFIs.length; i++){
		refidList += nodeFIs[i].userObject.refid;
		refidList +=",";
	}
	refidList = refidList.replace(/,$/, "");
	YAHOO.util.Connect
	.asyncRequest(
				'POST',
				"/ReactomeGWT/entrypoint/elv/PSICQUICProxyServlet",
				callback,
						'label='
						+ label
						+ '&retrievalmethod='
						+ method
						+ '&refid=' + refidList
						+ '&si=' + selectedIndex
					);
	
    var intsDiv = $("interactionstableid");
    // A display set to blank actually causes the div to be display (display="none" hides it).
    // If the interaction table is visible, update the data with interactions from the newly selected 
    // interaction database.
	if(intsDiv.style.display==""){
		intsDiv.scrollTop = "0px";
		this.processInteractionTable();
	}
};

this.onClearOverlayClick =  function(){
	$("ficanvas").getElementsBySelector('div.WireIt-Layer').invoke('remove');
	$("ficanvas").getElementsBySelector('div.queryTerminal').invoke('remove');
	// Add function in PBA instead of accessing pathwayDiagramPane directly.
	pba.clearFIOverlay();
};

this.onUploadInteractionDataClick = function(){
	var uploadcontainer = $("uploadinteractionfilecontainer");
	var x = this.controlPanel.element.offsetLeft;
	var y = this.controlPanel.element.offsetTop;	
	this.uploadFIFileDialog.displayUploadFIFileDialog(x-50,y-20);
};

this.onSetThresholdExceededColourClick = function(){
	// Pass in the current colour for exceed threshold along with '1' to indicate
	// we are editing colour for exceed. Will be used by onChangedEdgeColour below
	this.colourPickerDialog.showPicker($("exceedthresholdbuttonid").style.background, 1);
};

this.onSetBelowThresholdColourClick = function(){
	this.colourPickerDialog.showPicker($("belowthresholdbuttonid").style.background, 0);
};

this.onApplyColoursButtonClick = function(){
	if(this.validateConfThreshold()==false){
		alert("Invalid characters found in confidence threshold. Valid characters are 0-9 and '.'. If a '.'" +
				" is not present one will be prepended to the input.");
		return;
	}
	alert("Interactions will be coloured based on the confidence scores of those interactions.");
	var confthreshold = $("confthresholdid");
	pba.applyConfidenceColours(confthreshold.value,this.exceedColour, this.belowColour);
};



/*
 * Check the confidence level threshold. Ensure digits and a single decimal point only are found
 * and the value is not blank.
 */
this.validateConfThreshold = function(){
        var confThresholdValue = $("confthresholdid").value;
        if(confThresholdValue.length == 0){
                return false;
        }
        confThresholdValue= confThresholdValue.replace(/\./,""); // a single decimal point is valid. strip out first one present
                                                                                // to facilitate checks for digits and more decimal points
        if(!confThresholdValue.match(/^\d+$/)){
                return false;
        }
        confThresholdValue = $("confthresholdid").value;
        if(!confThresholdValue.match(/\./)){
                $("confthresholdid").value = "0." + confThresholdValue;
        }
        return true;
};


/*
 * Iterate through wires and change colours back to default.
 */
this.onResetColoursButtonClick = function(){	
	pba.resetColours();
};


// Listens for event fired by ColourPickerDialog after user has selected a colour for interactions exceeding/
// falling below certain confidence score.
// type is 1 or 0 depending on whether exceed or below colour changed.
this.onChangedEdgeColour = function(e,args){
	var type = args[0];
	var colour = args[1];
	colour = "rgb("+colour+")";
	
	if(type==1){
		this.exceedColour=colour;
		var button =$("exceedthresholdbuttonid"); 
		button.style.background = colour;	
	}else{
		this.belowColour = colour;
		var button =$("belowthresholdbuttonid"); 
		button.style.background = colour;
	}
	
	var confthreshold = $("confthresholdid");
	pba.applyConfidenceColours(confthreshold.value, this.exceedColour, this.belowColour);
	}
};
