"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.Sections = exports.MergeState = exports.MergeLoopState = exports.AppendLoopState = void 0;
exports.appendLoop = appendLoop;
exports.appendLoopState = appendLoopState;
exports.mergeLoopState = mergeLoopState;
exports.mergeStrategy = mergeStrategy;
exports.sections = sections;

var _Case = /*#__PURE__*/require("@effect-ts/core/Case");

var C = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect-ts/core/Collections/Immutable/Chunk"));

var _Function = /*#__PURE__*/require("@effect-ts/core/Function");

var IO = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect-ts/core/IO"));

var HorizontalMergeRules = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../HorizontalMergeRules/index.js"));

var MA = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../MergeAction/index.js"));

function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }

function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }

// ets_tracing: off
class MergeState extends _Case.Case {}
/**
 * Represents the status of the merge loop.
 */


exports.MergeState = MergeState;

class MergeLoopState extends _Case.Case {}
/**
 * Represents the status of the append loop.
 */


exports.MergeLoopState = MergeLoopState;

class AppendLoopState extends _Case.Case {}
/**
 * Represents the three sections of a set of columns.
 */


exports.AppendLoopState = AppendLoopState;

class Sections extends _Case.Case {} // -----------------------------------------------------------------------------
// Constructors
// -----------------------------------------------------------------------------


exports.Sections = Sections;

function sections(left, overlap, right) {
  return new Sections({
    left,
    overlap,
    right
  });
}

function appendLoopState(lastCharWidth = 0) {
  return new AppendLoopState({
    lastCharWidth
  });
}

function mergeLoopState(params) {
  return new MergeLoopState({
    a: C.empty(),
    b: C.empty(),
    overlap: 0,
    partialResult: C.empty(),
    appendLoopState: appendLoopState(),
    ...params
  });
} // -----------------------------------------------------------------------------
// Operations
// -----------------------------------------------------------------------------

/**
 * Creates a merge strategy to perform horizontal merging, based on the given
 * `RenderOptions`.
 *
 * @param options The `RenderOptions` used to build the `MergeStrategy`.
 * @return A `MergeStrategy` function that performs horizontal merging.
 */


function mergeStrategy(options) {
  return HorizontalMergeRules.mergeStrategy(options);
}

function appendLoop(options, figures, partial, state) {
  return IO.run(appendLoopRec(options, figures, partial, state));
}

function appendLoopRec(options, figures, partial, state) {
  return IO.gen(function* (_) {
    if (C.isEmpty(figures)) {
      return partial;
    }

    const {
      tuple: [head, remainingChars]
    } = C.splitAt_(figures, 1);
    const figChar = C.unsafeGet_(head, 0);
    const {
      tuple: [upperLines, last]
    } = C.splitAt_(partial, partial.length - 1);
    const lastLine = C.unsafeGet_(last, 0);
    const merged = yield* _(mergeRec(options, mergeLoopState({
      a: lastLine,
      b: figChar,
      appendLoopState: state
    })));
    const onBorder = yield* _(mergeRec(options, mergeLoopState({
      b: figChar
    })));
    const result = merged.length <= options.maxWidth ? C.append_(upperLines, merged) : C.append_(partial, onBorder);
    const nextState = state.copy({
      lastCharWidth: figChar.length
    });
    return yield* _(appendLoopRec(options, remainingChars, result, nextState));
  });
}

function mergeRec(options, state) {
  return IO.gen(function* (_) {
    if (state.overlap === 0) {
      return yield* _(mergeRec(options, state.copy({
        overlap: 1,
        partialResult: C.concat_(state.a, state.b)
      })));
    }

    if (state.overlap > state.b.length) {
      return state.partialResult;
    }

    const mState = new MergeState({
      overlap: state.overlap,
      currentCharWidth: state.b.length,
      lastCharWidth: state.appendLoopState.lastCharWidth
    });
    const aLeftCut = Math.max(0, state.a.length - state.overlap);
    const aRightCut = Math.min(state.a.length, state.a.length - state.overlap + state.b.length);
    const aSections = splitSections(aLeftCut, aRightCut, state.a);
    const bLeftCut = Math.max(0, state.overlap - state.a.length);
    const bRightCut = Math.min(state.overlap, state.b.length);
    const bSections = splitSections(bLeftCut, bRightCut, state.b);
    const leftSide = mergeOnLeftBorder(options, mState, bSections.left);
    const merged = mergeOverlappingSections(options, mState, aSections.overlap, bSections.overlap);
    const rightSide = new MA.Continue({
      value: C.concat_(aSections.right, bSections.right)
    });
    const result = MA.map_(MA.tuple(leftSide, merged, rightSide), ([_, merged, right]) => C.concat_(aSections.left, C.concat_(merged, right)));

    switch (result._tag) {
      case "Stop":
        return state.partialResult;

      case "CurrentLast":
        return result.value;

      case "Continue":
        return yield* _(mergeRec(options, state.copy({
          overlap: state.overlap + 1,
          partialResult: result.value
        })));
    }
  });
}
/**
 * Divides a set of columns into 3 sections with cuts in 2 points.
 */


function splitSections(aPoint, bPoint, figure) {
  return C.reduce_(C.zipWithIndex(figure), sections(C.empty(), C.empty(), C.empty()), (store, {
    tuple: [column, i]
  }) => {
    if (i < aPoint) return store.copy({
      left: C.append_(store.left, column)
    });
    if (i >= bPoint) return store.copy({
      right: C.append_(store.right, column)
    });
    return store.copy({
      overlap: C.append_(store.overlap, column)
    });
  });
}
/**
 * Merges the two overlapping sections of two characters.
 */


function mergeOverlappingSections(options, state, aSection, bSection) {
  return C.forEachF(MA.Applicative)(({
    tuple: [aActiveColumn, bActiveColumn]
  }) => {
    const aColumnSplit = C.from(aActiveColumn.split(""));
    const bColumnSplit = C.from(bActiveColumn.split(""));
    return MA.map_(C.forEachF(MA.Applicative)(({
      tuple: [aChar, bChar]
    }) => mergeStrategy(options)(state)(aChar, bChar))(C.zip_(aColumnSplit, bColumnSplit)), C.join(""));
  })(C.zip_(aSection, bSection));
}
/**
 * Merges a character on the left border.
 */


function mergeOnLeftBorder(options, state, section) {
  return MA.map_(C.forEachF(MA.Applicative)(col => C.forEachF(MA.Applicative)(char => char === " " ? mergeStrategy(options)(state)(options.font.header.hardblank, " ") : new MA.Stop())(C.from(col.split(""))))(section), _Function.constVoid);
}
//# sourceMappingURL=index.js.map