"use strict";

function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.useDetectSchema = useDetectSchema;
exports.useMergedSchema = useMergedSchema;
exports.getDetailsForSchema = getDetailsForSchema;
exports.schemaDetectors = void 0;
var _react = _interopRequireWildcard(require("react"));
var _i18n = require("../i18n");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) { "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); } return f; })(e, t); }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) { n[e] = r[e]; } return n; } /*
 * SPDX-License-Identifier: Apache-2.0
 *
 * The OpenSearch Contributors require contributions made to
 * this file be licensed under the Apache-2.0 license or a
 * compatible open source license.
 *
 * Modifications Copyright OpenSearch Contributors. See
 * GitHub history for details.
 */ /*
 * Licensed to Elasticsearch B.V. under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Elasticsearch B.V. 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.
 */
var numericChars = new Set(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '-']);
var schemaDetectors = [{
  type: 'boolean',
  detector: function detector(value) {
    return value.toLowerCase() === 'true' || value.toLowerCase() === 'false' ? 1 : 0;
  },
  comparator: function comparator(a, b, direction) {
    var aValue = a.toLowerCase() === 'true';
    var bValue = b.toLowerCase() === 'true';
    if (aValue < bValue) return direction === 'asc' ? -1 : 1;
    if (aValue > bValue) return direction === 'asc' ? 1 : -1;
    return 0;
  },
  icon: 'tokenBoolean',
  sortTextAsc: /*#__PURE__*/_react.default.createElement(_i18n.OuiI18n, {
    token: "ouiDataGridSchema.booleanSortTextAsc",
    default: "False-True"
  }),
  sortTextDesc: /*#__PURE__*/_react.default.createElement(_i18n.OuiI18n, {
    token: "ouiDataGridSchema.booleanSortTextDesc",
    default: "True-False"
  })
}, {
  type: 'currency',
  detector: function detector(value) {
    var matchLength = (value.match(
    // currency prefers starting with 1-3 characters for the currency symbol
    // then it matches against numerical data + $
    /(^[^-(.]{1,3})?[$-(]*[\d,]+(\.\d*)?[$)]*/) || [''])[0].length;

    // if there is no currency symbol then reduce the score
    var hasCurrency = value.indexOf('$') !== -1;
    var confidenceAdjustment = hasCurrency ? 1 : 0.95;
    return matchLength / value.length * confidenceAdjustment || 0;
  },
  comparator: function comparator(a, b, direction) {
    var aChars = a.split('').filter(function (char) {
      return numericChars.has(char);
    });
    var aValue = parseFloat(aChars.join(''));
    var bChars = b.split('').filter(function (char) {
      return numericChars.has(char);
    });
    var bValue = parseFloat(bChars.join(''));
    if (aValue < bValue) return direction === 'asc' ? -1 : 1;
    if (aValue > bValue) return direction === 'asc' ? 1 : -1;
    return 0;
  },
  icon: 'currency',
  color: 'ouiColorVis0',
  sortTextAsc: /*#__PURE__*/_react.default.createElement(_i18n.OuiI18n, {
    token: "ouiDataGridSchema.currencySortTextAsc",
    default: "Low-High"
  }),
  sortTextDesc: /*#__PURE__*/_react.default.createElement(_i18n.OuiI18n, {
    token: "ouiDataGridSchema.currencySortTextDesc",
    default: "High-Low"
  })
}, {
  type: 'datetime',
  detector: function detector(value) {
    // matches the most common forms of ISO-8601
    var isoTimestampMatch = value.match(
    // 2019 - 09    - 17     T 12     : 18    : 32      .853     Z or -0600
    /^\d{2,4}-\d{1,2}-\d{1,2}(T?\d{1,2}:\d{1,2}:\d{1,2}(\.\d{3})?(Z|[+-]\d{4})?)?/);

    // matches 9 digits (seconds) or 13 digits (milliseconds) since unix epoch
    var unixTimestampMatch = value.match(/^(\d{9}|\d{13})$/);
    var isoMatchLength = isoTimestampMatch ? isoTimestampMatch[0].length : 0;

    // reduce the confidence of a unix timestamp match to 75%
    // (a column of all unix timestamps should be numeric instead)
    var unixMatchLength = unixTimestampMatch ? unixTimestampMatch[0].length * 0.75 : 0;
    return Math.max(isoMatchLength, unixMatchLength) / value.length || 0;
  },
  icon: 'tokenDate',
  sortTextAsc: /*#__PURE__*/_react.default.createElement(_i18n.OuiI18n, {
    token: "ouiDataGridSchema.dateSortTextAsc",
    default: "Old-New"
  }),
  sortTextDesc: /*#__PURE__*/_react.default.createElement(_i18n.OuiI18n, {
    token: "ouiDataGridSchema.dateSortTextDesc",
    default: "New-Old"
  })
}, {
  type: 'numeric',
  detector: function detector(value) {
    var matchLength = (value.match(/[%-(]*[\d,]+(\.\d*)?[%)]*/) || [''])[0].length;
    return matchLength / value.length || 0;
  },
  comparator: function comparator(a, b, direction) {
    // sort on all digits groups
    var aGroups = a.split(/\D+/);
    var bGroups = b.split(/\D+/);
    var maxGroups = Math.max(aGroups.length, bGroups.length);
    for (var i = 0; i < maxGroups; i++) {
      // if A and B's group counts differ and they match until that difference, prefer whichever is shorter
      if (i >= aGroups.length) return direction === 'asc' ? -1 : 1;
      if (i >= bGroups.length) return direction === 'asc' ? 1 : -1;
      var aChars = aGroups[i];
      var bChars = bGroups[i];
      var aValue = parseInt(aChars, 10);
      var bValue = parseInt(bChars, 10);
      if (aValue < bValue) return direction === 'asc' ? -1 : 1;
      if (aValue > bValue) return direction === 'asc' ? 1 : -1;
    }
    return 0;
  },
  icon: 'tokenNumber',
  sortTextAsc: /*#__PURE__*/_react.default.createElement(_i18n.OuiI18n, {
    token: "ouiDataGridSchema.numberSortTextAsc",
    default: "Low-High"
  }),
  sortTextDesc: /*#__PURE__*/_react.default.createElement(_i18n.OuiI18n, {
    token: "ouiDataGridSchema.numberSortTextDesc",
    default: "High-Low"
  })
}, {
  type: 'json',
  detector: function detector(value) {
    // does this look like it might be a JSON object?
    var maybeArray = value[0] === '[' && value[value.length - 1] === ']';
    var maybeObject = value[0] === '{' && value[value.length - 1] === '}';
    if (!maybeArray && !maybeObject) return 0;
    try {
      JSON.parse(value);
      return 1;
    } catch (e) {
      return 0;
    }
  },
  comparator: function comparator(a, b, direction) {
    if (a.length > b.length) return direction === 'asc' ? 1 : -1;
    if (a.length < b.length) return direction === 'asc' ? 1 : -1;
    return 0;
  },
  icon: 'tokenObject',
  sortTextAsc: /*#__PURE__*/_react.default.createElement(_i18n.OuiI18n, {
    token: "ouiDataGridSchema.jsonSortTextAsc",
    default: "Small-Large"
  }),
  sortTextDesc: /*#__PURE__*/_react.default.createElement(_i18n.OuiI18n, {
    token: "ouiDataGridSchema.jsonSortTextDesc",
    default: "Large-Small"
  })
}];
exports.schemaDetectors = schemaDetectors;
function scoreValueBySchemaType(value) {
  var schemaDetectors = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
  var scores = [];
  for (var i = 0; i < schemaDetectors.length; i++) {
    var _schemaDetectors$i = schemaDetectors[i],
      type = _schemaDetectors$i.type,
      detector = _schemaDetectors$i.detector;
    var score = detector(value);
    scores.push({
      type: type,
      score: score
    });
  }
  return scores;
}

// completely arbitrary minimum match I came up with
// represents lowest score a type detector can have to be considered valid
var MINIMUM_SCORE_MATCH = 0.5;
var emptyArray = []; // for in-memory object permanence
function useDetectSchema(inMemory, inMemoryValues, schemaDetectors, definedColumnSchemas, autoDetectSchema) {
  var _inMemory$skipColumns;
  var inMemorySkipColumns = (_inMemory$skipColumns = inMemory === null || inMemory === void 0 ? void 0 : inMemory.skipColumns) !== null && _inMemory$skipColumns !== void 0 ? _inMemory$skipColumns : emptyArray;
  var schema = (0, _react.useMemo)(function () {
    var schema = {};
    if (autoDetectSchema === false) {
      return schema;
    }
    var columnSchemas = {};

    // for each row, score each value by each detector and put the results on `columnSchemas`
    var rowIndices = Object.keys(inMemoryValues);
    var columnIdsWithDefinedSchemas = new Set([].concat(_toConsumableArray(inMemorySkipColumns), _toConsumableArray(Object.keys(definedColumnSchemas))));
    for (var i = 0; i < rowIndices.length; i++) {
      var rowIndex = rowIndices[i];
      var rowData = inMemoryValues[rowIndex];
      var columnIds = Object.keys(rowData);
      for (var j = 0; j < columnIds.length; j++) {
        var _columnId = columnIds[j];
        if (columnIdsWithDefinedSchemas.has(_columnId)) continue;
        var schemaColumn = columnSchemas[_columnId] = columnSchemas[_columnId] || {};
        var columnValue = rowData[_columnId].trim();
        var valueScores = scoreValueBySchemaType(columnValue, schemaDetectors);
        for (var k = 0; k < valueScores.length; k++) {
          var valueScore = valueScores[k];
          if (schemaColumn.hasOwnProperty(valueScore.type)) {
            var existingScore = schemaColumn[valueScore.type];
            existingScore.push(valueScore.score);
          } else {
            // first entry for this column
            schemaColumn[valueScore.type] = [valueScore.score];
          }
        }
      }
    }

    // for each column, reduce each detector type's score to a single value and find the best fit
    return Object.keys(columnSchemas).reduce(function (schema, columnId) {
      var columnScores = columnSchemas[columnId];
      var typeIds = Object.keys(columnScores);
      var typeSummaries = {};
      var bestType = null;
      var bestScore = 0;
      for (var _i = 0; _i < typeIds.length; _i++) {
        var typeId = typeIds[_i];
        var typeScores = columnScores[typeId];

        // find the mean
        var totalScore = 0;
        for (var _j = 0; _j < typeScores.length; _j++) {
          var _score = typeScores[_j];
          totalScore += _score;
        }
        var mean = totalScore / typeScores.length;

        // compute standard deviation
        var sdSum = 0;
        for (var _j2 = 0; _j2 < typeScores.length; _j2++) {
          var _score2 = typeScores[_j2];
          sdSum += (_score2 - mean) * (_score2 - mean);
        }
        var sd = Math.sqrt(sdSum / typeScores.length);
        var summary = {
          mean: mean,
          sd: sd
        };

        // the mean-standard_deviation calculation is fairly arbitrary but fits the patterns I've thrown at it
        // it is meant to represent the scores' average and distribution
        var score = summary.mean - summary.sd;
        if (score > MINIMUM_SCORE_MATCH) {
          if (bestType == null || score > bestScore) {
            bestType = typeId;
            bestScore = score;
          }
        }
        typeSummaries[typeId] = summary;
      }
      schema[columnId] = {
        columnType: bestType
      };
      return schema;
    }, {});
  }, [autoDetectSchema, definedColumnSchemas, inMemorySkipColumns, inMemoryValues, schemaDetectors]);
  return schema;
}
function useMergedSchema(detectedSchema, columns) {
  return (0, _react.useMemo)(function () {
    var mergedSchema = _objectSpread({}, detectedSchema);
    for (var i = 0; i < columns.length; i++) {
      var _columns$i = columns[i],
        id = _columns$i.id,
        schema = _columns$i.schema;
      if (schema != null) {
        if (detectedSchema.hasOwnProperty(id)) {
          mergedSchema[id] = _objectSpread(_objectSpread({}, detectedSchema[id]), {}, {
            columnType: schema
          });
        } else {
          mergedSchema[id] = {
            columnType: schema
          };
        }
      }
    }
    return mergedSchema;
  }, [detectedSchema, columns]);
}

// Given a provided schema, return the details for the schema
// Useful for grabbing the color or icon
function getDetailsForSchema(detectors, providedSchema) {
  var results = detectors.filter(function (matches) {
    return matches.type === providedSchema;
  });
  return results[0];
}

/* OUI -> EUI Aliases: Build-Time */