/**
 * Calculate the values that are used for normalizing the data.
 * @param  {array} nodes
 * @return {object}    that contains the normalization parameters.
 */
function calculateNormalization (nodes) {
  var STANDARD_DEV = 2.0,
    properties = Object.keys(nodes[0]),
    sums = calculateSums(nodes, properties),
    average = [],
    sigma = [];

  // For each property, calculate mean and sigma.
  for (var i = 0; i < properties.length; i++) {
    var avg = sums.sumOfVal[i] / nodes.length;
    average[i] = avg;
    sigma[i] = Math.sqrt((sums.sumOfSq[i] - (nodes.length * Math.pow(avg, 2))) / nodes.length);
  }
  return {
    avg: average,
    sig: sigma,
    st_d: standardDevation(nodes, properties, average)
  };
}

function standardDevation (nodes, properties, avg) {
  var stDev = new Array(properties.length).fill(0);

  for (var i = 0; i < properties.length; i++) {
    var sum = 0;

    nodes.forEach(function (node) {
      var val = node[properties[i]];
      var parsedDate = Date.parse(val);
      var propAvg = avg[i];

      if (isNaN(val) && !isNaN(parsedDate)) {
        val = parsedDate.valueOf();
      } else if (isNumeric(val)) {
        val = parseFloat(val);
        // Ignore the strings.
      } else {
        val = 0;
      }

      sum += Math.pow(val - propAvg, 2);
    });

    stDev[i] = Math.sqrt(sum / nodes.length);
  }

  return stDev;
}

// Calculate the sum of values and the squared sum
/**
 * Calculate the sums of each property.
 * @param  {array} nodes
 * @param  {array} properties - list of properties
 * @return {object}       that contains arrays with sum of values
 *     and the squared sums.
 */
function calculateSums (nodes, properties) {
  var sumOfValues = new Array(properties.length).fill(0),
    sumOfSquares = new Array(properties.length).fill(0);

  // Calculate the sums for each node.
  nodes.forEach(function (node) {
    for (var i = 0; i < properties.length; i++) {
      var val = node[properties[i]];
      var parsedDate = Date.parse(val);

      if (isNaN(val) && !isNaN(parsedDate)) {
        sumOfValues[i] += parsedDate.valueOf();
        sumOfSquares[i] += Math.pow(parsedDate.valueOf(), 2);
      } else if (isNumeric(val)) {
        sumOfValues[i] += parseFloat(val);
        sumOfSquares[i] += Math.pow(parseFloat(val), 2);
        // Ignore the strings.
      } else {
        sumOfValues[i] += 0;
        sumOfSquares[i] += 0;
      }
    }
  });
  return {
    sumOfVal: sumOfValues,
    sumOfSq: sumOfSquares
  };
}
