# Source: spectrumparameters.js

    /**	@function SpectrumParameters
     * @description Get data from global variable spectrum_data and utilities to manupulate
     * the data
     */
    SpectrumParameters = function() {
      /* Attributes to decide what to be shown on the graph */

      // this contain the showCircles,showIons,isAddbgColor,showSequence
      this.graphFeatures = {};

      /*assign the mono m/z value when clicked on mono m/z*/
      this.minMz ;
      this.maxMz ;
      this.centerMz ;
      this.xScale = 0;
      this.yScale;

      this.dataMinMz ;
      this.dataMaxMz ;
      this.dataMaxInte ;
      this.dataMinInte;
      this.maxInte;
      this.fixedShiftRatio = 1.000684;

      this.svgWidth = 910;
      this.svgHeight = 220;
    	/*	Set padding values to the svg------------------*/
    	this.padding = {left:70, right:20, head:10, bottom:50};
    	this.specWidth = this.svgWidth - this.padding.left - this.padding.right;
      this.specHeight = this.svgHeight - this.padding.head - this.padding.bottom;
      this.labelAdjustVal = 15;

      this.specScale = 1.0;
      this.specX = 0;

      /*	Colors for the envelope circles	*/
      this.spectrumColorArray = ["red","orange","blue","green"];
      /*	Radius factor and setting min and max radius	*/
      this.mzRadius = 0.05;
      this.minRadius = 2;
      this.maxRadius = 5;

      this.tickWidthList = [10000,8000,6000,5000,4000,3000,2000,1000,800,700,600,500,450,400,350,300,250,200,150,100,50,20,10,5,3,2,1,0.5,0.2,0.1,0.05,0.01,0.005,0.001,0.0005,0.0001,0.00005,0.00001,0.000005,0.000001];
      this.tickHeightList = [50,40,30,25,20,15,10,5,3,2,1,0.5,0.2,0.1,0.05,0.01,0.005,0.001];
      this.onClickMassAdjacentRange = 3;
      this.mouseOverPadding = {head:20,middle:14};

    /* number of ticks on x and y axis*/
    	this.xTicks = 10;
      this.yTicks = 5 ;
      //Height/size of the tick
      this.ticklength = 7 ;
      this.errorYticks = 2;

      //Limiting the peaks and envelopes to 500
      this.ranges=[0,0,0,0,0,0];
      this.limits=[0,0,0,0,0];
      this.bufferPercent = 0.01; //10 percent

      /**
       * @function initScale
       * @description Initializing the spectrum Parameters with the data from the peak list and envilopelist.
       * initializing xScale, yScale.
       */
      this.initScale = function(currminMz, currmaxMz, dataMaxInte,dataMinInte,minMzData,maxMzData,currentMaxIntensity) {
        this.dataMinMz = minMzData;
        this.dataMaxMz = maxMzData + (0.10 * maxMzData);
        this.minMz = currminMz;
        this.maxMz = currmaxMz;
        if(currminMz == minMzData && currmaxMz == maxMzData)
        {
          this.minMz = 0;
          this.maxMz = this.maxMz + (0.10*this.maxMz);
        }
        this.centerMz = (this.minMz + this.maxMz)/2.0;
        this.xScale = this.specWidth/(this.maxMz - this.minMz);

        // add 1/4th of max intensity to keep the max point at 3/4 of the y axis*
        this.dataMaxInte = dataMaxInte + 0.25*dataMaxInte;
        this.dataMinInte = dataMinInte ;
        this.maxInte = currentMaxIntensity;
        // add 1/4th of max intensity to keep the max point at 3/4 of the y axisd
        // dataMaxInte = dataMaxInte + 0.25*dataMaxInte ;
        currentMaxIntensity = currentMaxIntensity + 0.25*currentMaxIntensity ;
          this.yScale = this.specHeight/currentMaxIntensity;
        this.setLimits();
      }
      // this.setColorToEnvelops = function(envelopes){
      //     envelopes.sort(function(x,y){
      //       return d3.ascending(x.env_peaks[0].mz, y.env_peaks[0].mz);
      //     })
      //     let colorListsize = this.spectrumColorArray.length;
      //     let i = envelopes.length ;
      //     while(i--)
      //     {
      //       envelopes[i].color = this.spectrumColorArray[i%colorListsize];
      //     }
      //     return envelopes;
      // }
      /**
       * @function getPeakXPos
       * @description Function provides the x coordinate for the mass
       */
      this.getPeakXPos = function (mz) {
        let peakX = (mz - this.minMz) * this.xScale + this.padding.left;
        return peakX;
      }
      /**
       * @function getPeakYPos
       * @description Function provides the y coordinate for the intensity
       */
      this.getPeakYPos = function (intensity) {
        let peakY = this.svgHeight - intensity * this.yScale - this.padding.bottom;
        return peakY;
      }
      /**
       * @function getErrorYPos
       * @description Function provides the y coordinate for the error val on the error plot
       */
      this.getErrorYPos = function(erroVal){
        let yErrorScale = this.graphFeatures.heightForErrorPlot/(this.graphFeatures.errorThreshHoldVal*2);// Multiply with 2 as the coordinates has to be both positive and negative
        console.log("yErrorScale : ", yErrorScale);
        let peakY = this.svgHeight - (erroVal * yErrorScale) - this.graphFeatures.errorplot_padding.bottom - this.graphFeatures.heightForErrorPlot/2;
        return peakY;
      }
      /**
       * @function getCircleSize
       * @description Function provides the radius of the circles drawn on the graph as zoomed in and out
       */
      this.getCircleSize = function() {
        radius = this.mzRadius * this.xScale;
        if (radius < this.minRadius) {
          radius = this.minRadius;
        }
        if (radius > this.maxRadius) {
          radius = this.maxRadius;
        }
        return radius;
      }
      /**
       * @function getTickWidth
       * @description Function Provides width between each tick when zoomed in and out or dragged
       */
      this.getTickWidth = function(){
        let tempDiff = this.maxMz - this.minMz;
        let tickWidth = parseInt(this.tickWidthList[0]) ;
        for(let i = 0; i < this.tickWidthList.length; i++)
        {
          if(tempDiff/this.xTicks <= parseFloat(this.tickWidthList[i]) && tempDiff/this.xTicks > parseFloat(this.tickWidthList[i+1]))
          {
            tickWidth = parseFloat(this.tickWidthList[i]);
            break ;
          }
        }
    	  return 	tickWidth ;
      }
      /**
       * @function getTickHeight
       * @description Function Provides height between each tick when zoomed in and out or dragged
       */
      this.getTickHeight = function(){
        let tickheight = parseInt(this.tickHeightList[0]) ;
        let maxIntPercent = this.maxInte/this.dataMaxInte * 100;
    		for(let i = 0; i < this.tickHeightList.length; i++)
    		{
    			if(maxIntPercent/this.yTicks <= parseFloat(this.tickHeightList[i]) && maxIntPercent/this.yTicks > parseFloat(this.tickHeightList[i+1]))
    			{
    				tickheight = parseFloat(this.tickHeightList[i]);
    				break ;
    			}
        }
    	  return tickheight ;
      }
      /**
       * @function xZoom
       * @description Function provides with current xScale, current minMz and MaxMz based on the zoom on x-axis.
       * Function also calls setLimita which helps in drawing limited number of peaks and circles per eachbin/range of mz values.
       */
      this.xZoom = function (mouseSvgX, ratio) {
       if ((ratio > 1.0) || ((this.maxMz - this.minMz) < this.dataMaxMz) ) {
          let mouseSpecX = mouseSvgX - this.padding.left;
          this.centerMz =  mouseSpecX/this.xScale + this.minMz;
          /*self is a global variable of datasource object containing all the data needed to use when zoomed*/
          this.xScale = this.xScale * ratio ;
          this.minMz = this.centerMz - mouseSpecX / this.xScale;
          this.maxMz = this.centerMz + (this.specWidth - mouseSpecX) / this.xScale;
        }
        this.setLimits();
      }
      /**
       * @function yZoom
       * @description Function provides with current yScale, current max Intensity based on the zoom on y-axis
       */
      this.yZoom = function (ratio) {
        //Reducing zoom factor to smoothenup and remove gliches
        if(ratio > 1 ) ratio = 1.4;
        else if(ratio < 1) ratio = 0.9;
        if ((ratio > 1.0 && this.maxInte >= this.dataMinInte ) || (ratio < 1.0 && this.maxInte <= this.dataMaxInte)) {
          this.yScale = this.yScale * ratio;
          this.maxInte = this.specHeight / this.yScale;
        }
      }
      /**
       * @function zoom
       * @description
       * Function to invoke respective zoom functionality(zoom on x or y) based on position of X, Y
       * It fixes amount of zoom based on zooming in or out
       */
      this.zoom = function(mouseSvgX, mouseSvgY, ratio) {
        if(ratio > 1 ) ratio = 1.4; // Zooming in and fixing ration to 1.4 (fixed values based on testing the smooting of zoom)
        else if(ratio < 1) ratio = 0.9; // Zooming out and fixing ration to 0.9 (fixed values based on testing the smooting of zoom)
        if (mouseSvgY > this.svgHeight - this.padding.bottom) {
          this.xZoom(mouseSvgX, ratio);
        }
        else {
          this.yZoom(ratio);
        }
      }
      /**
       * @function drag
       * @description
       * Function provides minMz and maxMz based on the amount of drag done
       */
      this.drag = function(distX) {
        let mzDist = distX / this.xScale;
        this.minMz = this.minMz - mzDist;
        this.maxMz = this.maxMz - mzDist;
        this.centerMz = this.centerMz - mzDist;
        this.onDragLimits(mzDist);
      }
      /**
       * @function setLimits
       * @description
       * when zoomed function provides the bin ranges to divide the complete x axis into 5 bins.
       * This helps setting the number of peaks and circles to a limited number in each bin.
       * This speeds up the zoom and drag functionality.
       */
      this.setLimits = function(){
        let avg = (this.maxMz - this.minMz)/this.limits.length ;
        avg = avg + (this.bufferPercent*avg);
        for(let i=0; i<this.ranges.length;i++)
        {
          this.ranges[i] = this.minMz + (i*avg) ;
        }
      }
      /**
       * @function onDragLimits
       * @description
       * When dragged function provides the bin ranges to divide the complete x axis into 5 bins.
       * This helps setting the number of peaks and circles to a limited number in each bin.
       * This speeds up the zoom and drag functionality.
       */
      this.onDragLimits = function(mzDist){
        let tempRanges = this.ranges ;
        let avg = (this.maxMz - this.minMz)/this.limits.length ;
        avg = avg + (avg*this.bufferPercent);
        if(mzDist < 0)
        {
          if(tempRanges[0] < (this.minMz-avg)) tempRanges.shift();
          if(tempRanges[(tempRanges.length-1)] < (this.maxMz))
          {
            let tempVal = tempRanges[(tempRanges.length-1)]+avg;
            tempRanges.push(tempVal);
          }
        }
        else
        {
          if(tempRanges[0] > this.minMz)
          {
            let tempVal = tempRanges[0]-avg;
            tempRanges.unshift(tempVal);
          }
          if(tempRanges[(tempRanges.length-1)] > (this.maxMz+avg)) tempRanges.pop();
        }
        this.ranges = tempRanges;
      }
    }