import { __extends, __decorate, __metadata, __assign } from 'tslib';
import { ResizeGroupDirection } from './ResizeGroup.types.js';
import { Prop, Component } from 'vue-property-decorator';
import BaseComponent from '../BaseComponent.js';

var RESIZE_DELAY = 16;
var getMeasurementCache = function() {
  var measurementsCache = {};
  return {
    getCachedMeasurement: function(data) {
      if (data && data.cacheKey && measurementsCache.hasOwnProperty(data.cacheKey)) {
        return measurementsCache[data.cacheKey];
      }
      return void 0;
    },
    addMeasurementToCache: function(data, measurement) {
      if (data.cacheKey) {
        measurementsCache[data.cacheKey] = measurement;
      }
    }
  };
};
var getNextResizeGroupStateProvider = function(measurementCache) {
  if (measurementCache === void 0) {
    measurementCache = getMeasurementCache();
  }
  var _measurementCache = measurementCache;
  var _containerDimension;
  function _getMeasuredDimension(measuredData, getElementToMeasureDimension) {
    var cachedDimension = _measurementCache.getCachedMeasurement(measuredData);
    if (cachedDimension !== void 0) {
      return cachedDimension;
    }
    var measuredDimension = getElementToMeasureDimension();
    _measurementCache.addMeasurementToCache(measuredData, measuredDimension);
    return measuredDimension;
  }
  function _shrinkContentsUntilTheyFit(data, onReduceData, getElementToMeasureDimension) {
    var dataToMeasure = data;
    var measuredDimension = _getMeasuredDimension(data, getElementToMeasureDimension);
    while (measuredDimension > _containerDimension) {
      var nextMeasuredData = onReduceData(dataToMeasure);
      if (nextMeasuredData === void 0) {
        return {
          renderedData: dataToMeasure,
          resizeDirection: void 0,
          dataToMeasure: void 0
        };
      }
      measuredDimension = _measurementCache.getCachedMeasurement(nextMeasuredData);
      if (measuredDimension === void 0) {
        return {
          dataToMeasure: nextMeasuredData,
          resizeDirection: "shrink"
        };
      }
      dataToMeasure = nextMeasuredData;
    }
    return {
      renderedData: dataToMeasure,
      resizeDirection: void 0,
      dataToMeasure: void 0
    };
  }
  function _growDataUntilItDoesNotFit(data, onGrowData, getElementToMeasureDimension, onReduceData) {
    var dataToMeasure = data;
    var measuredDimension = _getMeasuredDimension(data, getElementToMeasureDimension);
    while (measuredDimension < _containerDimension) {
      var nextMeasuredData = onGrowData(dataToMeasure);
      if (nextMeasuredData === void 0) {
        return {
          renderedData: dataToMeasure,
          resizeDirection: void 0,
          dataToMeasure: void 0
        };
      }
      measuredDimension = _measurementCache.getCachedMeasurement(nextMeasuredData);
      if (measuredDimension === void 0) {
        return {
          dataToMeasure: nextMeasuredData
        };
      }
      dataToMeasure = nextMeasuredData;
    }
    return __assign({ resizeDirection: "shrink" }, _shrinkContentsUntilTheyFit(dataToMeasure, onReduceData, getElementToMeasureDimension));
  }
  function _updateContainerDimension(newDimension, fullDimensionData, renderedData, onGrowData) {
    var nextState;
    if (newDimension > _containerDimension) {
      if (onGrowData) {
        nextState = {
          resizeDirection: "grow",
          dataToMeasure: onGrowData(renderedData)
        };
      } else {
        nextState = {
          resizeDirection: "shrink",
          dataToMeasure: fullDimensionData
        };
      }
    } else {
      nextState = {
        resizeDirection: "shrink",
        dataToMeasure: renderedData
      };
    }
    _containerDimension = newDimension;
    return __assign(__assign({}, nextState), { measureContainer: false });
  }
  function getNextState(props, currentState, getElementToMeasureDimension, newContainerDimension) {
    if (newContainerDimension === void 0 && currentState.dataToMeasure === void 0) {
      return void 0;
    }
    if (newContainerDimension) {
      if (_containerDimension && currentState.renderedData && !currentState.dataToMeasure) {
        return __assign(__assign({}, currentState), _updateContainerDimension(newContainerDimension, props.data, currentState.renderedData, props.onGrowData));
      }
      _containerDimension = newContainerDimension;
    }
    var nextState = __assign(__assign({}, currentState), { measureContainer: false });
    if (currentState.dataToMeasure) {
      if (currentState.resizeDirection === "grow" && props.onGrowData) {
        nextState = __assign(__assign({}, nextState), _growDataUntilItDoesNotFit(currentState.dataToMeasure, props.onGrowData, getElementToMeasureDimension, props.onReduceData));
      } else {
        nextState = __assign(__assign({}, nextState), _shrinkContentsUntilTheyFit(currentState.dataToMeasure, props.onReduceData, getElementToMeasureDimension));
      }
    }
    return nextState;
  }
  function shouldRenderDataForMeasurement(dataToMeasure) {
    if (!dataToMeasure || _measurementCache.getCachedMeasurement(dataToMeasure) !== void 0) {
      return false;
    }
    return true;
  }
  function getInitialResizeGroupState(data) {
    return {
      dataToMeasure: __assign({}, data),
      resizeDirection: "grow",
      measureContainer: true
    };
  }
  return {
    getNextState: getNextState,
    shouldRenderDataForMeasurement: shouldRenderDataForMeasurement,
    getInitialResizeGroupState: getInitialResizeGroupState
  };
};
var hiddenDivStyles = { position: "fixed", visibility: "hidden" };
var hiddenParentStyles = { position: "relative" };
var ResizeGroupBase = function(_super) {
  __extends(ResizeGroupBase2, _super);
  function ResizeGroupBase2() {
    var _this = _super !== null && _super.apply(this, arguments) || this;
    _this.nextResizeGroupStateProvider = getNextResizeGroupStateProvider();
    _this.hasRenderedContent = false;
    _this.dataToMeasure = {};
    _this.measureContainer = false;
    _this.renderedData = {};
    _this.resizeDirection = "grow";
    return _this;
  }
  ResizeGroupBase2.prototype.created = function() {
    var state = this.nextResizeGroupStateProvider.getInitialResizeGroupState(this.data);
    this.dataToMeasure = state.dataToMeasure;
    this.measureContainer = state.measureContainer;
    this.renderedData = state.renderedData;
    this.resizeDirection = state.resizeDirection;
  };
  ResizeGroupBase2.prototype.mounted = function() {
    this.events.on(window, "resize", this._async.debounce(this._onResize, RESIZE_DELAY, { leading: true }));
    this.componentDidUpdate();
  };
  ResizeGroupBase2.prototype.updated = function() {
    this.componentDidUpdate();
  };
  ResizeGroupBase2.prototype.componentDidUpdate = function() {
    console.log("componentDidUpdate");
    this.dataToMeasure = this.data;
    this.resizeDirection = "grow";
    this.measureContainer = true;
    if (this.renderedData) {
      this.hasRenderedContent = true;
      if (this.dataDidRender) {
        this.dataDidRender(this.renderedData);
      }
    }
    this._afterComponentRendered(this.direction);
  };
  ResizeGroupBase2.prototype._afterComponentRendered = function(direction) {
    var _this = this;
    this._async.requestAnimationFrame(function() {
      var containerDimension;
      if (_this.measureContainer && _this.$refs.root) {
        var boundingRect = _this.$refs.root.getBoundingClientRect();
        containerDimension = direction && direction === ResizeGroupDirection.vertical ? boundingRect.height : boundingRect.width;
      }
      var nextState = _this.nextResizeGroupStateProvider.getNextState(_this.$props, _this.$data, function() {
        var refToMeasure = !_this.hasRenderedContent ? _this.$refs.initialHiddenDiv : _this.$refs.updateHiddenDiv;
        if (!refToMeasure) {
          return 0;
        }
        return direction && direction === ResizeGroupDirection.vertical ? refToMeasure.scrollHeight : refToMeasure.scrollWidth;
      }, containerDimension);
      if (nextState) {
        _this.dataToMeasure = nextState.dataToMeasure;
        _this.measureContainer = nextState.measureContainer;
        _this.renderedData = nextState.renderedData;
        _this.resizeDirection = nextState.resizeDirection;
      }
    });
  };
  ResizeGroupBase2.prototype._onResize = function() {
    if (this.$refs.root) {
      this.measureContainer = true;
    }
  };
  ResizeGroupBase2.prototype.render = function(h) {
    var _a = this, className = _a.className, dataToMeasure = _a.dataToMeasure; _a.renderedData;
    var dataNeedsMeasuring = this.nextResizeGroupStateProvider.shouldRenderDataForMeasurement(dataToMeasure);
    var isInitialMeasure = !this.hasRenderedContent && dataNeedsMeasuring;
    return h("div", { class: className, attrs: { ref: "root" } }, [
      h("div", { style: hiddenParentStyles }, [
        dataNeedsMeasuring && !isInitialMeasure && h("div", {
          ref: "updateHiddenDiv",
          style: hiddenDivStyles
        }, "Test"),
        h("div", {
          ref: "initialHiddenDiv",
          style: isInitialMeasure ? hiddenDivStyles : void 0
        }, this.$slots.default)
      ])
    ]);
  };
  __decorate([
    Prop(),
    __metadata("design:type", Object)
  ], ResizeGroupBase2.prototype, "data", void 0);
  __decorate([
    Prop({ type: Number, default: ResizeGroupDirection.horizontal }),
    __metadata("design:type", Object)
  ], ResizeGroupBase2.prototype, "direction", void 0);
  __decorate([
    Prop({ type: Function, default: null }),
    __metadata("design:type", Function)
  ], ResizeGroupBase2.prototype, "dataDidRender", void 0);
  ResizeGroupBase2 = __decorate([
    Component
  ], ResizeGroupBase2);
  return ResizeGroupBase2;
}(BaseComponent);

export { ResizeGroupBase, getMeasurementCache, getNextResizeGroupStateProvider };
