# Source: calculateprefixandsuffixmass.js

    /**
     * Class to calculate prefix and suffix mass
     */
    class CalculatePrefixAndSuffixMass{
    	// Constructor setting the default values of fixedptmlist with mass
    	constructor(){
    		this.fixedPtmList = [{name:"Carbamidomethylation",acid:"C",mass:57.021464},
    								{name:"Carboxymethyl",acid:"C",mass:58.005479}];
    	}
    	/**
    	 * Check for ionType and return the corresponding mass shift value
    	 * @param {String} ionType - String with Corresponding iontype
    	 */
    	getIonTypeMass(ionType){
    		let ionTypeMassList={
    			"A":-27.9949,
    			"A-H2O":-46.0149,
    			"A-NH3":-45.02542,
    			"B":0,
    			"B-H2O":-18.02,
    			"B-NH3":-17.03052,
    			"C":17.0266,
    			"C-H2O":-0.9934,
    			"C-NH3":-0.00392,
    			"X":43.99,
    			"X-H2O":25.97,
    			"X-NH3":26.95948,
    			"Y":18.0106,
    			"Y-H2O":0,
    			"Y-NH3":0.98008,
    			"Z":0.984,
    			"Z-H2O":-17.026,
    			"Z-NH3":-16.04652,
    			"Z0":1.9919,
    			"Z0-H2O":-16.018664,
    			"Z0-NH3":-15.03862
    		};
    		return ionTypeMassList[ionType.toUpperCase()];
    	}
    	/**
    	 * Get the sequence from the prsm_data global variable from data file
    	 * @param {Object} prsm_data - This is a global object from data file which contains all the prsm information
    	 */
    	getSequence(prsm_data){
    		let sequence = [];
    		let firstposition = prsm_data.prsm.annotated_protein.annotation.first_residue_position;
    		let lastposition = prsm_data.prsm.annotated_protein.annotation.last_residue_position;
    		prsm_data.prsm.annotated_protein.annotation.residue.forEach(function(eachrow,i){
    			if(parseInt(eachrow.position) >= parseInt(firstposition)&&
    				parseInt(eachrow.position) <= parseInt(lastposition))
    			{
    				sequence = sequence+eachrow.acid;
    			}
    		})
    	   return sequence;
    	}
    	/**
    	 * Get unknow mass list
    	 */
    	getUnknownMassList()
    	{
    		let unknownMassShiftList = [];
    		let l_prsm = prsm_data;
    		if(l_prsm.prsm.annotated_protein.annotation.hasOwnProperty('mass_shift'))
    		{
    			let mass_shift = l_prsm.prsm.annotated_protein.annotation.mass_shift ;
    				if(Array.isArray(mass_shift))
    				{
    					let len = mass_shift.length;
    					mass_shift.forEach(function(each_mass_shift, i){
    						// Removing -1 as the sequece in inspect elements takes from 0
    						let position = parseInt(each_mass_shift.left_position) ;
    						let mass = parseFloat(each_mass_shift.anno);
    						unknownMassShiftList.push({"position":position,"mass":mass})
    					})
    				}
    				else if(mass_shift.shift_type == "unexpected")
    				{
    					// Removing -1 as the sequece in inspect elements takes from 0
    					let position = parseInt(mass_shift.left_position);
    					let mass = parseFloat(mass_shift.anno);
    					unknownMassShiftList.push({"position":position,"mass":mass})
    				}
    		}
    		return unknownMassShiftList;
    	}
    	/**
    	 * Calculate and generate Prefix mass list
    	 * @param {String} sequence - Contains sequence of the protein
    	 * @param {Array} massShiftList - Contains the Mass shift which are to be added in the corresponding positions
    	 * @param {Float} ionType_massShift - Contains the mass based on the ion Type
    	 */
    	getPrefixMassList(sequence,massShiftList,ionType_massShift){
    		let seqln = sequence.length;
    		let emptyMassList = [] ;
    		massShiftList = massShiftList.slice();
    		massShiftList = this.getFixedPTMMassList(massShiftList,prsm_data.prsm);
    		if(seqln != 0)
    		{
    			let prefixMassList = new Array(seqln);
    			let shiftListln = massShiftList.length;
    			for(let i=0;i<seqln;i++)
    			{
    				// Get Calculated AminoAcidDistribution from aminoAcidDistributuion.js
    				// evaluate the return value for the case when the user enters wrong character by mistake
    				let AcidMass;

    				try{
    					AcidMass = getAminoAcidDistribution(sequence[i])[0].mass;

    					if(i == 0)
    					{
    						// Add 1 to i as the seq start from 0 but the peak id starts from 1
    						if(shiftListln != 0)
    						{
    							AcidMass = this.addMassShift(i,massShiftList,AcidMass);
    						}
    						let tempObj = {acid:sequence[i], position:(i+1),mass:AcidMass} ;
    						prefixMassList[i] = tempObj;
    					}
    					else
    					{
    						let mass = prefixMassList[i-1].mass + AcidMass;
    						if(shiftListln != 0)
    						{
    							mass = this.addMassShift(i,massShiftList,mass);
    						}
    						// Add 1 to i as the seq start from 0 but the peak id starts from 1
    						let tempObj = {acid:sequence[i],position:(i+1),mass:mass};
    						prefixMassList[i] = tempObj;
    					}
    				}
    				catch(error){
    					// invalid character entered for protein sequence
    					// window.alert("Error! Invalid amino acid in the sequence.")
    					$('#errorAlertModal').modal('show');
    					break;
    				}
    			}
    			// Adding Mass Shift based on selection of Ion
    			// let utilFunctionsObj = new utilFunctions();
    			// let ionMassShiftVal = utilFunctionsObj.getNTerminusMassShiftVal();
    			if(ionType_massShift != 0)
    			{
    				for(let j=0;j<seqln;j++)
    				{
    					prefixMassList[j].mass = prefixMassList[j].mass + ionType_massShift;
    				}
    			}
    			return prefixMassList;
    		}
    		return emptyMassList;
    	}
    	/**
     	* Generate Suffix mass list
    	* @param {String} sequence - Contains sequence of the protein
    	* @param {Array} massShiftList - Contains the Mass shift which are to be added in the corresponding positions
    	* @param {Float} ionType_massShift - Contains the mass based on the ion Type
    	*/
    	getSuffixMassList(sequence,massShiftList,ionType_massShift){
    		let seqln = sequence.length;
    		let emptyMassList = [];
    		// As the elements starts from 0
    		if(seqln != 0)
    		{
    			let temp_seqln = seqln-1;
    			massShiftList = this.getFixedPTMMassList(massShiftList,prsm_data.prsm);;
    			let shiftListln = massShiftList.length;
    			let suffixMassList = new Array(seqln);
    			for(let i=temp_seqln ; i >= 0 ; i--)
    			{
    				// Get Calculated AminoAcidDistribution from aminoAcidDistributuion.js
    				let AcidMass = getAminoAcidDistribution(sequence[i])[0].mass;
    				if(i == temp_seqln)
    				{
    					// Add 1 to i as the seq start from 0 but the peak id starts from 1
    					let position = temp_seqln - i;
    					// Adding water mass for suffix, indirectly this will add water mass to all the masses
    					let mass = AcidMass;//
    					if(suffixMassList != 0)
    					{
    						mass = this.addMassShift(i,massShiftList,mass)
    					}
    					let tempObj = {acid:sequence[i],position:(i+1),mass:mass};
    					//let tempObj = {position:(position+1),mass:mass} ;
    					suffixMassList[position] = tempObj;
    				}
    				else
    				{
    					//Don't add water here
    					let position = temp_seqln - i;
    					let mass = suffixMassList[(position-1)].mass + AcidMass;
    					if(suffixMassList != 0)
    					{
    						mass = this.addMassShift(i,massShiftList,mass)
    					}
    					// Add 1 to i as the seq start from 0 but the peak id starts from 1
    					let tempObj = {acid:sequence[i],position:(i+1),mass:mass};
    					//let tempObj = {position:(position+1),mass:mass};
    					suffixMassList[position] = tempObj;
    				}
    			}
    			if(ionType_massShift != 0)
    			{
    				for(let j=0;j<seqln;j++)
    				{
    					suffixMassList[j].mass = suffixMassList[j].mass + ionType_massShift  ;
    				}
    			}
    			return suffixMassList;
    		}
    		return emptyMassList ;
    	}
    	/**
    	 * Add mass shifts to massShift list
    	 * @param {int} position - position of the mass list
    	 * @param {Array} massShiftList - Contains the list of all the mass shifts
    	 * @param {Float} mass - Mass shift to be added to the list
    	 */
    	addMassShift(position,massShiftList,mass){
    		let len = massShiftList.length;
    		for(let i=0;i<len ; i++)
    		{
    			if(position == massShiftList[i].position)
    			{
    				mass = mass + massShiftList[i].mass ;
    				return mass ;
    			}
    		}
    		return mass ;
    	}
    	/**
    	 * Get all the Fixed Ptms and add the corresponding mass shits to mass shift list
    	 * @param {Array} massShiftList - Contains all the mass shifts
    	 * @param {Object} prsm - Contains the data of the prsm(Attribute inside prsm_data global variable from data file)
    	 */
    	getFixedPTMMassList(massShiftList,prsm){
    		let occurence_list = [] ;
    		if(prsm.annotated_protein.annotation.hasOwnProperty("ptm") )
    		{
    			if(Array.isArray(prsm.annotated_protein.annotation.ptm))
    			{
    				prsm.annotated_protein.annotation.ptm.forEach(function(ptm,index){
    					if(ptm.ptm_type == "Fixed")
    					{
    						let mass = this.getMassofFixedPtm(ptm.ptm.abbreviation);

    						if(ptm.hasOwnProperty("occurence"))
    						{
    							if(Array.isArray(ptm.occurence))
    							{
    								ptm.occurence.forEach(function(occurence,i){
    									let tempObj = {"position":occurence.left_pos,"mass":mass}
    									massShiftList.push(tempObj);
    								});
    							}
    							else
    							{
    								let tempObj = {"position":occurence.left_pos,"mass":mass}
    								massShiftList.push(tempObj);
    							}
    						}
    					}
    				})
    			}
    			else
    			{
    				if(prsm.annotated_protein.annotation.ptm.hasOwnProperty("occurence"))
    				{
    					if(prsm.annotated_protein.annotation.ptm.ptm_type == "Fixed")
    					{
    						let mass = this.getMassofFixedPtm(prsm.annotated_protein.annotation.ptm.ptm.abbreviation);
    						if(Array.isArray(prsm.annotated_protein.annotation.ptm.occurence))
    						{
    							prsm.annotated_protein.annotation.ptm.occurence.forEach(function(occurence,i){
    								let tempObj = {"position":occurence.left_pos,"mass":mass}
    								massShiftList.push(tempObj);
    							});
    						}
    						else
    						{
    							let tempObj = {"position":prsm.annotated_protein.annotation.ptm.occurence.left_pos,"mass":mass}
    							massShiftList.push(tempObj);
    						}
    					}
    				}
    			}
    		}
    		return massShiftList ;
    	}
    	/**
    	 * Returns Fixed Mass for certain abbrivation
    	 * @param {String} abbrevation - Contains abbrevation to get corresponding fixed mass
    	 */
    	getMassofFixedPtm(abbrevation)
    	{
    		let len = this.fixedPtmList.length;
    		for(let i=0;i<len;i++)
    		{
    			if(this.fixedPtmList[i].name == abbrevation)
    			{
    				return this.fixedPtmList[i].mass;
    			}
    		}
    	}
    }