"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;
var _react = _interopRequireDefault(require("react"));
var _i18n = require("@kui-shell/core/mdist/api/i18n");
var _Coloring = _interopRequireDefault(require("./Coloring"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/*
 * Copyright 2020 The Kubernetes Authors
 *
 * Licensed 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.
 */

const strings = (0, _i18n.i18n)('plugin-client-common');
class Timeline extends _react.default.PureComponent {
  constructor(props) {
    super(props);
    this.state = Timeline.computeBuckets(props.response, props.nBuckets || Timeline.defaultNBuckets);
  }
  static getDerivedStateFromProps(props) {
    return Timeline.computeBuckets(props.response, props.nBuckets || Timeline.defaultNBuckets);
  }
  static computeBuckets(response, nBuckets) {
    const idx1 = response.startColumnIdx;
    const idx2 = response.completeColumnIdx;
    const coloring = new _Coloring.default(response);
    const {
      minStart,
      maxEnd
    } = response.body.reduce((range, row) => {
      const startCell = row.attributes[idx1];
      const startTime = startCell && startCell.value ? new Date(startCell.value).getTime() : 0;
      const endCell = row.attributes[idx2];
      const endTime = endCell && endCell.value ? new Date(endCell.value).getTime() : 0;
      if (range.minStart === 0 || startTime < range.minStart) {
        range.minStart = startTime;
      }
      if (endTime > range.maxEnd) {
        range.maxEnd = endTime;
      }
      return range;
    }, {
      minStart: 0,
      maxEnd: 0
    });
    const bucketTimeRange = Math.max(1, maxEnd - minStart);
    const timeRangePerBucket = Math.floor(bucketTimeRange / nBuckets);
    const bucketOf = millis => Math.min(nBuckets - 1, Math.floor((millis - minStart) / timeRangePerBucket));
    const initialBuckets = Array(nBuckets).fill(0).map((_, idx) => ({
      startMillis: minStart + timeRangePerBucket * idx,
      endMillis: idx === nBuckets - 1 ? maxEnd : minStart + timeRangePerBucket * (idx + 1),
      coldStart: 0,
      execution: 0,
      durationSplit: Array(coloring.nDurationBuckets()).fill(0).map(() => ({
        execution: 0,
        coldStart: 0
      }))
    }));
    // need to slice so as not to permute the original table model
    const buckets = response.body.reduce((buckets, row) => {
      const startMillis = new Date(row.attributes[idx1].value).getTime();
      const endMillis = !row.attributes[idx2].value || row.attributes[idx2].value === '<none>' ? startMillis : new Date(row.attributes[idx2].value).getTime();
      // const coldStart =
      // response.coldStartColumnIdx >= 0 ? parseInt(row.attributes[response.coldStartColumnIdx].value, 10) : 0
      const startBucketIdx = bucketOf(startMillis);
      const coldStartEndBucketIdx = startBucketIdx; // bucketOf(startMillis + coldStart)
      const endBucketIdx = bucketOf(endMillis);
      // const nColdBucketsSpanned = coldStartEndBucketIdx - startBucketIdx + 1
      // const nExecutionBucketsSpanned = endBucketIdx - coldStartEndBucketIdx + 1
      const splitIdx = coloring.durationBucket(endMillis - startMillis);
      /* for (let bucketIdx = startBucketIdx; bucketIdx < coldStartEndBucketIdx + 1; bucketIdx++) {
        buckets[bucketIdx].coldStart++
        buckets[bucketIdx].durationSplit[splitIdx].coldStart++
      } */
      for (let bucketIdx = coldStartEndBucketIdx; bucketIdx < endBucketIdx + 1; bucketIdx++) {
        buckets[bucketIdx].execution++;
        buckets[bucketIdx].durationSplit[splitIdx].execution++;
      }
      return buckets;
    }, initialBuckets);
    return {
      bucketTimeRange,
      maxBucketOccupancy: buckets.reduce((max, bucket) => Math.max(max, bucket.coldStart + bucket.execution), 0),
      coloring,
      buckets
    };
  }
  getFraction(numerator) {
    const denominator = this.state.maxBucketOccupancy;
    return `${(numerator / denominator * 100).toFixed(10).toString()}%`;
  }
  bar(occupancy, css, title, needsOverlay = false) {
    return occupancy > 0 ? _react.default.createElement("div", {
      key: `${css}-${needsOverlay}-${occupancy}`,
      className: css,
      style: {
        height: this.getFraction(occupancy)
      },
      title: title
    }, needsOverlay ? _react.default.createElement("div", {
      className: "kui--bar-overlay"
    }, "\u00A0") : _react.default.createElement(_react.default.Fragment, null, "\u00A0")) : undefined;
  }
  buckets() {
    return _react.default.createElement("div", {
      className: "kui--timeline-buckets"
    }, this.state.buckets.map((bucket, idx) => {
      const {
        coldStart = 0,
        execution = 0,
        durationSplit
      } = bucket;
      const leftover = this.state.maxBucketOccupancy - coldStart - execution;
      return _react.default.createElement("div", {
        className: "kui--timeline-bucket",
        key: `${idx}-${bucket.coldStart}-${bucket.execution}`
      }, this.bar(leftover, 'leftover'), durationSplit.reverse().map((split, idx) => {
        const splitIdx = durationSplit.length - idx - 1;
        const range = this.state.coloring.durationRangeOfSplit(splitIdx);
        return _react.default.createElement(_react.default.Fragment, {
          key: splitIdx
        }, this.bar(split.execution, this.state.coloring.durationCssForBucket(splitIdx), strings(`concurrencyInDurationSplit`, split.execution, range)), this.bar(split.coldStart, this.state.coloring.durationCssForBucket(splitIdx), strings(`concurrencyColdStartInDurationSplit`, split.coldStart, range), true));
      }));
    }));
  }
  yAxis() {
    const nTicks = 3;
    return _react.default.createElement("div", {
      className: "kui--timeline-y-axis"
    }, _react.default.createElement("div", {
      className: "kui--timeline-ticks"
    }, _react.default.createElement("div", {
      className: "kui--timeline-occupancy-line kui--timeline-tick"
    }, _react.default.createElement("div", {
      className: "kui--timeline-occupancy-line-label"
    }, this.state.maxBucketOccupancy, " max concurrency")), Array(nTicks).fill(0).map((_, idx) => _react.default.createElement("div", {
      key: idx,
      className: "kui--timeline-tick"
    }, "\u00A0"))));
  }
  xAxis() {
    return _react.default.createElement(_react.default.Fragment, null);
  }
  render() {
    if (!this.state) {
      return _react.default.createElement(_react.default.Fragment, null);
    }
    return _react.default.createElement("div", {
      className: "kui--data-table-container kui--timeline-container"
    }, _react.default.createElement("div", {
      className: "kui--timeline"
    }, this.yAxis(), this.xAxis(), this.buckets()));
  }
}
/**
 * Default number of buckets in the timeline
 *
 */
exports.default = Timeline;
Timeline.defaultNBuckets = 50;