/*
 * SDK Pullenti Unitext, version 4.33, fabruary 2026. Copyright (c) 2013-2026, Pullenti. All rights reserved. 
 * Non-Commercial Freeware and Commercial Software. 
 * This class is generated using the converter UniSharping (www.unisharping.ru) from Pullenti C# project. 
 * The latest version of the code is available on the site www.pullenti.ru
 */

const Utils = require("./../../../unisharp/Utils");
const Hashtable = require("./../../../unisharp/Hashtable");
const RefOutArgWrapper = require("./../../../unisharp/RefOutArgWrapper");
const XmlNode = require("./../../../unisharp/XmlNode");

const UnitextNewline = require("./../../UnitextNewline");
const UnitextTable = require("./../../UnitextTable");
const FileFormat = require("./../../FileFormat");
const UnitextPagebreak = require("./../../UnitextPagebreak");
const UnitextDocument = require("./../../UnitextDocument");
const BorderInfo = require("./BorderInfo");
const DocTextStyles = require("./../word/DocTextStyles");
const MyXmlNodeType = require("./MyXmlNodeType");
const UnitextItem = require("./../../UnitextItem");
const UnitextPlaintext = require("./../../UnitextPlaintext");
const UnitextTablecell = require("./../../UnitextTablecell");
const UnitextContainer = require("./../../UnitextContainer");

class ExcelHelper {
    
    static _getColNum(v) {
        if (v !== null && v.length >= 2) {
            let num = ((v.charCodeAt(0)) - ('A'.charCodeAt(0)));
            if (v.length > 2 && Utils.isLetter(v[1])) 
                num = (((num + 1)) * 26) + (((v.charCodeAt(1)) - ('A'.charCodeAt(0))));
            return num;
        }
        return -1;
    }
    
    static _getRowNum(v) {
        if (v !== null && v.length >= 2) {
            let ii = 1;
            if (v.length > 2 && Utils.isLetter(v[1])) 
                ii = 2;
            let num = 0;
            let wrapnum71 = new RefOutArgWrapper();
            let inoutres72 = Utils.tryParseInt(v.substring(ii), wrapnum71);
            num = wrapnum71.value;
            if (inoutres72) 
                return num;
        }
        return -1;
    }
    
    static _getColMnem(n) {
        if (n < 0) 
            return "?";
        let n0 = Utils.intDiv(n, 26);
        let n1 = n % 26;
        if (n0 === 0) 
            return ((String.fromCharCode((n1 + ('A'.charCodeAt(0))))));
        return ((String.fromCharCode(((n0 - 1) + ('A'.charCodeAt(0))))) + (String.fromCharCode((n1 + ('A'.charCodeAt(0))))));
    }
    
