/* eslint-disable jsdoc/require-description-complete-sentence */ "use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "ViewDiffer", {
    enumerable: true,
    get: function() {
        return ViewDiffer;
    }
});
const _constants = require("../constants");
const _viewOrder = require("./viewOrder");
class ViewDiffer {
    /**
   * A method which generates commands/leads which has to be executed to achieve new DOM
   * nodes order based on new offset and view size.
   *
   * For example, if current order looks like this (offset = 0, viewSize = 1):
   *   <body> (root node)
   *     └ <tr> (row 0)
   * and next order should look like this (offset: 0, viewSize = 5):
   *   <body> (root node)
   *     ├ <tr> (row 0)
   *     ├ <tr> (row 1)
   *     ├ <tr> (row 2)
   *     ├ <tr> (row 3)
   *     └ <tr> (row 4)
   * the generated commands/leads will look like this:
   *   <body> (root node)
   *     ├ <tr> (none, do nothing, leave as it is)
   *     ├ <tr> (append this element at index 1)
   *     ├ <tr> (append this element at index 2)
   *     ├ <tr> (append this element at index 3)
   *     └ <tr> (append this element at index 4)
   *
   * @returns {Array[]} Returns an array with generated commands/leads.
   */ diff() {
        const { sizeSet } = this;
        const { currentSize: currentViewSize, nextSize: nextViewSize, currentOffset, nextOffset } = sizeSet.getViewSize();
        let maxSize = Math.max(nextViewSize, currentViewSize);
        if (maxSize === 0) {
            return [];
        }
        const currentViewOrder = new _viewOrder.ViewOrder(currentOffset, currentViewSize);
        const isShared = sizeSet.isShared();
        const useAppend = !isShared || sizeSet.isPlaceOn(_constants.WORKING_SPACE_BOTTOM);
        const leads = [];
        for(let i = 0; i < maxSize; i++){
            const currentIndex = currentViewOrder.get(i);
            const nextIndex = i < nextViewSize ? nextOffset + i : -1;
            // Current index exceeds the next DOM index so it is necessary to generate a "remove" command
            // to achieve new order.
            if (nextIndex === -1) {
                leads.push([
                    _constants.CMD_REMOVE,
                    currentIndex
                ]);
            // Next index exceeds the current DOM index so it is necessary to generate a "append" command
            // to achieve new order.
            } else if (currentIndex === -1) {
                // Check what command should be generated (depends on if this work as a shared root node
                // and in what position or not)
                if (useAppend) {
                    /**
           * If the differ has only one root node to manage with, the "append" command is generated.
           *
           * For example:
           *     ┌─────────── <body> (root node)
           *     │              <tr>
           *     │              <tr>
           *  (managed by one   <tr>
           *   differ - TRs)    <tr>
           *     │              <tr>
           *     └───────────   <tr> <--- Generates "append" command (which later executes `rootNode.appendChild(node)`)
           */ leads.push([
                        _constants.CMD_APPEND,
                        nextIndex
                    ]);
                } else {
                    /**
           * If the differ is sharing root node, the "prepend" command is generated.
           *
           * For example:
           *     ┌─────────── <tr> (root node, shared between two differs)
           *  (first differ)    <th> <--- Generates "prepend" command (which later executes `rootNode.insertBefore(...)`)
           *     ├───────────   <td>
           *     │              <td>
           *  (second differ    <td>
           *   - TDs)           <td>
           *     │              <td>
           *     └───────────   <td>
           */ leads.push([
                        _constants.CMD_PREPEND,
                        nextIndex
                    ]);
                }
            } else if (nextIndex > currentIndex) {
                // This emulates DOM behavior when we try to append (or replace) an element which is already
                // mounted. The old index in the array has to be popped out indicating that an element was
                // moved to a different position.
                if (currentViewOrder.has(nextIndex)) {
                    currentViewOrder.remove(nextIndex);
                    // Decrease loop size to prevent generating "remove" leads. "remove" leads are necessary only for nodes
                    // which are not mounted in current DOM order.
                    if (nextViewSize <= currentViewOrder.length) {
                        maxSize -= 1;
                    }
                }
                leads.push([
                    _constants.CMD_REPLACE,
                    nextIndex,
                    currentIndex
                ]);
            } else if (nextIndex < currentIndex) {
                const indexToRemove = currentViewOrder.prepend(nextIndex);
                leads.push([
                    _constants.CMD_INSERT_BEFORE,
                    nextIndex,
                    currentIndex,
                    indexToRemove
                ]);
            } else {
                leads.push([
                    _constants.CMD_NONE,
                    nextIndex
                ]);
            }
        }
        return leads;
    }
    constructor(sizeSet){
        this.sizeSet = sizeSet;
    }
}
