/**
 * This class contains functions {sequenceOfExecution} and {onClickSequenceOfExecution}.
 * @function {sequenceOfExecution} executes when user clicks submit in th UI.
 * @function {onClickSequenceOfExecution} executes when user enters mass shift 
 * on any amino acid and click "OK" button.
 */
class SeqOfExecution
{
	constructor(){
		this.onClickMassShift = {};
	}
	/**
	 * Function executes all the functionalities one by one and displays all the 
	 * needed contant on to HTML.
	 * @param {string} errorType - This gives which type of error needed to be 
	 * considered when matched peaks are to be considered.
	 * @param {float} errorVal - This gives the user entered threshhold value to 
	 * be considered when calculating matched peaks.
	 * @param {char} removeAcid - This gives the acid up on which the fixed ptm 
	 * mass has to be removed when "X" is clicked at fixed ptms.
	 */
	sequenceOfExecution(errorType,errorVal,removeAcid){
		/**
		 * unbind all the actions previously binded else each action will be 
		 * binded multiple times.
		 */
		$( "#"+Constants.SPECDOWNLOADPNG ).unbind();
		$( "#"+Constants.SPECDOWNLOADSVG ).unbind();
		$( "#"+Constants.SEQDOWNLOADPNG ).unbind();
		$( "#"+Constants.SEQDOWNLOADSVG ).unbind();
		let massShiftList = [];
		let completeShiftList = [];
		let fixedMassShiftList = [];
		let peakDataList = [];
		let massErrorthVal = null;
		let matchedPeakList = [];

		let ppmErrorthVal = null;
		/**
		 * Hide everything when page launched before data is computed
		 */
		$("#"+Constants.SEQSVGID ).hide();
		$("#"+Constants.SVGDOWNLOADID).hide();
		$("#"+Constants.SPECTRUMGRAPHID).hide();
		$("#"+Constants.SPECTRUMDOWNLOADID).hide();
		$("#"+Constants.DIVTABLECONTAINER).hide();
		$("#"+Constants.PEAKCOUNTID).hide();
		
		let sequence = "";
		let massShift_ClassId = "."+ Constants.MASSSHIFT_CLASSID;
		/**
		 * Remove all the mass shift notation on the sequence if exists
		 */
		$(massShift_ClassId).remove();
		/**
		 * Get all the Mass List data entered by the user.
		 */
		let UIHelperObj = new UIHelper();
		let monoMassList = UIHelperObj.getMassListFromUI();
		/**
		 * Get the parsed sequence after removing mass shift list from 
		 * the entered sequence. 
		 * Returns mass list embedded in [] in sequence of user entered sequence.
		 */
		let massShiftObj = new MassShifts();
		[sequence,massShiftList] = massShiftObj.getSequenceFromUI();
		/** 
		* Get fixed mass selected by user
		*/
		fixedMassShiftList = massShiftObj.getFixedMassList(sequence);
		/**
		 * If user removed fixed ptm mass, remove the mass from the list
		 */
		if(removeAcid != "")
		{
			massShiftList = massShiftObj.removeFixedMassList(sequence,massShiftList,removeAcid);
		}
		/**
		 * Get the combined mass shift, easier when combined to plot on the HTML
		 */
		completeShiftList = massShiftObj.getCombinedMassShiftList(massShiftList,fixedMassShiftList);
		/**
		 * Check if mass shift is entered by clicking on the acid. If entered 
		 * consider that mass shift and and append to the current mass shift list
		 */
		if(!$.isEmptyObject(this.onClickMassShift))
		{
			let tempPosition = this.onClickMassShift.position;
			let tempMass = this.onClickMassShift.mass;
			completeShiftList = massShiftObj.appendtoMassShiftList(tempPosition,tempMass,completeShiftList);
		}
		/**
		 * Form sequence with mass shift embedded in []
		 */
		let seqToUI = massShiftObj.formSequence(sequence,completeShiftList);
		/**
		 * Write back to UI
		 */
		massShiftObj.writeSeqToTextBox(seqToUI);
		/**
		 * Get all the peak list data entered by the user 
		 */
		peakDataList = UIHelperObj.getPeakListFromUI();
		let peakListLen = peakDataList.length;
		let monoMassListLen = monoMassList.length;
		let seqln = sequence.length;
		let distributionList = [];
		let matchedUnMatchedPeaks = [];
		/**
		 * Setting masserror threshold value and ppm error threshhold value
		 */
		if(errorType == Constants.MASSERROR) massErrorthVal = errorVal ;
		else ppmErrorthVal = errorVal ;
		
		let calculatePrefixAndSuffixMassObj = new calculatePrefixAndSuffixMass();
		let iontabledataObj = new iontabledata();
		/**
		 * Get all the n terminus ions selected.
		 */
		let n_TerminusList = iontabledataObj.getNterminusCheckedList();
		/**
		 * Get all the matched peaks for all the n terminus fragmented ions selected.
		 */
		n_TerminusList.forEach(function(ion){
			let matchedPeaksObj = new MatchedPeaks();
			let prefixMassList = [];
			let matchedPeaks = [];
			let massShift = parseFloat(ion.mass);
			let ionType = ion.ionType;
			/**
			 * Get claculated prefix mass list
			 */
			prefixMassList = calculatePrefixAndSuffixMassObj
											.getPrefixMassList(sequence,completeShiftList,massShift);
			/**
			 * Get matched peak list
			 */
			matchedPeaks = matchedPeaksObj.getMatchedPeakList(prefixMassList,monoMassList,
												sequence,massErrorthVal,ppmErrorthVal,ionType,"prefix");	
			/**
			 * copy the matched peaks to a new list for each ion selected
			 */									
			let temp_matchedPeaks =  matchedPeaks.map(x => ({...x}));
			matchedPeakList = matchedPeakList.concat(temp_matchedPeaks);
		})
		/**
		 * Get all the c terminus ions selected
		 */
		let c_TerminusList = iontabledataObj.getCterminusCheckedList();
		/**
		 * Get all the matched peaks for all the c terminus fragmented ions selected.
		 */
		c_TerminusList.forEach(function(ion){
			let matchedPeaksObj = new MatchedPeaks();
			let suffixMassList = [];
			let matchedPeaks = [];
			let massShift = parseFloat(ion.mass);
			let ionType = ion.ionType;
			/**
			 * Get claculated suffix mass list
			 */
			suffixMassList = calculatePrefixAndSuffixMassObj
												.getSuffixMassList(sequence,
																		completeShiftList,massShift);
			/**
			 * Get matched peak list
			 */															
			matchedPeaks	= matchedPeaksObj.getMatchedPeakList(suffixMassList,monoMassList,
														sequence,massErrorthVal,ppmErrorthVal,ionType,"suffix");	
			/**
			 * copy the matched peaks to a new list for each ion selected
			 */												
			let temp_matchedPeaks =  matchedPeaks.map(x => ({...x}));
			matchedPeakList = matchedPeakList.concat(temp_matchedPeaks);													
		})
		let matchedPeaksObj = new MatchedPeaks();
		/**
		 * Get combined list of both matched and unmatched peaks to write to table
		 */
		matchedUnMatchedPeaks = matchedPeaksObj.getMatchedAndUnMatchedList(monoMassList,matchedPeakList);
		/**
		 * Do the below function when peak list data is not empty
		 */
		if(peakListLen != 0)
		{
			let matchedPeaksObj = new MatchedPeaks();
			distributionList = matchedPeaksObj.getDistribution(peakDataList,sequence,matchedUnMatchedPeaks);
			/**
			 * Display the graph formed
			 */
			$("#"+Constants.SPECTRUMGRAPHID).show();
			/**
			 * Call addSpectrum function in invokeSpectrum function to draw graph 
			 */
			addSpectrum("spectrum",peakDataList,distributionList,null);
			$("#"+Constants.SPECTRUMDOWNLOADID).show();
		}
		/**
		 * Do the below function when Sequence entered is not empty
		 */
		if(seqln != 0)
		{
			/**
			 *  Draw SVG of Sequence
			 */
			let para = new parameters();
			para = buildSvg(para,sequence,Constants.SEQSVGID,completeShiftList,monoMassList);
			getNumValues(para,sequence,Constants.SEQSVGID);
			annotations(para,matchedPeakList,Constants.SEQSVGID);
			$("#"+Constants.SEQSVGID).show();
			$("#"+Constants.SVGDOWNLOADID).show();
			/**
			 * Get total mass and wite to HTML
			 */
			let totalMass = calculatePrefixAndSuffixMassObj.getTotalSeqMass(sequence,completeShiftList);
			UIHelperObj.setTotalSeqMass(totalMass);
		}	
		/**
		 * Do the below function when mono mass list entered is not empty
		 */
		if(monoMassListLen != 0)
		{
			$("#"+Constants.DIVTABLECONTAINER).show();
			/**
			 * Display All-peaks/matched/non-matched buttons on click of submit
			 */
			$("#peakCount").show();
			/**
			 * Create tabe to display the input mass list data and calculated data
			 */
			UIHelperObj.createMonoMassTable();
			/**
			 * 	Add data to the table
			 */
			UIHelperObj.addMassDataToTable(matchedUnMatchedPeaks);
			/**
			 * function to show the count of matched peaks, un matched peaks and All peaks
			 */
			$("#"+Constants.PEAKCOUNTID).show();
			/**
			 * Bootstrap syntax to keep the table box to 400px height 
			 * and setting properties to the table.
			 */
			this.setBootStarpTableProperties();
			UIHelperObj.showPeakCounts();
		}
		/**
		 * Local function to set the actions on click of download button in HTML
		 */
		this.download();
		let completeListofMasswithMatchedInd = [];
		/**
		 * Code to form the second table with all the prefix masses with matched 
		 * masses for each ion fragment selected.
		 */
		n_TerminusList.forEach(function(ion){
			let matchedPeaksObj = new MatchedPeaks();
			let prefixMassList = new Array();
			let matchedAndUnMatchedList = new Array();
			let matchedAndUnMatchedListObj = {};
			let massShift = parseFloat(ion.mass);
			let ionType = ion.ionType;
			/**
			 * Get calculated prefix mass 
			 */
			prefixMassList = calculatePrefixAndSuffixMassObj
								.getPrefixMassList(sequence,completeShiftList,massShift);
			/**
			 * Get Matched peaks
			 */
			matchedAndUnMatchedList	= matchedPeaksObj.getMatchedAndUnmatchedPrefixAndSuffixMassList(prefixMassList,
																 monoMassList,massErrorthVal,ppmErrorthVal,"prefix");
			matchedAndUnMatchedListObj = {ionFragment:ionType,massList:matchedAndUnMatchedList};
			/**
			 * Complete list of all the peaks for each ion fragment 
			 */													 
			completeListofMasswithMatchedInd.push(matchedAndUnMatchedListObj);													
		})
		c_TerminusList.forEach(function(ion){
			let matchedPeaksObj = new MatchedPeaks();
			let suffixMassList = new Array();
			let matchedAndUnMatchedList = new Array();
			let matchedAndUnMatchedListObj = {};
			let massShift = parseFloat(ion.mass);
			let ionType = ion.ionType;
			/**
			 * Get calculated prefix mass 
			 */
			suffixMassList = calculatePrefixAndSuffixMassObj
								.getSuffixMassList(sequence,completeShiftList,massShift);
			/**
			 * Get Matched peaks
			 */					
			matchedAndUnMatchedList	= matchedPeaksObj.getMatchedAndUnmatchedPrefixAndSuffixMassList(suffixMassList,
																 monoMassList,massErrorthVal,ppmErrorthVal,"suffix");
			matchedAndUnMatchedListObj = {ionFragment:ionType,massList:matchedAndUnMatchedList};
			/**
			 * Complete list of all the peaks for each ion fragment 
			 */	
			completeListofMasswithMatchedInd.push(matchedAndUnMatchedListObj);													
		})
		let getMassTableOfSelectedIonsObj = new GetMassTableOfSelectedIons();
		/**
		 * Disply the table of masses for all the fragmented ions
		 */
		if(completeListofMasswithMatchedInd.length !=0)
		{
			$("#"+Constants.H_FRAGMENTEDTABLE).show();
		}
		getMassTableOfSelectedIonsObj.createTableForSelectedFragmentIons(sequence,completeListofMasswithMatchedInd);
		/**
		 * Set the properties for the table.
		 */
		this.setBootStarpropertiesforFragmentIons();
		$("#divselectediontablecontainer").show();
	}
	/**
	 * Function executes all the functionalities one by one and displays all the 
	 * needed contant on to HTML on change of mass shift on any acid.
	 * @param {string} errorType - This gives which type of error needed to be 
	 * considered when matched peaks are to be considered.
	 * @param {float} errorVal - This gives the user entered threshhold value to 
	 * be considered when calculating matched peaks.
	 */
	onClickSequenceOfExecution(errorType,errorVal){
		/**
		 * unbind all the actions previously binded else each action will be 
		 * binded multiple times.
		 */
		$( "#"+Constants.SPECDOWNLOADPNG ).unbind();
		$( "#"+Constants.SPECDOWNLOADSVG ).unbind();
		$( "#"+Constants.SEQDOWNLOADPNG ).unbind();
		$( "#"+Constants.SEQDOWNLOADSVG ).unbind();
		let massShiftList = [];
		let sequence = "";
		let massErrorthVal = null;
		let ppmErrorthVal = null;
		let matchedPeakList  = []; 
		let monoMassList = [];
		let peakDataList = [];

		let massShift_ClassId = "."+Constants.MASSSHIFT_CLASSID;
		/**
		 * Remove all the mass shift notation on the sequence if exists
		 */
		$(massShift_ClassId).remove();
		/**
		 * Get all the Mass List data entered by the user.
		 */
		let UIHelperObj = new UIHelper();
		monoMassList = UIHelperObj.getMassListFromUI();
		/**
		 * Get the parsed sequence after removing mass shift list from 
		 * the entered sequence. 
		 * Returns mass list embedded in [] in sequence of user entered sequence.
		 */
		let massShiftObj = new MassShifts();
		[sequence,massShiftList] = massShiftObj.getSequenceFromUI();
		/**
		 * Check if mass shift is entered by clicking on the acid. If entered 
		 * consider that mass shift and and append to the current mass shift list
		 */
		if(!$.isEmptyObject(this.onClickMassShift))
		{
			let tempPosition = this.onClickMassShift.position;
			let tempMass = this.onClickMassShift.mass;
			massShiftList = massShiftObj.appendtoMassShiftList(tempPosition,tempMass,massShiftList);
		}
		let seqToUI = massShiftObj.formSequence(sequence,massShiftList);
		massShiftObj.writeSeqToTextBox(seqToUI);
		peakDataList = UIHelperObj.getPeakListFromUI();
		let peakListLen = peakDataList.length;
		let monoMassListLen = monoMassList.length;
		let seqln = sequence.length;
		let matchedUnMatchedPeaks = [];
		
		if(peakListLen != 0 && monoMassListLen != 0 && seqln != 0)
		{
			/**
		 	* Setting masserror threshold value and ppm error threshhold value
		 	*/
			if(errorType == Constants.MASSERROR) massErrorthVal = errorVal ;
			else ppmErrorthVal = errorVal ;
			
			let calculatePrefixAndSuffixMassObj = new calculatePrefixAndSuffixMass();
			let iontabledataObj = new iontabledata();
			let n_TerminusList = iontabledataObj.getNterminusCheckedList();
			/**
			 * Get all the matched peaks for all the n terminus fragmented ions selected.
			 */
			n_TerminusList.forEach(function(ion){
				// Calculate Matched Peaks and Distribution
				let matchedPeaksObj = new MatchedPeaks();
				let prefixMassList = [];
				let matchedPeaks = [];
				let massShift = parseFloat(ion.mass);
				let ionType = ion.ionType;
				/**
				 * Get claculated prefix mass list
				 */
				prefixMassList = calculatePrefixAndSuffixMassObj
												.getPrefixMassList(sequence,massShiftList,massShift);
				/**
				 * Get matched peak list
				 */
				matchedPeaks	= matchedPeaksObj.getMatchedPeakList(prefixMassList,monoMassList,
													sequence,massErrorthVal,ppmErrorthVal,ionType,"prefix");	
				/**
				 * copy the matched peaks to a new list for each ion selected
				 */	
				let temp_matchedPeaks =  matchedPeaks.map(x => ({...x}));
				matchedPeakList = matchedPeakList.concat(temp_matchedPeaks);//concat(matchedPeaks);		
			})
			/**
			 * Get all the c terminus ions selected
			 */
			let c_TerminusList = iontabledataObj.getCterminusCheckedList();
			/**
			 * Get all the matched peaks for all the c terminus fragmented ions selected.
			 */
			c_TerminusList.forEach(function(ion){
				let matchedPeaksObj = new MatchedPeaks();
				let suffixMassList = [];
				let matchedPeaks = [];
				let massShift = parseFloat(ion.mass);
				let ionType = ion.ionType;
				/**
				 * Get claculated suffix mass list
				 */
				suffixMassList = calculatePrefixAndSuffixMassObj
													.getSuffixMassList(sequence,
															massShiftList,massShift);
				/**
				 * Get matched peak list
				 */	
				matchedPeaks	= matchedPeaksObj.getMatchedPeakList(suffixMassList,monoMassList,
															sequence,massErrorthVal,ppmErrorthVal,ionType,"suffix");	
				let temp_matchedPeaks =  matchedPeaks.map(x => ({...x}));
				/**
				 * copy the matched peaks to a new list for each ion selected
				 */		
				matchedPeakList = matchedPeakList.concat(temp_matchedPeaks);														
			})
			let matchedPeaksObj = new MatchedPeaks();
			/**
			 * Get combined list of both matched and unmatched peaks to write to table
			 */
			matchedUnMatchedPeaks = matchedPeaksObj.getMatchedAndUnMatchedList(monoMassList,matchedPeakList);
			/**
			 * Get calculated distribution 
			 */
			let distributionList = matchedPeaksObj.getDistribution(peakDataList,sequence,matchedUnMatchedPeaks);
			/**
			 *  Draw SVG of Sequence
			 */
			let para = new parameters();
			para = buildSvg(para,sequence,Constants.SEQSVGID,massShiftList,monoMassList);
			getNumValues(para,sequence,Constants.SEQSVGID);
			annotations(para,matchedPeakList,Constants.SEQSVGID);
			$("#"+Constants.SEQSVGID).show();
			$("#"+Constants.SVGDOWNLOADID).show();
			/**
			 * Get total mass and wite to HTML
			 */
			let totalMass = calculatePrefixAndSuffixMassObj.getTotalSeqMass(sequence,massShiftList);
			UIHelperObj.setTotalSeqMass(totalMass);
			$("#"+Constants.SPECTRUMGRAPHID).show();
			/** 
			 * Call addSpectrum function in invokeSpectrum function to draw graph 
			 */
			addSpectrum("spectrum",peakDataList,distributionList,null);
			$("#"+Constants.SPECTRUMDOWNLOADID).show();
			/**
			 * Display All-peaks/matched/non-matched buttons on click of submit
			 */
			$("#peakCount").show();
			/**
			 * Create tabe to display the input mass list data and calculated data
			 */
			UIHelperObj.createMonoMassTable();
			/**
			 * Add data to the table
			 */
			UIHelperObj.addMassDataToTable(matchedUnMatchedPeaks);
			/**
			 * function to show the count of matched peaks, un matched peaks and All peaks
			 */
			$("#"+Constants.PEAKCOUNTID).show();
			/**
			 * Bootstrap syntax to keep the table box to 400px height and setting properties to the table
			 */
			this.setBootStarpTableProperties();
			UIHelperObj.showPeakCounts();
			/**
			 * Local function to set the actions on click of download button in HTML
			 */
			this.download();
		}
	}
	/**
	 * Sets the properties of bootstrap table 
	 */
	setBootStarpTableProperties()
	{
		$("#"+Constants.TABLECONTAINERID).DataTable({
			"scrollY": Constants.TABLEHEIGHT,
			"scrollCollapse": true,
			"paging":         false,
			"bSortClasses": false,
			"searching": false,
			"bInfo" : false
		});
	}
	/**
	 * Sets the properties of bootstrap table 
	 */
	setBootStarpropertiesforFragmentIons()
	{
		$("#"+Constants.FRAGMENTIONTABLECONTAINER).DataTable({
			"scrollY": Constants.TABLEHEIGHT,
			"scrollCollapse": true,
			"paging":         false,
			"bSortClasses": false,
			"searching": false,
			"bInfo" : false
		});
	}
	/**
	 * Download function to download the SVG's
	 */
	download()
	{
		/**
		 * On click action to download sequence SVG in .svg format
		 */
		$("#"+Constants.SEQDOWNLOADSVG).click(function(){
			let name = "seq.svg"
			let svg_element = d3.selectAll("#"+Constants.SEQSVGID).node();
			svg2svg(svg_element,name);
		})
		/**
		 * On click action to download sequence SVG in .png format
		 */
		$("#"+Constants.SEQDOWNLOADPNG).click(function(){
			let l_svgContainer = d3.select("#"+Constants.SEQSVGID);
			let svgString = getSVGString(l_svgContainer.node());
			let svg_element = document.getElementById(Constants.SEQSVGID);
			let bBox = svg_element.getBBox();
			let width = bBox.width;
			let height = bBox.height ;
			svgString2Image( svgString, 2*width, 2*height, 'png', save ); 
			function save( dataBlob, filesize ){
				saveAs( dataBlob, 'seq.png' ); 
			}
		})
		// /**
		//  * On click action to download spectrum graph SVG in .svg format
		//  */
		// $("#"+Constants.SPECDOWNLOADSVG).click(function(){
		// 	let name = "spectrum.svg"
		// 	let svg_element = d3.selectAll("#"+Constants.SPECTRUMGRAPHID).node();
		// 	svg2svg(svg_element,name);
		// })
		// /**
		//  * On click action to download spectrum graph PNG in .png format
		//  */
		// $("#"+Constants.SPECDOWNLOADPNG).click(function(){
		// 	let l_svgContainer = d3.select("#"+Constants.SPECTRUMGRAPHID);
		// 	let svgString = getSVGString(l_svgContainer.node());
		// 	let svg_element = document.getElementById(Constants.SPECTRUMGRAPHID);
		// 	let bBox = svg_element.getBBox();
		// 	let width = bBox.width;
		// 	let height = bBox.height ;
		// 	svgString2Image( svgString, 2*width, 2*height, 'png', save ); 
		// 	function save( dataBlob, filesize ){
		// 		saveAs( dataBlob, 'spectrum.png' ); 
		// 	}
		// })
	}	
}