
import { ExpParser } from '../util/expparser.js';
var pasteDataFormater = require('../util/pasteDataFormatter.js');

var jsep = require("../vendors/jsep.js");

(function ($) {
    var dataKey = 'cellsSelector';
    var selectableTableClass = 'tcs';
    var selectedCellClass = 'tcs-selected';
    var selectionEnabled = 'tcs-selection-enabled';
    var isMouseDown = false;
    var rgTextBuffer = null;
    var widthStart = 0;
    var heightStart = 0;
    var oppositeActions = {
        "mergeCells": "unMergeCells",
        "unMergeCells": "mergeCells",
        "hideCol": "showCol",
        "showCol": "hideCol",
        "hideRow": "showRow",
        "showRow": "hideRow",
        "deleteCol": "colRight",
        "deleteRow": "rowTop",
        "rowTop": "deleteRow",
        "colRight": "deleteCol",
        "CutCell": "PasteCell",
        "erase": "PasteCell",
        "eraseStyle": "PasteCellStyle",
        "LinkedCell": "PasteCell",
        "NodeInCell": "PasteCell",
        "NodeNameInCell": "PasteCell",
        "NodeValueNameInCell": "PasteCell",
        "Consolidate": "PasteCell",
        "TotalSum": "PasteCell",
        "PartialSum": "PasteCell",
        "GroupSum": "PasteCell",
        "ColumnSum": "PasteCell",
        "Average": "PasteCell",
        "Max": "PasteCell",
        "Min": "PasteCell",
        "info:'4'": "PasteCell",
        "info:'7'": "PasteCell",
        "info:'8'": "PasteCell",
        "info:'9'": "PasteCell",
        "info:'10'": "PasteCell",
        "periodname:'_'": "PasteCell",
        "perioddate:'_'": "PasteCell",
        "periodyear:'_'": "PasteCell",
    }
    var rgCommandList = {
        "textBold": "style",
        "textItalic": "style",
        "textUnderline": "style",
        "textFontFamily": "style",
        "textFontSize": "style",
        "align": "style",
        "textColor": "style",
        "backColor": "style",
        "cellStyle": "style",
        "eraseStyle": "style",
        "textWrap": "style",
        "erase": "style",
        "border": "style",
        "financialPeriod": "extraParam",
        "minusRedText": "extraParam",
        "minusParenthese": "extraParam",
        "dataType": "extraParam",
        "decimals": "extraParam",
        "accountType": "extraParam",
        "percent": "extraParam",
        "valueSource": "extraParam",
        "valueAccountType": "extraParam",
        "valueDisplay": "extraParam",
        "zeroDisplay": "extraParam",
        "roundingApproach": "extraParam",
        "groupType": "totalCost",
        "sortDirection": "totalCost",
        "mergeCells": "tableAction",
        "unMergeCells": "tableAction",
        "hideCol": "tableAction",
        "showCol": "tableAction",
        "hideRow": "tableAction",
        "showRow": "tableAction",
        "deleteCol": "tableAction",
        "deleteRow": "tableAction",
        "rowTop": "tableAction",
        "colRight": "tableAction",
        "width": "tableAction",
        "height": "tableAction",
        "LinkedCell": "setValue",
        "ClearNode": "setValue",
        "Consolidate": "setValue",
        "Column": "setValue",
        "TotalSum": "setValue",
        "GroupSum": "setValue",
        "ColumnSum": "setValue",
        "Average": "setValue",
        "PartialSum": "setSpecialValue",
        "Max": "setValue",
        "Min": "setValue",
        "info:'4'": "setValue",
        "info:'7'": "setValue",
        "info:'8'": "setValue",
        "info:'9'": "setValue",
        "info:'10'": "setValue",
        "periodname:'_'": "setValue",
        "perioddate:'_'": "setValue",
        "periodyear:'_'": "setValue",
        "info:'25'": "setValue",
        "xbrlConcept": "xbrlConcept",
        "colSortDirection": "financialProperties",
        "region": "financialProperties",
        "NodeInCell": "treeActions",
        "NodeNameInCell": "treeActions",
        "NodeValueNameInCell": "treeActions",
        "Formula": "formulaActions",
        "CellTyping": "setText",
        "PasteCell": "eventActions",
        "PasteCellStyle": "eventActions",
        "ChangeDesc": "setText",
    }
    var tagRender = function () {
        var getPeriodId = function (str) {
            var numb = str.match(/\d/g);
            numb = numb.join("");
            return Number(numb);
        }
        var cellInfo = function (ul, cell) {
            $(ul).empty();
            if (cell.cellInfos.length === 0)
                return;
            var cellInfo = cell.cellInfos[0];
            var item = _h.getEnumItem(cellInfoTypes, cellInfo.type);
            if (item) {
                $(ul).css("display", "block");
            }
            var li = _hh.createTag({
                name: "li",
                parent: ul
            });
            var a = _hh.createTag({
                name: "a",
                parent: li,
                attributes: {
                    "title": cellInfo.title ? cellInfo.title : item.text,
                    "data-container": "body"
                }
            });
            var baseAddr = "/App/src/images/Icons/";
            var val = item.value;
            if (cellInfo.type === 33 || cellInfo.type === 34 || cellInfo.type === 35) {
                baseAddr += cellInfo.type + "/";
                val = getPeriodId(cell.value);
            }

            _hh.createTag({
                name: "img",
                parent: a,
                className: "icon-image-xxsmall clickable",
                attributes: { "src": baseAddr + val + '.png' },
                onclick: function (event) {
                    if (event.target.src.indexOf("18.png") === -1 || !event.shiftKey)
                        return false;

                    var td = $(event.target).closest("td");
                    var table = $(event.target).closest("table");

                    table = rgUtil.getTable(table);
                    var model = rgUtil.getModel(table);
                    var address = $(td).attr("data-address");
                    var cell = model.cells.filter(a => a.address === address)[0];
                    if (cell.value && cell.value.indexOf("link") !== -1) {
                        _h.kocnx().ttvm().designBtn([{
                            id: cell.linkedTemplate.id,
                            templateTableType: cell.linkedTemplate.templateTableType,
                            title: cell.linkedTemplate.title
                        }]);
                    }
                },
                ondblclick: function (event) {
                    var td = $(event.target).closest("td");
                    var table = $(event.target).closest("table")[0];
                    if ($(table).hasClass("tsc-cs") || !$(table).hasClass("editable-table"))
                        return;
                    table = rgUtil.getTable(table);
                    var model = rgUtil.getModel(table);
                    var address = $(td).attr("data-address");
                    var cell = model.cells.filter(a => a.address === address)[0];
                    rgUtil.executeCommand($(table), model, { id: "ClearNode", value: undefined, cells: [cell] });
                }
            });
        }
        var buildCell = function (cell, frag, type, model) {
            var styles = "";
            var attributes = {
                'data-address': cell.address,
                'data-row': cell.row,
                'data-col': cell.col,
                'rowspan': cell.rowSpan,
                'colspan': cell.colSpan
            };
            switch (type) {
                case "cellSelect":
                    if (cell.value === null)
                        cell.value = "";
                    styles = (cell.value.indexOf("node") !== -1 || cell.value.startsWith("="))
                        ? ""
                        : "background-color:#e4e5e7;";
                    if (!styles) {
                        attributes["data-tag"] = cell.tag;
                        attributes["data-id"] = model.id;
                        attributes["data-ttType"] = model.tableTemplateType;
                        attributes["data-title"] = model.title;
                    }
                    break;
                default:
                    styles = cell.hidden ? "background-color:#e1e1e1;" : "";
                    break;
            }
            var td = _hh.cloneTag({
                name: "td",
                className: "rp-gen-cell",
                parent: frag,
                styles: styles,
                attributes: attributes
            });
            var iFrag = document.createDocumentFragment();
            _hh.createTag({
                name: "input",
                parent: iFrag,
                styles: cellFunc.translateCellStyle(cell),
                className: "cell-input",
                attributes: { "autocomplete": "off123" },
                value: cell.text
            });
            cellFunc.addCellEvents(td, type, styles);

            var ul = _hh.createTag({
                name: "ul",
                className: "cell-infos",
                parent: iFrag
            });
            if (cell.cellInfos.length)
                tagRender.cellInfo(ul, cell);
            var warningA = _hh.createTag({
                name: "a",
                className: "warning-sign",
                styles: "display:none;",
                attributes: { "data-container": "body" },
                parent: iFrag
            });
            _hh.createTag({
                name: "img",
                className: "icon-image-xxsmall",
                parent: iFrag,
                attributes: { "src": "/App/src/images/ico/warning.png" },
                parent: warningA
            });
            _hh.createTag({
                name: "div",
                className: "triangle-datatype",
                styles: !(cell.extraParams.dataType === 1) ? "display:none;" : "",
                parent: iFrag
            });
            _hh.createTag({
                name: "div",
                className: "triangle-format",
                styles: !cell.extraParams.minusRedText && !cell.extraParams.minusParenthese ? "display:none;" : "",
                parent: iFrag
            });
            _hh.createTag({
                name: "div",
                className: "triangle-xbrl",
                styles: !cell.xbrlConcept ? "display:none;" : "",
                "title": cell.xbrlConcept ? cell.xbrlConcept.title : '',
                parent: iFrag
            });
            _hh.createTag({
                name: "div",
                className: "triangle-desc",
                attributes: {
                    "data-container": "body",
                    "title": cell.desc
                },
                styles: !cell.desc ? "display:none;" : "",
                parent: iFrag
            });


            td.appendChild(iFrag);
        }
        var buildRow = function (tbody, model, rowHeight, type, append) {
            var cells = model.cells.filter(a => a.row === rowHeight.id);
            var trRow;
            if (!append) {
                trRow = _hh.createTag({
                    name: "tr",
                    parent: tbody
                });
            } else {
                trRow = _hh.createTag({
                    name: "tr",
                    attach: false
                });
                if (rowHeight.id > 1) {
                    var prevSib = $(tbody)
                        .find(".first-cell[data-row='" + (rowHeight.id - 1) + "']")
                        .parent();
                    $(trRow).insertAfter(prevSib);
                } else {
                    var currentEl = $(tbody)
                        .find(".first-cell")[0];
                    $(trRow).insertBefore($(currentEl).parent());
                }
            }
            var thRow = _hh.createTag({
                name: "th",
                parent: trRow,
                className: "first-cell",
                styles: "height:" + rowHeight.size,
                attributes: { "data-row": rowHeight.id }
            });
            _hh.createTag({
                name: "span",
                className: "th-label",
                parent: thRow,
                text: rowHeight.id,
                styles: "position: absolute;top: 23%;left: 41%;"
            });

            var frag = document.createDocumentFragment();
            for (let j = 0; j < cells.length; j++) {
                var cell = cells[j];
                buildCell(cell, frag, type, model);
            }
            trRow.appendChild(frag);

            if (type === "cellSelect") {
                _hh.createTag({
                    name: "th",
                    parent: trRow,
                    text: rowHeight.id,
                    className: "last-cell",
                    styles: "height:" + rowHeight.size,
                    attributes: { "data-row": rowHeight.id }
                });
            }

        }
        var buildThCol = function (colWidth, i, trCol, model) {
            if (i === 0) {
                _hh.createTag({
                    name: "th",
                    parent: trCol,
                    className: "cross-cell",
                    attributes: { "data-col": 0 }
                });
            }
            var parent = _hh.createTag({
                name: "th",
                parent: trCol,
                styles: "width:" + colWidth.size,
                className: "rp-gen-col",
                text: _h.numberToAlphabet(colWidth.id),
                attributes: { "data-col": colWidth.id }
            });
            var className = "fa";
            if (colWidth.id === model.financialProperties.sortColumn.id) {
                className = model.financialProperties.sortColumn.sortDirection === 0 ?
                    "fa fa-sort-amount-asc" : "fa fa-sort-amount-desc";

            }
            _hh.createTag({
                name: "span",
                parent: parent,
                className: className,
                attributes: { "data-col": colWidth.id }
            });

        }
        var buildTable = function (hostEl, model, type) {
            var table = _hh.createTag({
                name: "table",
                parent: hostEl,
                className: type === "cellSelect" ? "tsc-cs" : "tsc-ed"
            });
            var thead = _hh.createTag({
                name: "thead",
                parent: table
            });
            var trCol = _hh.createTag({
                name: "tr",
                styles: "height: 28px;",
                parent: thead
            });
            for (let i = 0; i < model.colsWidth.length; i++) {
                var colWidth = model.colsWidth[i];
                buildThCol(colWidth, i, trCol, model);
            }
            var tbody = _hh.createTag({
                name: "tbody",
                parent: table
            });
            for (let i = 0; i < model.rowsHeight.length; i++) {
                var rowHeight = model.rowsHeight[i];
                buildRow(tbody, model, rowHeight, type, false);
            }
            if (type === "cellSelect") {

                _hh.createTag({
                    name: "th",
                    parent: trCol,
                    className: "cross-cell",
                    attributes: { "data-col": 0 }
                });

                var tfoot = _hh.createTag({
                    name: "tfoot",
                    parent: table
                });
                trCol = _hh.createTag({
                    name: "tr",
                    styles: "height: 28px;",
                    parent: tfoot
                });
                for (let i = 0; i < model.colsWidth.length; i++) {
                    var colWidth = model.colsWidth[i];
                    buildThCol(colWidth, i, trCol, model);
                }

                _hh.createTag({
                    name: "th",
                    parent: trCol,
                    className: "cross-cell",
                    attributes: { "data-col": 0 }
                });
            }


            return table;
        }
        var sortRowTdList = function (tr) {
            var cols = $(tr).find("td").get();
            cols.sort(function (a, b) {
                var colA = Number($(a).attr('data-col'));
                var colB = Number($(b).attr('data-col'));
                if (colA < colB)
                    return -1;
                if (colA > colB)
                    return 1;
                return 0;
            });
            $.each(cols, function (index, col) {
                $(tr).append(col);
            });
        }
        var applyToTable = function (type, table, model, val) {
            var cells, cell, target, rowId, colId, rowHeight, colNumber, trList, col;
            switch (type) {
                case "unMergeCells":
                    trList = $(table).find("tr");
                    for (var i = 0; i < val.length; i++) {
                        var item = val[i];
                        cell = model.cells.filter(a => a.row === item.row && a.col === item.col)[0];
                        buildCell(cell, trList[item.row]);
                        sortRowTdList(trList[item.row]);
                    }
                    break;
                case "hiddenCells":
                    var arrayRows = model.hiddenRows;
                    var arrayCols = model.hiddenCols;
                    for (let i = 0; i < model.rowsHeight.length; i++) {
                        rowHeight = model.rowsHeight[i];
                        cells = model.cells.filter(a => a.row === rowHeight.id);
                        for (var j = 0; j < cells.length; j++) {
                            target = cells[j];
                            if ((arrayRows && arrayRows.indexOf(target.row) !== -1) ||
                                (arrayCols && arrayCols.indexOf(target.col) !== -1)) {
                                $(table).find('[data-address="' + target.address + '"]').css("background-color", "#e1e1e1");
                            } else {
                                $(table).find('[data-address="' + target.address + '"]').css("background-color", "");
                            }
                        }
                    }
                    break;
                case "DynamicValueHiddenCells":
                    var arrayRows = val[0];
                    var arrayCols = val[1];
                    for (let i = 0; i < model.rowsHeight.length; i++) {
                        rowHeight = model.rowsHeight[i];
                        cells = model.cells.filter(a => a.row === rowHeight.id);
                        for (var j = 0; j < cells.length; j++) {
                            target = cells[j];
                            if ((arrayRows && arrayRows.indexOf(target.row) !== -1) ||
                                (arrayCols && arrayCols.indexOf(target.col) !== -1)) {
                                $(table).find('[data-address="' + target.address + '"]').css("background-color", "#e1e1e1");
                            } else {
                                $(table).find('[data-address="' + target.address + '"]').css("background-color", "");
                            }
                        }
                    }

                    break;
                case "removeCol":
                    if (val.reduceCells.length > 0)
                        for (var n = 0; n < val.reduceCells.length; n++) {
                            target = $(table).find("td[data-address='" + val.reduceCells[n] + "']");
                            target.attr("colSpan", Number(target.attr("colSpan")) - 1);
                        }

                    var colElement = $(table).find("th[data-col='" + val.targetCol + "']");
                    $(colElement).remove();
                    var removeList = $(table).find("td[data-col='" + val.targetCol + "']");
                    for (var q = 0; q < removeList.length; q++) {
                        target = removeList[q];
                        var dAddr = $(target).attr("data-address");
                        if (!val.reduceCells || val.reduceCells.indexOf(dAddr) === -1)
                            $(target).remove();
                    }
                    var colList = $(table).find("th.rp-gen-col");
                    for (var k = 0; k < colList.length; k++) {
                        col = colList[k];
                        colNumber = Number($(col).attr("data-col"));

                        if (colNumber > val.targetCol) {
                            $(col).attr("data-col", colNumber - 1);
                            $(col).text(_h.numberToAlphabet(colNumber - 1));
                        }
                    }
                    var cellList = $(table).find("td");
                    for (var l = 0; l < cellList.length; l++) {
                        colNumber = Number($(cellList[l]).attr("data-col"));
                        if (colNumber > val.targetCol) {
                            $(cellList[l]).attr("data-col", colNumber - 1);
                            $(cellList[l]).attr("data-address",
                                _h.numberToAlphabet(colNumber - 1) + $(cellList[l]).attr("data-row"));
                        }
                    }
                    break;
                case "colRight":
                    if (val.increaseCells.length > 0)
                        for (var n = 0; n < val.increaseCells.length; n++) {
                            target = $(table).find("td[data-address='" + val.increaseCells[n] + "']");
                            target.attr("colSpan", Number(target.attr("colSpan")) + 1);
                        }

                    cells = $(table).find("td.rp-gen-cell");
                    for (var m = 0; m < cells.length; m++) {
                        cell = cells[m];
                        colId = Number($(cell).attr("data-col"));
                        if (colId >= val.targetCol) {
                            $(cell).attr("data-col", colId + 1);
                            if (cell.nodeName === "TD") {
                                rowId = $(cell).attr("data-row");
                                $(cell).attr("data-address", _h.numberToAlphabet(colId + 1) + rowId);
                            }
                        }
                    }

                    trList = $(table).find("tr");
                    if (val.addCells.length)
                        for (var r = 0; r < val.addCells.length; r++) {
                            cell = val.addCells[r];
                            buildCell(cell, trList[cell.row]);
                            sortRowTdList(trList[cell.row]);
                        }

                    $(trList[0]).empty();
                    for (let i = 0; i < model.colsWidth.length; i++) {
                        var colWidth = model.colsWidth[i];
                        buildThCol(colWidth, i, trList[0], model);
                    }
                    break;
                case "removeRow":
                    if (val.reduceCells.length > 0)
                        for (var n = 0; n < val.reduceCells.length; n++) {
                            target = $(table).find("td[data-address='" + val.reduceCells[n] + "']");
                            target.attr("rowSpan", Number(target.attr("rowSpan")) - 1);
                        }
                    var targetTr = $(table).find("th[data-row='" + val.targetRow + "']").parent();
                    var sortList = [];
                    if (val.reduceAndReplaceCells.length > 0)
                        for (var p = 0; p < val.reduceAndReplaceCells.length; p++) {
                            target = $(table).find("td[data-address='" + val.reduceAndReplaceCells[p] + "']");
                            var rNum = Number(target.attr("rowSpan"));
                            target.attr("rowSpan", rNum - 1);
                            var newTargetTr = $(table).find("th[data-row='" + (val.targetRow + 1) + "']").parent();
                            sortList.push(newTargetTr);
                            $(target).appendTo(newTargetTr);

                        }
                    targetTr.remove();
                    cells = $(table).find("th.first-cell, td.rp-gen-cell");
                    for (var m = 0; m < cells.length; m++) {
                        cell = cells[m];
                        rowId = Number($(cell).attr("data-row"));
                        if (rowId > val.targetRow) {
                            $(cell).attr("data-row", rowId - 1);
                            if (cell.nodeName === "TH") {
                                var targetSpan = $(cell).find(".th-label");
                                $(targetSpan).text(rowId - 1);
                            }
                            if (cell.nodeName === "TD") {
                                colId = $(cell).attr("data-col");
                                $(cell).attr("data-address", _h.numberToAlphabet(colId) + (rowId - 1));
                            }
                        }
                    }
                    if (sortList.length)
                        for (var o = 0; o < sortList.length; o++) {
                            sortRowTdList(sortList[o]);
                        }
                    break;
                case "rowTop":
                    if (val.increaseCells.length > 0)
                        for (var n = 0; n < val.increaseCells.length; n++) {
                            target = $(table).find("td[data-address='" + val.increaseCells[n] + "']");
                            target.attr("rowSpan", Number(target.attr("rowSpan")) + 1);
                        }

                    var tbody = $(table).find("tbody");
                    cells = $(table).find("th.first-cell, td.rp-gen-cell");
                    for (var m = 0; m < cells.length; m++) {
                        cell = cells[m];
                        rowId = Number($(cell).attr("data-row"));
                        if (rowId >= val.targetRow) {
                            $(cell).attr("data-row", rowId + 1);
                            if (cell.nodeName === "TH") {
                                var targetSpan = $(cell).find(".th-label");
                                $(targetSpan).text(rowId + 1);
                            }
                            if (cell.nodeName === "TD") {
                                colId = $(cell).attr("data-col");
                                $(cell).attr("data-address", _h.numberToAlphabet(colId) + (rowId + 1));
                            }
                        }
                    }
                    rowHeight = model.rowsHeight.filter(a => a.id === val.targetRow)[0];
                    buildRow(tbody.get(0), model, rowHeight, "edit", true);
                    break;
                case "setDynamicValue":
                    $(table).addClass('preview-mode');
                    break;
                case "resetDynamicValue":
                    $(table).removeClass('preview-mode');
                    break;
                case "colSortDirection":
                    var iList = $(table).find(".fa");
                    for (var i = 0; i < iList.length; i++) {
                        var target = iList[i];
                        var colId = $(target).attr("data-col");
                        $(target).attr("class", "fa");
                        if (Number(colId) === model.financialProperties.sortColumn.id) {
                            var className;
                            switch (model.financialProperties.sortColumn.sortDirection) {
                                case 0:
                                    className = "fa fa-sort-amount-asc";
                                    $(target).attr("class", className);
                                    break;
                                case 1:
                                    className = "fa fa-sort-amount-desc";
                                    $(target).attr("class", className);
                                    break;
                            }
                        }
                    }
                    break;
                case "colSortDirectionReset":
                    var iList = $(table).find(".fa");
                    for (var i = 0; i < iList.length; i++) {
                        $(iList[i]).attr("class", "fa");
                    }
                    break;
            }
        }
        var applyToElement = function (table, cell, type, value) {
            var cellElement = $(table).find('[data-col="' + cell.col + '"][data-row="' + cell.row + '"]');
            var target, styles;
            switch (type) {
                case "NodeInCell":
                case "Consolidate":
                case "Column":
                case "LinkedCell":
                case "NodeNameInCell":
                    $(cellElement).find("input").val(undefined);
                    target = $(cellElement).find(".cell-infos");
                    tagRender.cellInfo(target[0], cell);
                    if (type === "NodeInCell") {
                        $(".txtFormula:visible").val(cell.value);
                    }
                    break;
                case "info":
                    $(cellElement).find("input").val(undefined);
                    target = $(cellElement).find(".cell-infos");
                    tagRender.cellInfo(target[0], cell);
                    break;
                case "style":
                    target = $(cellElement).find("input");
                    styles = cellFunc.translateCellStyle(cell);
                    $(target).attr("style", styles);
                    break;
                case "erase":
                    $(cellElement).find("input").val(undefined);
                    $(cellElement)
                        .find(".triangle-format").css("display", "none");
                    $(cellElement)
                        .find(".triangle-datatype").css("display", "block");
                    $(cellElement)
                        .find(".triangle-xbrl").css("display", "none");
                    $(cellElement)
                        .find(".triangle-desc").css("display", "none");
                    target = $(cellElement).find(".cell-infos");
                    tagRender.cellInfo(target[0], cell);
                    break;
                case "paste":
                    var bSelector = $(table).data("baseSelector");
                    target = $(cellElement).find("input");
                    target.val(cell.text);
                    styles = cellFunc.translateCellStyle(cell);
                    $(target).attr("style", styles);
                    target = $(cellElement).find(".cell-infos");
                    tagRender.cellInfo(target[0], cell);
                    target = $(cellElement).find(".triangle-format");
                    cell.extraParams.minusRedText || cell.extraParams.minusParenthese
                        ? target.css("display", "block")
                        : target.css("display", "none");
                    target = $(cellElement).find(".triangle-datatype");
                    cell.extraParams.dataType === 1 ? target.css("display", "block") : target.css("display", "none");
                    if (cell.value && cell.value.startsWith("=")) {
                        $(bSelector + ' .txtFormula').val(cell.value);
                    }
                    break;
                case "cut":
                    $(cellElement).find("input").val(undefined);
                    $(cellElement)
                        .find(".triangle-format").css("display", "none");
                    $(cellElement)
                        .find(".triangle-datatype").css("display", "block");
                    $(cellElement)
                        .find(".triangle-xbrl").css("display", "none");
                    $(cellElement).find(".cell-infos").empty();
                    break;
                case "span":
                    $(cellElement).attr("colspan", cell.colSpan);
                    $(cellElement).attr("rowspan", cell.rowSpan);
                    break;
                case "removeCell":
                    $(cellElement).remove();
                    break;
                case "Formula":
                    var bSelector = $(table).data("baseSelector");
                    $(cellElement).find("input").val(undefined);
                    target = $(cellElement).find(".cell-infos");
                    tagRender.cellInfo(target[0], cell);
                    if (cell.value && cell.value.startsWith("=")) {
                        $(bSelector + ' .txtFormula').val(cell.value);
                    }
                    break;
                case "setDynamicValue":
                    $(cellElement).find(".cell-infos").css("display", "none");
                    $(cellElement).find("input").val(cell.text);
                    if (cell.redText) {
                        $(cellElement).find("input").css("color", "red");
                    }
                    var triangle = $(cellElement).find(".triangle-desc");
                    if (cell.desc) {
                        triangle.css("display", "block");
                        triangle.attr("title", "");
                        triangle.attr("data-original-title", cell.desc);
                        _h.activeTooltip(true);
                    } else {
                        triangle.css("display", "none");
                        triangle.attr("title", "");
                        triangle.attr("data-original-title", "");
                    }
                    break;
                case "resetDynamicValue":
                    $(cellElement).find(".cell-infos").css("display", "");
                    if (!cell.style.textColor) {
                        $(cellElement).find("input").css("color", "");
                    } else {
                        $(cellElement).find("input").css("color", cell.style.textColor);
                    }

                    var triangle = $(cellElement).find(".triangle-desc");
                    if (cell.desc) {
                        triangle.css("display", "block");
                        triangle.attr("title", "");
                        triangle.attr("data-original-title", cell.desc);
                        _h.activeTooltip(true);
                    } else {
                        triangle.css("display", "none");
                        triangle.attr("title", "");
                        triangle.attr("data-original-title", "");
                    }
                    break;
                case "minusRedText":
                    target = $(cellElement).find(".triangle-format");
                    var status = value || cell.extraParams.minusParenthese;
                    status ? target.css("display", "block") : target.css("display", "none");
                    break;
                case "minusParenthese":
                    target = $(cellElement).find(".triangle-format");
                    var status = value || cell.extraParams.minusRedText;
                    status ? target.css("display", "block") : target.css("display", "none");
                    break;
                case "dataType":
                    target = $(cellElement).find(".triangle-datatype");
                    value ? target.css("display", "block") : target.css("display", "none");
                    break;
                case "resetFormula":
                    target = $(cellElement).find(".cell-infos");
                    $(cellElement).find(".cell-infos").empty();
                    break;
                case "xbrlConcept":
                    target = $(cellElement).find(".triangle-xbrl");
                    if (cell.xbrlConcept) {
                        target.css("display", "block");
                        target.attr("title", cell.xbrlConcept.title);
                        target.attr("data-container", "body");
                    } else {
                        target.css("display", "none");
                        target.attr("data-container", "");
                        target.attr("title", undefined);
                    }
                    break;
                case "ClearNode":
                    $(cellElement).find(".cell-infos").empty();
                    $('.txtFormula:visible').val("");
                    $(".tooltip").remove();
                    break;
                case "CellTyping":
                    $(cellElement).find(".cell-infos").empty();
                    $('.txtFormula:visible').val("");
                    $(cellElement).find("input").val(value);
                    break;
                case "ChangeDesc":
                    var triangle = $(cellElement).find(".triangle-desc");
                    if (cell.desc) {
                        triangle.css("display", "block");
                        triangle.attr("title", "");
                        triangle.attr("data-original-title", cell.desc);
                        _h.activeTooltip(true);
                    } else {
                        triangle.attr("title", "");
                        triangle.attr("data-original-title", "");
                        triangle.css("display", "none");
                    }
                    break;
            }
        }
        return {
            cellInfo: cellInfo,
            buildTable: buildTable,
            buildRow: buildRow,
            buildCell: buildCell,
            applyToTable: applyToTable,
            applyToElement: applyToElement
        }
    }();
    var cellFunc = function () {
        var hasItem = function (cell, type) {
            switch (type) {
                case "node":
                    return !_h.isNullOrEmpty(cell.value) && cell.value.startsWith("node:");
                case "info":
                    return !_h.isNullOrEmpty(cell.value) && (cell.value.indexOf("info") || cell.value.indexOf("period"));
                case "formatData":
                    return cell.extraParams.minusParenthese || cell.extraParams.minusRedText;
                case "attachCell":
                    return !_h.isNullOrEmpty(cell.value) && cell.value.startsWith("#");
                case "formula":
                    return !_h.isNullOrEmpty(cell.value) && cell.value.startsWith("=");
                case "column":
                    return !_h.isNullOrEmpty(cell.value) && cell.value.indexOf("table") !== -1;
            }
        }
        var eraseCell = function (cell, accountType, defaultVal) {
            cell.text = "";
            cell.value = "";
            cell.desc = "";
            cell.cellInfos = [];
            cell.xbrlConcept = undefined;
            cell.columnId = undefined;
            cell.tableId = undefined;
            cell.extraParams = createEmptyModel("extraParams", null, null, accountType, defaultVal);
        }
        var addStyles = function (table, cell, type, value, defaultVal) {
            var resModel = {};
            switch (type) {
                case "textBold":
                case "textItalic":
                case "textUnderline":
                    resModel.old = cell.style[type];
                    cell.style[type] = !cell.style[type];
                    resModel.new = cell.style[type];
                    break;
                case "align":
                    resModel.old = cell.style.textAlign;
                    cell.style.textAlign = value;
                    resModel.new = cell.style.textAlign;
                    break;
                case "cellStyle":
                    resModel.old = ko.toJS(cell.style);
                    cellFunc.fillCellStyle(cell, value);
                    resModel.new = ko.toJS(cell.style);
                    break;
                case "textFontFamily":
                case "textFontSize":
                case "textColor":
                case "backColor":
                    resModel.old = cell.style[type];
                    cell.style[type] = value;
                    resModel.new = cell.style[type];
                    break;
                case "eraseStyle":
                    resModel.old = ko.toJS(cell.style);
                    cell.style = createEmptyModel("style", null, null, null, defaultVal);
                    resModel.new = ko.toJS(cell.style);
                    break;
                case "erase":
                    resModel.old = ko.toJS(cell);
                    eraseCell(cell, value, defaultVal);
                    tagRender.applyToElement(table, cell, type);
                    resModel.new = ko.toJS(cell);
                    break;
                case "textWrap":
                    resModel.old = cell.style[type];
                    cell.style[type] = value;
                    resModel.new = cell.style[type];
                    break;
                case "border":
                    resModel.old = ko.toJS(cell.style);
                    var side = value.side, width = value.width, style = value.style, color = value.color;
                    var data = getAllSideBorders(cell);
                    var borderStyles = data[0];
                    var borderWidths = data[1];
                    var borderColors = data[2];
                    switch (side) {
                        case "left":
                            if (!_h.isNullOrEmpty(style))
                                borderStyles[3] = style;
                            if (!_h.isNullOrEmpty(width))
                                borderWidths[3] = width;
                            if (!_h.isNullOrEmpty(color))
                                borderColors[3] = color;
                            break;
                        case "right":
                            if (!_h.isNullOrEmpty(style))
                                borderStyles[1] = style;
                            if (!_h.isNullOrEmpty(width))
                                borderWidths[1] = width;
                            if (!_h.isNullOrEmpty(color))
                                borderColors[1] = color;
                            break;
                        case "top":
                            if (!_h.isNullOrEmpty(style))
                                borderStyles[0] = style;
                            if (!_h.isNullOrEmpty(width))
                                borderWidths[0] = width;
                            if (!_h.isNullOrEmpty(color))
                                borderColors[0] = color;
                            break;
                        case "bottom":
                            if (!_h.isNullOrEmpty(style))
                                borderStyles[2] = style;
                            if (!_h.isNullOrEmpty(width))
                                borderWidths[2] = width;
                            if (!_h.isNullOrEmpty(color))
                                borderColors[2] = color;
                            break;
                        case "full":
                            if (!_h.isNullOrEmpty(style)) {
                                borderStyles[0] = style;
                                borderStyles[1] = style;
                                borderStyles[2] = style;
                                borderStyles[3] = style;
                            }
                            if (!_h.isNullOrEmpty(width)) {
                                borderWidths[0] = width;
                                borderWidths[1] = width;
                                borderWidths[2] = width;
                                borderWidths[3] = width;
                            }
                            if (!_h.isNullOrEmpty(color)) {
                                borderColors[0] = color;
                                borderColors[1] = color;
                                borderColors[2] = color;
                                borderColors[3] = color;
                            }
                            break;
                        case "none":
                            if (!_h.isNullOrEmpty(style)) {
                                borderStyles[0] = "none";
                                borderStyles[1] = "none";
                                borderStyles[2] = "none";
                                borderStyles[3] = "none";
                            }
                            if (!_h.isNullOrEmpty(width)) {
                                borderWidths[0] = "0";
                                borderWidths[1] = "0";
                                borderWidths[2] = "0";
                                borderWidths[3] = "0";
                            }
                            if (!_h.isNullOrEmpty(color)) {
                                borderColors[0] = "#000000";
                                borderColors[1] = "#000000";
                                borderColors[2] = "#000000";
                                borderColors[3] = "#000000";
                            }
                            break;
                    }
                    cell.style
                        .borderStyle = borderStyles[0] + " " + borderStyles[1] + " " + borderStyles[2] + " " + borderStyles[3];
                    cell.style
                        .borderWidth = borderWidths[0] + " " + borderWidths[1] + " " + borderWidths[2] + " " + borderWidths[3];
                    cell.style
                        .borderColor = borderColors[0] + " " + borderColors[1] + " " + borderColors[2] + " " + borderColors[3];
                    resModel.new = ko.toJS(cell.style);
                    break;
            }
            tagRender.applyToElement(table, cell, "style");
            return resModel;
        }
        var addValues = function (table, cell, type, values, reset) {
            var item = _h.getEnumItemByText(cellInfoTypes, type);
            var resModel = {};
            var numb = "";
            if (!item) {
                if (type.indexOf("period") !== -1) {
                    numb = type.match(/\d/g);
                    if (numb.length > 1) {
                        numb = numb[0] + numb[1];
                    } else {
                        numb = numb[0];
                    }
                    type = type.replace(numb, "_")
                }
                item = _h.getEnumItemByText(cellInfoTypes, type);
            }
            resModel.old = ko.toJS(cell);
            switch (type) {
                default:
                    cell.extraParams.percent = false;
                    cell.extraParams.minusParenthese = false;
                    cell.extraParams.minusRedText = false;
                    cell.text = "";
                    cell.value = "[" + item.enText + "]";

                    if (item.enText.indexOf("_") !== -1) {
                        cell.value = cell.value.replace("_", numb);
                        numb = Number(numb);
                    }
                    cell.hasError = false;
                    cell.cellInfos = [];
                    if (type === "info:'4'" || type === "info:'9'" || type === "info:'10'"
                        || type.indexOf("period") !== -1) {
                        values = "";
                    }
                    cell.cellInfos.push({
                        title: item.text + " " + numb,
                        type: item.value,
                        value: values ? values : Number(numb)
                    });
                    tagRender.applyToElement(table, cell, "info");
                    break;
                case "ClearNode":
                    cell.value = "";
                    cell.text = "";
                    cell.hasError = false;
                    cell.linkedTemplate = undefined;
                    cell.cellInfos = [];
                    cell.columnId = undefined;
                    cell.extraParams.financialPeriod = undefined;
                    tagRender.applyToElement(table, cell, type);
                    break;
                case "NodeInCell":
                    var oldValues = [];
                    if (!reset)
                        oldValues = getCellValues(cell, "node");

                    oldValues.push(...values);
                    cell.text = "";
                    cell.hasError = false;
                    cell.value = mergeValues(oldValues, "node");
                    var title = mergeValues(oldValues, "nodeTitle");
                    cell.cellInfos = [];
                    if (oldValues.length > 0)
                        cell.cellInfos.push({
                            title: title,
                            type: item.value
                        });
                    if (_h.any(values))
                        cell.extraParams.financialPeriod = values[0].periodId;
                    tagRender.applyToElement(table, cell, type);
                    break;
                case "NodeNameInCell":
                    cell.text = "";
                    cell.hasError = false;
                    cell.value = "[nodename:'" + values.code + "']";
                    cell.cellInfos = [];
                    cell.cellInfos.push({
                        title: values.name,
                        type: item.value
                    });
                    cell.extraParams.financialPeriod = values.periodId;
                    tagRender.applyToElement(table, cell, type);
                    break;
                case "Consolidate":
                    cell.text = "";
                    cell.hasError = false;
                    cell.cellInfos = [];
                    cell.cellInfos.push({
                        title: values[1],
                        type: item.value
                    });
                    cell.value = "[" + type.toLowerCase() + ":'" + values[0] + "']";
                    tagRender.applyToElement(table, cell, type);
                    break;
                case "Column":
                    cell.columnId = Number(values.id);
                    cell.value = "[table:'" + values.id + "']";
                    cell.cellInfos.push({
                        title: values.title,
                        type: item.value
                    });
                    tagRender.applyToElement(table, cell, type);
                    break;
                case "Formula":
                    var parseTree;
                    try {
                        cell.hasError = false;
                        if (!values) {
                            cell.value = undefined;
                            cell.columnId = undefined;
                            cell.tableId = undefined;
                            cell.cellInfos = [];
                            tagRender.applyToElement(table, cell, type);
                            return;
                        }
                        parseTree = jsep(values.trim().substring(1));
                    } catch (ex) {
                        cell.hasError = true;
                    }
                    if (!cell.hasError) {
                        cell.text = "";
                        cell.cellInfos = [];
                        var temp = values.trim().toUpperCase();
                        temp = _h.replaceAll(temp, " ", "");
                        cell.value = temp;
                        cell.columnId = undefined;
                        cell.tableId = undefined;
                        cell.cellInfos.push({
                            title: item.text,
                            type: item.value
                        });
                        tagRender.applyToElement(table, cell, type);
                    }
                    break;
                case "PartialSum":
                    cell.text = "";
                    var vertexes = calculateVertexes(values);
                    cell.value = "=Sum(" + _h.numberToAlphabet(cell.col) + ":" + vertexes.sRow + ":" + vertexes.bRow + ")";
                    cell.cellInfos = [];
                    cell.cellInfos.push({
                        title: "",
                        type: item.value
                    });
                    tagRender.applyToElement(table, cell, "info");
                    break;
                case "TotalSum":
                case "GroupSum":
                case "ColumnSum":
                case "Average":
                case "Max":
                case "Min":
                    cell.text = "";
                    cell.cellInfos = [];
                    cell.cellInfos.push({
                        title: "",
                        type: item.value
                    });
                    cell.value = "=" + item.ph + "(" + _h.numberToAlphabet(cell.col) + ")";
                    tagRender.applyToElement(table, cell, "info");
                    break;
                case "LinkedCell":
                    cell.extraParams.percent = false;
                    cell.extraParams.minusParenthese = false;
                    cell.extraParams.minusRedText = false;
                    cell.text = "";
                    cell.cellInfos = [];
                    cell.linkedTemplate = {
                        id: Number(values.tId),
                        templateTableType: Number(values.templateTableType),
                        title: values.tTitle
                    };
                    cell.cellInfos.push({
                        title: values.title,
                        type: item.value
                    });
                    cell.value = "[link:'" + values.tag + "']";

                    tagRender.applyToElement(table, cell, type);
                    break;
                case "xbrlConcept":
                    if (values) {
                        cell.xbrlConcept = { id: values.id, title: values.title };
                    } else {
                        cell.xbrlConcept = undefined;
                    }
                    tagRender.applyToElement(table, cell, "xbrlConcept");
                    break;
            }
            resModel.new = ko.toJS(cell);
            return resModel;
        }
        var setText = function (table, cell, type, value) {
            var resModel = {};
            switch (type) {
                case "CellTyping":
                    resModel.old = cell.text;
                    resModel.new = value;
                    cell.text = value;
                    break;
                case "ChangeDesc":
                    resModel.old = cell.desc;
                    resModel.new = value;
                    cell.desc = value;
                    break;
            }

            tagRender.applyToElement(table, cell, type);
            return resModel;
        }
        var addExtraParams = function (table, cell, type, values) {
            var resModel = {};
            resModel.old = cell.extraParams[type];
            cell.extraParams[type] = values;
            tagRender.applyToElement(table, cell, type, cell.extraParams[type]);
            resModel.new = cell.extraParams[type];
            return resModel;
        }
        var getAllSideBorders = function (cell) {
            var borderStyles = cell.style.borderStyle.split(" ");
            borderStyles = _h.cleanArray(borderStyles);
            var borderWidths = cell.style.borderWidth.split(" ");
            borderWidths = _h.cleanArray(borderWidths);
            var borderColors = cell.style.borderColor.split(" ");
            borderColors = _h.cleanArray(borderColors);
            if (_h.any(borderColors))
                for (var i = 0; i < borderColors.length; i++) {
                    if (borderColors[i].indexOf("undefined") !== -1) {
                        borderColors[i] = "#000000";
                    }
                }
            return [borderStyles, borderWidths, borderColors];
        }
        var calculateVertexes = function (cells) {
            var sCol = 0;
            var bCol = 0;
            var sRow = 0;
            var bRow = 0;
            for (var i = 0; i < cells.length; i++) {
                var cell = cells[i];
                if (i === 0) {
                    sCol = cell.col;
                    sRow = cell.row;
                }
                if (cell.col < sCol)
                    sCol = cell.col;
                if (cell.col > bCol)
                    bCol = cell.col;

                if (cell.row < sRow)
                    sRow = cell.row;
                if (cell.row > bRow)
                    bRow = cell.row;
            }
            return { sCol: sCol, bCol: bCol, sRow: sRow, bRow: bRow };
        }
        var splitNodeValuePhrase = function (valueTemp) {
            if (_h.isEmpty(valueTemp))
                return [];
            var splits = valueTemp.split(/[+-/*]+/);
            var array = [];
            for (var j = 0; j < valueTemp.length; j++) {
                if (valueTemp[j] === '+' || valueTemp[j] === '-' || valueTemp[j] === '/' || valueTemp[j] === '*') {
                    array.push(valueTemp[j]);
                }
            }
            var array2 = [];
            for (var i = 0; i < splits.length; i++) {
                var p = splits[i];
                if (p.startsWith("[node:'"))
                    array2.push({
                        operator: array[i],
                        code: p.replace("[node:'", "").replace("']", ""),
                        type: "node"
                    });
                else {
                    array2.push({
                        operator: array[i],
                        code: p,
                        type: ""
                    });
                }
            }
            return array2;
        }
        var getCellValues = function (cell, type) {
            var values = [];
            switch (type) {
                case "node":
                    if (!_h.isNullOrEmpty(cell.value) && cell.value.startsWith("[node:")) {
                        var cellInfo = cell.cellInfos[0];
                        var titles = cellInfo.title.split("|");
                        titles = _h.cleanArray(titles);
                        var valueTemp = cell.value.trim();
                        var splits = splitNodeValuePhrase(valueTemp);
                        for (var i = 0; i < splits.length; i++) {
                            var target = splits[i];
                            var title = "";
                            if (target.type === 'node')
                                title = titles[i];
                            target.title = title;
                            values.push(target);
                        }
                    }
                    return values;
            }
        }
        var mergeValues = function (values, type) {
            var str = "";
            var item;
            switch (type) {
                case "node":
                    if (values.length === 1 && values[0].type === 'node')
                        str += "[node:'" + values[0].code + "']";
                    else if (values.length === 1 && values[0].type !== 'node')
                        str += values[0].code;
                    else
                        for (var k = 0; k < values.length; k++) {
                            item = values[k];
                            if (!item.operator)
                                item.operator = "+";
                            if (item.type === "node") {
                                if (values.length !== k + 1)
                                    str += "[node:'" + item.code + "']" + item.operator;
                                else
                                    str += "[node:'" + item.code + "']";

                            } else {
                                if (values.length !== k + 1)
                                    str += item.code + item.operator;
                                else
                                    str += item.code;
                            }
                        }
                    break;
                case "nodeTitle":
                    for (var j = 0; j < values.length; j++) {
                        if (j === 0) {
                            str = values[j].title;
                        } else {
                            str += "|" + values[j].title;
                        }
                    }
                    break;
            }
            return str;
        }
        var isUniqueNode = function (cell, newCode) {
            var isUnique = true;
            var values = getCellValues(cell, "node");
            if (values.length === 0)
                return true;
            for (var m = 0; m < values.length; m++) {
                var nodeTarget = values[m];
                if (nodeTarget.code === newCode) {
                    isUnique = false;
                }
            }
            return isUnique;
        }
        var fillCellStyle = function (cell, model) {
            if (model.backColor)
                cell.style.backColor = model.backColor;
            if (model.textColor)
                cell.style.textColor = model.textColor;
            if (model.textAlign)
                cell.style.textAlign = model.textAlign;
            if (model.textBold)
                cell.style.textBold = model.textBold;
            if (model.textItalic)
                cell.style.textItalic = model.textItalic;
            if (model.textUnderline)
                cell.style.textUnderline = model.textUnderline;
            if (model.borderStyle)
                cell.style.borderStyle = model.borderStyle;
            if (model.borderWidth)
                cell.style.borderWidth = model.borderWidth;
            if (model.borderColor)
                cell.style.borderColor = model.borderColor;
            if (model.textWrap)
                cell.style.textWrap = model.textWrap;
            if (model.textFontFamily)
                cell.style.textFontFamily = model.textFontFamily;
            if (model.textFontSize)
                cell.style.textFontSize = model.textFontSize;
        }
        var translateBorder = function (cell) {
            if (cell.borderStyle !== undefined &&
                cell.borderStyle !== "") {
                var splits = cell.borderStyle.trim().split(" ");
                splits = _h.cleanArray(splits);
                switch (splits.length) {
                    case 1:
                        cell.borderStyle = splits[0] + " " + splits[0] + " " + splits[0] + " " + splits[0];
                        break;
                    case 2:
                        cell.borderStyle = splits[0] + " " + splits[1] + " " + splits[0] + " " + splits[1];
                        break;
                    case 3:
                        cell.borderStyle = splits[0] + " " + splits[1] + " " + splits[2] + " " + splits[1];
                        break;
                }
            } else {
                cell.borderStyle = "none none none none";
            }

            if (cell.borderWidth !== undefined &&
                cell.borderWidth !== "") {
                var borderWidths = cell.borderWidth.trim().split(" ");
                borderWidths = _h.cleanArray(borderWidths);
                switch (borderWidths.length) {
                    case 1:
                        cell.borderWidth =
                            borderWidths[0] + " " + borderWidths[0] + " " + borderWidths[0] + " " + borderWidths[0];
                        break;
                    case 2:
                        cell.borderWidth =
                            borderWidths[0] + " " + borderWidths[1] + " " + borderWidths[0] + " " + borderWidths[1];
                        break;
                    case 3:
                        cell.borderWidth =
                            borderWidths[0] + " " + borderWidths[1] + " " + borderWidths[2] + " " + borderWidths[1];
                        break;
                }
            } else
                cell.borderWidth = "0 0 0 0";

            if (cell.borderColor !== undefined && cell.borderColor !== "0 0 0 0" && cell.borderColor !== "") {
                var borderColors = cell.borderColor.trim().split(" ");
                borderColors = _h.cleanArray(borderColors);
                switch (borderColors.length) {
                    case 1:
                        cell.borderColor =
                            borderColors[0] + " " + borderColors[0] + " " + borderColors[0] + " " + borderColors[0];
                        break;
                    case 2:
                        cell.borderColor =
                            borderColors[0] + " " + borderColors[1] + " " + borderColors[0] + " " + borderColors[1];
                        break;
                    case 3:
                        cell.borderColor =
                            borderColors[0] + " " + borderColors[1] + " " + borderColors[2] + " " + borderColors[1];
                        break;
                }
            } else
                cell.borderColor = "#000000 #000000 #000000 #000000";
        }
        var translateCellStyle = function (cell) {
            if (!cell.style)
                return "";
            var st = "";
            if (cell.style.textItalic)
                st += "font-style: italic;";

            if (cell.style.textBold)
                st += "font-weight: bold;";

            if (cell.style.textWrap)
                st += "white-space: nowrap;";

            if (cell.style.textUnderline)
                st += "text-decoration: underline;";

            if (cell.style.backColor)
                st += "background-color:" + cell.style.backColor + ";";
            if (cell.style.textColor)
                st += "color:" + cell.style.textColor + ";";

            if (cell.style.textFontFamily)
                st += "font-family:" + cell.style.textFontFamily + ";";

            if (cell.style.textFontSize)
                st += "font-size:" + cell.style.textFontSize + ";";


            if (cell.style.textAlign)
                st += "text-align:" + cell.style.textAlign + ";";

            if (cell.style.borderStyle && cell.style.borderStyle !== "none none none none")
                st += "border-style:" + cell.style.borderStyle + ";";
            if (cell.style.borderWidth && cell.style.borderWidth !== "0 0 0 0")
                st += "border-width:" + cell.style.borderWidth + ";";
            if (cell.style.borderColor)
                st += "border-color:" + cell.style.borderColor + ";";

            translateBorder(cell);
            return st;
        }
        var addCellEvents = function (el, type, ne) {
            if (type === "cellSelect" && !ne) {
                el.addEventListener("click",
                    event => {
                        var table = $(event.target).closest("table");
                        table.find(".rp-gen-cell").removeClass("tcs-selected");
                        var td = $(event.target).closest(".rp-gen-cell");
                        td.addClass(selectedCellClass);
                        var address = td.attr("data-address");
                        var tag = td.attr("data-tag");
                        var id = td.attr("data-id");
                        var templateTableType = td.attr("data-ttType");
                        var title = td.attr("data-title");
                        table.trigger('selectionchange', {
                            address: address,
                            tag: tag,
                            id: id,
                            templateTableType: templateTableType,
                            title: title
                        });
                        event.preventDefault();
                    });
                return;
            }
            el.addEventListener("focusin",
                event => {
                    if (!event.target)
                        return;
                    if (event.target.nodeName === "INPUT") {
                        var td = $(event.target).closest("td");
                        var address = $(td).attr("data-address");
                        if (rgTextBuffer && rgTextBuffer.address != address) {
                            var table = $("table:visible");
                            var model = rgUtil.getModel(table);
                            if (model) {
                                var cell = model.cells.filter(a => a.address === rgTextBuffer.address);
                                if (cell.length && cell[0].text !== rgTextBuffer.text) {
                                    rgUtil.addToHistory(table, cell, { type: "CellTyping" }, [{ old: rgTextBuffer.text, new: cell[0].text }]);
                                }
                            }
                        }
                        rgTextBuffer = { address: $(td).attr("data-address"), text: event.target.value };
                    }
                });
            el.addEventListener("focusout",
                event => {
                    if (!event.currentTarget)
                        return;
                    if (event.currentTarget.nodeName === "INPUT") {
                        $(event.currentTarget).css("caret-color", "");
                        $(event.currentTarget).find("td").removeClass(selectionEnabled);
                    } else {
                        var target = $(event.currentTarget).find("input");
                        target.css("caret-color", "");
                        $(event.currentTarget).removeClass(selectionEnabled);
                    }
                });
            el.addEventListener("drop",
                event => {
                    try {
                        event.preventDefault();
                        var dragInfo = event.dataTransfer.getData("application/json");
                        dragInfo = JSON.parse(dragInfo);
                        var el = event.currentTarget;
                        if (event.currentTarget.nodeName !== "TD")
                            el = $(event.currentTarget).parent();
                        switch (dragInfo.action) {
                            case "nodeDrag":
                                handleNodeDrop(el, dragInfo.list, dragInfo.nodeDisplayType);
                                break;
                            case "consolidate":
                                handleConsolidateDrop(el, dragInfo.model);
                                break;
                            case "tableCol":
                                handleTableColDrop(el, dragInfo.model);
                                break;
                            case "xbrlConcept":
                                handleXbrlConceptDrop(el, dragInfo.model);
                                break;
                            default:
                                handleSignDrop(el, dragInfo.actionType, dragInfo.dataType);
                                break;
                        }
                        _h.activeTooltip(true);

                    } catch (e) {
                        //
                    }
                });
            el.addEventListener("dragenter",
                event => {
                    event.preventDefault();
                });
            el.addEventListener("dragover",
                event => {
                    event.preventDefault();
                });
            el.addEventListener("dragover",
                event => {
                    event.preventDefault();
                });
            el.addEventListener("click",
                event => {
                    if (event.shiftKey && event.target.nodeName !== "IMG") {
                        if ($("#tree_view").length > 0) {
                            var list = $("#tree_view").treeView("getDragList");
                            var ele = document.getElementsByName('nodeDisplayType');
                            var nodeDisplayType = null;
                            for (var i = 0; i < ele.length; i++) {
                                if (ele[i].checked)
                                    nodeDisplayType = ele[i].value
                            }
                            if (list.length) {
                                handleNodeDrop(event.target, list, nodeDisplayType);
                                _h.activeTooltip(true);
                            }
                        }
                    }
                    event.preventDefault();
                });
        }
        var handleNodeDrop = function (el, dragList, nodeDisplayType) {
            if (el.nodeName === "INPUT")
                el = el.parentNode;
            var table = $(el).closest("table");
            var row = Number($(el).attr("data-row"));
            var col = Number($(el).attr("data-col"));
            var isSelectedCell = $(el).hasClass("tcs-selected");
            var model = rgUtil.getModel(table);
            var cell = model.cells.filter(a => a.row === row && a.col === col)[0];
            switch (nodeDisplayType) {
                case "NodeInCell":
                case 1:
                    var nodeList = [];
                    for (var l = 0; l < dragList.length; l++) {
                        var node = dragList[l];
                        if (cellFunc.isUniqueNode(cell, node.code)) {
                            nodeList.push({
                                treeId: node.treeId,
                                code: node.code,
                                operator: "+",
                                title: node.path.replace(" :: ", "") + " (" + node.code + ")",
                                type: 'node',
                                periodId: node.periodId,
                            });
                        }
                    }
                    if (nodeList.length) {
                        rgUtil.selectRangeCells(table, [cell.address], function (res) {
                            var result = rgUtil.executeCommand(table, model, { id: "NodeInCell", value: nodeList, cells: [cell] });
                            $(".txtFormula:visible").val(cell.value);
                            table.data("model", model);
                            $("#tree_view").treeView("clearSelectItems");
                            _h.kocnx().ttvm().focusDesignItem().refreshToolBar(true);
                        });
                    }
                    break;
                case "NodeNameInCell":
                case 2:
                    var cells = rgUtil.getSelectedCellModels(table);
                    $("#tree_view").treeView("clearSelectItems");
                    var shapeData = findShapeSelection(cells);
                    if (shapeData[0] === "Ver") {
                        if (!isSelectedCell) {
                            rgUtil.selectRangeCells(table, [cell.address], function (res) {
                                cells = rgUtil.getSelectedCellModels(table);
                                rgUtil.executeCommand(table, model, { id: "NodeNameInCell", value: dragList, cells: cells });
                                _h.kocnx().ttvm().focusDesignItem().refreshToolBar(true);
                            });
                        } else {
                            rgUtil.executeCommand(table, model, { id: "NodeNameInCell", value: dragList, cells: cells });
                            _h.kocnx().ttvm().focusDesignItem().refreshToolBar(true);
                        }
                    }
                    break;
                case "NodeValueNameInCell":
                case 3:
                    var cells = rgUtil.getSelectedCellModels(table);
                    $("#tree_view").treeView("clearSelectItems");
                    var shapeData = findShapeSelection(cells);
                    if (shapeData[0] === "Ver" || (shapeData[0] === "Hor" && cells.length === 2)) {
                        var hasEnoughCol = cells.filter(a => a.col === (cells[0].col + 1)).length > 0;
                        if (!hasEnoughCol) {
                            var text = _h.getApiMessage("NotEnoughCol");
                            _h.failToast(text);
                            return;
                        }

                        var firstColCells = cells.filter(a => a.col === shapeData[1]);
                        var result = rgUtil.executeCommand(table, model, { id: "NodeValueNameInCell", value: dragList, cells: firstColCells });
                        _h.kocnx().ttvm().focusDesignItem().refreshToolBar(true);
                    }
                    break;
            }
        }
        var handleConsolidateDrop = function (el, data) {
            var table = $(el).closest("table");
            var row = $(el).attr("data-row");
            var col = $(el).attr("data-col");
            var model = rgUtil.getModel(table);
            var cell = model.cells.filter(a => a.row === Number(row) && a.col === Number(col))[0];
            var tCell;
            var isValidCommand = false;
            var name = data.name;
            var id = Number(data.id);
            var isRoot = data.isRoot === "true";
            var cols = $(".rp-gen-cell[data-col=" + col + "]");
            if (name && id) {
                switch (model.tableTemplateType) {
                    case 3:
                        if ((cell.col === 1 && cell.row > 1) || (cell.row === 1 && cell.col > 1)) {
                            isValidCommand = true;
                        }
                        break;
                    case 5:
                        if (cell.col === 1 && cell.row === 1)
                            return;
                        if ((cell.col === 1 && cell.row > 1) || (cell.row === 1 && cell.col > 1 && isRoot)) {
                            isValidCommand = true;
                        }
                        break;
                    case 4:
                        for (var k = 0; k < cols.length; k++) {
                            tCell = model.cells.filter(a => a.row === k + 1 && a.col === Number(col))[0];

                            if (!_h.isNullOrEmpty(tCell) &&
                                !_h.isNullOrEmpty(tCell.value) &&
                                tCell.value.indexOf("Consolidate") !== -1) {
                                var cellElement = $(table).find('[data-col="' + cell.col + '"][data-row="' + cell.row + '"]');
                                var target = $(cellElement).find(".cell-infos");
                                $(target).empty();
                            }
                        }
                        isValidCommand = true;
                        break;
                    default:
                        isValidCommand = true;
                        break;
                }

                if (isValidCommand) {
                    rgUtil.selectRangeCells(table, [cell.address], function (res) {
                        rgUtil.executeCommand(table, model, { id: "Consolidate", value: [id, name], cells: [cell] });
                        _h.kocnx().ttvm().focusDesignItem().refreshToolBar(true);
                    });
                }

                for (var l = 0; l < cols.length; l++) {
                    tCell = model.cells.filter(a => a.row === l + 1 && a.col === Number(col))[0];
                    if (isRoot)
                        tCell.extraParams.valueSource = 1;
                    else
                        tCell.extraParams.valueSource = 2;
                }
                table.data("model", model);
            }
        }
        var handleTableColDrop = function (el, data) {
            var table = $(el).closest("table");
            var model = rgUtil.getModel(table);
            var address = $(el).attr("data-address");
            var row = Number($(el).attr("data-row"));
            var col = Number($(el).attr("data-col"));
            var cell = model.cells.filter(a => a.address === address)[0];
            var [rowNumber, rowNumberSign] = getColumnActiveRow(model, true);
            if ((rowNumber && rowNumber !== Number(row)) || (rowNumberSign && rowNumberSign !== Number(row))) {
                _h.removeDragLabel();
                toast.custom("error", _h.getApiMessage('RpError1'));
                return;
            }
            if (model.tableId && model.tableId !== data.tableId) {
                _h.removeDragLabel();
                toast.custom("error", _h.getApiMessage('RpError2'));
                return;
            }
            var hasRowNumberCellInfo = model.cells.filter(a => a.col === col &&
                !_h.isNullOrEmpty(a.value) && a.value.indexOf("info:'25'") !== -1).length > 0;
            if (hasRowNumberCellInfo) {
                _h.removeDragLabel();
                toast.custom("error", _h.getApiMessage('RpError3'));
                return;
            }
            var mTableId = model.tableId;
            model.tableId = data.tableId;
            rgUtil.executeCommand(table, model, { id: "Column", value: data, cells: [cell], extraObj: { tableId: mTableId } });//todo extraobj??
            _h.removeDragLabel();
        }
        var handleSignDrop = function (el, action, dt) {
            var table = $(el).closest("table");
            var row = Number($(el).attr("data-row"));
            var col = Number($(el).attr("data-col"));
            var model = rgUtil.getModel(table);
            if (model.tableTemplateType !== 4 && (action === "GroupSum" || action === "ColumnSum")) {
                return;
            }
            if (model.tableTemplateType === 4 && (action !== "GroupSum" && action !== "ColumnSum")) {
                return;
            }

            var cell = model.cells.filter(a => a.row === row && a.col === col)[0];
            var isPartialSum = action === "PartialSum";
            var selectedCells = rgUtil.getSelectedCellModels(table);
            if (selectedCells.length > 1) {
                if (action === "info:'25'")
                    return;
                var inSelectedZone = false;
                var inSameCol = true;
                for (var j = 0; j < selectedCells.length; j++) {
                    var selectedCell = selectedCells[j];
                    if (selectedCell.address === cell.address)
                        inSelectedZone = true;
                    if (cell.col !== selectedCell.col)
                        inSameCol = false;
                }
                if (!isPartialSum) {
                    if (!inSelectedZone)
                        addValues(table, cell, action);
                    if (inSelectedZone)
                        for (var i = 0; i < selectedCells.length; i++) {
                            var targetCell = selectedCells[i];
                            rgUtil.executeCommand(table, model, { id: action, value: action, cells: [targetCell] });
                        }
                    return;
                }
                if (inSelectedZone) {
                    toast.custom("error", _h.getApiMessage('RpError4'));
                    return;
                }
                if (!inSameCol) {
                    toast.custom("error", _h.getApiMessage('RpError5'));
                    return;
                }
                rgUtil.executeCommand(table, model, { id: action, value: selectedCells, cells: [cell], cellsEffected: selectedCells });
            } else {
                if (isPartialSum) {
                    toast.custom("error", _h.getApiMessage('RpError6'));
                    return;
                }
                if (action === "info:'25'") {
                    var res = hasColTableColumn(model, Number(col));
                    if (res) {
                        toast.custom("error", _h.getApiMessage('RpError7'));
                        return;
                    } else {
                        var info = getColumnActiveRow(model);
                        if (info[0] && info[0] !== row) {
                            toast.custom("error", _h.getApiMessage('RpError8'));
                            return;
                        }
                        rgUtil.executeCommand(table, model, { id: action, value: action, cells: [cell] });
                    }
                } else {
                    rgUtil.selectRangeCells(table, [cell.address], function () {
                        rgUtil.executeCommand(table, model, { id: action, value: action, cells: [cell] });
                    });
                }
            }
            table.data("model", model);
            setTimeout(function () {
                _h.kocnx().ttvm().focusDesignItem().refreshToolBar(true);
            }, 50);
        }
        var handleXbrlConceptDrop = function (el, data) {
            var table = $(el).closest("table");
            var row = Number($(el).attr("data-row"));
            var col = Number($(el).attr("data-col"));
            var model = rgUtil.getModel(table);
            var cell = model.cells.filter(a => a.row === row && a.col === col)[0];
            if (cell) {
                rgUtil.executeCommand(table, model, { id: "xbrlConcept", value: { id: data.id, title: data.title }, cells: [cell] });
            }
        }
        var findShapeSelection = function (cells) {
            if (cells.length === 1) {
                return ['Ver', cells[0].col, cells[0].row];
            } else {
                var points = rgUtil.getRectanglePoints(cells);
                if (points.sCol !== points.bCol && points.sRow !== points.bRow) {
                    return ['Ver', cells[0].col, cells[0].row];
                }
                if (points.sCol === points.bCol && points.sRow !== points.bRow) {
                    return ['Ver', points.sCol, cells[0].sRow];
                }
                if (points.sCol !== points.bCol && points.sRow === points.bRow) {
                    return ['Hor', points.sCol, cells[0].sRow];
                }
            }
        }
        var getColumnActiveRow = function (model, chkRowNumberSign) {
            var rowNumber, rowNumberSign;
            for (var i = 0; i < model.cells.length; i++) {
                var cell = model.cells[i];
                if (cell.columnId) {
                    rowNumber = cell.row;
                }
                if (chkRowNumberSign &&
                    !_h.isNullOrEmpty(cell.value) &&
                    cell.value.indexOf("info:'25'") !== -1) {
                    rowNumberSign = cell.row;
                }
            }

            return [rowNumber, rowNumberSign];
        }
        var hasColTableColumn = function (model, col) {
            var has = false;
            for (var i = 0; i < model.cells.length; i++) {
                var cell = model.cells[i];
                if (cell.col === col && cell.columnId && model.tableId) {
                    has = true;
                }
            }
            return has;
        }
        var pasteCell = function (table, cell, oldCell, colsCount, rowsCount) {
            if (oldCell["backColor"]) {
                var dataCopy = { ...oldCell }
                cell.style = dataCopy;
            }
            else if (!_h.isNullOrEmpty(oldCell["text"])) {
                cell.text = oldCell.text;
                cell.cellInfos = [];
                var copyValue = true;
                if (_h.any(oldCell.cellInfos))
                    for (var j = 0; j < oldCell.cellInfos.length; j++) {
                        var cellInfo = oldCell.cellInfos[j];
                        if (cellInfo.type !== 24) {
                            cell.cellInfos.push({
                                title: cellInfo.title,
                                type: cellInfo.type
                            });
                        } else {
                            copyValue = false;
                        }
                    }
                if (copyValue)
                    cell.value = oldCell.value;
                if (cell.value && cell.value.startsWith("=")) {
                    refreshFormulaCell(table, cell, oldCell.address, colsCount, rowsCount);
                }
                if (!_h.isNullOrEmpty(oldCell.style)) {
                    var dataCopy = { ...oldCell.style }
                    cell.style = dataCopy;
                }
                if (!_h.isNullOrEmpty(oldCell.extraParams)) {
                    var dataCopy = { ...oldCell.extraParams }
                    cell.extraParams = dataCopy;
                }
                if (oldCell.linkedTemplate) {
                    var dataCopy = { ...oldCell.linkedTemplate }
                    cell.linkedTemplate = dataCopy;
                }
            } else {
                cell.text = oldCell;
            }
            tagRender.applyToElement(table, cell, "paste");
        }
        var copyCell = function (cell) {
            return {
                text: cell.text,
                value: cell.value,
                address: cell.address,
                cellInfos: cell.cellInfos,
                style: cell.style,
                linkedTemplate: cell.linkedTemplate,
                extraParams: cell.extraParams,
                columnId: cell.columnId,
                xbrlConcept: cell.xbrlConcept,
                tableId: cell.tableId
            };
        }
        var cutCell = function (table, model, cell, defaultVal) {
            var json = copyCell(cell);
            cell.text = "";
            cell.value = "";
            cell.linkedTemplate = undefined;
            cell.extraParams = createEmptyModel("extraParams", null, null, model.accountType, null);
            cell.style = createEmptyModel("style", null, null, null, defaultVal);
            cell.cellinfos = [];
            tagRender.applyToElement(table, cell, "cut");
            return json;
        }
        var createEmptyModel = function (part, col, row, accountType, defaultVal) {
            var extraParams = {
                financialPeriod: 0,
                minusRedText: false,
                minusParenthese: false,
                dataType: 1,
                decimals: 0,
                negate: null,
                accountType: accountType,
                percent: false,
                valueSource: 1,
                valueAccountType: 0,
                valueDisplay: 1,
                zeroDisplay: 1,
                roundingApproach: 1
            };
            var style = {
                backColor: "",
                textColor: "",
                textAlign: "",
                textBold: false,
                textItalic: false,
                textUnderline: false,
                textWrap: false,
                textFontFamily: "",
                textFontSize: "",
                borderStyle: "none none none none",
                borderWidth: "0 0 0 0",
                borderColor: "#000000 #000000 #000000 #000000"
            }
            if (defaultVal) {
                if (defaultVal.textColor)
                    style.textColor = defaultVal.textColor;
                if (defaultVal.backColor)
                    style.backColor = defaultVal.backColor;
                if (defaultVal.textFontFamily)
                    style.textFontFamily = defaultVal.textFontFamily;
                if (defaultVal.textFontSize)
                    style.textFontSize = defaultVal.textFontSize;
                if (defaultVal.align)
                    style.textAlign = defaultVal.align;
            }
            switch (part) {
                case "extraParams":
                    return extraParams;
                case "style":
                    return style;
                case "cell":
                    return {
                        row: row,
                        col: col,
                        address: _h.numberToAlphabet(col) + row,
                        hidden: false,
                        warning: false,
                        warningMessage: "",
                        xbrlConcept: undefined,
                        colSpan: 1,
                        rowSpan: 1,
                        text: "",
                        oldAddress: "",
                        hasError: false,
                        value: "",
                        tag: "",
                        dynamicValue: "",
                        redText: false,
                        cellInfos: [],
                        columnId: undefined,
                        tableId: undefined,
                        extraParams: extraParams,
                        style: style
                    };
            }
        }
        var refreshFormulaCell = function (table, cell, lastAddress, colsCount, rowsCount) {
            var str = cell.value;
            var temp,
                letter,
                number,
                last,
                lastNumber,
                lastLetter,
                isRowCopy,
                isColCopy;
            if ((str.indexOf("+") !== -1 ||
                str.indexOf("-") !== -1 ||
                str.indexOf("*") !== -1 ||
                str.indexOf("/") !== -1) && str.indexOf(":") === -1) {
                lastNumber = Number(lastAddress.replace(/^\D+/g, ''));
                lastLetter = lastAddress.replace(lastNumber, "");
                var parser = new ExpParser();
                isRowCopy = lastNumber === cell.row;
                isColCopy = lastLetter === _h.numberToAlphabet(cell.col);

                if (isColCopy) {
                    if (cell.row < lastNumber) {
                        cell.value = "";
                        cell.cellInfos = [];
                        return;
                    }
                    str = parser.afterColCopy(str,
                        colsCount,
                        rowsCount,
                        cell.row,
                        lastNumber);
                    if (!_h.isNullOrEmpty(str) && str !== "") {
                        cell.value = str;
                    } else {
                        cell.value = "";
                        cell.cellInfos = [];
                    }
                }
                if (isRowCopy) {
                    temp = str.replace(/[\])}[{(=]/g, '');
                    temp = _h.replaceAll(temp, ' ', '');
                    var splits = _h.splitMulti(temp, ['+', '-', '*', '/']);
                    splits = _h.cleanArray(splits);
                    var sameCol = true;
                    var rArray = [], rArray2 = [];
                    if (_h.any(splits))
                        for (var i = 0; i < splits.length; i++) {
                            number = splits[i].replace(/^\D+/g, '');
                            letter = splits[i].replace(number, '');
                            if (i === 0)
                                last = letter;
                            if (letter !== "" && letter !== last)
                                sameCol = false;
                        }
                    if (sameCol && lastNumber === cell.row) {
                        for (var k = 0; k < splits.length; k++) {
                            number = splits[k].replace(/^\D+/g, '');
                            letter = splits[k].replace(number, "");
                            if (letter !== "" && rArray.indexOf(letter) === -1) {
                                rArray.push(letter);
                            }
                        }
                        if (_h.any(rArray)) {
                            for (var j = 0; j < rArray.length; j++) {
                                str = _h.replaceAll(str, rArray[j], _h.numberToAlphabet(cell.col));
                            }
                        }
                        str = parser.minMaxControl(str, colsCount, rowsCount);
                        if (!_h.isNullOrEmpty(str) && str !== "") {
                            cell.value = str;
                        } else {
                            cell.value = "";
                            cell.cellInfos = [];
                        }
                    }
                }
            }
            else if (str.indexOf("Sum") !== -1 && str.indexOf(":") !== -1) {
                temp = str.replace("=Sum(", "").replace(")", "").split(":");
                if (temp.length > 1) {
                    letter = temp[0];
                    lastNumber = lastAddress.replace(/^\D+/g, '');
                    lastLetter = lastAddress.replace(lastNumber, "");
                    isRowCopy = Number(lastNumber) === cell.row;
                    isColCopy = lastLetter === _h.numberToAlphabet(cell.col);
                    if (isColCopy && Number(lastNumber) < cell.row) {
                        var sNumber = (cell.row - Number(lastNumber)) + Number(temp[1]);
                        var eNumber = (cell.row - Number(lastNumber)) + Number(temp[2]);
                        cell.value = "=Sum(" +
                            _h.numberToAlphabet(cell.col) +
                            ":" +
                            sNumber +
                            ":" +
                            eNumber +
                            ")";
                    }
                    if (isRowCopy) {
                        if (Number(lastNumber) === cell.row)
                            cell.value = "=Sum(" +
                                _h.numberToAlphabet(cell.col) +
                                ":" +
                                temp[1] +
                                ":" +
                                temp[2] +
                                ")";
                        else {
                            cell.value = "";
                            cell.cellInfos = [];
                        }
                    }
                }
            }
            else if ((str.indexOf("Sum") !== -1 || str.indexOf("GSum") !== -1 || str.indexOf("CSum") !== -1) &&
                str.indexOf(":") === -1) {
                lastNumber = lastAddress.replace(/^\D+/g, '');
                lastLetter = lastAddress.replace(lastNumber, "");
                if (cell.row === 1) {
                    cell.value = "";
                    cell.cellInfos = [];
                }
                if (Number(lastNumber) === cell.row && str.indexOf("Sum") !== -1) {
                    cell.value = "=Sum(" + _h.numberToAlphabet(cell.col) + ")";
                }
                if (Number(lastNumber) === cell.row && str.indexOf("GSum") !== -1) {
                    cell.value = "=GSum(" + _h.numberToAlphabet(cell.col) + ")";
                }
                if (Number(lastNumber) === cell.row && str.indexOf("CSum") !== -1) {
                    cell.value = "=CSum(" + _h.numberToAlphabet(cell.col) + ")";
                }

            }
            else if (str.indexOf("Avg") !== -1 || str.indexOf("Max") !== -1 || str.indexOf("Min") !== -1) {
                var st = rgUtil.getFormulaType(str);
                lastNumber = lastAddress.replace(/^\D+/g, '');
                lastLetter = lastAddress.replace(lastNumber, "");
                if (cell.row === 1) {
                    cell.value = "";
                    cell.cellInfos = [];
                } else {
                    cell.value = "=" + st + "(" + _h.numberToAlphabet(cell.col) + ")";

                }
            }
        }
        return {
            addExtraParams: addExtraParams,
            eraseCell: eraseCell,
            isUniqueNode: isUniqueNode,
            hasItem: hasItem,
            addValues: addValues,
            addCellEvents: addCellEvents,
            translateCellStyle: translateCellStyle,
            translateBorder: translateBorder,
            pasteCell: pasteCell,
            copyCell: copyCell,
            cutCell: cutCell,
            fillCellStyle: fillCellStyle,
            createEmptyModel: createEmptyModel,
            getCellValues: getCellValues,
            addStyles: addStyles,
            calculateVertexes: calculateVertexes,
            setText: setText
        }
    }();
    var rgUtil = function () {
        var getDefault = function () {
            var model = {};
            var data = clientStorage.getSetting("DefaultTemplateStyle");
            if (!_h.isEmpty(data)) {
                model = JSON.parse(data);
                if (!model.textFontSize)
                    model.textFontSize = "12px";
                if (!model.textFontFamily)
                    model.textFontFamily = "Nazanin";

            } else {
                return {
                    textColor: "",
                    backColor: "",
                    textFontSize: "12px",
                    textFontFamily: "Nazanin",
                    align: undefined
                };
            }
            return model;
        }
        var addTableEvents = function ($table) {
            $table
                .on('mouseover', onMouseOver)
                .on('mousedown', onMouseDown)
                .on('mouseup', onMouseUp)
                .on("keydown", onKeyDown)
                .on("dblclick", onDoubleClick)
                .on('contextmenu', onContextMenu);
            var table = $table[0];
            $(document).on("keydown", "#" + table.id, onKeyDown);
            $(table.ownerDocument).on('click', function (event) {
                isMouseDown = false;
                $table.trigger('outOfTable', [event.target]);
            });
            $(document).on("copy", "#" + table.id, function (event) {
                if ($(event.target).hasClass("cell-input")) {
                    var tTable = $(event.originalEvent.target).closest("table");
                    copyCellsData(event.originalEvent, tTable);
                }
                if (!$(event.target).hasClass("cell-input")) {
                    var $ta = $(".tcs:visible")
                    if ($ta.length) {
                        copyCellsData(event.originalEvent, $ta);
                    }
                }
            });
            $(document).on("paste", "#" + table.id, function (event) {
                if ($(event.target).hasClass("cell-input")) {
                    var tTable = $(event.originalEvent.target).closest("table");
                    pasteCellsData(event.originalEvent, tTable);
                    _h.activeTooltip(true);
                }
                if (!$(event.target).hasClass("cell-input")) {
                    var $ta = $(".tcs:visible")
                    pasteCellsData(event.originalEvent, $ta);
                    _h.activeTooltip(true);
                }
            });
            $(document).on("cut", "#" + table.id, function (event) {
                if ($(event.target).hasClass("cell-input")) {
                    var tTable = $(event.originalEvent.target).closest("table");
                    cutCellsData(event.originalEvent, tTable);
                    _h.activeTooltip(true);
                }
                if (!$(event.target).hasClass("cell-input")) {
                    var $ta = $(".tcs:visible")
                    cutCellsData(event.originalEvent, $ta);
                    _h.activeTooltip(true);
                }
            });
        }
        var onContextMenu = function (event) {
            if (event.target.nodeName === "TH") {
                $(event.currentTarget).trigger('contextMenu', event.target);
                return false;
            }
            if ((event.target.nodeName === "TD" || event.target.nodeName === "INPUT") && event.shiftKey) {
                $(event.currentTarget).trigger('contextMenu', event.target);
                return false;
            }
        }
        var onDoubleClick = function (evt) {
            if (evt.target.className.indexOf("rp-gen-col") !== -1) {
                var col = Number($(evt.target).attr("data-col"));
                var bWidth = 0;
                var colWidth = Number($(evt.target).css("width").replace("px", ""));
                var cells = $(".rp-gen-cell[data-col='" + col + "']");
                for (var i = 0; i < cells.length; i++) {
                    var cell = cells[i];
                    var scrollWidth = cell.scrollWidth;
                    if (scrollWidth > colWidth) {
                        if (i === 0) {
                            bWidth = scrollWidth;
                        } else {
                            if (scrollWidth > bWidth) {
                                bWidth = scrollWidth;
                            }
                        }
                    }
                }
                if (bWidth > 0)
                    $(evt.target).css("width", bWidth + "px");
            }
            if (evt.target.className.indexOf("cell-input") !== -1) {
                $(evt.target).css("caret-color", "black");
                $(evt.target).closest("td").addClass(selectionEnabled);
            }
            if (evt.target.className.indexOf("rp-gen-cell") !== -1) {
                $(evt.target).find("input").css("caret-color", "black");
                $(evt.target).addClass(selectionEnabled);
            }
        }
        var isArrowKey = function (evt) {
            return evt.keyCode === 38 || evt.keyCode === 39 || evt.keyCode === 40 || evt.keyCode === 37;
        }
        var onKeyDown = function (evt) {
            evt.stopPropagation();
            if (isArrowKey(evt)) {
                document.activeElement?.blur();
            }
            var $table = $(evt.currentTarget);
            var cells = getSelectedCells($table);
            if (cells.length === 0)
                return;
            var bCol = 0;
            var sRow = 0;
            var sCol = 0;
            var $cell;
            var endCol = $table.find(".rp-gen-col").length;
            var endRow = $table.find(".first-cell").length;
            cells.each(function (key, cell) {
                var row = Number($(cell).attr("data-row"));
                var col = Number($(cell).attr("data-col"));
                if (key === 0) {
                    sCol = col;
                    bCol = col;
                    sRow = row;
                } else {
                    if (sCol > col)
                        sCol = col;
                    if (bCol < col)
                        bCol = col;
                    if (sRow > row)
                        sRow = row;
                }
            });
            $cell = $table.find('td[data-col="' + bCol + '"][data-row="' + sRow + '"]');
            switch (evt.keyCode) {
                case 37:
                    $cell = $table.find('td[data-col="' + sCol + '"][data-row="' + sRow + '"]');
                    if ($cell) {
                        var nextCell = $cell.next();
                        if (nextCell.length)
                            selectNextCell(nextCell.attr("data-col"), nextCell.attr("data-row"), $table, $cell, true);
                        else {
                            if (sCol + 1 > endCol && sRow + 1 <= endRow)
                                selectNextCell(1, sRow + 1, $table, $cell, true);

                            if (sCol + 1 > endCol && sRow + 1 > endRow)
                                selectNextCell(1, 1, $table, $cell, true);
                        }
                        $table[0].parentNode.scrollLeft -= 40;
                    }
                    break;
                case 38:
                    selectNextCell(bCol, sRow - 1, $table, $cell, true);
                    window.scrollBy(0, -10);
                    break;
                case 39:
                    if ($cell.length) {
                        var prevCell = $cell.prev();
                        if (prevCell.length && !prevCell.hasClass("first-cell")) {
                            selectNextCell(prevCell.attr("data-col"), prevCell.attr("data-row"), $table, $cell, true);
                            $table[0].parentNode.scrollLeft += 40;
                        }
                    }
                    break;
                case 40:
                    if ($cell) {
                        selectNextCell(bCol, sRow + 1, $table, $cell, true);
                        window.scrollBy(0, 10);
                    }

                    break;
                case 13:
                    var input = $cell.find("input");
                    var val = $(input).val();
                    if (val && val.startsWith("=")) {
                        $(input).val("");
                        var formulaInput = $table.parent().parent().parent().find(".txtFormula");
                        $(formulaInput).val(val);
                        var e = jQuery.Event("keydown");
                        e.which = 13;
                        $(formulaInput).trigger(e, val);
                    }

                    break;
                case 16:
                    break;
                default:
                    if (!evt.ctrlKey) {
                        $(evt.target).css("caret-color", "black");
                        var model = rgUtil.getModel($table);
                        var celldata = model.cells.filter(a => a.address === cells[0]
                            .getAttribute("data-address"))[0];
                        if (celldata.cellInfos && celldata.cellInfos.length > 0) {
                            return false;
                        }
                        setTimeout(function () {
                            var txt = $(evt.target).val();
                            celldata.text = txt;
                        }, 10)
                    }
                    break;
            }
        }
        var selectGroupCells = function ($table, cells) {
            deselectAll($table);
            for (var i = 0; i < cells.length; i++) {
                var cellTag = $table.find('td[data-address="' + cells[i] + '"]');
                if (cellTag.length) {
                    cellTag.addClass(selectedCellClass);
                }
            }
            $table.trigger('selectionchange');

        }
        var selectNextCell = function (col, row, $table, $cell, focus) {
            if (!$cell)
                return;
            var nextCell = $table.find('td[data-col="' + col + '"][data-row="' + row + '"]');
            if (nextCell.length) {
                var data = $table.data(dataKey);
                data.selFrom = getCoordinates(nextCell);
                data.selFrom.$el = nextCell;
                $cell.removeClass(selectedCellClass);
                $cell.find("input").css("caret-color", "");
                deselectAll($table);
                nextCell.addClass(selectedCellClass);
                if (focus) {
                    nextCell.find("input").focus();
                }
                data.$pointX1 = nextCell.offset().left;
                data.$pointX1width = nextCell.offset().left + nextCell.width();
                data.$pointY1 = nextCell.offset().top;
                data.$pointY1height = nextCell.offset().top + nextCell.height();
                data.isHighlighted = nextCell.hasClass(selectedCellClass);
                $table.data(dataKey, data);
                $table.trigger('selectionchange');

            }
        }
        var onMouseOver = function (event) {
            if (event.ctrlKey)
                return;
            var pluginData = getPluginDataByEvent(event);
            var $table = pluginData.$table;

            var $cell = pluginData.$cell;

            if ($cell.length === 0) return;


            var data = pluginData.data;
            data.$currCell = $cell;


            if (!isMouseDown) return false;


            $table.find('.' + selectionEnabled).removeClass(selectionEnabled);
            data.selTo = getCoordinates($cell);

            setPointCoordinates(data, $cell);
            coordinateManipulateMagic($table, data);
            selectCells($table, data);
            $table.data(data);
            return true;
        }
        var findRectangle = function (pointA, pointB) {
            var first, second;
            if (pointA.address < pointB.address) {
                first = pointA;
                second = pointB;
            } else {
                first = pointB;
                second = pointA;
            }
            var array = [];
            for (var i = first.col; i < second.col + 1; i++) {
                for (var j = first.row; j < second.row + 1; j++) {
                    var col = _h.numberToAlphabet(i);
                    array.push(col + j);

                }
            }
            return array;
        }
        var onMouseDown = function (event) {
            var pluginData = getPluginDataByEvent(event);
            var $table = pluginData.$table;
            var $cell = pluginData.$cell;
            var isRightClick = isRightMouseButton(event);
            if (isRightClick && event.shiftKey)
                return;
            if ($cell.length === 0)
                return;
            if (event.shiftKey) {
                var cells = getSelectedCells($table);
                if (cells.length === 1) {
                    var addressList = findRectangle({
                        address: $(cells[0]).attr("data-address"),
                        col: Number($(cells[0]).attr("data-col")),
                        row: Number($(cells[0]).attr("data-row"))
                    }, {
                        address: $cell.attr("data-address"),
                        col: Number($cell.attr("data-col")),
                        row: Number($cell.attr("data-row"))
                    });
                    for (var i = 0; i < addressList.length; i++) {
                        var $tCell = $table.find('td[data-address="' + addressList[i] + '"]');
                        $tCell.addClass(selectedCellClass);
                    }
                    $table.trigger('selectionchange');
                    return true;
                }
            }
            if ($cell[0].nodeName === "TD" && isRightClick) {
                deselectAll($table);
                $cell.addClass(selectedCellClass);
                $table.trigger('selectionchange');
                return true;
            }
            if (event.ctrlKey) {
                $cell.addClass(selectedCellClass);
                $table.trigger('selectionchange');
                return true;
            }

            if ($cell[0].nodeName === "TH" && !isRightClick) {
                deselectAll($table);
                if ($cell.hasClass("rp-gen-col")) {
                    var colId = Number($cell.attr("data-col"));
                    $table.find('td[data-col="' + colId + '"]').addClass(selectedCellClass);
                    $table.trigger('selectionchange');
                }
                if ($cell.hasClass('first-cell')) {
                    var rowId = Number($cell.attr("data-row"));
                    $table.find('td[data-row="' + rowId + '"]').addClass(selectedCellClass);
                    $table.trigger('selectionchange');
                }
                return;
            }
            if ($cell[0].nodeName === "TH" && isRightClick)
                return;
            var data = pluginData.data;
            isMouseDown = true;
            data.selFrom = getCoordinates($cell);
            data.selFrom.$el = $cell;
            deselectAll($table);
            $cell.addClass(selectedCellClass);
            var offSet = $cell.offset();
            data.$pointX1 = offSet.left;
            data.$pointX1width = offSet.left + $cell.width();
            data.$pointY1 = offSet.top;
            data.$pointY1height = offSet.top + $cell.height();
            data.isHighlighted = $cell.hasClass(selectedCellClass);
            $table.data(data);
            return true;
        }
        var onMouseUp = function (event) {
            var pluginData = getPluginDataByEvent(event);
            var data = pluginData.data;
            isMouseDown = false;
            data.selFrom = false;
            data.selTo = false;
            pluginData.$table.data(data);
            // if (event.target.nodeName != "IMG")  //why this line add before??
            pluginData.$table.trigger('selectionchange');
            return true;
        }
        var selectCells = function ($table, data) {
            deselectAll($table);
            var cells = $table[0].getElementsByTagName("td");
            for (var i = 0; i < cells.length; i++) {
                var cell = $(cells[i]);
                var offset = cell.offset();
                data.$elemX = offset.left;
                data.$elemXwidth = offset.left + cell.width();
                data.$elemY = offset.top;
                data.$elemXheight = offset.top + cell.height();

                if ((data.$elemX >= data.$pointXmin) && (data.$elemXwidth <= data.$pointXwidth)
                    && (data.$elemXwidth <= data.$pointXwidth) && (data.$elemY >= data.$pointYmin)
                    && (data.$elemY <= data.$pointYheight) && (data.$elemYheight >= data.$pointYheight) &&
                    cells[i].nodeName === "TD") {
                    cells[i].classList.toggle(selectedCellClass);
                }
            }
        }
        var getTable = function (el) {
            var table;
            if ($(el).hasClass("rp-gen")) {
                table = el.find("table");
            }
            if ($(el).hasClass("tsc-cs") || $(el).hasClass("tsc-ed")) {
                table = el;
            }
            if (!table) {
                var table = $(el).closest("table");
            }
            var model = rgUtil.getModel(table);
            if (!model) {
                var parent = $(el).closest(".rg-c");
                var id = $(parent).attr("id");
                table = $("#" + id).find("table.tcs");
            }
            return table;
        }
        var getModel = function (el) {
            if (el.nodeName === "Table") {
                return $(table).data('model');
            }
            var table = $(el).closest("table");
            return $(table).data('model');
        }
        var getSelectedCells = function ($table) {
            return $table.find('.' + selectedCellClass);
        }
        var getSelectedCellModels = function (table) {
            var elements = getSelectedCells(table);
            var model = rgUtil.getModel(table);
            var cells = [];
            for (var i = 0; i < elements.length; i++) {
                var row = $(elements[i]).attr("data-row");
                var col = $(elements[i]).attr("data-col");
                var cell = model.cells.filter(a => a.row === Number(row) && a.col === Number(col))[0];
                cells.push(cell);
            }
            return cells;
        }
        var getCoordinates = function ($cell) {
            var cell = $cell[0];
            var colspan = cell.getAttribute('colspan');
            var rowspan = cell.getAttribute('rowspan');

            return {
                x: parseInt(cell.getAttribute('data_x')),
                y: parseInt(cell.parentNode.getAttribute('data_y')),
                colspan: colspan ? parseInt(colspan) : 0,
                rowspan: rowspan ? parseInt(rowspan) : 0
            };
        }
        var deselectAll = function ($table) {
            var selectedCells = getSelectedCells($table);
            selectedCells.removeClass(selectedCellClass);
            return 0;
        }
        var isRightMouseButton = function (event) {
            var isRightMb;
            event = event || window.event;
            if ("which" in event)
                isRightMb = event.which === 3;
            else if ("button" in event)
                isRightMb = event.button === 2;
            return isRightMb;
        }
        var getPluginDataByEvent = function (event) {
            var $target = $(event.target);
            var $table = $target.closest('table');
            return {
                $target: $target,
                $table: $table,
                $cell: $target.closest('td,th'),
                data: $table.data(dataKey)
            }
        }
        var coordinateManipulateMagic = function ($table, data) {
            var i = 1;
            while (i > 0) {
                i = 0;
                var cells = $table[0].getElementsByTagName("td");
                for (var j = 0; j < cells.length; j++) {
                    var cell = $(cells[j]);
                    var offSet = cell.offset();
                    data.$elemX = offSet.left;
                    data.$elemXwidth = offSet.left + cell.width();

                    data.$elemY = offSet.top;
                    data.$elemYheight = offSet.top + cell.height();

                    if ((data.$elemX < data.$pointXmin) && (data.$elemXwidth >= data.$pointXmin) && (data.$elemXwidth <= data.$pointXwidth) && (data.$elemYheight <= data.$pointYheight) && (data.$elemYheight > data.$pointYmin)) {
                        data.$temp = data.$elemX;
                        if (data.$temp != data.$pointXmin) {
                            data.$pointXmin = data.$temp;
                            i = 1;
                        }
                    }

                    if ((data.$elemX >= data.$pointXmin) && (data.$elemX < data.$pointXwidth) && (data.$elemXwidth >= data.$pointXwidth) && (data.$elemYheight <= data.$pointYheight) && (data.$elemYheight > data.$pointYmin)) {
                        data.$temp = data.$elemXwidth;
                        if (data.$temp != data.$pointXwidth) {
                            data.$pointXwidth = data.$temp;
                            i = 1;
                        }
                    }

                    if ((data.$elemY < data.$pointYmin) && (data.$elemYheight >= data.$pointYmin) && (data.$elemYheight <= data.$pointYheight) && (data.$elemXwidth <= data.$pointXwidth) && (data.$elemXwidth > data.$pointXmin)) {
                        data.$temp = data.$elemY;
                        if (data.$temp != data.$pointYmin) {
                            data.$pointYmin = data.$temp;
                            i = 1;
                        }
                    }

                    if ((data.$elemY >= data.$pointYmin) && (data.$elemY < data.$pointYheight) && (data.$elemYheight >= data.$pointYheight) && (data.$elemXwidth <= data.$pointXwidth) && (data.$elemXwidth > data.$pointXmin)) {
                        data.$temp = data.$elemYheight;
                        if (data.$temp != data.$pointYheight) {
                            data.$pointYheight = data.$temp;
                            i = 1;
                        }
                    }

                    if ((data.$elemX < data.$pointXmin) && (data.$elemXwidth >= data.$pointXwidth) && (data.$elemYheight <= data.$pointYheight) && (data.$elemYheight > data.$pointYmin)) {
                        data.$temp = data.$elemX;
                        if (data.$temp < data.$pointXmin) {
                            data.$pointXmin = data.$temp;
                            i = 1;
                        }
                    }
                    if ((data.$elemX > data.$pointXmin) && (data.$elemX < data.$pointXwidth) && (data.$elemY < data.$pointYheight) && (data.$elemY > data.$pointYmin)) {
                        data.$temp = data.$elemXwidth;
                        if (data.$temp > data.$pointXwidth) {
                            data.$pointXwidth = data.$temp;
                            i = 1;
                        }
                    }

                    if ((data.$elemY < data.$pointYmin) && (data.$elemYheight >= data.$pointYmin) && (data.$elemYheight <= data.$pointYheight) && (data.$elemXwidth <= data.$pointXwidth) && (data.$elemXwidth > data.$pointXmin)) {
                        data.$temp = data.$elemY;
                        if (data.$temp < data.$pointYmin) {
                            data.$pointYmin = data.$temp;
                            i = 1;
                        }
                    }
                    if ((data.$elemY > data.$pointYmin) && (data.$elemYheight <= data.$pointYheight) && (data.$elemX <= data.$pointXwidth)) {
                        data.$temp = data.$elemYheight;
                        if (data.$temp > data.$pointYheight) {
                            data.$pointYheight = data.$temp;
                            i = 1;
                        }
                    }
                }
            }
        }
        var setPointCoordinates = function (data, $cell) {
            var offset = $cell.offset();
            data.$pointX2 = offset.left;
            data.$pointX2width = offset.left + $cell.width();
            data.$pointY2 = offset.top;
            data.$pointY2height = offset.top + $cell.height();

            if (data.$pointX1 < data.$pointX2) {
                data.$pointXmin = data.$pointX1;
                data.$pointXmax = data.$pointX2;
            } else {
                data.$pointXmin = data.$pointX2;
                data.$pointXmax = data.$pointX1;
            }
            if (data.$pointX1width > data.$pointX2width) {
                data.$pointXwidth = data.$pointX1width;
            } else {
                data.$pointXwidth = data.$pointX2width;
            }
            if (data.$pointY1 < data.$pointY2) {
                data.$pointYmin = data.$pointY1;
                data.$pointYmax = data.$pointY2;
            } else {
                data.$pointYmin = data.$pointY2;
                data.$pointYmax = data.$pointY1;
            }
            if (data.$pointY1height > data.$pointY2height) {
                data.$pointYheight = data.$pointY1height;
            } else {
                data.$pointYheight = data.$pointY2height;
            }
        }
        var resizeFunc = function (table) {
            $(table).find('.rp-gen-col').resizable({
                handles: 'w',
                minWidth: 5,
                _h: "resizable-_h",
                resize: function (event, ui) {
                    $(event.target).css("left", 0);
                },
                stop: function (event, ui) {
                    var width = event.target.offsetWidth;
                    var colNum = event.target.getAttribute("data-col");
                    var model = rgUtil.getModel($(table));
                    rgUtil.executeCommand($(table), model, { id: "width", type: "width", viewType: "col", value: width, colNumber: Number(colNum) });
                    setTimeout(function () {
                        _h.kocnx().ttvm().focusDesignItem().refreshToolBar(true);
                    }, 50);
                },
            });
            $(table).find('.first-cell').resizable({
                handles: 's',
                minHeight: 5,
                _h: "resizable-_h",
                stop: function (event, ui) {
                    $(event.target).css("top", 0);
                    var height = event.target.offsetHeight;
                    var rowNum = event.target.getAttribute("data-row");
                    var model = rgUtil.getModel($(table));
                    rgUtil.executeCommand($(table), model, { id: "height", type: "height", viewType: "row", value: height, rowNumber: Number(rowNum) });
                    setTimeout(function () {
                        _h.kocnx().ttvm().focusDesignItem().refreshToolBar(true);
                    }, 50);
                },
            });
        }
        var copyCellsData = function (e, table) {
            var cells = getSelectedCellModels($(table));
            if (cells.length > 0) {
                var array = [];
                for (var i = 0; i < cells.length; i++) {
                    var cell = cellFunc.copyCell(cells[i]);
                    array.push(cell);
                }
                if (array.length > 0) {
                    e.clipboardData.clearData('application/json');
                    if (array.length === 1) {
                        e.clipboardData.setData('text/plain', array[0].text);
                    }
                    e.clipboardData.setData('application/json', JSON.stringify(array));
                    e.preventDefault();
                }
            }
        }
        var pasteCellsData = function (e, table) {
            var model = rgUtil.getModel(table);
            var cells = getSelectedCellModels($(table));
            var cell;
            if (cells.length > 0) {
                var data = e.clipboardData.getData('application/json');
                if (!_h.isEmpty(data)) {
                    var json = JSON.parse(data);
                    if (json.length === 1)
                        for (var i = 0; i < cells.length; i++) {
                            cell = cells[i];
                            cellFunc.pasteCell(table, cell, json[0], model.cols, model.rows);
                        }
                    else {
                        if (cells.length === json.length) {
                            for (var j = 0; j < cells.length; j++) {
                                cell = cells[j];
                                cellFunc.pasteCell(table, cell, json[j], model.cols, model.rows);
                            }
                        }
                    }
                }
                var html = e.clipboardData.getData('text/html');
                data = e.clipboardData.getData('text/plain');
                var dataJson = e.clipboardData.getData('application/json');
                if (!_h.isEmpty(data) && !html && _h.isEmpty(dataJson)) {
                    for (var k = 0; k < cells.length; k++) {
                        cell = cells[k];
                        cellFunc.pasteCell(table, cell, data, model.cols, model.rows);
                    }
                }
                if (!_h.isEmpty(data) && !_h.isEmpty(html) && _h.isEmpty(dataJson)) {
                    var list = pasteDataFormater.textToJson(data);
                    if (_h.any(list)) {
                        for (var i = 0; i < cells.length; i++) {
                            var cell = cells[i];
                            cellFunc.pasteCell(table, cell, list[i], model.cols, model.rows);
                        }
                    }
                }
                if (!_h.isEmpty(data) && _h.isEmpty(html) && _h.isEmpty(dataJson)) {
                    for (var k = 0; k < cells.length; k++) {
                        cell = cells[k];
                        cellFunc.pasteCell(table, cell, data, model.cols, model.rows);
                    }
                }
                e.preventDefault();
                $(table).data("model", model);
            }
        }
        var cutCellsData = function (e, table) {
            var model = rgUtil.getModel(table);
            var cells = getSelectedCellModels($(table));
            var defaultVal = getDefault();
            if (cells.length > 0) {
                var array = [];
                for (var i = 0; i < cells.length; i++) {
                    var cell = cells[i];
                    var cellData = cellFunc.cutCell(table, model, cell, defaultVal);
                    array.push(cellData);
                }
                if (array.length > 0) {
                    rgUtil.addToHistory(table, array, { type: "CutCell" }, [{ old: array, new: [] }]);
                    var clipboardData = e.originalEvent ? e.originalEvent.clipboardData : e.clipboardData;

                    clipboardData.clearData('application/json');
                    if (array.length === 1) {
                        clipboardData.setData('text/plain', array[0].text);
                    }
                    clipboardData.setData('application/json', JSON.stringify(array));
                    e.preventDefault();
                }
                $(table).data("model", model);
            }
        }
        var replaceHiddenRows = function (table, model, row, action) {
            if (model.hiddenRows.length === 0) {
                tagRender.applyToTable("hiddenCells", table, model);
                return;
            }
            var delList = [];
            for (var i = 0; i < model.hiddenRows.length; i++) {
                var target = model.hiddenRows[i];
                if (action === "add") {
                    if (row <= target)
                        model.hiddenRows[i] = target + 1;
                } else {
                    if (row < target)
                        model.hiddenRows[i] = target - 1;
                    if (row === target)
                        delList.push(i);
                }
            }
            for (var j = 0; j < delList.length; j++) {
                model.hiddenRows.splice(delList[j], 1);
            }
            tagRender.applyToTable("hiddenCells", table, model);
        }
        var replaceHiddenCols = function (table, model, col, action) {
            if (model.hiddenCols.length === 0) {
                tagRender.applyToTable("hiddenCells", table, model);
                return;
            }
            var delList = [];
            for (var i = 0; i < model.hiddenCols.length; i++) {
                var target = model.hiddenCols[i];
                if (action === "add") {
                    if (col <= target)
                        model.hiddenCols[i] = target + 1;
                } else {
                    if (col < target)
                        model.hiddenCols[i] = target - 1;
                    if (col === target)
                        delList.push(i);
                }
            }
            for (var j = 0; j < delList.length; j++) {
                model.hiddenCols.splice(delList[j], 1);
            }
            tagRender.applyToTable("hiddenCells", table, model);
        }
        var refreshFormulaCells = function (table, model, rowNumber, colNumber, type) {
            for (let i = 0; i < model.rowsHeight.length; i++) {
                var rowHeight = model.rowsHeight[i];
                var cells = model.cells.filter(a => a.row === rowHeight.id);
                for (var j = 0; j < cells.length; j++) {
                    var cell = cells[j];
                    var temp, letter, numLetter, parser;
                    var str = cell.value;
                    if (str && str.startsWith("=") && rowNumber && cell.row >= rowNumber) {
                        if ((str.indexOf("+") !== -1 || str.indexOf("-") !== -1 || str.indexOf("*") !== -1 || str.indexOf("/") !== -1) &&
                            str.indexOf(":") === -1) {
                            parser = new ExpParser();
                            temp = type === "remove"
                                ? parser.removeRow(str, rowNumber)
                                : parser.addRow(str, rowNumber);
                            cell.value = temp;

                        } else if (str.indexOf("Sum") !== -1 && str.indexOf(":") !== -1) {
                            fixPartialSumRowValue(table, str, type, rowNumber, cell);
                        }
                    }
                    else if (str && str.startsWith("=") && colNumber && cell.col >= colNumber) {
                        if ((str.indexOf("+") !== -1 || str.indexOf("-") !== -1 || str.indexOf("*") !== -1 || str.indexOf("/") !== -1) && str.indexOf(":") === -1) {
                            parser = new ExpParser();
                            temp = type === "remove"
                                ? parser.removeCol(str, colNumber)
                                : parser.addCol(str, colNumber);
                            cell.value = temp;
                        }
                        else if (str.indexOf("Sum") !== -1 && str.indexOf(":") !== -1) {
                            fixPartialSumColValue(str, type, cell);
                        }
                        else if ((str.indexOf("Sum") !== -1
                            || str.indexOf("GSum") !== -1
                            || str.indexOf("CSum") !== -1) && str.indexOf(":") === -1) {
                            var st = getFormulaType(str);
                            letter = str.toLowerCase()
                                .replace(")", '')
                                .replace("=", '')
                                .replace("" + st.toLowerCase() + "(", '');
                            if (type === "remove") {
                                numLetter = _h.alphabetToNumber(letter.toUpperCase()) - 1;
                                cell.value = "=" + st + "(" + _h.numberToAlphabet(numLetter) + ")";
                            }
                            if (type === "add") {
                                numLetter = _h.alphabetToNumber(letter.toUpperCase()) + 1;
                                cell.value = "=" + st + "(" + _h.numberToAlphabet(numLetter) + ")";
                            }
                        }
                        else if (str.indexOf("Avg") !== -1 || str.indexOf("Max") !== -1 || str.indexOf("Min") !== -1) {
                            var st = getFormulaType(str);
                            letter = str.toLowerCase()
                                .replace(")", '')
                                .replace("=", '')
                                .replace("" + st.toLowerCase() + "(", '');
                            if (type === "remove") {
                                numLetter = _h.alphabetToNumber(letter.toUpperCase()) - 1;
                                cell.value = "=" + st + "(" + _h.numberToAlphabet(numLetter) + ")";
                            }
                            if (type === "add") {
                                numLetter = _h.alphabetToNumber(letter.toUpperCase()) + 1;
                                cell.value = "=" + st + "(" + _h.numberToAlphabet(numLetter) + ")";
                            }
                        }


                    } else if (str && str.startsWith("{") && rgUtil.stringIsEnglish(str) && rowNumber && cell.row >= rowNumber) {
                        parser = new ExpParser();
                        temp = type === "remove"
                            ? parser.removeNodeRow(str, rowNumber)
                            : parser.addNodeRow(str, rowNumber);
                        cell.value = temp;
                    }
                    else if (str && str.startsWith("{") && rgUtil.stringIsEnglish(str) && colNumber && cell.col >= colNumber) {
                        parser = new ExpParser();
                        temp = type === "remove"
                            ? parser.removeNodeCol(str, colNumber)
                            : parser.addNodeCol(str, colNumber);
                        cell.value = temp;
                    }

                }
            }
        }
        var stringIsEnglish = function () {
            var index;
            var english = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~!@#$%^&*(){}:_+-.<>?|\\/";
            for (index = str.length - 1; index >= 0; --index) {
                if (english.indexOf(str.substring(index, index + 1)) < 0) {
                    return false;
                }
            }
            return true;
        }
        var refreshCompareCells = function (table, model, rowNumber, colNumber, type) {
            var cellBinds = model.cellBinds;
            for (var i = 0; i < cellBinds.length; i++) {
                var item = cellBinds[i];
                var firstLetter = item.firstCell.replace(/\d+/g, '');
                var firstLetterNumber = _h.alphabetToNumber(firstLetter);
                var secondLetter = item.secondCell.replace(/\d+/g, '');
                var secondLetterNumber = _h.alphabetToNumber(secondLetter);
                var firstNumber = Number(item.firstCell.replace(/^\D+/g, ''));
                var secondNumber = Number(item.secondCell.replace(/^\D+/g, ''));
                if (type === "remove") {
                    if (colNumber === firstLetterNumber || colNumber === secondLetterNumber || rowNumber === firstNumber || rowNumber === secondNumber) {
                        item.deleted = true;
                        continue;
                    }
                    if (colNumber && firstLetterNumber > colNumber) {
                        item.firstCell = _h.numberToAlphabet(firstLetterNumber - 1) + firstNumber;

                    }
                    if (colNumber && secondLetterNumber > colNumber) {
                        item.secondCell = _h.numberToAlphabet(secondLetterNumber - 1) + secondNumber;
                    }

                    if (rowNumber && firstNumber > rowNumber) {
                        item.firstCell = _h.numberToAlphabet(firstLetterNumber) + (firstNumber - 1);
                    }
                    if (rowNumber && secondNumber > rowNumber) {
                        item.secondCell = _h.numberToAlphabet(secondLetterNumber) + (secondNumber - 1);
                    }
                    else if (rowNumber && (firstNumber > rowNumber && secondNumber < rowNumber)) {
                        item.secondCell = secondLetterNumber + (secondNumber - 1);
                    }
                } else {
                    if (colNumber && firstLetterNumber >= colNumber) {
                        item.firstCell = _h.numberToAlphabet(firstLetterNumber + 1) + firstNumber;
                    }
                    if (colNumber && secondLetterNumber > colNumber) {
                        item.secondCell = _h.numberToAlphabet(secondLetterNumber + 1) + secondNumber;
                    }
                    if (colNumber && (firstLetterNumber < colNumber && secondLetterNumber >= colNumber)) {
                        item.secondCell = _h.numberToAlphabet(secondLetterNumber + 1) + secondNumber;
                    }
                    if (rowNumber && firstNumber >= rowNumber) {
                        item.firstCell = _h.numberToAlphabet(firstLetterNumber) + (firstNumber + 1);
                    }
                    if (rowNumber && secondNumber >= rowNumber) {
                        item.secondCell = _h.numberToAlphabet(secondLetterNumber) + (secondNumber + 1);
                    }
                    if (rowNumber && (firstNumber < rowNumber && secondNumber >= rowNumber)) {
                        item.secondCell = _h.numberToAlphabet(secondLetterNumber) + (secondNumber + 1);
                    }
                }
            }
            model.cellBinds = model.cellBinds.filter(a => !a.deleted);
        }
        var getFormulaType = function (val) {
            if (val && val.indexOf("GSum") !== -1)
                return "GSum";
            if (val && val.indexOf("CSum") !== -1)
                return "CSum";
            if (val && val.indexOf("Sum") !== -1)
                return "Sum";
            if (val && val.indexOf("Avg") !== -1)
                return "Avg";
            if (val && val.indexOf("Max") !== -1)
                return "Max";
            if (val && val.indexOf("Min") !== -1)
                return "Min";
            return "";
        };
        var fixPartialSumRowValue = function (table, str, type, rowNumber, cell) {
            var letter,
                resetFormula = false;
            const temp = str.replace("=Sum(", "").replace(")", "").split(":");
            if (temp.length > 1) {
                letter = temp[0];
                var start = Number(temp[1]);
                var end = Number(temp[2]);
                if (type === "remove") {
                    var newStart, newEnd;
                    if (rowNumber < start) {
                        newStart = start - 1;
                        if (newStart === 0)
                            newStart = 1;
                        newEnd = end - 1;
                        cell.value = "=Sum(" +
                            letter +
                            ":" +
                            newStart +
                            ":" +
                            newEnd +
                            ")";
                    }
                    if (rowNumber >= start && rowNumber <= end) {
                        if (start < end - 1) {
                            cell.value = "=Sum(" +
                                letter + ":" + start + ":" + (end - 1) + ")";
                        } else {
                            resetFormula = true;
                        }
                    }
                    if (resetFormula) {
                        cell.value = "";
                        tagRender.applyToElement(table, cell, "resetFormula")
                    }
                }
                if (type === "add") {
                    if (rowNumber < start) {
                        cell.value = "=Sum(" +
                            letter +
                            ":" +
                            (start + 1) +
                            ":" +
                            (end + 1) +
                            ")";
                    }
                    if (rowNumber >= start && rowNumber <= end) {
                        if (rowNumber === start) {
                            cell.value = "=Sum(" +
                                letter +
                                ":" +
                                (start + 1) +
                                ":" +
                                (end + 1) +
                                ")";
                        } else {
                            cell.value = "=Sum(" +
                                letter +
                                ":" +
                                start +
                                ":" +
                                (end + 1) +
                                ")";
                        }
                    }
                }
            }
        }
        var fixPartialSumColValue = function (str, type, cell) {
            var numLetter;
            var temp = str.replace("=Sum(", "").replace(")", "").split(":");
            if (temp.length > 1) {
                if (type === "remove") {
                    numLetter = _h.alphabetToNumber(temp[0]) - 1;
                    cell.value = "=Sum(" +
                        _h.numberToAlphabet(numLetter) +
                        ":" +
                        temp[1] +
                        ":" +
                        temp[2] +
                        ")";
                }
                if (type === "add") {
                    numLetter = _h.alphabetToNumber(temp[0]) + 1;
                    cell.value = "=Sum(" +
                        _h.numberToAlphabet(numLetter) +
                        ":" +
                        temp[1] +
                        ":" +
                        temp[2] +
                        ")";
                }
            }
        }
        var getRectanglePoints = function (cells) {
            var sCol = 0;
            var bCol = 0;
            var sRow = 0;
            var bRow = 0;
            for (var i = 0; i < cells.length; i++) {
                var cell = cells[i];
                if (i === 0) {
                    sCol = cell.col;
                    sRow = cell.row;
                }
                if (cell.colSpan > 1) {
                    for (var j = 1; j < cell.colSpan; j++) {
                        var innerCol = cell.col + j;
                        if (innerCol < sCol)
                            sCol = innerCol;
                        if (innerCol > bCol)
                            bCol = innerCol;
                    }
                }
                if (cell.rowSpan > 1) {
                    for (var k = 1; k < cell.rowSpan; k++) {
                        var innerRow = cell.row + k;
                        if (innerRow < sRow)
                            sRow = innerRow;
                        if (innerRow > bRow)
                            bRow = innerRow;
                    }
                }
                if (cell.col < sCol)
                    sCol = cell.col;
                if (cell.col > bCol)
                    bCol = cell.col;

                if (cell.row < sRow)
                    sRow = cell.row;
                if (cell.row > bRow)
                    bRow = cell.row;
            }
            return { sCol: sCol, bCol: bCol, sRow: sRow, bRow: bRow };
        };
        var getSelectedCellsShape = function (cells) {
            var v = cellFunc.calculateVertexes(cells);
            var left = true, right = true, top = true, bottom = true;
            var address;

            for (var i = v.sRow; i < v.bRow + 1; i++) {
                address = _h.numberToAlphabet(v.bCol) + i;
                if (cells.filter(a => a.address === address).length === 0)
                    left = false;

                address = _h.numberToAlphabet(v.sCol) + i;
                if (cells.filter(a => a.address === address).length === 0)
                    right = false;

            }

            for (var i = v.sCol; i < v.bCol + 1; i++) {
                address = _h.numberToAlphabet(i) + v.sRow;
                if (cells.filter(a => a.address === address).length === 0)
                    top = false;

                address = _h.numberToAlphabet(i) + v.bRow;
                if (cells.filter(a => a.address === address).length === 0)
                    bottom = false;
            }
            return [left, right, top, bottom, left && right && top && bottom];
        }
        var mergeCells = function (model, table, selectedCells) {
            var points = getRectanglePoints(selectedCells);
            var deleteArray = [];
            var cell;
            var outCellAddress = null;
            for (var i = 0; i < selectedCells.length; i++) {
                cell = selectedCells[i];
                if (cell.col === points.sCol && cell.row === points.sRow) {
                    cell.rowSpan = points.bRow - points.sRow + 1;
                    cell.colSpan = points.bCol - points.sCol + 1;
                    tagRender.applyToElement(table, cell, "span");
                    outCellAddress = cell.address;
                }
                else {
                    deleteArray.push(cell.address);
                    tagRender.applyToElement(table, cell, "removeCell");
                }
            }

            var newCells = model.cells.filter(a => deleteArray.indexOf(a.address) === -1);

            model.cells = newCells;
            return outCellAddress;
        }
        var unMergeCells = function (model, table, cell, defaultVal) {
            var rowSpan = cell.rowSpan;
            var colSpan = cell.colSpan;
            var array = [];
            var outArray = [];
            var newCell;
            for (var j = 0; j < colSpan; j++) {
                var col = cell.col + j;
                for (var i = 0; i < rowSpan - 1; i++) {
                    array.push({ col: col, row: cell.row + (i + 1), address: _h.numberToAlphabet(col) + (cell.row + (i + 1)) });
                    newCell = cellFunc.createEmptyModel("cell", col, cell.row + (i + 1), model.accountType, defaultVal);
                    model.cells.push(newCell);
                }
            }

            if (colSpan > 1) {
                for (var l = 0; l < colSpan - 1; l++) {
                    array.push({
                        col: cell.col + (l + 1), row: cell.row,
                        address: _h.numberToAlphabet((cell.col + (l + 1))) + cell.row
                    });
                    newCell = cellFunc.createEmptyModel("cell", cell.col + (l + 1), cell.row, model.accountType, defaultVal);
                    model.cells.push(newCell);
                }
            }
            cell.colSpan = 1;
            cell.rowSpan = 1;
            tagRender.applyToElement(table, cell, "span");
            tagRender.applyToTable("unMergeCells", table, model, array);
            array.filter(a => outArray.push(a.address));
            outArray.push(cell.address);
            return outArray;
        }
        var getColsWidth = function (table) {
            var colsWidth = [];
            var cols = $(table).find("thead th");
            for (var i = 0; i < cols.length; i++) {
                var col = cols[i];
                if ($(col).hasClass("rp-gen-col")) {
                    //var width = col.offsetWidth;
                    //var w2 = col.getBoundingClientRect();
                    colsWidth.push({
                        id: Number($(col).attr("data-col")),
                        size: $(col).css("width")
                    });
                }
            }
            return colsWidth;
        }
        var getRowsHeight = function (table) {
            var rowsHeight = [];
            var rows = $(table).find("tbody th");
            for (var i = 0; i < rows.length; i++) {
                var row = rows[i];
                if ($(row).attr("data-row")) {
                    rowsHeight.push({ id: Number($(row).attr("data-row")), size: $(row).css("height") });
                }
            }
            return rowsHeight;
        }
        var findHigherCell = function (model, col, row) {
            var reducer = row - 1;
            while (reducer > 0) {
                var target = model.cells.filter(a => a.col === col && a.row === reducer)[0];
                if (target)
                    return target;
                reducer = reducer - 1;
            }
        }
        var removeRow = function (table, model, cell) {
            var targetRow = cell.row;
            var resModel = [];
            var reduceRsAndReplaceCells = [];
            var reduceRsCells = [];
            var ignoreCells = [];
            for (var b = 0; b < model.cols; b++) {
                var addr = _h.numberToAlphabet(b + 1) + cell.row;
                var rCell = model.cells.filter(a => a.address === addr)[0];
                if (!rCell) {
                    if (ignoreCells.indexOf(addr) === -1) {
                        var target = findHigherCell(model, b + 1, targetRow);
                        if (target) {
                            target.rowSpan = target.rowSpan - 1;
                            reduceRsCells.push(target.address);
                            if (target.colSpan > 1) {
                                for (var i = 0; i < target.colSpan; i++) {
                                    if (i !== 0) {
                                        var addr3 = _h.numberToAlphabet(target.col + i) + cell.row;
                                        ignoreCells.push(addr3);
                                    }
                                }
                            }
                        }
                    }
                } else {
                    if (rCell.colSpan >= 1 && rCell.rowSpan === 1) {
                        rCell.remove = true;
                        resModel.push(rCell);
                    }
                    if (rCell.rowSpan > 1) {
                        rCell.rowSpan = rCell.rowSpan - 1;
                        reduceRsAndReplaceCells.push(rCell.address);
                    }
                    if (rCell.colSpan > 1) {
                        for (var i = 0; i < rCell.colSpan; i++) {
                            if (i !== 0) {
                                var addr2 = _h.numberToAlphabet(rCell.col + i) + cell.row;
                                ignoreCells.push(addr2);
                            }
                        }
                    }
                }
            }
            model.cells = model.cells.filter(a => !a["remove"]);
            for (var j = 0; j < model.cells.length; j++) {
                var targetCell = model.cells[j];
                if (targetCell.row > targetRow) {
                    targetCell.row = targetCell.row - 1;
                    targetCell.address = _h.numberToAlphabet(targetCell.col) + targetCell.row;
                }
            }
            var newRowsHeight = getRowsHeight(table);
            newRowsHeight = newRowsHeight.filter(a => a.id !== targetRow);
            for (var k = 0; k < newRowsHeight.length; k++) {
                var rowHeight = newRowsHeight[k];
                if (rowHeight.id > targetRow)
                    rowHeight.id = rowHeight.id - 1;
            }
            model.rowsHeight = newRowsHeight;
            model.rows = model.rows - 1;
            tagRender.applyToTable("removeRow", table, model,
                {
                    targetRow: targetRow,
                    reduceAndReplaceCells: reduceRsAndReplaceCells,
                    reduceCells: reduceRsCells
                });
            replaceHiddenRows(table, model, cell.row, "remove");
            refreshFormulaCells(table, model, cell.row, undefined, "remove");
            refreshCompareCells(table, model, cell.row, undefined, "remove");
            resizeFunc(table);
            return resModel;
        }
        var findRighterCell = function (model, col, row) {
            var reducer = col - 1;
            while (reducer > 0) {
                var target = model.cells.filter(a => a.col === reducer && a.row === row)[0];
                if (target)
                    return target;
                reducer = reducer - 1;
            }
        }
        var removeCol = function (table, model, cell) {
            var resModel = [];
            var targetCol = cell.col;
            var reduceCsCells = [];
            var ignoreCells = [];
            var newColsWidth = getColsWidth(table);
            newColsWidth = newColsWidth.filter(a => a.id !== targetCol);
            for (var k = 0; k < newColsWidth.length; k++) {
                var colWidth = newColsWidth[k];
                if (colWidth.id > targetCol)
                    colWidth.id = colWidth.id - 1;
            }
            model.colsWidth = newColsWidth;
            for (var i = 0; i < model.rows; i++) {
                var addr = _h.numberToAlphabet(cell.col) + (i + 1);
                var rCell = model.cells.filter(a => a.address === addr)[0];
                if (!rCell) {
                    if (ignoreCells.indexOf(addr) === -1) {
                        var target = findRighterCell(model, targetCol, i + 1);
                        if (target) {
                            target.colSpan = target.colSpan - 1;
                            reduceCsCells.push(target.address);
                            if (target.rowSpan > 1) {
                                for (var b = 0; b < target.rowSpan; b++) {
                                    if (b !== 0) {
                                        var addr3 = _h.numberToAlphabet(targetCol) + (target.row + b);
                                        ignoreCells.push(addr3);
                                    }
                                }
                            }
                        }
                    }
                } else {
                    if ((rCell.colSpan === 1 && rCell.rowSpan >= 1) || (rCell.rowSpan >= 1 && rCell.colSpan === 1)) {
                        rCell.remove = true;
                        resModel.push(rCell);
                    }
                    if (rCell.colSpan > 1) {
                        rCell.colSpan = rCell.colSpan - 1;
                        reduceCsCells.push(rCell.address);
                    }
                    if (rCell.rowSpan > 1) {
                        for (var c = 0; c < rCell.rowSpan; c++) {
                            if (c !== 0) {
                                var addr2 = _h.numberToAlphabet(targetCol) + (rCell.row + c);
                                ignoreCells.push(addr2);
                            }
                        }
                    }
                }
            }

            model.cells = model.cells.filter(a => !a["remove"]);
            model.cols = model.cols - 1;
            for (var j = 0; j < model.cells.length; j++) {
                var targetCell = model.cells[j];
                if (targetCell.col > targetCol) {
                    targetCell.col = targetCell.col - 1;
                    targetCell.address = _h.numberToAlphabet(targetCell.col) + targetCell.row;
                }
            }

            tagRender.applyToTable("removeCol", table, model, {
                targetCol: targetCol,
                reduceCells: reduceCsCells
            });
            replaceHiddenCols(table, model, cell.col, "remove");
            refreshFormulaCells(table, model, undefined, targetCol, "remove");
            refreshCompareCells(table, model, undefined, targetCol, "remove");
            return resModel;
        }
        var getRecursiveCell = function (table, model, type, col, row) {
            var current;
            var cell = undefined;
            var dataModel;
            if (type === "row") {
                current = row;
                while (current !== 0) {
                    cell = $(table).find("[data-address='" + (_h.numberToAlphabet(col) + current) + "']");
                    if (cell.length) {
                        dataModel = model.cells.filter(a => a.col === col && a.row === current)[0];
                        return dataModel;
                    }
                    current = current - 1;
                }
                return undefined;
            } else {
                current = col;
                while (current !== 0) {
                    cell = $(table).find("[data-address='" + (_h.numberToAlphabet(current) + row) + "']");
                    if (cell.length) {
                        dataModel = model.cells.filter(a => a.col === current && a.row === row)[0];
                        return dataModel;
                    }
                    current = current - 1;
                }
                return undefined;
            }
        }
        var getRecursiveClosestCell = function (table, model, col, row) {
            var cell = $(table).find("[data-address='" + (_h.numberToAlphabet(col) + row) + "']");
            if (cell.length) {
                return model.cells.filter(a => a.col === col && a.row === row)[0];
            }
            var cellRow = getRecursiveCell(table, model, "row", col, row);
            var cellCol = getRecursiveCell(table, model, "col", col, row);
            var array = [];
            var array2 = [];
            if (cellRow && cellCol && cellRow.address === cellCol.address)
                return cellRow;

            if (cellRow)
                for (var i = 0; i < cellRow.colSpan; i++) {
                    for (var k = 0; k < cellRow.rowSpan; k++) {
                        array.push(_h.numberToAlphabet(cellRow.col + i) + (cellRow.row + k));
                    }
                }

            if (array.indexOf((_h.numberToAlphabet(col) + row)) !== -1)
                return cellRow;
            if (cellCol)
                for (var m = 0; m < cellCol.colSpan; m++) {
                    for (var n = 0; n < cellCol.rowSpan; n++) {
                        array2.push(_h.numberToAlphabet(cellCol.col + m) + (cellCol.row + n));
                    }
                }

            if (array2.indexOf((_h.numberToAlphabet(col) + row)) !== -1)
                return cellCol;

        }
        var hasRowBackCell = function (table, model, item) {
            if (item.col === 1)
                return true;
            for (var i = item.col - 1; i > 0; i--) {
                for (var j = item.row; j > 0; j--) {
                    var adr = (_h.numberToAlphabet(i) + j)
                    var cell = (table).find("[data-address='" + adr + "']");
                    if (cell.length) {
                        return true;
                    }
                }
            }
        }
        var hasColBackCell = function (table, item) {
            return $(table).find("[data-address='" +
                (_h.numberToAlphabet(item.col) + (item.row - 1)) + "']").length;
        }
        var addToNewCellArray = function (array, newCell) {
            var hasRecord = array.filter(a => a.address === newCell.address).length > 0;
            if (hasRecord)
                return array;
            array.push(newCell);
            return array;
        }
        var addRow = function (table, model, cell, defaultVal) {
            if (model.rows >= 100) {
                var text = _h.getApiMessage("ErrorMaxRowReportGenerator");
                _h.failToast(text);
                return;
            }
            var increaseRsCells = [];
            var addCells = [];
            var targetRow = cell.row;
            var newCell;
            var newRowsHeight = getRowsHeight(table);
            for (var i = 0; i < newRowsHeight.length; i++) {
                if (newRowsHeight[i].id >= targetRow) {
                    newRowsHeight[i].id++;
                }
            }
            newRowsHeight.push({ id: targetRow, size: "30px" });
            newRowsHeight.sort(function (a, b) {
                return a.id - b.id;
            });
            model.rowsHeight = newRowsHeight;


            for (var j = 0; j < model.cols; j++) {
                var rightCell = getRecursiveClosestCell(table, model, j + 1, cell.row);
                if (!_h.isNullOrEmpty(rightCell)) {
                    if (rightCell.col === j + 1 && rightCell.rowSpan > 1 && rightCell.row < cell.row) {
                        increaseRsCells.push(rightCell.address);
                        rightCell.rowSpan = rightCell.rowSpan + 1;
                    }

                    if (rightCell.col === j + 1 && rightCell.colSpan > 1) {
                        for (var i = 0; i < rightCell.colSpan; i++) {
                            newCell = cellFunc.createEmptyModel("cell", rightCell.col + i, rightCell.row, model.accountType, defaultVal);
                            if (newCell.row === cell.row)
                                addToNewCellArray(addCells, newCell);
                        }
                    }

                    if (rightCell.row === cell.row && rightCell.rowSpan === 1) {
                        newCell = cellFunc.createEmptyModel("cell", rightCell.col, rightCell.row, model.accountType, defaultVal);
                        if (newCell.row === cell.row)
                            addToNewCellArray(addCells, newCell);
                    }
                    if (rightCell.row === cell.row && rightCell.rowSpan > 1) {
                        newCell = cellFunc.createEmptyModel("cell", j + 1, rightCell.row, model.accountType, defaultVal);
                        addToNewCellArray(addCells, newCell);
                    }

                    if (rightCell.row === cell.row && rightCell.rowSpan > 1 && hasColBackCell(table, rightCell)) {
                        newCell = cellFunc.createEmptyModel("cell", j + 1, rightCell.row, model.accountType, defaultVal);
                        if (newCell.row === cell.row)
                            addToNewCellArray(addCells, newCell);
                    }
                }
            }
            for (var k = 0; k < model.cells.length; k++) {
                var targetCell = model.cells[k];
                if (targetCell.row >= targetRow) {
                    targetCell.row = targetCell.row + 1;
                    targetCell.address = _h.numberToAlphabet(targetCell.col) + targetCell.row;
                }
            }
            for (var l = 0; l < addCells.length; l++) {
                addCells[l].added = true;
                model.cells.push(addCells[l]);
            }
            model.cells.sort(function (a, b) {
                return a.row - b.row;
            });
            model.rows = model.rows + 1;
            tagRender.applyToTable("rowTop", table, model,
                {
                    targetRow: targetRow,
                    addCells: addCells,
                    increaseCells: increaseRsCells
                });
            replaceHiddenRows(table, model, targetRow, "add");
            refreshFormulaCells(table, model, targetRow, undefined, "add");
            refreshCompareCells(table, model, targetRow, undefined, "add");

            resizeFunc(table);
        }
        var addCol = function (table, model, cell, defaultVal) {
            if (model.cols >= 100) {
                var text = _h.getApiMessage("ErrorMaxColReportGenerator");
                _h.failToast(text);
                return;
            }
            var addCells = [];
            var increaseCsCells = [];
            var targetCol = cell.col;
            var newCell;
            var newColsWidth = getColsWidth(table);
            for (var k = 0; k < newColsWidth.length; k++) {
                var colWidth = newColsWidth[k];
                if (colWidth.id >= targetCol)
                    colWidth.id = colWidth.id + 1;
            }
            newColsWidth.push({ id: targetCol, size: "150px" });
            newColsWidth.sort(function (a, b) {
                return a.id - b.id;
            });
            model.colsWidth = newColsWidth;

            for (var j = 0; j < model.rows; j++) {
                var rightCell = getRecursiveClosestCell(table, model, cell.col, j + 1);
                if (!_h.isNullOrEmpty(rightCell)) {
                    if (rightCell.row === j + 1 && rightCell.colSpan > 1 && rightCell.col < cell.col) {
                        rightCell.colSpan = rightCell.colSpan + 1;
                        increaseCsCells.push(rightCell.address);
                    }
                    if (rightCell.row === j + 1 && rightCell.rowSpan > 1) {
                        for (var i = 0; i < rightCell.rowSpan; i++) {
                            newCell = cellFunc.createEmptyModel("cell", rightCell.col, rightCell.row + i, model.accountType, defaultVal);
                            if (newCell.col === cell.col)
                                addToNewCellArray(addCells, newCell);

                        }
                    }
                    if (rightCell.col === cell.col && rightCell.rowSpan > 1) {
                        newCell = cellFunc.createEmptyModel("cell", rightCell.col, j + 1, model.accountType, defaultVal);
                        if (newCell.col === cell.col)
                            addToNewCellArray(addCells, newCell);
                    }
                    if (rightCell.col === cell.col && rightCell.colSpan === 1) {
                        newCell = cellFunc.createEmptyModel("cell", rightCell.col, rightCell.row, model.accountType, defaultVal);
                        if (newCell.col === cell.col)
                            addToNewCellArray(addCells, newCell);
                    }
                    if (rightCell.col === cell.col && rightCell.colSpan > 1 && hasRowBackCell(table, model, rightCell)) {
                        newCell = cellFunc.createEmptyModel("cell", rightCell.col, j + 1, model.accountType, defaultVal);
                        if (newCell.col === cell.col)
                            addToNewCellArray(addCells, newCell);
                    }
                }
            }


            for (var k = 0; k < model.cells.length; k++) {
                var targetCell = model.cells[k];
                if (targetCell.col >= targetCol) {
                    targetCell.col = targetCell.col + 1;
                    targetCell.address = _h.numberToAlphabet(targetCell.col) + targetCell.row;
                }
            }
            for (var l = 0; l < addCells.length; l++) {
                addCells[l].added = true;
                model.cells.push(addCells[l]);
            }
            model.cells.sort(function (a, b) {
                return a.row - b.row;
            });
            model.cols = model.cols + 1;
            tagRender.applyToTable("colRight", table, model,
                {
                    targetCol: targetCol,
                    addCells: addCells,
                    increaseCells: increaseCsCells
                });
            replaceHiddenCols(table, model, targetCol, "add");
            refreshFormulaCells(table, model, undefined, targetCol, "add");
            refreshCompareCells(table, model, undefined, targetCol, "add");
            resizeFunc(table);
        }
        var tableActions = function (table, model, cells, obj) {
            var cell = cells[0];
            var resModel = {};
            if (!cell && obj.type !== "width" && obj.type !== "height")
                return;
            switch (obj.id) {
                case "colRight":
                    resModel.old = cell.address;
                    addCol(table, model, cell, obj.default);
                    setFinancialProperties(table, model, { type: "reset" });
                    resModel.new = cell.address;
                    break;
                case "rowTop":
                    resModel.old = cell.address;
                    addRow(table, model, cell, obj.default);
                    setFinancialProperties(table, model, { type: "reset" });
                    resModel.new = cell.address;
                    break;
                case "deleteCol":
                    resModel.old = { address: cell.address };
                    var res = removeCol(table, model, cell);
                    setFinancialProperties(table, model, { type: "reset" });
                    resModel.new = { address: cell.address, removeCells: res };
                    break;
                case "deleteRow":
                    resModel.old = { address: cell.address };
                    var res = removeRow(table, model, cell);
                    setFinancialProperties(table, model, { type: "reset" });
                    resModel.new = { address: cell.address, removeCells: res };
                    break;
                case "mergeCells":
                    if (cells.length > 1) {
                        var cList = [];
                        cells.filter(a => cList.push(a.address));
                        resModel.old = cList;
                        resModel.new = mergeCells(model, table, cells);
                    }
                    break;
                case "unMergeCells":
                    if (cells.length === 1) {
                        resModel.old = cell.address;
                        resModel.new = unMergeCells(model, table, cell, obj.default);
                    }
                    break;
                case "hideCol":
                    if (model.hiddenCols.indexOf(cell.col) === -1) {
                        resModel.old = cell.col;
                        resModel.new = cell.col;
                        model.hiddenCols.push(cell.col);
                        tagRender.applyToTable("hiddenCells", table, model);
                    }
                    break;
                case "showCol":
                    if (model.hiddenCols.indexOf(cell.col) !== -1) {
                        resModel.old = cell.col;
                        resModel.new = cell.col;
                        model.hiddenCols.remove(cell.col);
                        tagRender.applyToTable("hiddenCells", table, model);
                    }
                    break;
                case "hideRow":
                    if (model.hiddenRows.indexOf(cell.row) === -1) {
                        resModel.old = cell.row;
                        model.hiddenRows.push(cell.row);
                        tagRender.applyToTable("hiddenCells", table, model);
                        resModel.new = cell.row;
                    }
                    break;
                case "showRow":
                    if (model.hiddenRows.indexOf(cell.row) !== -1) {
                        resModel.old = cell.row;
                        model.hiddenRows.remove(cell.row);
                        tagRender.applyToTable("hiddenCells", table, model);
                        resModel.new = cell.row;
                    }
                    break;
                case "width":
                    var colsWidth;
                    resModel.old = { address: obj.colNumber, viewType: obj.viewType };
                    resModel.new = { address: obj.colNumber, viewType: obj.viewType };
                    if (obj.viewType !== "cross") {
                        colsWidth = model.colsWidth.filter(a => a.id === obj.colNumber);
                        resModel.old.value = Number(colsWidth[0].size.replace("px", ""));
                        resModel.new.value = Number(obj.value);
                    }
                    else {
                        resModel.old.address = "";
                        resModel.new.address = "";
                        colsWidth = model.colsWidth;
                        resModel.old.value = Number(colsWidth[0].size.replace("px", ""));
                        resModel.new.value = Number(obj.value);
                    }
                    for (var i = 0; i < colsWidth.length; i++) {
                        colsWidth[i].size = obj.value + "px";
                        $(table)
                            .find("th[data-col='" + colsWidth[i].id + "']").css("width", obj.value + "px");
                    }
                    break;
                case "height":
                    var rowsHeight;
                    resModel.old = { address: obj.rowNumber, viewType: obj.viewType };
                    resModel.new = { address: obj.rowNumber, viewType: obj.viewType };
                    if (obj.viewType !== "cross") {
                        rowsHeight = model.rowsHeight.filter(a => a.id === obj.rowNumber);
                        resModel.old.value = Number(rowsHeight[0].size.replace("px", ""));
                        resModel.new.value = Number(obj.value);
                    }
                    else {
                        resModel.old.address = "";
                        resModel.new.address = "";
                        rowsHeight = model.rowsHeight;
                        resModel.old.value = Number(rowsHeight[0].size.replace("px", ""));
                        resModel.new.value = Number(obj.value);
                    }

                    for (var i = 0; i < rowsHeight.length; i++) {
                        rowsHeight[i].size = obj.value + "px";
                        $(table)
                            .find("th[data-row='" + rowsHeight[i].id + "']").css("height", obj.value + "px");
                    }
                    break;
            }
            return resModel;
        }
        var addWarnings = function (table, list) {
            if (list && list.length > 0)
                for (let i = 0; i < list.length; i++) {
                    var target = $(table).find('[data-address="' + list[i].key + '"]');
                    var a = target.find(".warning-sign");
                    $(a).css("display", "block");
                    $(a).attr("title", list[i].value);
                }
        }
        var removeAllWarning = function (table) {
            var allSign = $(table).find(".warning-sign");
            if (allSign && allSign.length)
                for (var i = 0; i < allSign.length; i++) {
                    $(allSign[i]).css("display", "none");
                }
        }
        var setDynamicValues = function (table, model, list) {
            resetDynamicValue(table, model);
            if (_h.any(list)) {
                for (var i = 0; i < list.length; i++) {
                    var target = list[i];
                    var cell = model.cells.filter(a => a.address === target.value)[0];
                    if (cell) {
                        cell.hasDynamicValue = true;
                        cell.oldText = cell.text;
                        cell.text = target.text;
                        cell.redText = target.redText;
                        cell.oldDesc = cell.desc;
                        cell.desc = target.desc;
                        tagRender.applyToElement(table, cell, "setDynamicValue");
                    }
                }
                model.previewMode = true;
                tagRender.applyToTable("setDynamicValue", table, model);
            } else {
                model.previewMode = false;
                tagRender.applyToTable("resetDynamicValue", table, model);
            }
        }
        var resetDynamicValue = function (table, model) {
            var cells = model.cells.filter(a => a.hasDynamicValue);
            model.previewMode = false;
            tagRender.applyToTable("resetDynamicValue");
            for (var i = 0; i < cells.length; i++) {
                var cell = cells[i];
                var needrefresh = false;
                if ('oldText' in cell) {
                    cell.text = cell.oldText;
                    delete cell["oldText"];
                    delete cell["hasDynamicValue"];
                    needrefresh = true;
                }
                if ('oldDesc' in cell) {
                    cell.desc = cell.oldDesc;
                    delete cell["oldDesc"];
                    delete cell["hasDynamicValue"];
                    needrefresh = true;
                }
                if (cell.cellInfos.length > 0 && cell.cellInfos[0].type > 3) {
                    cell.text = "";
                    needrefresh = true;
                }
                if (needrefresh) {
                    tagRender.applyToElement(table, cell, "setDynamicValue");
                    tagRender.applyToElement(table, cell, "resetDynamicValue");
                }
                cell.redText = false;
                delete cell["hasDynamicValue"];
            }
        }
        var addExtraParams = function (table, cells, obj) {
            var array = [];
            for (var i = 0; i < cells.length; i++) {
                var res = cellFunc.addExtraParams(table, cells[i], obj.type, obj.value);
                array.push(res);
            }
            return array;
        }
        var addStyles = function (table, cells, obj) {
            var array = [];
            for (var i = 0; i < cells.length; i++) {
                var res = cellFunc.addStyles(table, cells[i], obj.type, obj.value, obj.defaultVal);
                array.push(res);
            }
            return array;
        }
        var setValues = function (table, cells, obj) {
            var array = [];
            for (var i = 0; i < cells.length; i++) {
                var res = cellFunc.addValues(table, cells[i], obj.type, obj.value, obj.title);
                array.push(res);
            }
            return array;
        }
        var setNodeValueName = function (table, model, obj) {
            var array = [];
            var cells = obj.cells;
            switch (obj.type) {
                case "NodeInCell":
                    array = cellFunc.addValues(table, cells[0], obj.type, obj.value, obj.reset);
                    break;
                case "NodeNameInCell":
                    for (var i = 0; i < cells.length; i++) {
                        nameCell = cells[i];
                        if (nameCell) {
                            var res = cellFunc.addValues(table, nameCell, "NodeNameInCell", obj.value[i]);
                            array.push(res);
                        }
                    }
                    break;
                case "NodeValueNameInCell":
                    for (var i = 0; i < cells.length; i++) {
                        var nameCell = cells[i];
                        var valCell = model.cells.filter(a => a.row === nameCell.row && a.col === nameCell.col + 1);
                        if (valCell.length && nameCell) {
                            var res = cellFunc.addValues(table, valCell[0], "NodeInCell", [{
                                treeId: obj.value[i].treeId,
                                code: obj.value[i].code,
                                operator: "+",
                                title: obj.value[i].path.replace(" :: ", "") + " (" + obj.value[i].code + ")",
                                type: 'node',
                                periodId: obj.value[i].periodId
                            }], true);
                            var res2 = cellFunc.addValues(table, nameCell, "NodeNameInCell", obj.value[i]);
                            array.push({ old: { NodeInCell: res.old, NodeNameInCell: res2.old }, new: { NodeInCell: res.new, NodeNameInCell: res2.new } });
                        }
                    }
                    break;

            }
            return array;
        }
        var setTotalCost = function (table, model, cells, obj) {
            var cell = cells[0];
            var res = false;
            var resModel = { old: ko.toJS(model.totalCostProperties) };
            switch (obj.type) {
                case "groupType":
                    res = changeGroupType(model, obj.value, cell.value);
                    break;
                case "sortDirection":
                    res = changeSortDirection(model, obj.value, cell.value);
                    break;
            }
            resModel.new = ko.toJS(model.totalCostProperties);
            if (res)
                return resModel;
            else
                return res;
        }
        var setFinancialProperties = function (table, model, obj) {
            if (model.financialProperties.sortColumn.id !== obj.colNumber) {
                model.financialProperties.sortColumn.regions = undefined;
                model.financialProperties.sortColumn.sortDirection = undefined;
            }
            switch (obj.type) {
                case "colSortDirection":
                    model.financialProperties.sortColumn.sortDirection = obj.value;
                    model.financialProperties.sortColumn.id = obj.colNumber;
                    tagRender.applyToTable(obj.type, table, model);
                    break;
                case "region":
                    model.financialProperties.sortColumn.id = obj.colNumber;
                    model.financialProperties.sortColumn.regions = obj.value;
                    if (_h.isNullOrEmpty(model.financialProperties.sortColumn.sortDirection)) {
                        model.financialProperties.sortColumn.sortDirection = 0;
                        tagRender.applyToTable("colSortDirection", table, model);
                    }
                    break;
                case "reset":
                    model.financialProperties.sortColumn.id = undefined;
                    model.financialProperties.sortColumn.regions = [];
                    model.financialProperties.sortColumn.sortDirection = undefined;
                    tagRender.applyToTable("colSortDirectionReset", table, model);

                    break;
            }
            return true;
        }
        var init = function (target, options) {
            if (!target.length)
                return false;
            target = target.get(0);
            options.el = target;
            target.innerHTML = "";
            var model = options.model;
            var table = tagRender.buildTable(target, model, options.type);
            if (options.type === "cellSelect") {
                return;
            }
            var $table = $(table);
            $table.data("model", options.model);
            var oldModel = JSON.parse(JSON.stringify(options.model));
            $table.data("oldModel", oldModel);
            $table.data("baseSelector", options.baseSelector);
            $table.data("historyModel", { position: 0, history: [] });
            $table.attr("id", options.baseSelector.replace("#rg", "rgt"));
            tagRender.applyToTable("hiddenCells", table, model);
            resizeFunc(table);
            $table.addClass(selectableTableClass);
            addTableEvents($table);
            $table.data(dataKey, {
                selFrom: false,
                selTo: false,
                isHighlighted: undefined,
                $currTR: $(),
                $currTH: $(),
                $currCell: $()
            });
            if (options.bindErrors && options.bindErrors.length) {
                addWarnings(table, options.bindErrors);
            }
            _h.activeTooltip(true);
        }
        var changeGroupType = function (model, val, cellVal) {
            if (_h.isNullOrEmpty(cellVal)
                || cellVal === "" || cellVal.indexOf("table") === -1)
                return false;
            var array = cellVal.split(":");
            array = _h.cleanArray(array);
            var temp = array[2].replace("]", "");
            var id = Number(temp);
            if (_h.isNullOrEmpty(val) && model.totalCostProperties.groupColumn.id === id) {
                model.totalCostProperties.groupColumn = { id: undefined, groupType: undefined };
                return true;
            }
            if (!_h.isNullOrEmpty(id) && !_h.isNullOrEmpty(val)) {
                model.totalCostProperties.groupColumn = { id: id, groupType: val };
                return true;
            }
        }
        var changeSortDirection = function (model, val, cellVal) {
            if (_h.isNullOrEmpty(cellVal) || cellVal === "" || cellVal.indexOf("table") === -1)
                return false;
            var array = cellVal.split(":");
            array = _h.cleanArray(array);
            var temp = array[2].replace("]", "");
            var id = Number(temp);
            var isEdit = false;
            if (_h.any(model.totalCostProperties.sortColumns)) {
                var deleteItem;
                for (var i = 0; i < model.totalCostProperties.sortColumns.length; i++) {
                    var item = model.totalCostProperties.sortColumns[i];
                    if (item.id === id) {
                        if (val && val !== item.sortDirection) {
                            item.sortDirection = val;
                            isEdit = true;
                        }
                        if (!val)
                            deleteItem = item;
                    }
                }
                if (deleteItem)
                    model.totalCostProperties.sortColumns.remove(deleteItem);
                return true;
            }
            if (!isEdit && !_h.isNullOrEmpty(val)) {
                model.totalCostProperties
                    .sortColumns.push({ id: id, sortDirection: val });
                return true;
            }
            return false;
        }
        var compareModels = function (table) {
            var oldModel = $(table).data('oldModel');
            var model = $(table).data('model');
            //var start = performance.now();
            var res = comparator.isEqual(model, oldModel);
            //var duration = performance.now() - start;
            //console.log("duration : " + duration);

            return !res;
        }
        var fixFindingTable = function ($this) {
            var table = $($this).find("table.tcs");
            var id = $(table).attr("id");
            table = $("#" + id);
            return table;
        }
        var addToHistory = function (table, cells, obj, result) {
            //var dataModel = $(table).data("historyModel");
            //if (dataModel.position < dataModel.history.length - 1) {
            //    dataModel.history = dataModel.history.slice(0, dataModel.position + 1);
            //}
            //dataModel.position += 1;
            //var idList = [];
            //if (cells && cells.length) {
            //    cells.filter(a => idList.push(a.address));
            //}
            //var cellsEffected = [];
            //if (obj["cellsEffected"])
            //    obj.cellsEffected.filter(a => cellsEffected.push(a.address));
            //var command = new RgCommand({ old: result[0].old, new: result[0].new, type: obj.type, cellsSelected: idList, cellsEffected: cellsEffected });
            //console.log(command);
            //dataModel.history.push(command);
            //$(table).data("historyModel", dataModel);
        }
        var selectRangeCells = function (table, list, callback) {
            $(table).find("td").removeClass(selectedCellClass);
            for (var i = 0; i < list.length; i++) {
                var target = $(table).find('td[data-address="' + list[i] + '"]');
                if (!$(target).hasClass(selectedCellClass))
                    $(target).addClass(selectedCellClass);
            }
            setTimeout(function () {
                callback(true);
            }, 50);
        }
        var fixHistoryArray = function (array) {
            if (Array.isArray(array)) {
                return array;
            } else {
                return [array];
            }
        }
        var setEventActions = function (table, model, type, cells, oldCells) {
            for (var j = 0; j < cells.length; j++) {
                var cell = cells[j];
                switch (type) {
                    case "PasteCell":
                        if (typeof oldCells === 'object' && !Array.isArray(oldCells)) {
                            cellFunc.pasteCell(table, cell, oldCells, model.cols, model.rows);
                        }
                        if (Array.isArray(oldCells)) {
                            var oldCell = oldCells.filter(a => a.address === cell.address);
                            if (oldCell.length) {
                                cellFunc.pasteCell(table, cell, oldCell[0], model.cols, model.rows);
                            }
                        }
                        break;
                    case "PasteCellStyle":
                        cellFunc.pasteCell(table, cell, oldCells, model.cols, model.rows);
                        break;
                }
            }
        }
        var findCommandGroup = function (obj) {
            var type = obj.id;
            obj.type = obj.id;
            var group = rgCommandList[obj.id];
            if (!group) {
                type = findPeriodAction(obj.type);
                group = rgCommandList[type];
            }
            return group;
        }
        var findPeriodAction = function (type) {
            if (type.indexOf("period") !== -1) {
                var numb = type.match(/\d/g);
                if (numb.length > 1) {
                    numb = numb[0] + numb[1];
                } else {
                    numb = numb[0];
                }
                type = type.replace(numb, "_");
            }
            return type;
        }
        var executeCommand = function (table, model, obj) {
            var group = findCommandGroup(obj);
            var cells = rgUtil.getSelectedCellModels(table);
            var result, resModel = undefined;
            switch (group) {
                case "tableAction":
                    resModel = rgUtil.tableActions(table, model, cells, obj);
                    if (obj.type === "width" || obj.type === "height") {
                        if (!obj["undoAction"])
                            rgUtil.addToHistory(table, cells, { type: obj.type, value: value }, fixHistoryArray(resModel));
                        return true;
                    }
                    break;
                case "style":
                    var value = obj.value;
                    if (obj.type === "erase")
                        value = model.accountType;
                    if (obj.cell)
                        resModel = rgUtil.addStyles(table, [obj.cell], obj);
                    else
                        resModel = rgUtil.addStyles(table, cells, { type: obj.type, value: value, defaultVal: obj.default });
                    break;
                case "extraParam":
                    resModel = rgUtil.addExtraParams(table, cells, obj);
                    break;
                case "setValue":
                    if (obj.cells)
                        resModel = rgUtil.setValues(table, obj.cells, obj);
                    else
                        resModel = rgUtil.setValues(table, cells, obj);
                    break;
                case "totalCost":
                    resModel = rgUtil.setTotalCost(table, model, cells);
                    break;
                case "xbrlConcept":
                    resModel = rgUtil.setValues(table, cells, { type: "xbrlConcept", value: false });
                    break;
                case "financialProperties":
                    resModel = rgUtil.setFinancialProperties(table, model, obj);
                    break;
                case "treeActions":
                    resModel = rgUtil.setNodeValueName(table, model, obj);
                    break;
                case "formulaActions":
                    if (!obj.cell)
                        obj.cell = cells[0];

                    resModel = cellFunc.addValues(table, obj.cell, obj.type, obj.value, obj.reset);
                    break;
                case "setText":
                    resModel = cellFunc.setText(table, obj.cell, obj.type, obj.value);
                    break;
                case "eventActions":
                    resModel = rgUtil.setEventActions(table, model, obj.type, cells, obj.value);
                    break;
                case "setSpecialValue":
                    resModel = rgUtil.setValues(table, obj.cells, obj);
                    if (!obj["undoAction"])
                        rgUtil.addToHistory(table, obj.cells, { type: obj.type, value: value, cellsEffected: obj["cellsEffected"] }, fixHistoryArray(resModel));
                    return true
            }
            if (resModel) {
                result = true;
                if (!obj["undoAction"])
                    rgUtil.addToHistory(table, cells, { type: obj.type, value: value }, fixHistoryArray(resModel));
            }
            return result;
        }
        return {
            init: init,
            getTable: getTable,
            findPeriodAction: findPeriodAction,
            getModel: getModel,
            fixFindingTable: fixFindingTable,
            tableActions: tableActions,
            addExtraParams: addExtraParams,
            setValues: setValues,
            getSelectedCells: getSelectedCells,
            getSelectedCellModels: getSelectedCellModels,
            setDynamicValues: setDynamicValues,
            resetDynamicValue: resetDynamicValue,
            addWarnings: addWarnings,
            removeAllWarning: removeAllWarning,
            addStyles: addStyles,
            getRectanglePoints: getRectanglePoints,
            getColsWidth: getColsWidth,
            getRowsHeight: getRowsHeight,
            getSelectedCellsShape: getSelectedCellsShape,
            selectGroupCells: selectGroupCells,
            setTotalCost: setTotalCost,
            compareModels: compareModels,
            setFinancialProperties: setFinancialProperties,
            addToHistory: addToHistory,
            executeCommand: executeCommand,
            selectRangeCells: selectRangeCells,
            setNodeValueName: setNodeValueName,
            setEventActions: setEventActions,
            stringIsEnglish: stringIsEnglish,
            getFormulaType: getFormulaType,
            fixHistoryArray: fixHistoryArray
        };
    }();
    var rgMethods = {
        init: function (options) {
            rgUtil.init(this, options);
        },
        command: function (obj) {
            obj.type = obj.id;
            var table = rgUtil.fixFindingTable(this);
            var model = rgUtil.getModel(table);
            var result = rgUtil.executeCommand(table, model, obj);
            return result;
        },
        getCellValues: function () {
            var array = [];
            var table = rgUtil.fixFindingTable(this);
            var cells = rgUtil.getSelectedCellModels(table);
            if (cells.length === 1) {
                array = cellFunc.getCellValues(cells[0], "node");
            }
            return array;
        },
        getTotalCostModel: function (value) {
            var table = rgUtil.fixFindingTable(this);
            var model = rgUtil.getModel(table);
            var dataModel = { groupType: undefined, sortDirection: undefined };
            if (_h.isNullOrEmpty(value) || value === "" || value.indexOf("table") === -1)
                return dataModel;
            var array = value.split(":");
            array = _h.cleanArray(array);
            var temp = array[2].replace("]", "");
            var id = Number(temp);
            if (isNaN(id) || _h.isNullOrEmpty(id))
                return dataModel;
            if (!_h.isNullOrEmpty(model.totalCostProperties.groupColumn) &&
                model.totalCostProperties.groupColumn.id === id) {
                model.groupType = model.totalCostProperties.groupColumn.groupType;
            }
            if (_h.any(model.totalCostProperties.sortColumns))
                for (var i = 0; i < model.totalCostProperties.sortColumns.length; i++) {
                    var item = model.totalCostProperties.sortColumns[i];
                    if (item.id === id) {
                        model.sortDirection = item.sortDirection;
                    }
                }
            return dataModel;

        },
        setFormula: function (obj) {
            var table = rgUtil.fixFindingTable(this);
            var cells = rgUtil.getSelectedCellModels(table);
            var model = rgUtil.getModel(table);
            obj.reset = true;
            obj.cells = cells;
            var result = rgUtil.executeCommand(table, model, obj);
            return cells[0];
        },
        getModel: function () {
            var table = rgUtil.fixFindingTable(this);
            return table.data("model");
        },
        getSelectedCells: function () {
            var table = rgUtil.fixFindingTable(this);
            var cells = rgUtil.getSelectedCellModels(table);
            return cells;
        },
        getSelectedCellsData: function () {
            var table = rgUtil.fixFindingTable(this);
            var cells = rgUtil.getSelectedCellModels(table);
            var shapeData = rgUtil.getSelectedCellsShape(cells);
            return { cells: cells, shapeData: shapeData };
        },
        previewMode: function (type, list, bindErrors, hiddenRows, hiddenCols) {
            var table = rgUtil.fixFindingTable(this);
            var model = rgUtil.getModel(table);
            if (type === "reset") {
                rgUtil.resetDynamicValue(table, model);
                rgUtil.removeAllWarning(table);
                tagRender.applyToTable("hiddenCells", table, model);
            }
            if (type === "set") {
                rgUtil.removeAllWarning(table);
                rgUtil.setDynamicValues(table, model, list);
                rgUtil.addWarnings(table, bindErrors);
                tagRender.applyToTable("DynamicValueHiddenCells", table, model, [hiddenRows, hiddenCols]);
            }
        },
        setWarning: function (list) {
            var table = rgUtil.fixFindingTable(this);
            rgUtil.removeAllWarning(table);
            if (_h.any(list))
                rgUtil.addWarnings(table, list);
        },
        removeWarnings: function () {
            var table = rgUtil.fixFindingTable(this);
            rgUtil.removeAllWarning(table);
        },
        setCellBinds: function (list) {
            var table = rgUtil.fixFindingTable(this);
            var model = rgUtil.getModel(table);
            model.cellBinds = list;
            table.data("model", model);
        },
        getCellBinds: function () {
            var table = rgUtil.fixFindingTable(this);
            var model = rgUtil.getModel(table);
            return model.cellBinds;
        },
        getBorder: function () {
            var table = rgUtil.fixFindingTable(this);
            var cells = rgUtil.getSelectedCellModels(table);
            return rgUtil.getRectanglePoints(cells);
        },
        toServer: function (sign) {
            var table = $(this).find("table.tcs");
            //var inPreviewMode = $(table).hasClass("preview-mode");
            var model = rgUtil.getModel(table);
            if (!model)
                return undefined;
            //var colsWidth = rgUtil.getColsWidth(table);
            //var rowsHeight = rgUtil.getRowsHeight(table);
            // inPreviewMode || sign
            if (sign) {
                var outModel = ko.toJS(model);
                for (var i = 0; i < outModel.cells.length; i++) {
                    var cell = outModel.cells[i];
                    if ('oldText' in cell) {
                        cell.text = cell.oldText;
                    }
                    if (cell.cellInfos.length > 0 && cell.cellInfos[0].type > 3) {
                        cell.text = "";
                    }
                }
                //outModel.colsWidth = colsWidth;
                //outModel.rowsHeight = rowsHeight;
                return [outModel, true];
            } else {
                //model.colsWidth = colsWidth;
                //model.rowsHeight = rowsHeight;
                var isChanged = rgUtil.compareModels(table);
                return [model, isChanged];
            }
        },
        selectGroupCells: function (list) {
            var table = $(this).find("table.tcs");
            rgUtil.selectGroupCells(table, list);
            var cells = rgUtil.getSelectedCellModels(table);
            return cells;
        },
        getCellElement: function () {
            var table = $(this).find("table.tcs")[0];
            var cells = rgUtil.getSelectedCells($(table));
            if (cells.length === 1) {
                return cells[0];
            }
        },
        refreshCellsTag: function (list) {
            var table = rgUtil.getTable(this);
            var model = rgUtil.getModel(table);
            if (list && list.length)
                for (var i = 0; i < list.length; i++) {
                    var cell = model.cells.filter(a => a.address === list[i].key)[0];
                    if (cell) {
                        cell.tag = list[i].value;
                    }
                }
        },
        undo: function (defaultVal) {
            var table = rgUtil.fixFindingTable(this);
            var model = rgUtil.getModel(table);
            var historyModel = table.data("historyModel");
            if (historyModel.position > 0) {
                var lastAction = historyModel.history[historyModel.position - 1];
                var tType = lastAction.type;
                if (lastAction.type.indexOf("period") !== -1) {
                    tType = rgUtil.findPeriodAction(lastAction.type);
                }
                var oppositeAction = oppositeActions[tType];
                if (oppositeAction) {
                    switch (oppositeAction) {
                        case "mergeCells":
                            rgUtil.selectRangeCells(table, lastAction.new, function () {
                                var cells = rgUtil.getSelectedCellModels(table);
                                rgUtil.executeCommand(table, model, {
                                    type: lastAction.type,
                                    id: oppositeAction,
                                    value: lastAction.old,
                                    cells: cells,
                                    cell: cells[0],
                                    undoAction: true,
                                    default: defaultVal
                                });
                            });
                            break;
                        case "deleteRow":
                        case "deleteCol":
                            rgUtil.selectRangeCells(table, [lastAction.old], function () {
                                var cells = rgUtil.getSelectedCellModels(table);
                                rgUtil.executeCommand(table, model, {
                                    type: lastAction.type,
                                    id: oppositeAction,
                                    value: lastAction.old,
                                    cells: cells,
                                    cell: cells[0],
                                    undoAction: true,
                                    default: defaultVal
                                });
                            });
                            break;
                        case "colRight":
                        case "rowTop":
                            rgUtil.selectRangeCells(table, [lastAction.old.address], function () {
                                var cells = rgUtil.getSelectedCellModels(table);
                                rgUtil.executeCommand(table, model, {
                                    type: lastAction.type,
                                    id: oppositeAction,
                                    value: lastAction.old,
                                    cells: cells,
                                    cell: cells[0],
                                    undoAction: true,
                                    default: defaultVal
                                });
                                var nCells = [];
                                lastAction.new.removeCells.filter(a => nCells.push(a.address));
                                rgUtil.selectRangeCells(table, nCells, function () {
                                    cells = rgUtil.getSelectedCellModels(table);
                                    rgUtil.executeCommand(table, model, {
                                        type: "PasteCell",
                                        id: "PasteCell",
                                        value: lastAction.new.removeCells,
                                        cells: cells,
                                        cell: cells[0],
                                        undoAction: true,
                                        default: defaultVal
                                    });
                                });
                            });
                            break;
                        default:
                            if (lastAction.type === "PartialSum") {
                                rgUtil.selectRangeCells(table, lastAction.cellsSelected, function () {
                                    var cells = rgUtil.getSelectedCellModels(table);
                                    rgUtil.executeCommand(table, model,
                                        {
                                            type: lastAction.type,
                                            id: oppositeAction,
                                            value: lastAction.old,
                                            cells: cells,
                                            cell: cells[0],
                                            undoAction: true,
                                            default: defaultVal
                                        });
                                    rgUtil.selectRangeCells(table, lastAction.cellsEffected, function () {
                                    });
                                });
                            } else {
                                rgUtil.selectRangeCells(table, lastAction.cellsSelected, function () {
                                    var cells = rgUtil.getSelectedCellModels(table);
                                    rgUtil.executeCommand(table, model,
                                        {
                                            type: lastAction.type,
                                            id: oppositeAction,
                                            value: lastAction.old,
                                            cells: cells,
                                            cell: cells[0],
                                            undoAction: true,
                                            default: defaultVal
                                        });
                                });
                            }
                            break;
                    }
                } else {
                    switch (lastAction.type) {
                        case "height":
                        case "width":
                            rgUtil.executeCommand(table, model, {
                                type: lastAction.type,
                                id: lastAction.type,
                                viewType: lastAction.old.viewType,
                                rowNumber: lastAction.old["address"],
                                colNumber: lastAction.old["address"],
                                value: lastAction.old.value,
                                cells: [],
                                cell: null,
                                undoAction: true,
                                default: defaultVal
                            });
                            break;
                        default:
                            rgUtil.selectRangeCells(table, lastAction.cellsSelected, function () {
                                var cells = rgUtil.getSelectedCellModels(table);
                                rgUtil.executeCommand(table, model, {
                                    type: lastAction.type,
                                    id: lastAction.type,
                                    value: lastAction.old,
                                    cells: cells,
                                    cell: cells[0],
                                    undoAction: true,
                                    default: defaultVal
                                });
                            });
                            break;
                    }

                }
                historyModel.position -= 1;
            }
        },
        redo: function (defaultVal) {
            var table = rgUtil.fixFindingTable(this);
            var historyModel = table.data("historyModel");
            if (historyModel.position <= historyModel.history.length - 1) {
                var nextAction = historyModel.history[historyModel.position];
                var oppositeAction = oppositeActions[nextAction.type];
                if (oppositeAction) {
                    switch (oppositeAction) {
                        case "mergeCells":
                            rgUtil.selectRangeCells(table, nextAction.new, function () {
                                rgUtil.executeCommand(table, model, {
                                    type: nextAction.type,
                                    id: oppositeAction,
                                    value: nextAction.new,
                                    cellsSelected: nextAction.cellsSelected,
                                    undoAction: true, defaultVal: defaultVal
                                });
                            });
                            break;
                        case "deleteRow":
                        case "deleteCol":
                            rgUtil.selectRangeCells(table, [nextAction.new], function () {
                                var cells = rgUtil.getSelectedCellModels(table);
                                rgUtil.executeCommand(table, model, {
                                    type: nextAction.type,
                                    id: oppositeAction,
                                    value: nextAction.new,
                                    cells: cells,
                                    cell: cells[0],
                                    undoAction: true,
                                    default: defaultVal
                                });
                            });
                            break;
                        case "colRight":
                        case "rowTop":
                            rgUtil.selectRangeCells(table, [nextAction.old.address], function () {
                                var cells = rgUtil.getSelectedCellModels(table);
                                rgUtil.executeCommand(table, model, {
                                    type: nextAction.type,
                                    id: oppositeAction,
                                    value: nextAction.old,
                                    cells: cells,
                                    cell: cells[0],
                                    undoAction: true,
                                    default: defaultVal
                                });
                                var nCells = [];
                                rgUtil.selectRangeCells(table, nCells, function () {
                                    cells = rgUtil.getSelectedCellModels(table);
                                    rgUtil.executeCommand(table, model, {
                                        type: "PasteCell",
                                        id: "PasteCell",
                                        value: lastAction.new.removeCells,
                                        cells: cells,
                                        cell: cells[0],
                                        undoAction: true,
                                        default: defaultVal
                                    });
                                });
                            });
                            break;
                        default:
                            if (nextAction.type === "PartialSum") {
                                rgUtil.selectRangeCells(table, nextAction.cellsSelected, function () {
                                    var cells = rgUtil.getSelectedCellModels(table);
                                    rgUtil.executeCommand(table, model,
                                        {
                                            type: nextAction.type,
                                            id: oppositeAction,
                                            value: nextAction.new,
                                            cells: cells,
                                            cell: cells[0],
                                            undoAction: true,
                                            default: defaultVal
                                        });
                                    rgUtil.selectRangeCells(table, nextAction.cellsEffected, function () {
                                    });
                                });
                            } else {
                                rgUtil.selectRangeCells(table, nextAction.cellsSelected, function () {
                                    var cells = rgUtil.getSelectedCellModels(table);
                                    rgUtil.executeCommand(table, model,
                                        {
                                            type: nextAction.type,
                                            id: oppositeAction,
                                            value: nextAction.new,
                                            cells: cells,
                                            cell: cells[0],
                                            undoAction: true,
                                            default: defaultVal
                                        });
                                });
                            }
                            break;
                    }
                } else {
                    switch (lastAction.type) {
                        case "height":
                        case "width":
                            rgUtil.selectRangeCells(table, nextAction.cellsSelected, function () {
                                rgUtil.executeCommand(table, model, {
                                    type: nextAction.type,
                                    id: nextAction.type,
                                    value: nextAction.new.value,
                                    cellsSelected: nextAction.cellsSelected,
                                    viewType: nextAction.old.viewType,
                                    rowNumber: nextAction.old["address"],
                                    colNumber: nextAction.old["address"],
                                    undoAction: true,
                                    defaultVal: defaultVal
                                });
                            });
                            break;
                        default:
                            rgUtil.selectRangeCells(table, nextAction.cellsSelected, function () {
                                rgUtil.executeCommand(table, model, {
                                    type: nextAction.type,
                                    id: nextAction.type, value: nextAction.new,
                                    cellsSelected: nextAction.cellsSelected,
                                    undoAction: true,
                                    defaultVal: defaultVal
                                });
                            });
                            break;
                    }

                }
                historyModel.position += 1;
            }
        },
        getToolbarStateData: function () {
            try {
                var table = rgUtil.fixFindingTable(this);
                var model = table.data("model");
                var historyModel = table.data("historyModel");
                var cells = rgUtil.getSelectedCellModels(table);
                var shapeData = rgUtil.getSelectedCellsShape(cells);
                var showUndo = false, showRedo = false;
                if (!historyModel)
                    return [cells, shapeData, model, false, false];
                //if (historyModel.position > 0) {
                //    showUndo = true
                //}
                //if (historyModel.position < historyModel.history.length) {
                //    showRedo = true
                //}

                return [cells, shapeData, model, showUndo, showRedo];
            } catch (e) {
                var table = rgUtil.fixFindingTable(this);
                var model = table.data("model");
                var shapeData = rgUtil.getSelectedCellsShape(cells);
                return [[], [0, 0, 0, 0, 0], model, false, false];
            }
        },
        toggleEditable: function (res) {
            var table = rgUtil.fixFindingTable(this);
            if (res) {
                $(table).addClass("editable-table");
            } else {
                $(table).removeClass("editable-table");
            }
        }
    }
    $.fn.rg = function (methodOrOptions) {
        if (rgMethods[methodOrOptions]) {
            return rgMethods[methodOrOptions].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof methodOrOptions === 'object' || !methodOrOptions) {

            return rgMethods.init.apply(this, arguments);
        } else {
            $.error('Method ' + methodOrOptions + ' does not exist on jQuery.reportGenerator');
        }
    };

})(jQuery);

class RgCommand {
    constructor(model) {
        this.type = model.type;
        this.old = model.old;
        this.new = model.new;
        this.cellsSelected = model.cellsSelected;
        this.cellsEffected = model.cellsEffected;
    }
}