# Source: prsmtohtml.js

    /**
     * Create title and navigation urls to "all proteins","protein" and "proteoform" of the prsm
     * @param {String} folderpath - provides folder path to the data and helps in building urls
     */
    function BuildUrl(folderpath)
    {
    	document.title = "Protein-Spectrum-Match for Spectrum #"+prsm_data.prsm.ms.ms_header.ids;
    	let l_allproteins_url = "proteins.html?folder="+folderpath;
    	document.getElementById("allprotein_url").href = l_allproteins_url;
    	document.getElementById("allprotein_url_end").href = l_allproteins_url;
    	let l_protein_URL = prsm_data.prsm.annotated_protein.sequence_name + " " + prsm_data.prsm.annotated_protein.sequence_description;
    	document.getElementById("protien_url").innerHTML = l_protein_URL;
    	document.getElementById("protien_url").href = "protein.html?folder="+folderpath+"&protein_Id="+prsm_data.prsm.annotated_protein.sequence_id;
    	document.getElementById("protien_url_end").innerHTML = l_protein_URL;
    	document.getElementById("protien_url_end").href = "protein.html?folder="+folderpath+"&protein_Id="+prsm_data.prsm.annotated_protein.sequence_id;
    	let l_protroform_URL = "Proteoform #"+prsm_data.prsm.annotated_protein.proteoform_id ;
    	document.getElementById("proteoform_url").innerHTML = l_protroform_URL;
    	document.getElementById("proteoform_url").href = "proteoform.html?folder="+folderpath+"&proteoform_Id="+prsm_data.prsm.annotated_protein.proteoform_id;
    	document.getElementById("proteoform_url_end").innerHTML = l_protroform_URL;
    	document.getElementById("proteoform_url_end").href ="proteoform.html?folder="+folderpath+"&proteoform_Id="+prsm_data.prsm.annotated_protein.proteoform_id;
    	document.getElementById("Protein-Spectrum-Match-Id-SpecId").innerHTML ="Protein-Spectrum-Match #"+prsm_data.prsm.prsm_id+" for Spectrum #" + prsm_data.prsm.ms.ms_header.ids;
    }
    /**
     * Get the data of the prsm from global data variable prsm_data.
     * Build the data into html to show the information about the prsm
     */
    function loadDatafromJson2Html(){
    	document.getElementById("File_name").innerHTML = prsm_data.prsm.ms.ms_header.spectrum_file_name;
    	document.getElementById("PrSM_ID").innerHTML = prsm_data.prsm.prsm_id;
    	document.getElementById("Scan").innerHTML = prsm_data.prsm.ms.ms_header.scans;
    	document.getElementById("Precursor_charge").innerHTML = prsm_data.prsm.ms.ms_header.precursor_charge;
    	document.getElementById("precursormz").innerHTML = prsm_data.prsm.ms.ms_header.precursor_mz ;
    	document.getElementById("Precursor_mass").innerHTML = prsm_data.prsm.ms.ms_header.precursor_mono_mass;
    	document.getElementById("Proteoform_mass").innerHTML = prsm_data.prsm.annotated_protein.proteoform_mass;
    	document.getElementById("matched_peaks").innerHTML = prsm_data.prsm.matched_peak_number;
    	document.getElementById("matched_fragment_ions").innerHTML = prsm_data.prsm.matched_fragment_number;
    	document.getElementById("unexpected_modifications").innerHTML = prsm_data.prsm.annotated_protein.unexpected_shift_number;
    	document.getElementById("E_value").innerHTML = prsm_data.prsm.e_value;
    	document.getElementById("P_value").innerHTML = prsm_data.prsm.p_value;
    	document.getElementById("Q_value").innerHTML = prsm_data.prsm.fdr;
    }
    /**
     * Build the monomass table with all the data from the peak variable of the prsm_data
     * Provide a unique class name to the m/z values to provide on click action to xoom the
     * spectrum graph to that position
     */
    function createTableElements(){
    	var table = document.getElementById('spectrum');
    	var tbdy = document.createElement('tbody');
    	var ionArray = []; //contains the ion types used in the data
    	let l_scans = prsm_data.prsm.ms.ms_header.scans.split(" ") ;
    	let l_specIds = prsm_data.prsm.ms.ms_header.ids.split(" ") ;
    	let l_matched_peak_count = 0;
    	prsm_data.prsm.ms.peaks.peak.forEach(function(peak,i){
    		/*	Check if peak contain matched_ions_num attribute	*/

    		//for each peak, get the ion type and store it in ionArray to determine which ion type to be checked in Inspect
    		if (parseInt(peak.matched_ions_num)>0){
    			let ion = peak.matched_ions.matched_ion.ion_type;
    			if (ionArray.length < 1){
    				ionArray.push(ion);
    			}
    			else if (ionArray.indexOf(ion) < 0) {
    				ionArray.push(ion);
    			}
    		}

    		if(peak.hasOwnProperty('matched_ions_num') && parseInt(peak.matched_ions_num)>1)
    		{
    			peak.matched_ions.matched_ion.forEach(function(matched_ion,i){
    				peak.matched_ions.matched_ion = matched_ion ;
    				loop_matched_ions(peak,i) ;
    			})
    		}
    		else
    		{
    			loop_matched_ions(peak,i) ;
    		}
    	})

    	//after looping through the prsm files, store the ion type data to local storage
    	window.localStorage.setItem('ionType', ionArray);
    	/**
    	 * Inner function to create a rows and columns for monomass table
    	 * @param {object} peak - contains information of each peak
    	 * @param {int} i - index of the peak
    	 */
    	function loop_matched_ions(peak,i){
    		/*	Create row for each peak value object in the table	*/
    		var tr = document.createElement('tr');
    		id = peak.spec_id+"peak"+peak.peak_id;
    		let l_scan;
    		if((parseInt(peak.peak_id) + 1)%2 == 0)
    		{
    			// class name helps to get unmatched peaks when clicking unmatched peaks
    			l_class = "unmatched_peak even";
    		}
    		else
    		{
    			// class name helps to get unmatched peaks when clicking unmatched peaks
    			l_class = "unmatched_peak odd";
    		}
    		if(peak.hasOwnProperty('matched_ions_num'))
    		{
    			id = id + peak.matched_ions.matched_ion.ion_type;
    			if((parseInt(peak.peak_id) + 1)%2 == 0)
    			{
    				// class name helps to get matched peaks when clicking matched peaks
    				l_class = "matched_peak even";
    			}
    			else
    			{
    				// class name helps to get matched peaks when clicking matched peaks
    				l_class = "matched_peak odd";
    			}
    			l_matched_peak_count++;
    			//	create a name for each row
    			tr.setAttribute("name",peak.matched_ions.matched_ion.ion_position);
    		}
    		//	Set "id","class name" and "role" for each row
    		tr.setAttribute("id", id);
    		tr.setAttribute("class",l_class);
    		tr.setAttribute("role","row");
    		for(let i = 0;i<11;i++){
    			var td = document.createElement('td');
    			td.setAttribute("align","center");
    			if(i == 0)
    			{
    				if(peak.spec_id == l_specIds[0]) l_scan = l_scans[0];
    				else l_scan = l_scans[1];
    				td.setAttribute("class","row_scanIds");
    				td.innerHTML = l_scan ;
    			}
    			if(i == 1)
    			{
    				td.innerHTML = parseInt(peak.peak_id) + 1 ;
    				td.setAttribute("class","row_peakNum");
    			}
    			if(i == 2)
    			{
    				td.innerHTML = peak.monoisotopic_mass;
    				td.setAttribute("class","row_monoMass");
    			}
    			if(i == 3)
    			{
    				//	provide link to click on m/z value to view spectrum
    				let a = document.createElement('a');
    				a.href="#!"
    				a.className = "peakRows"
    				a.innerHTML = peak.monoisotopic_mz;
    				td.appendChild(a);
    			}
    			if(i == 4)
    			{
    				td.innerHTML = peak.intensity;
    				td.setAttribute("class","row_intensity");
    			}
    			if(i == 5)
    			{
    				td.innerHTML = peak.charge;
    				td.setAttribute("class","row_charge");
    			}
    			if(peak.hasOwnProperty('matched_ions_num'))
    			{
    				if(i == 6)
    				{
    					td.innerHTML = peak.matched_ions.matched_ion.theoretical_mass;
    				}
    				if(i == 7)
    				{
    					td.innerHTML = peak.matched_ions.matched_ion.ion_type+peak.matched_ions.matched_ion.ion_display_position;
    				}
    				if(i == 8)
    				{
    					td.innerHTML = peak.matched_ions.matched_ion.ion_position;
    				}
    				if(i == 9)
    				{
    					td.innerHTML = peak.matched_ions.matched_ion.mass_error;
    				}
    				if(i == 10)
    				{
    					td.innerHTML = peak.matched_ions.matched_ion.ppm;
    				}
    			}
    			tr.appendChild(td);
    		}
    		tbdy.appendChild(tr);
    	}
    	let l_All_Peaks = prsm_data.prsm.ms.peaks.peak.length;
    	let l_not_matched_peak_count = l_All_Peaks - l_matched_peak_count;
    	document.getElementById("all_peak_count").innerHTML = "All peaks (" + l_All_Peaks + ")" ;
    	document.getElementById("matched_peak_count").innerHTML = "Matched peaks (" + l_matched_peak_count + ")" ;
    	document.getElementById("not_matched_peak_count").innerHTML = "Not Matched peaks (" + l_not_matched_peak_count + ")" ;

    	table.appendChild(tbdy);

    }
    /**
     * Get occurence of "Variable" and "Fixed", convert the data to HTML
     * @param {object} prsm - prsm is the data attribute inside global prsm_data variable
     */
    function occurence_ptm(prsm)
    {
    	let variable_ptm = "";
    	let fixed_ptm = "" ;
    	// Check if annotation has ptm attribute inside it
    	if(prsm.annotated_protein.annotation.hasOwnProperty('ptm'))
    	{
    		let ptm = prsm.annotated_protein.annotation.ptm ;
    		// Check if ptm attribute is an array
    		if(Array.isArray(ptm))
    		{
    			ptm.forEach(function(ptm, index){
    				// Check if there exist variable or fixed ptms
    				if(ptm.ptm_type == "Variable")
    				{
    					variable_ptm_raw = getVariablePtm(ptm).replace("[", " [");
    					variable_ptm = variable_ptm + variable_ptm_raw + "] " ;
    				}
    				if(ptm.ptm_type == "Fixed")
    				{
    					fixed_ptm_raw = getFixedPtm(ptm).replace("[", " [");
    					fixed_ptm = fixed_ptm + fixed_ptm_raw + "] " ;
    				}
    			})
    		}
    		else
    		{
    			// Check if there exist variable or fixed ptms
    			if(ptm.ptm_type == "Variable")
    			{
    				variable_ptm_raw = getVariablePtm(ptm).replace("[", " [");
    				variable_ptm = variable_ptm + variable_ptm_raw  + "]" ;
    			}
    			if(ptm.ptm_type == "Fixed")
    			{
    				fixed_ptm_raw = getFixedPtm(ptm).replace("[", " [");
    				fixed_ptm = fixed_ptm + fixed_ptm_raw + "]" ;
    			}
    		}
    	}
    	// Add the information of fixed ptms to html at id - ptm_abbreviation
    	if(fixed_ptm != "")
    	{
    		let div = document.getElementById("ptm_abbreviation") ;
    		let text1 = document.createElement("text");
    		let text2 = document.createElement("text");
    		text1.innerHTML = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"+"Fixed PTMs: ";
    		text2.innerHTML = fixed_ptm ;
    		text2.target = "_blank";
    		text2.style = "color:red" ;
    		div.appendChild(text1);
    		div.appendChild(text2);
    	}
    	// Add the information of varibale ptms to html at id - ptm_abbreviation
    	if(variable_ptm != "")
    	{
    		let div = document.getElementById("ptm_abbreviation") ;
    		let text1 = document.createElement("text");
    		let text2 = document.createElement("text");
    		text1.innerHTML = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"+"Variable PTMs: ";
    		text2.innerHTML = variable_ptm ;
    		text2.target = "_blank";
    		text2.style = "color:red" ;
    		div.appendChild(text1);
    		div.appendChild(text2);
    	}
    }
    /**
     * Get the information about all the unknown ptms
     * @param {object} prsm - prsm is the data attribute inside global prsm_data variable
     */
    function getUnknownPtms(prsm)
    {
    	let data = " [";
    	// Check if annotation attribute has mass_shift attribute inside it
    	if(prsm.annotated_protein.annotation.hasOwnProperty('mass_shift'))
    	{
    		let mass_shift = prsm.annotated_protein.annotation.mass_shift ;
    		let UnknownExist =  false;
    			if(Array.isArray(mass_shift))
    			{
    				let len = mass_shift.length;
    				mass_shift.forEach(function(each_mass_shift, i){
    					// Check for unexpected mass shifts
    					if(each_mass_shift.shift_type == "unexpected")
    					{
    						UnknownExist = true;
    						if(i != len-1)
    						{
    							data = data + each_mass_shift.anno + "," ;
    						}
    						else{
    							data = data + each_mass_shift.anno + "]" ;
    						}
    					}
    				})
    			}
    			else if(mass_shift.shift_type == "unexpected")
    			{
    				UnknownExist = true;
    				data = data + mass_shift.anno + "]" ;
    			}
    			// If unexpected modifications exist add them to html at id - ptm_unexpectedmodifications
    			if(UnknownExist)
    			{
    				let val = "Unknown" + data;
    				document.getElementById("ptm_unexpectedmodification").style.display = "block";
    				let div = document.getElementById("ptm_unexpectedmodification") ;
    				let text1 = document.createElement("text");
    				let text2 = document.createElement("text");
    				text1.innerHTML = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"+"Unexpected modifications: "; // Adding space using &nbsp;
    				text2.innerHTML = val ;
    				text2.target = "_blank";
    				text2.style = "color:red" ;
    				div.appendChild(text1);
    				div.appendChild(text2);
    			}
    	}

    }
    /**
     * Get all the variable ptms
     * @param {object} prsm - prsm is the data attribute inside global prsm_data variable
     */
    function getVariablePtm(ptm)
    {
    	let variable_ptm = "[" ;
    	let abbrevation = ptm.ptm.abbreviation ;
    	if(Array.isArray(ptm.occurence))
    	{
    		ptm.occurence.forEach(function(occurence,i){
          let left = parseInt(occurence.left_pos) + 1;
    			variable_ptm = variable_ptm + left + "-" + occurence.right_pos ;
    			if(ptm.occurence.length-1 > i )
    			{
    				variable_ptm = variable_ptm + ";" ;
    			}
    		})
    	}
    	else
    	{
        let left = parseInt(ptm.occurence.left_pos) + 1;
    		variable_ptm = variable_ptm + left + "-" + ptm.occurence.right_pos ;
    	}
    	variable_ptm = ptm.ptm.abbreviation + variable_ptm ;
    	return variable_ptm ;
    }
    /**
     * Get all the "Fixed" ptms
     * @param {object} prsm - prsm is the data attribute inside global prsm_data variable
     */
    function getFixedPtm(ptm)
    {
    	let fixed_ptm = "[" ;
    	let abbrevation = ptm.ptm.abbreviation ;
    	if(Array.isArray(ptm.occurence))
    	{
    		ptm.occurence.forEach(function(occurence,i){
          	fixed_ptm = fixed_ptm + occurence.right_pos;
    			if(ptm.occurence.length-1 > i )
    			{
    				fixed_ptm = fixed_ptm + ";" ;
    			}
    		})
    	}
    	else
    	{
        	fixed_ptm = fixed_ptm + ptm.occurence.right_pos;
    	}
    	fixed_ptm = ptm.ptm.abbreviation + fixed_ptm ;
    	return fixed_ptm ;
    }
    /**
     * Create buttons to save the svg as png/svg and to redraw the svg with given dimensions
     * @param {object} para - contains the parameters to draw the sequence SVG
     * @param {object} prsm - prsm is the data attribute inside global prsm_data variable
     * @param {String} id - id from the html at which the svg needs to be redraw (Here it is from the modal block)
     */
    function buttonsAndAlerts(para,prsm,id)
    {
    	let x,y;
    	//	Id of the pop_up svg
    	id = "l_popup_svg" ;
    	//	On click action to get pop_up window
    	d3.select('#saveImage').on("click",function(){
    		d3.selectAll(".l_popup_svg_g").remove();
    		para = new parameters();
    		let prsm = prsm_data.prsm ;
    		[para,id] = buildSvg(para,prsm,id);
    		//	Get the amount of skipped acid and write the amount
    		// 	of skipped acid at the start and end of the sequence
    		skippedAcidNotification(para,prsm,id) ;
    		if(para.show_num)
    		{
    			// Get the numerical count at the start enad end of
    			// each row of sequence
    			getNumValues(para,prsm,id);
    		}
    		//	Determine the start and end position of the sequence
    		drawAnnoOfStartEndPosition(para,prsm,id);
    		//	Draw Annotations
    		annotations(para,prsm,id);
    		//	Get the position of the fixed ptms and color them to red
    		addColorToFixedPtms(para,prsm,id);
    		//	Color the background of occurence of mass shift
    		massShiftBackgroundColor(para,prsm,id);
    		//	set the dimensions of popup svg to default values
    		document.getElementById("row-size").value = para.row_length ;
    		document.getElementById("letter-width").value = para.letter_width ;
    		document.getElementById("row-height").value = para.row_height ;
    		document.getElementById("block-width").value = para.gap_width ;
    		document.getElementById("num-width").value = para.numerical_width ;
    		document.getElementsByName("show-num")[0].checked = para.show_num ;
    		document.getElementsByName("show-skipped-lines")[0].checked = para.show_skipped_lines ;

    		// Allows to drag the pop up windows
    		$("#myModal").draggable({
    			appendTo: "body"
    			});
    		});

    		//	Download the svg as ".svg" image
    		d3.select('#download_SVG').on("click",function(){
    				x = d3.event.pageX;
    				y = d3.event.pageY;
    				popupnamewindow("svg",id,x,y);
    			});
    		//	Download svg as PNG Image
    		d3.select('#download_PNG').on("click", function(){
    			x = d3.event.pageX;
    			y = d3.event.pageY;
    			popupnamewindow("png",id,x,y);
    		})	;

    		d3.select('#image_help').on("click",function(){
    			$("#helpModal").draggable({
    			appendTo: "#myModal"
    			});
    	});

    	//	On Click action to resize the svg with user dimensions
    	d3.select('#resize').on("click", function(){
    		d3.selectAll("."+id+"_g").remove();
    		//	Get dimension parameters of svg
    		var para = new parameters() ;
    		para.row_length = parseInt(document.getElementById("row-size").value);
    		para.letter_width = parseInt(document.getElementById("letter-width").value) ;
    		para.row_height = parseInt(document.getElementById("row-height").value) ;
    		para.gap_width = parseInt(document.getElementById("block-width").value) ;
    		para.numerical_width = parseInt(document.getElementById("num-width").value) ;

    		//	Check whether show numbers is checked
    		if(document.getElementsByName("show-num")[0].checked)
    		{
    			para.show_num = true ;
    		}
    		else
    		{
    			//	Reduce the left and right margins when numbers are
    			// 	no needed at start and end of each row in svg
    			para.show_num = false ;
    			para.left_margin = 20;
    			para.right_margin = 20;
    		}
    		//	Check to show skipped lines
    		if(document.getElementsByName("show-skipped-lines")[0].checked)
    		{
    			para.show_skipped_lines = true ;
    		}
    		else
    		{
    			para.show_skipped_lines = false ;
    		}
    		//	Redraw the svg with new dimension parameters
    		prsm = prsm_data.prsm ;
    		[para,id] = buildSvg(para,prsm,id);
    		//	Get the amount of skipped acid and write the amount
    		//	of skipped acid at the start and end of the sequence
    		skippedAcidNotification(para,prsm,id) ;
    		if(para.show_num)
    		{
    			// Get the numerical count at the start and end of
    			// each row of sequence
    			getNumValues(para,prsm,id);
    		}
    		//	Determine the start and end position of the sequence
    		drawAnnoOfStartEndPosition(para,prsm,id) ;
    		//	Draw Annotations
    		annotations(para,prsm,id);
    		//	Get the position of the fixed ptms and color them to red
    		addColorToFixedPtms(para,prsm,id);
    		//	Color the background of occurence of mass shift
    		massShiftBackgroundColor(para,prsm,id);
    	});
    }
    /**
     * Function to produce a pop up window to provide name and set name to
     * the image while downloading the image of Graph SVG and Sequence SVG
     * @param {String} type - Provides if the image is downloaded as svg or png
     * @param {String} id - Provides the id of the svg to be downloaded
     * @param {Float} x - Provides coordinate on where to show a tooltip block to enter name of the image to be downloaded
     * @param {Float} y - Provides coordinate on where to show a tooltip block to enter name of the image to be downloaded
     */
    function popupnamewindow(type,id,x,y){
    	d3.selectAll("#tooltip_imagename").remove() ;
    	var div = d3.select("body").append("div")
    	.attr("class", "tooltip")
    	.attr("id","tooltip_imagename")
    	.style("opacity", 1);

    	// Provides a tooltip to enter a name for the image to be downloaded
    	div.transition()
    	.duration(200)
    	.style("opacity", .9);
    	div.html(
    			'<input type="text" placeholder="Image Name" id="imagename" />'+
    			'<button id="saveimage" style = "none" type="button">save</button>'
    			)
    	.style("left", (x - 30) + "px")  // x Coordinate of the position of the tooltip
    	.style("top", (y - 60) + "px")	// y Coordinate of the position of the tooltip
    	.attr("box-sizing","border")
    	.attr("display","inline-block")
    	.attr("min-width","1.5em")
    	.attr("padding","2px")
    	.attr("margin-left","0px")
    	.attr("text-align","center")
    	.attr("text-decoration","none")
    	.attr("border","1px solid #111111")
    	.attr("background-color","white");

    	// On click action to save the image on click of download button
    	$("#saveimage").click(function(){
    		let imagename = $("#imagename").val();
    		if( imagename == null || imagename == "")
    		{
    			imagename = "spectrum";
    		}
    		// Check if the image needs to be downloaded as svg
    		if(type == "svg"){
    			d3.selectAll("#tooltip_imagename").remove() ;
    			let svg_element = d3.selectAll("#"+id).node();
    			svg2svg(svg_element,imagename);
    		}
    		// Check if the image needs to be downloaded as png
    		if(type == "png"){
    			d3.selectAll("#tooltip_imagename").remove() ;
    			let l_svgContainer = d3.select("#"+id);
    			let svgString = getSVGString(l_svgContainer.node());
    			let specParams =  new SpectrumParameters();
    			let width = specParams.svgWidth;
    			let height = specParams.svgHeight ;
    			svgString2Image( svgString, 2*width, 2*height, 'png', save );
    			function save( dataBlob, filesize ){
    				saveAs( dataBlob, imagename );
    			}
    		}
    	})
    }