    static _getRows(xml, sharedStrings, hiddenCols, styles, maxRows, rnum0) {
        rnum0.value = 0;
        let rows = new Array();
        let cols = 0;
        let allCols = 0;
        while (xml.read()) {
            if (xml.nodeType !== MyXmlNodeType.ELEMENT) 
                continue;
            if (xml.localName === "col" || xml.localName === "Column") {
                if (xml.getAttribute("hidden") === "1") 
                    hiddenCols.push(allCols);
                allCols++;
                continue;
            }
            if (Utils.compareStrings(xml.localName, "row", true) === 0) {
                let rn = rows.length;
                let nnn = 0;
                let wrapnnn84 = new RefOutArgWrapper();
                let inoutres85 = Utils.tryParseInt(Utils.notNull(xml.getAttribute("r"), ""), wrapnnn84);
                nnn = wrapnnn84.value;
                if (inoutres85) {
                    rn = nnn - 1;
                    if (rnum0.value === 0) 
                        rnum0.value = nnn;
                }
                while (rows.length <= rn) {
                    rows.push(new Array());
                }
                let row = rows[rn];
                if (xml.isEmptyElement) 
                    continue;
                while (xml.read()) {
                    if (xml.nodeType === MyXmlNodeType.ENDELEMENT && Utils.compareStrings(xml.localName, "row", true) === 0) 
                        break;
                    if (xml.nodeType === MyXmlNodeType.ELEMENT && ((xml.localName === "c" || xml.localName === "Cell"))) {
                        let num = -1;
                        let isExt = false;
                        let inlineStr = false;
                        let val = null;
                        let v = xml.getAttribute("r");
                        if (v !== null && v.length >= 2) 
                            num = ExcelHelper._getColNum(v);
                        else if ((((v = xml.getAttribute("ss:Index")))) !== null) {
                            let wrapnum73 = new RefOutArgWrapper();
                            let inoutres74 = Utils.tryParseInt(v, wrapnum73);
                            num = wrapnum73.value;
                            if (inoutres74) 
                                num--;
                        }
                        v = xml.getAttribute("t");
                        if (v === "s") 
                            isExt = true;
                        else if (v === "inlineStr") 
                            inlineStr = true;
                        let style = null;
                        if ((((v = xml.getAttribute("s")))) !== null) {
                            if (styles !== null) 
                                style = styles.getStyleById(v);
                        }
                        let mergeAcross = -1;
                        let mergeDown = -1;
                        if ((((v = xml.getAttribute("ss:MergeAcross")))) !== null) {
                            let wrapmergeAcross75 = new RefOutArgWrapper();
                            Utils.tryParseInt(v, wrapmergeAcross75);
                            mergeAcross = wrapmergeAcross75.value;
                        }
                        if ((((v = xml.getAttribute("ss:MergeDown")))) !== null) {
                            let wrapmergeDown76 = new RefOutArgWrapper();
                            Utils.tryParseInt(v, wrapmergeDown76);
                            mergeDown = wrapmergeDown76.value;
                        }
                        if (!xml.isEmptyElement) {
                            while (xml.read()) {
                                if (xml.nodeType === MyXmlNodeType.ELEMENT && xml.localName === "v") {
                                    if (xml.isEmptyElement) 
                                        break;
                                    if (!xml.read()) 
                                        break;
                                    if (xml.nodeType === MyXmlNodeType.TEXT) {
                                        if (!isExt) {
                                            val = UnitextPlaintext._new57(xml.value);
                                            continue;
                                        }
                                        let nu = 0;
                                        let wrapnu79 = new RefOutArgWrapper();
                                        let inoutres80 = Utils.tryParseInt(xml.value, wrapnu79);
                                        nu = wrapnu79.value;
                                        if (inoutres80) {
                                            if (nu >= 0 && (nu < sharedStrings.length)) {
                                                let ss = sharedStrings[nu];
                                                if (ss instanceof UnitextPlaintext) 
                                                    val = UnitextPlaintext._new57(ss.text);
                                                else if (ss !== null) 
                                                    val = ss.clone();
                                            }
                                        }
                                    }
                                }
                                else if (xml.nodeType === MyXmlNodeType.ELEMENT && xml.localName === "Data") {
                                    if (!xml.isEmptyElement) {
                                        xml.read();
                                        try {
                                            if (xml.nodeType === MyXmlNodeType.TEXT) 
                                                val = UnitextPlaintext._new57(xml.value);
                                        } catch (eee) {
                                            break;
                                        }
                                    }
                                }
                                else if (xml.nodeType === MyXmlNodeType.ELEMENT && xml.localName === "is") {
                                    xml.read();
                                    if (xml.nodeType === MyXmlNodeType.ELEMENT && xml.localName === "t" && !xml.isEmptyElement) {
                                        xml.read();
                                        if (xml.nodeType === MyXmlNodeType.TEXT) 
                                            val = UnitextPlaintext._new57(xml.value);
                                    }
                                }
                                if (xml.nodeType === MyXmlNodeType.ENDELEMENT && ((xml.localName === "c" || xml.localName === "Cell"))) 
                                    break;
                            }
                        }
                        if (num < 0) 
                            num = row.length;
                        if ((num + 1) > cols) 
                            cols = num + 1;
                        while (row.length <= num) {
                            row.push(null);
                        }
                        row[num] = UnitextTablecell._new83(num, num, rn, rn, (style === null ? null : style.xlsBorder));
                        if (val !== null) {
                            if (style !== null && style.xlsFormat !== null) {
                                let pt = Utils.as(val, UnitextPlaintext);
                                if (pt === null && (val instanceof UnitextContainer) && val.children.length === 1) 
                                    pt = Utils.as(val.children[0], UnitextPlaintext);
                                if (pt !== null) 
                                    pt.text = style.correctXlsText(pt.text);
                            }
                            row[num].content = val;
                        }
                        if (mergeAcross > 0) 
                            row[num].colEnd = row[num].colEnd + mergeAcross;
                        if (mergeDown > 0) 
                            row[num].rowEnd = row[num].rowEnd + mergeDown;
                    }
                }
            }
            else if (xml.localName === "mergeCell") {
                let val = xml.getAttribute("ref");
                if (val === null) 
                    continue;
                let ii = val.indexOf(':');
                if (ii < 2) 
                    continue;
                let v1 = val.substring(0, 0 + ii);
                let v2 = val.substring(ii + 1);
                if (v2.length < 2) 
                    continue;
                let col1 = ExcelHelper._getColNum(v1);
                let col2 = ExcelHelper._getColNum(v2);
                if (((col1 < 0) || (col2 < 0) || col1 >= cols) || col2 >= cols) 
                    continue;
                let row1 = ExcelHelper._getRowNum(v1);
                let row2 = ExcelHelper._getRowNum(v2);
                row1--;
                row2--;
                if (((row1 < 0) || (row2 < 0) || row1 >= rows.length) || row2 >= rows.length) 
                    continue;
                if (col2 > col1) {
                    if ((col1 < rows[row1].length) && rows[row1][col1] !== null) 
                        rows[row1][col1].colEnd = col2;
                    for (let jj = row1; jj <= row2; jj++) {
                        for (ii = col1 + 1; ii <= col2 && (ii < rows[jj].length); ii++) {
                            rows[jj][ii] = null;
                        }
                    }
                }
                if (row2 > row1) {
                    if ((col1 < rows[row1].length) && rows[row1][col1] !== null) 
                        rows[row1][col1].rowEnd = row2;
                    for (let jj = row1 + 1; jj <= row2; jj++) {
                        for (let kk = col1; kk <= col2; kk++) {
                            if (kk < rows[jj].length) 
                                rows[jj][kk] = null;
                        }
                    }
                }
            }
        }
        return rows;
    }
    
