// RegressionLine

//  A least-squares regression line function  ----------------------------------
//  adapted from the "Java Number Cruncher " (http://www.apropos-logic.com/nc)

function RegressionLine (x, y) {
  var sumX = 0; // sum of x
  var sumY = 0; // sum of y
  var sumXX = 0; // sum of x*x
  var sumXY = 0; // sum of x*y

  var a0 = 0; // line coefficient a0
  var a1 = 0; // line coefficient a1

  var n = 0; // number of data points
  var coefsValid = false; // true if coefficients valid
//  var j = 0;

//  -------------------------------------------------------------------------->
  this.toString = function () {
    return 'y = '+a0+' + '+a1+' * x ('+n+' points'+ ', sumX = '+sumX+ ', sumY = '+sumY+ ', sumXX = '+sumXX+ ', sumXY = '+sumXY+ ', coefsValid = '+coefsValid+')';
  }

//  --------------------------------------------------------------------------->
  this.getDataPointCount = function () {
    return n;
  }

//  --------------------------------------------------------------------------->
  this.getA0 = function () {
    validateCoefficients();
    return a0;
  }

//  --------------------------------------------------------------------------->
  this.getA1 = function () {
    validateCoefficients();
    return a1;
  }

//  --------------------------------------------------------------------------->
  this.getSumX = function () {
    return sumX;
  }

//  --------------------------------------------------------------------------->
  this.getSumY = function () {
    return sumY;
  }

//  --------------------------------------------------------------------------->
  this.getSumXX = function () {
    return sumXX;
  }

//  --------------------------------------------------------------------------->
  this.getSumXY = function () {
    return sumXY;
  }

//  --------------------------------------------------------------------------->
  this.addXY = function (x, y) {
//    show ('trace', (j++)+': addXY ('+x+', '+y+')');
    sumX += x;
    sumY += y;
    sumXX += x * x;
    sumXY += x * y;
    ++n;
    coefsValid = false;
  }

//  --------------------------------------------------------------------------->
  this.calc = function (x) {
    if (n < 2) return null;
    validateCoefficients();
    return a0 + a1 * x;
  }

//  --------------------------------------------------------------------------->
  this.reset = function () {
    n = 0;
    sumX = sumY = sumXX = sumXY = 0;
    coefsValid = false;
  }

//  --------------------------------------------------------------------------->
  validateCoefficients = function() {
    if (coefsValid) return;
    if (n < 2) {
      this.reset ()
    } else {
      var xBar = sumX / n;
      var yBar = sumY / n;
      a1 = ((n * sumXY - sumX * sumY) / (n * sumXX - sumX * sumX));
      a0 = (yBar - a1 * xBar);
      coefsValid = true;
    }
  }
//  -------------------------------------------------------------------------->
  this.reset ();
  if (x && y)
    for (var i = 0; i < x.length; i++) 
      this.addXY(x[i], y[i]);
  validateCoefficients ();
//  -------------------------------------------------------------------------->
}
