'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.getScatterplotData = exports.fetchScatterplotVars = exports.fetchReducedPair = exports.mergeDatasets = undefined;

var _axios = require('axios');

var _axios2 = _interopRequireDefault(_axios);

var _papaparse = require('papaparse');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }

function FetchException(message, urls, err) {
  this.message = message;
  this.name = 'FetchException';
  this.urls = urls;
  this.originalError = err;
}

/**
 * Takes multiple data sets with identifiers and merges them
 * into one for use with echarts scatterplot. Filters out 
 * entries where there are not values in all data sets.
 * @param {object} sets a variable amount of data sets - e.g. { "01001": 3.45, ... }
 * @returns {object} e.g. { "01001": [ 3.45, 5.10, 01001 ], ... }
 */
var mergeDatasets = exports.mergeDatasets = function mergeDatasets() {
  for (var _len = arguments.length, sets = Array(_len), _key = 0; _key < _len; _key++) {
    sets[_key] = arguments[_key];
  }

  // filter out IDs that are not common to all sets
  var ids = Object.keys(sets[0]).filter(function (id) {
    return sets.reduce(function (acc, curr) {
      return acc ? curr.hasOwnProperty(id) && parseFloat(curr[id]) > -9999 && parseFloat(curr[id]) > -9999 && id !== "" && id !== "id" : false;
    }, true);
  });
  // create an object with all merged data
  var merged = ids.reduce(function (acc, curr) {
    acc[curr] = [].concat(_toConsumableArray(sets.map(function (s) {
      return parseFloat(s[curr]);
    })), [curr]);
    return acc;
  }, {});
  return merged;
};

/**
 * 
 * @param {array} varNames e.g. [ 'id', 'all_avg', 'all_coh' ]
 * @param {object} data e.g { '01001': [ '01001', 3.22, 1.2 ], ... }
 * @returns {object} { 'all_avg': { '01001': 3.22, ... }, 'all_coh': { '01001': 3.22, ... }}
 */
var extractVarsFromDataArray = function extractVarsFromDataArray(varNames, data) {
  return varNames.reduce(function (obj, v, i) {
    if (v !== 'id') {
      obj[v] = Object.keys(data).reduce(function (a, c) {
        if (data[c][i]) a[c] = data[c][i];
        return a;
      }, {});
    }
    return obj;
  }, {});
};

/**
 * Creates a collection with keys in `varNames` with associated data
 * @param {*} varNames e.g. [ 'w_ses', 'b_ses' ]
 * @param {*} data 
 * @returns {object} { 'w_ses': { '01001': 0.43, ... }, 'b_ses': { '01001': 0.32, ... } }
 */
var createVariableCollection = function createVariableCollection(varNames, data, metaVars) {
  if (!data || data.length === 0) {
    return {};
  }
  return varNames.reduce(function (acc, curr, i) {
    if (curr === 'meta') {
      // extract variables from the "meta" file
      metaVars.forEach(function (v, j) {
        if (j > 0) {
          acc[v] = Object.keys(data[i]).reduce(function (a, c) {
            if (data[i][c][j]) a[c] = data[i][c][j];
            return a;
          }, {});
        }
      });
    } else {
      acc[curr] = data[i];
    }
    return acc;
  }, {});
};

/**
 * Parses a CSV string of scatterplot data.  Data is `string,number`
 * by default, except for if the data is from the meta file. The meta file
 * is formatted as `string,string,number,number,number,number,number`
 * @param {*} data 
 * @param {string} varName the name of the variable being parsed
 */
var parseCsvData = function parseCsvData(data, isMeta) {
  // parse CSV data
  var parsed = (0, _papaparse.parse)(data, {
    transform: function transform(value, column) {
      return (isMeta && column > 1 || !isMeta && column > 0) && (value || value === 0) && !isNaN(parseFloat(value)) ? parseFloat(value) : value;
    }
  });
  if (parsed.errors.length) {
    var errorMessage = parsed.errors[0].type + ':' + parsed.errors[0].code + ' on row ' + parsed.errors[0].row;
    throw new Error(errorMessage);
  }
  // reduce array of data into an object
  // e.g. { '0100001': 2.44, ... }
  return {
    'header': parsed.data[0],
    'data': parsed.data.reduce(function (acc, curr) {
      // skip header row
      if (curr[0] !== 'id') {
        acc[curr[0]] = curr.length === 2 ? curr[1] : curr;
      }
      return acc;
    }, {})
  };
};

