
var AspectRatioBanker = function(data, xScale, yScale, options){
  // data field to bank
  this._z             = null;
  this.maxWidth       = 500;
  this.maxHeight      = 500;
  this.bankYAxis      = true;
  this.banker         = this.averageAbsoluteAngle;
  this.xScale         = xScale;
  this.yScale         = yScale;

  _.extend(this, options);

  this.data       =  this.getValuesToBank(data);

  this.prototype  = {
    getValuesToBank: function(){
      var _data = [], me = this;
      this.data.forEach(function(d){
        if(me._z === null){
          return d;
        }else{
          return d[me._z];
        }
      });
    },
    init: function(){
      // compute the aspect ratio (= width/height)
      var aspectRatio = this.banker(this.data);
      if (this.bankYAxis === false) aspectRatio = 1/aspectRatio;

      aspectRatio = this.adjustToAxes(aspectRatio);
      // visualization.setAspectRatio(ar, maxWidth, maxHeight);
      // visualization.axes.update(t);

      console.log(aspectRatio);
    },

    adjustToAxes: function(vis, aspectRatio){
      // get axis scales for each data field
      // var axes:CartesianAxes = vis.xyAxes;
      var xsc = this.xScale,
          ysc = this.yScale,
          dy,
          dx;

      // compute adjusted aspect ratio: this is the inverse aspect ratio
      // of the interpolated data rectangle in data space multipled by
      // the desired aspect ratio for the data rectangle in screen space
      // dy = ysc.interpolate(ysc.max) - ysc.interpolate(ysc.min);
      // dx = xsc.interpolate(xsc.max) - xsc.interpolate(xsc.min);
      // return ar * dy / dx;
    },

    averageAbsoluteAngle(a){
        var alpha=0, alpha_p, f, fprime,
            x, Ry = _.max(a) - _.min(a),
            N = a.length-1, iter = 0,
            i, j;

          // compute constants, perform culling
          var c = [];
          for (i=0, j=0; i<N; ++i) {
            var slope = Math.abs(a[i+1] - a[i]) / Ry;
            if (slope > 1e-5) c.push(N * slope);
          }
          N = c.length;

          // Newton-Raphson iteration
          while (Math.abs(alpha - alpha_p) > 1e-5) {
              iter++;
              alpha_p = alpha;

              // compute function and function derivative
              f = fprime = 0;
              for (i=0; i<N; ++i) {
                  x = c[i] * alpha;
                  f += Math.atan(x);
                  fprime += c[i] / (1 + x*x);
              }
              f = f / N;
              fprime = fprime / N;
              f -= Math.PI/4;

              // apply the Newton-Raphson increment
              alpha = alpha_p - f/fprime;

           // finish iteration when update difference drops beneath tolerance
           };

           return 1/alpha;
      },
      medianAbsoluteSlope: function(a){
        var slopes = [], i,
            yRange = _.max(a) - _.min(a);

          for (i=1; i<a.length; ++i) {
              var slope = Math.abs(a[i] - a[i-1]);
              if (slope/yRange > 1e-5) {
                  slopes.push(slope);
              }
          }
          // slopes.sort(Array.NUMERIC);
          slopes.sort();
          var median = slopes[slopes.length >> 1];

          return (median*(a.length-1)) / yRange;
      }

  }
};

  