text: /**
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the
   * "License"); you may not use this file except in compliance
   * with the License.  You may obtain a copy of the License at
   *
   *   http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing,
   * software distributed under the License is distributed on an
   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   * KIND, either express or implied.  See the License for the
   * specific language governing permissions and limitations
   * under the License.
   */
  
  /* eslint-disable react/no-array-index-key, react/jsx-no-bind */
  import dist from 'distributions';
  import React from 'react';
  import { Table, Tr, Td, Thead, Th } from 'reactable-arc';
  import PropTypes from 'prop-types';
  export const dataPropType = PropTypes.arrayOf(PropTypes.shape({
    group: PropTypes.arrayOf(PropTypes.string),
    values: PropTypes.arrayOf(PropTypes.shape({
      x: PropTypes.number,
      y: PropTypes.number
    }))
  }));
  const propTypes = {
    alpha: PropTypes.number,
    data: dataPropType.isRequired,
    groups: PropTypes.arrayOf(PropTypes.string).isRequired,
    liftValPrec: PropTypes.number,
    metric: PropTypes.string.isRequired,
    pValPrec: PropTypes.number
  };
  const defaultProps = {
    alpha: 0.05,
    liftValPrec: 4,
    pValPrec: 6
  };
  
  class TTestTable extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        control: 0,
        liftValues: [],
        pValues: []
      };
    }
  
    componentDidMount() {
      const {
        control
      } = this.state;
      this.computeTTest(control); // initially populate table
    }
  
    getLiftStatus(row) {
      const {
        control,
        liftValues
      } = this.state; // Get a css class name for coloring
  
      if (row === control) {
        return 'control';
      }
  
      const liftVal = liftValues[row];
  
      if (Number.isNaN(liftVal) || !Number.isFinite(liftVal)) {
        return 'invalid'; // infinite or NaN values
      }
  
      return liftVal >= 0 ? 'true' : 'false'; // green on true, red on false
    }
  
    getPValueStatus(row) {
      const {
        control,
        pValues
      } = this.state;
  
      if (row === control) {
        return 'control';
      }
  
      const pVal = pValues[row];
  
      if (Number.isNaN(pVal) || !Number.isFinite(pVal)) {
        return 'invalid';
      }
  
      return ''; // p-values won't normally be colored
    }
  
    getSignificance(row) {
      const {
        control,
        pValues
      } = this.state;
      const {
        alpha
      } = this.props; // Color significant as green, else red
  
      if (row === control) {
        return 'control';
      } // p-values significant below set threshold
  
  
      return pValues[row] <= alpha;
    }
  
    computeLift(values, control) {
      const {
        liftValPrec
      } = this.props; // Compute the lift value between two time series
  
      let sumValues = 0;
      let sumControl = 0;
      values.forEach((value, i) => {
        sumValues += value.y;
        sumControl += control[i].y;
      });
      return ((sumValues - sumControl) / sumControl * 100).toFixed(liftValPrec);
    }
  
    computePValue(values, control) {
      const {
        pValPrec
      } = this.props; // Compute the p-value from Student's t-test
      // between two time series
  
      let diffSum = 0;
      let diffSqSum = 0;
      let finiteCount = 0;
      values.forEach((value, i) => {
        const diff = control[i].y - value.y;
        /* eslint-disable-next-line */
  
        if (isFinite(diff)) {
          finiteCount += 1;
          diffSum += diff;
          diffSqSum += diff * diff;
        }
      });
      const tvalue = -Math.abs(diffSum * Math.sqrt((finiteCount - 1) / (finiteCount * diffSqSum - diffSum * diffSum)));
  
      try {
        return (2 * new dist.Studentt(finiteCount - 1).cdf(tvalue)).toFixed(pValPrec); // two-sided test
      } catch (error) {
        return NaN;
      }
    }
  
    computeTTest(control) {
      // Compute lift and p-values for each row
      // against the selected control
      const {
        data
      } = this.props;
      const pValues = [];
      const liftValues = [];
  
      if (!data) {
        return;
      }
  
      for (let i = 0; i < data.length; i += 1) {
        if (i === control) {
          pValues.push('control');
          liftValues.push('control');
        } else {
          pValues.push(this.computePValue(data[i].values, data[control].values));
          liftValues.push(this.computeLift(data[i].values, data[control].values));
        }
      }
  
      this.setState({
        control,
        liftValues,
        pValues
      });
    }
  
    render() {
      const {
        data,
        metric,
        groups
      } = this.props;
      const {
        control,
        liftValues,
        pValues
      } = this.state; // Render column header for each group
  
      const columns = groups.map((group, i) => /*#__PURE__*/React.createElement(Th, {
        key: i,
        column: group
      }, group));
      const numGroups = groups.length; // Columns for p-value, lift-value, and significance (true/false)
  
      columns.push( /*#__PURE__*/React.createElement(Th, {
        key: numGroups + 1,
        column: "pValue"
      }, "p-value"));
      columns.push( /*#__PURE__*/React.createElement(Th, {
        key: numGroups + 2,
        column: "liftValue"
      }, "Lift %"));
      columns.push( /*#__PURE__*/React.createElement(Th, {
        key: numGroups + 3,
        column: "significant"
      }, "Significant"));
      const rows = data.map((entry, i) => {
        const values = groups.map((group, j) =>
        /*#__PURE__*/
        // group names
        React.createElement(Td, {
          key: j,
          column: group,
          data: entry.group[j]
        }));
        values.push( /*#__PURE__*/React.createElement(Td, {
          key: numGroups + 1,
          className: this.getPValueStatus(i),
          column: "pValue",
          data: pValues[i]
        }));
        values.push( /*#__PURE__*/React.createElement(Td, {
          key: numGroups + 2,
          className: this.getLiftStatus(i),
          column: "liftValue",
          data: liftValues[i]
        }));
        values.push( /*#__PURE__*/React.createElement(Td, {
          key: numGroups + 3,
          className: this.getSignificance(i).toString(),
          column: "significant",
          data: this.getSignificance(i)
        }));
        return /*#__PURE__*/React.createElement(Tr, {
          key: i,
          className: i === control ? 'control' : '',
          onClick: this.computeTTest.bind(this, i)
        }, values);
      }); // When sorted ascending, 'control' will always be at top
  
      const sortConfig = groups.concat([{
        column: 'pValue',
        sortFunction: (a, b) => {
          if (a === 'control') {
            return -1;
          }
  
          if (b === 'control') {
            return 1;
          }
  
          return a > b ? 1 : -1; // p-values ascending
        }
      }, {
        column: 'liftValue',
        sortFunction: (a, b) => {
          if (a === 'control') {
            return -1;
          }
  
          if (b === 'control') {
            return 1;
          }
  
          return parseFloat(a) > parseFloat(b) ? -1 : 1; // lift values descending
        }
      }, {
        column: 'significant',
        sortFunction: (a, b) => {
          if (a === 'control') {
            return -1;
          }
  
          if (b === 'control') {
            return 1;
          }
  
          return a > b ? -1 : 1; // significant values first
        }
      }]);
      return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("h3", null, metric), /*#__PURE__*/React.createElement(Table, {
        className: "table",
        id: `table_${metric}`,
        sortable: sortConfig
      }, /*#__PURE__*/React.createElement(Thead, null, columns), rows));
    }
  
  }
  
  TTestTable.propTypes = propTypes;
  TTestTable.defaultProps = defaultProps;
  export default TTestTable;