/**
 * Gets the data url to the provided prefix, varName, state
 * @param {string} endpoint endpoint for where the scatterplot data lives
 * @param {string} prefix data prefix or region (e.g. 'counties')
 * @param {string} varName the variable name to use
 * @param {string} state the state to fetch data, used for schools only (e.g. 01)
 */
var getDataUrlForVarName = function getDataUrlForVarName(endpoint, prefix, varName, state) {
  if (prefix === 'schools') {
    if (state) {
      return varName === 'meta' ? endpoint + 'meta/schools/' + state + '.csv' : endpoint + 'schools/' + state + '/' + varName + '.csv';
    }
  } else {
    return varName === 'meta' ? endpoint + 'meta/' + prefix + '.csv' : '' + endpoint + (prefix ? prefix + '/' : '') + varName + '.csv';
  }
};

/**
 * Fetches the data for a x / y pair for schools
 * @param {string} endpoint endpoint for where the scatterplot data lives
 * @param {string} var1 
 * @param {string} var2 
 */
var fetchReducedPair = exports.fetchReducedPair = function fetchReducedPair(endpoint, var1, var2) {
  var filename = [var1, var2].sort().join('-');
  var fetchUrl = endpoint + 'schools/reduced/' + filename + '.csv';
  return _axios2.default.get(fetchUrl).then(function (res) {
    return parseCsvData(res.data, true);
  }).then(function (_ref) {
    var header = _ref.header,
        data = _ref.data;
    return extractVarsFromDataArray(header, data);
  }).catch(function (err) {
    throw new FetchException('Could not fetch data', _defineProperty({}, filename, fetchUrl), err);
  });
};

/**
 * Fetches data and returns a promise that contains 
 * an array of all the requested vars data on success.
 * @param {Array<String>} vars array of variable names to fetch (e.g. [ 'all_avg', 'all_ses' ])
 * @param {string} prefix prefix to the varname to fetch (e.g. 'districts')
 * @returns {Promise<object>}
 */
var fetchScatterplotVars = exports.fetchScatterplotVars = function fetchScatterplotVars() {
  var vars = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
  var prefix = arguments[1];
  var endpoint = arguments[2];
  var metaVars = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
  var state = arguments[4];

  var fetchVars = vars.map(function (v) {
    return metaVars.indexOf(v) > -1 ? 'meta' : v;
  }).filter(function (value, index, self) {
    return self.indexOf(value) === index;
  });
  var fetchUrls = fetchVars.map(function (v) {
    return getDataUrlForVarName(endpoint, prefix, v, state);
  });
  var fetchMap = fetchVars.reduce(function (acc, curr, i) {
    if (fetchUrls[i]) {
      acc[curr] = fetchUrls[i];
    }
    return acc;
  }, {});
  return Promise.all(Object.keys(fetchMap).map(function (v) {
    return _axios2.default.get(fetchMap[v]).then(function (res) {
      return parseCsvData(res.data, v === 'meta').data;
    }, function (err) {
      throw new FetchException('Could not fetch data', fetchMap, err);
    });
  })).then(function (data) {
    return createVariableCollection(fetchVars, data, metaVars);
  });
};

/**
 * Returns provided datasets merged into an array that
 * can be used with eCharts data series.
 * @param  {...any} sets a variable number of data sets (e.g { '0100001' : 2.44, ... })
 */
var getScatterplotData = exports.getScatterplotData = function getScatterplotData() {
  if (arguments.length < 1) {
    throw new Error('Cannot create scatterplot data with less than two variables');
  }
  var merged = mergeDatasets.apply(undefined, arguments);
  return Object.keys(merged).map(function (k) {
    return merged[k];
  });
};