    static readSheet(xml, sharedStrings, sheetName, styles, maxRows) {
        let hiddenCols = new Array();
        let rnum0 = 0;
        let wraprnum086 = new RefOutArgWrapper();
        let rows = ExcelHelper._getRows(xml, sharedStrings, hiddenCols, styles, maxRows, wraprnum086);
        rnum0 = wraprnum086.value;
        if (maxRows > 0 && rows.length > maxRows) 
            rows.splice(maxRows, rows.length - maxRows);
        hiddenCols.splice(0, hiddenCols.length);
        return ExcelHelper.createTable(rows, hiddenCols, sheetName, rnum0);
    }
    
    static createTable(rows, hiddenCols, sheetName, rnum0) {
        let cnt = new UnitextContainer();
        let tab = null;
        let rnu = 0;
        let rnu0 = 0;
        let remptyMax = 0;
        let allRowsNoBorder = true;
        for (let rn = 0; rn < rows.length; rn++) {
            let row = new Array();
            for (let cn = 0; cn < rows[rn].length; cn++) {
                if (rows[rn][cn] !== null) {
                    if (hiddenCols.includes(cn)) 
                        continue;
                    let c = rows[rn][cn];
                    row.push(c);
                    if (c.tag instanceof BorderInfo) {
                        if (!c.tag.isEmpty) {
                            allRowsNoBorder = false;
                            break;
                        }
                    }
                }
            }
            if (!allRowsNoBorder) 
                break;
        }
        for (let rn = 0; rn < rows.length; rn++) {
            let row = new Array();
            let hasBorder = false;
            let hasData = 0;
            for (let cn = 0; cn < rows[rn].length; cn++) {
                if (rows[rn][cn] !== null) {
                    if (hiddenCols.includes(cn)) 
                        continue;
                    let c = rows[rn][cn];
                    row.push(c);
                    if (c.tag instanceof BorderInfo) {
                        if (!c.tag.isEmpty) 
                            hasBorder = true;
                    }
                    if (c.content !== null) 
                        hasData++;
                }
            }
            if (hasData === 0) {
                if (rn <= remptyMax) 
                    continue;
                if (!hasBorder || tab === null) {
                    tab = null;
                    if (cnt.children.length > 0 && (cnt.children[cnt.children.length - 1] instanceof UnitextNewline)) 
                        cnt.children[cnt.children.length - 1].count++;
                    else 
                        cnt.children.push(new UnitextNewline());
                    continue;
                }
                continue;
            }
            if (hasData === rows[rn].length && hasData > 2) {
            }
            else if (!hasBorder && !allRowsNoBorder) {
                if ((row.length < 3) || tab === null) {
                    tab = null;
                    let fi = true;
                    for (let cn = 0; cn < row.length; cn++) {
                        if (row[cn] !== null && row[cn].content !== null && !hiddenCols.includes(cn)) {
                            if (fi) 
                                fi = false;
                            else 
                                cnt.children.push(UnitextPlaintext._new57(" "));
                            cnt.children.push(row[cn].content);
                            row[cn].content.sourceInfo = ("XLS_CELL:" + cn + (rn + rnu0 + rnum0));
                        }
                    }
                    if (cnt.children.length > 0 && (cnt.children[cnt.children.length - 1] instanceof UnitextNewline)) 
                        cnt.children[cnt.children.length - 1].count++;
                    else 
                        cnt.children.push(new UnitextNewline());
                    continue;
                }
            }
            if (tab === null) {
                cnt.children.push(new UnitextNewline());
                tab = new UnitextTable();
                cnt.children.push(tab);
                rnu = 0;
                rnu0 = rn;
                remptyMax = rn;
                tab.sourceInfo = ("XLS_SHEET:" + sheetName);
            }
            for (let cn = 0; cn < row.length; cn++) {
                if (row[cn] !== null && !hiddenCols.includes(cn)) {
                    let rr = row[cn];
                    if (rr.rowEnd > remptyMax) 
                        remptyMax = rr.rowEnd;
                    rr.rowBegin = rr.rowBegin - rnu0;
                    rr.rowEnd = rr.rowEnd - rnu0;
                    let cc = tab.addCell(rr.rowBegin, rr.rowEnd, rr.colBegin, rr.colEnd, rr.content, false);
                    if (cc !== null && cc.sourceInfo === null) {
                        cc.sourceInfo = ("XLS_CELL:" + ExcelHelper._getColMnem(rr.colBegin) + (rr.rowBegin + rnu0 + rnum0));
                        if (rr.colEnd > rr.colBegin || rr.rowEnd > rr.rowBegin) 
                            cc.sourceInfo = (cc.sourceInfo + "-" + ExcelHelper._getColMnem(rr.colEnd) + (rr.rowEnd + rnu0 + rnum0));
                        if (rr.content !== null) 
                            rr.content.sourceInfo = cc.sourceInfo;
                    }
                }
            }
            rnu++;
        }
        return cnt.optimize(true, null);
    }
    
    static createDocForXml(xml, maxRows) {
        let res = UnitextDocument._new47(FileFormat.XLSX);
        let cnt = new UnitextContainer();
        let borders = new Hashtable();
        let styles = new DocTextStyles();
        let sheetName = null;
        while (xml.read()) {
            if (xml.nodeType !== MyXmlNodeType.ELEMENT) 
                continue;
            if (xml.localName === "Worksheet") {
                if (cnt.children.length > 0) 
                    cnt.children.push(new UnitextPagebreak());
                if (xml.attributes.length > 0) {
                    for (const a of xml.attributes.entries) {
                        let name = a.value;
                        sheetName = name;
                        cnt.children.push(UnitextPlaintext._new89(name, "SheetName"));
                        cnt.children.push(new UnitextNewline());
                        break;
                    }
                }
                continue;
            }
            if (xml.localName === "Table") {
                let tab = ExcelHelper.readSheet(xml, null, sheetName, styles, maxRows);
                if (tab !== null) 
                    cnt.children.push(tab);
            }
        }
        res.content = cnt;
        res.optimize(false, null);
        return res;
    }
}


module.exports = ExcelHelper