import { getRefField } from './utils.js';

const INSERT_MODES = {
  threshold: (prev, next, threshold) => prev + threshold,
  midpoint: (prev, next, threshold) => (prev + next) / 2,
  // previous time + 1ms to prevent StateTimeline from forward-interpolating prior state
  plusone: (prev, next, threshold) => prev + 1
};
function applyNullInsertThreshold(opts) {
  if (opts.frame.length === 0) {
    return opts.frame;
  }
  let { frame, refFieldName, refFieldPseudoMax, refFieldPseudoMin, insertMode } = opts;
  if (!insertMode) {
    insertMode = INSERT_MODES.threshold;
  }
  const refField = getRefField(frame, refFieldName);
  if (refField == null) {
    return frame;
  }
  refField.state = {
    ...refField.state,
    nullThresholdApplied: true
  };
  const thresholds = frame.fields.map((field) => {
    var _a;
    return ((_a = field.config.custom) == null ? void 0 : _a.insertNulls) || refField.config.interval || null;
  });
  const uniqueThresholds = new Set(thresholds);
  uniqueThresholds.delete(null);
  if (uniqueThresholds.size === 0) {
    return frame;
  }
  if (uniqueThresholds.size === 1) {
    const threshold = uniqueThresholds.values().next().value;
    if (threshold <= 0) {
      return frame;
    }
    const refValues = refField.values;
    const frameValues = frame.fields.map((field) => field.values);
    const filledFieldValues = nullInsertThreshold(
      refValues,
      frameValues,
      threshold,
      refFieldPseudoMin,
      refFieldPseudoMax,
      insertMode);
    if (filledFieldValues === frameValues) {
      return frame;
    }
    return {
      ...frame,
      length: filledFieldValues[0].length,
      fields: frame.fields.map((field, i) => ({
        ...field,
        values: filledFieldValues[i]
      }))
    };
  }
  return frame;
}
function nullInsertThreshold(refValues, frameValues, threshold, refFieldPseudoMin = null, refFieldPseudoMax = null, getInsertValue, thorough) {
  const len = refValues.length;
  const refValuesNew = [];
  if (refFieldPseudoMin != null && refFieldPseudoMin < refValues[0]) {
    let preFillCount = Math.ceil((refValues[0] - refFieldPseudoMin) / threshold);
    let prevSlot = refValues[0] - preFillCount * threshold;
    while (prevSlot < refValues[0]) {
      refValuesNew.push(getInsertValue(prevSlot - threshold, prevSlot, threshold));
      prevSlot += threshold;
    }
  }
  refValuesNew.push(refValues[0]);
  let prevValue = refValues[0];
  for (let i = 1; i < len; i++) {
    const curValue = refValues[i];
    while (curValue - prevValue > threshold) {
      refValuesNew.push(getInsertValue(prevValue, curValue, threshold));
      prevValue += threshold;
    }
    refValuesNew.push(curValue);
    prevValue = curValue;
  }
  if (refFieldPseudoMax != null && refFieldPseudoMax > prevValue) {
    while (prevValue + threshold < refFieldPseudoMax) {
      refValuesNew.push(getInsertValue(prevValue, refFieldPseudoMax, threshold));
      prevValue += threshold;
    }
  }
  const filledLen = refValuesNew.length;
  if (filledLen === len) {
    return frameValues;
  }
  const filledFieldValues = [];
  for (let fieldValues of frameValues) {
    let filledValues;
    if (fieldValues !== refValues) {
      filledValues = Array(filledLen);
      for (let i = 0, j = 0; i < filledLen; i++) {
        filledValues[i] = refValues[j] === refValuesNew[i] ? fieldValues[j++] : null;
      }
    } else {
      filledValues = refValuesNew;
    }
    filledFieldValues.push(filledValues);
  }
  return filledFieldValues;
}

export { applyNullInsertThreshold };
//# sourceMappingURL=nullInsertThreshold.js.map
