"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WorkbookXform = void 0;
const col_cache_1 = require("../../../utils/col-cache.js");
const xml_stream_1 = require("../../../utils/xml-stream.js");
const base_xform_1 = require("../base-xform.js");
const static_xform_1 = require("../static-xform.js");
const list_xform_1 = require("../list-xform.js");
const defined_name_xform_1 = require("./defined-name-xform.js");
const sheet_xform_1 = require("./sheet-xform.js");
const workbook_view_xform_1 = require("./workbook-view-xform.js");
const workbook_properties_xform_1 = require("./workbook-properties-xform.js");
const workbook_calc_properties_xform_1 = require("./workbook-calc-properties-xform.js");
const workbook_pivot_cache_xform_1 = require("./workbook-pivot-cache-xform.js");
class WorkbookXform extends base_xform_1.BaseXform {
    constructor() {
        super();
        this.map = {
            fileVersion: WorkbookXform.STATIC_XFORMS.fileVersion,
            workbookPr: new workbook_properties_xform_1.WorkbookPropertiesXform(),
            bookViews: new list_xform_1.ListXform({
                tag: "bookViews",
                count: false,
                childXform: new workbook_view_xform_1.WorkbookViewXform()
            }),
            sheets: new list_xform_1.ListXform({ tag: "sheets", count: false, childXform: new sheet_xform_1.WorksheetXform() }),
            definedNames: new list_xform_1.ListXform({
                tag: "definedNames",
                count: false,
                childXform: new defined_name_xform_1.DefinedNamesXform()
            }),
            calcPr: new workbook_calc_properties_xform_1.WorkbookCalcPropertiesXform(),
            pivotCaches: new list_xform_1.ListXform({
                tag: "pivotCaches",
                count: false,
                childXform: new workbook_pivot_cache_xform_1.WorkbookPivotCacheXform()
            })
        };
    }
    prepare(model) {
        model.sheets = model.worksheets;
        // collate all the print areas from all of the sheets and add them to the defined names
        const printAreas = [];
        let index = 0; // sheets is sparse array - calc index manually
        model.sheets.forEach((sheet) => {
            if (sheet.pageSetup && sheet.pageSetup.printArea) {
                sheet.pageSetup.printArea.split("&&").forEach((printArea) => {
                    const printAreaComponents = printArea.split(":");
                    const definedName = {
                        name: "_xlnm.Print_Area",
                        ranges: [`'${sheet.name}'!$${printAreaComponents[0]}:$${printAreaComponents[1]}`],
                        localSheetId: index
                    };
                    printAreas.push(definedName);
                });
            }
            if (sheet.pageSetup &&
                (sheet.pageSetup.printTitlesRow || sheet.pageSetup.printTitlesColumn)) {
                const ranges = [];
                if (sheet.pageSetup.printTitlesColumn) {
                    const titlesColumns = sheet.pageSetup.printTitlesColumn.split(":");
                    ranges.push(`'${sheet.name}'!$${titlesColumns[0]}:$${titlesColumns[1]}`);
                }
                if (sheet.pageSetup.printTitlesRow) {
                    const titlesRows = sheet.pageSetup.printTitlesRow.split(":");
                    ranges.push(`'${sheet.name}'!$${titlesRows[0]}:$${titlesRows[1]}`);
                }
                const definedName = {
                    name: "_xlnm.Print_Titles",
                    ranges,
                    localSheetId: index
                };
                printAreas.push(definedName);
            }
            index++;
        });
        if (printAreas.length) {
            model.definedNames = model.definedNames.concat(printAreas);
        }
        (model.media || []).forEach((medium, i) => {
            // assign name
            medium.name = medium.type + (i + 1);
        });
    }
    render(xmlStream, model) {
        xmlStream.openXml(xml_stream_1.XmlStream.StdDocAttributes);
        xmlStream.openNode("workbook", WorkbookXform.WORKBOOK_ATTRIBUTES);
        this.map.fileVersion.render(xmlStream);
        this.map.workbookPr.render(xmlStream, model.properties);
        this.map.bookViews.render(xmlStream, model.views);
        this.map.sheets.render(xmlStream, model.sheets);
        this.map.definedNames.render(xmlStream, model.definedNames);
        this.map.calcPr.render(xmlStream, model.calcProperties);
        this.map.pivotCaches.render(xmlStream, model.pivotTables);
        xmlStream.closeNode();
    }
    parseOpen(node) {
        if (this.parser) {
            this.parser.parseOpen(node);
            return true;
        }
        switch (node.name) {
            case "workbook":
                return true;
            default:
                this.parser = this.map[node.name];
                if (this.parser) {
                    this.parser.parseOpen(node);
                }
                return true;
        }
    }
    parseText(text) {
        if (this.parser) {
            this.parser.parseText(text);
        }
    }
    parseClose(name) {
        if (this.parser) {
            if (!this.parser.parseClose(name)) {
                this.parser = undefined;
            }
            return true;
        }
        switch (name) {
            case "workbook":
                this.model = {
                    sheets: this.map.sheets.model,
                    properties: this.map.workbookPr.model || {},
                    views: this.map.bookViews.model,
                    calcProperties: {}
                };
                if (this.map.definedNames.model) {
                    this.model.definedNames = this.map.definedNames.model;
                }
                if (this.map.pivotCaches.model && this.map.pivotCaches.model.length > 0) {
                    this.model.pivotCaches = this.map.pivotCaches.model;
                }
                return false;
            default:
                // not quite sure how we get here!
                return true;
        }
    }
    reconcile(model) {
        const rels = (model.workbookRels || []).reduce((map, rel) => {
            map[rel.Id] = rel;
            return map;
        }, {});
        // reconcile sheet ids, rIds and names
        const worksheets = [];
        let worksheet;
        let index = 0;
        (model.sheets || []).forEach((sheet) => {
            const rel = rels[sheet.rId];
            if (!rel) {
                return;
            }
            // if rel.Target start with `[space]/xl/` or `/xl/` , then it will be replaced with `''` and spliced behind `xl/`,
            // otherwise it will be spliced directly behind `xl/`. i.g.
            worksheet = model.worksheetHash[`xl/${rel.Target.replace(/^(\s|\/xl\/)+/, "")}`];
            // If there are "chartsheets" in the file, rel.Target will
            // come out as chartsheets/sheet1.xml or similar here, and
            // that won't be in model.worksheetHash.
            // As we don't have the infrastructure to support chartsheets,
            // we will ignore them for now:
            if (worksheet) {
                worksheet.name = sheet.name;
                worksheet.id = sheet.id;
                worksheet.state = sheet.state;
                worksheets[index++] = worksheet;
            }
        });
        // reconcile print areas
        const definedNames = [];
        if (model.definedNames) {
            model.definedNames.forEach((definedName) => {
                if (definedName.name === "_xlnm.Print_Area") {
                    worksheet = worksheets[definedName.localSheetId];
                    if (worksheet) {
                        if (!worksheet.pageSetup) {
                            worksheet.pageSetup = {};
                        }
                        const range = col_cache_1.colCache.decodeEx(definedName.ranges[0]);
                        worksheet.pageSetup.printArea = worksheet.pageSetup.printArea
                            ? `${worksheet.pageSetup.printArea}&&${range.dimensions}`
                            : range.dimensions;
                    }
                }
                else if (definedName.name === "_xlnm.Print_Titles") {
                    worksheet = worksheets[definedName.localSheetId];
                    if (worksheet) {
                        if (!worksheet.pageSetup) {
                            worksheet.pageSetup = {};
                        }
                        const rangeString = definedName.ranges.join(",");
                        const dollarRegex = /\$/g;
                        const rowRangeRegex = /\$\d+:\$\d+/;
                        const rowRangeMatches = rangeString.match(rowRangeRegex);
                        if (rowRangeMatches && rowRangeMatches.length) {
                            const range = rowRangeMatches[0];
                            worksheet.pageSetup.printTitlesRow = range.replace(dollarRegex, "");
                        }
                        const columnRangeRegex = /\$[A-Z]+:\$[A-Z]+/;
                        const columnRangeMatches = rangeString.match(columnRangeRegex);
                        if (columnRangeMatches && columnRangeMatches.length) {
                            const range = columnRangeMatches[0];
                            worksheet.pageSetup.printTitlesColumn = range.replace(dollarRegex, "");
                        }
                    }
                }
                else {
                    definedNames.push(definedName);
                }
            });
        }
        model.definedNames = definedNames;
        // used by sheets to build their image models
        model.media.forEach((media, i) => {
            media.index = i;
        });
    }
}
exports.WorkbookXform = WorkbookXform;
WorkbookXform.WORKBOOK_ATTRIBUTES = {
    xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
    "xmlns:r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
    "xmlns:mc": "http://schemas.openxmlformats.org/markup-compatibility/2006",
    "mc:Ignorable": "x15",
    "xmlns:x15": "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"
};
WorkbookXform.STATIC_XFORMS = {
    fileVersion: new static_xform_1.StaticXform({
        tag: "fileVersion",
        $: { appName: "xl", lastEdited: 5, lowestEdited: 5, rupBuild: 9303 }
    })
};
