"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const loader_1 = require("../../loader");
const carnatic_1 = require("../../carnatic");
const grids_1 = require("../../grids");
const block_1 = require("../../block");
const cellFactory_1 = require("../utils/cellFactory");
const DEFAULT_CONFIG = {
    maxDepth: 1,
    enableReordering: false,
    enableAddCell: true,
    enableDeleteCell: true,
};
class NotebookView {
    constructor(container, config = {}) {
        var _a, _b;
        this.notation = null;
        this.notationSource = "";
        this.cells = [];
        this.cellElements = new Map();
        this.cellNotationViews = new Map();
        this.layoutChangeUnsubscribe = null;
        this.config = Object.assign(Object.assign({}, DEFAULT_CONFIG), config);
        this.rootElement = document.createElement("div");
        this.rootElement.className = "notebook-view";
        if ((_a = this.config.cssClasses) === null || _a === void 0 ? void 0 : _a.root) {
            this.rootElement.className += " " + this.config.cssClasses.root;
        }
        container.appendChild(this.rootElement);
        this.gridLayoutGroup = (_b = this.config.sharedGridLayoutGroup) !== null && _b !== void 0 ? _b : new grids_1.GridLayoutGroup();
        this.layoutChangeUnsubscribe = this.gridLayoutGroup.onLayoutChange((event) => {
            this.handleLayoutChange(event);
        });
    }
    loadNotation(source) {
        this.notationSource = source;
        const [notation, beatLayout, errors] = (0, loader_1.load)(source, { log: false });
        if (errors.length > 0) {
            console.error("Notation parse errors:", errors);
            return;
        }
        this.notation = notation;
        this.cells = (0, cellFactory_1.createCellModels)(notation, {
            maxDepth: this.config.maxDepth,
            notationSource: source,
            includeLines: true,
            includeRawBlocks: true,
        });
        this.render();
    }
    getNotation() {
        return this.notation;
    }
    getCells() {
        return this.cells;
    }
    getVisibleCells() {
        return (0, cellFactory_1.getVisibleCells)(this.cells);
    }
    getCell(cellId) {
        return (0, cellFactory_1.findCellById)(this.cells, cellId);
    }
    render() {
        this.rootElement.innerHTML = "";
        this.cellElements.clear();
        this.cellNotationViews.clear();
        for (let i = 0; i < this.cells.length; i++) {
            const cell = this.cells[i];
            this.renderCell(cell, this.rootElement);
            if (this.config.enableAddCell && i < this.cells.length - 1) {
                this.renderAddCellButton(this.rootElement, i + 1);
            }
        }
        if (this.config.enableAddCell) {
            this.renderAddCellButton(this.rootElement, this.cells.length);
        }
    }
    renderCell(cell, parent) {
        var _a, _b;
        const cellClass = ((_a = this.config.cssClasses) === null || _a === void 0 ? void 0 : _a.cell) || "";
        const container = document.createElement("div");
        container.className = `notebook-cell notebook-cell-${cell.state.type} ${cellClass}`;
        container.dataset.cellId = cell.state.id;
        container.dataset.depth = String(cell.state.depth);
        this.renderCellHeader(cell, container);
        const contentContainer = document.createElement("div");
        contentContainer.className = "notebook-cell-content";
        if ((_b = this.config.cssClasses) === null || _b === void 0 ? void 0 : _b.cellContent) {
            contentContainer.className += " " + this.config.cssClasses.cellContent;
        }
        container.appendChild(contentContainer);
        if (cell.state.isEditing) {
            this.renderCellEditMode(cell, contentContainer);
        }
        else {
            this.renderCellPreviewMode(cell, contentContainer);
        }
        this.cellElements.set(cell.state.id, container);
        parent.appendChild(container);
        if (cell.state.isExpanded && cell.children.length > 0) {
            const childrenContainer = document.createElement("div");
            childrenContainer.className = "notebook-cell-children";
            container.appendChild(childrenContainer);
            for (const child of cell.children) {
                this.renderCell(child, childrenContainer);
            }
        }
    }
    renderCellHeader(cell, container) {
        var _a, _b, _c;
        const headerClass = ((_a = this.config.cssClasses) === null || _a === void 0 ? void 0 : _a.cellHeader) || "";
        const header = document.createElement("div");
        header.className = `notebook-cell-header ${headerClass}`;
        const badge = document.createElement("span");
        badge.className = `notebook-cell-badge badge-${cell.state.type}`;
        badge.textContent = cell.state.type;
        header.appendChild(badge);
        if ((0, block_1.isBlock)(cell.blockItem)) {
            const block = cell.blockItem;
            if (block.name) {
                const name = document.createElement("span");
                name.className = "notebook-cell-name";
                name.textContent = block.name;
                header.appendChild(name);
            }
        }
        if (cell.children.length > 0) {
            const expandBtn = document.createElement("button");
            expandBtn.className = "notebook-btn notebook-expand-btn";
            expandBtn.textContent = cell.state.isExpanded ? "▼" : "▶";
            expandBtn.title = cell.state.isExpanded ? "Collapse" : "Expand";
            expandBtn.addEventListener("click", () => this.toggleExpanded(cell.state.id));
            header.appendChild(expandBtn);
        }
        const controlsClass = ((_b = this.config.cssClasses) === null || _b === void 0 ? void 0 : _b.cellControls) || "";
        const controls = document.createElement("div");
        controls.className = `notebook-cell-controls ${controlsClass}`;
        const editBtn = document.createElement("button");
        editBtn.className = "notebook-btn notebook-edit-btn";
        editBtn.textContent = cell.state.isEditing ? "Cancel" : "Edit";
        editBtn.addEventListener("click", () => {
            if (cell.state.isEditing) {
                this.cancelEdit(cell.state.id);
            }
            else {
                this.startEdit(cell.state.id);
            }
        });
        controls.appendChild(editBtn);
        if (this.config.enableDeleteCell) {
            const deleteBtn = document.createElement("button");
            deleteBtn.className = "notebook-btn notebook-delete-btn";
            deleteBtn.textContent = "Delete";
            deleteBtn.addEventListener("click", () => this.deleteCell(cell.state.id));
            controls.appendChild(deleteBtn);
        }
        header.appendChild(controls);
        container.appendChild(header);
        if (cell.state.hasError && cell.state.errorMessage) {
            const errorClass = ((_c = this.config.cssClasses) === null || _c === void 0 ? void 0 : _c.errorMessage) || "";
            const errorDiv = document.createElement("div");
            errorDiv.className = `notebook-cell-error ${errorClass}`;
            errorDiv.textContent = cell.state.errorMessage;
            container.appendChild(errorDiv);
        }
    }
    renderCellPreviewMode(cell, container) {
        if ((0, block_1.isRawBlock)(cell.blockItem)) {
            const rawBlock = cell.blockItem;
            const content = document.createElement("div");
            content.className = "notebook-rawblock-content";
            if (this.config.markdownParser && rawBlock.contentType === "md") {
                content.innerHTML = this.config.markdownParser(rawBlock.content);
            }
            else {
                content.textContent = rawBlock.content;
            }
            container.appendChild(content);
        }
        else if ((0, block_1.isLine)(cell.blockItem) || (0, block_1.isBlock)(cell.blockItem)) {
            const viewContainer = document.createElement("div");
            viewContainer.className = "notebook-notation-view";
            container.appendChild(viewContainer);
            const notationView = new carnatic_1.NotationView(viewContainer, {
                sharedGridLayoutGroup: this.gridLayoutGroup,
                markdownParser: this.config.markdownParser,
            });
            this.cellNotationViews.set(cell.state.id, notationView);
            const placeholder = document.createElement("div");
            placeholder.className = "notebook-notation-placeholder";
            placeholder.textContent = `[${cell.state.type} notation content]`;
            viewContainer.appendChild(placeholder);
        }
    }
    renderCellEditMode(cell, container) {
        var _a;
        const textareaClass = ((_a = this.config.cssClasses) === null || _a === void 0 ? void 0 : _a.editTextarea) || "";
        const textarea = document.createElement("textarea");
        textarea.className = `notebook-edit-textarea ${textareaClass}`;
        textarea.value = cell.source;
        textarea.rows = Math.max(3, cell.source.split("\n").length);
        container.appendChild(textarea);
        const actions = document.createElement("div");
        actions.className = "notebook-edit-actions";
        const applyBtn = document.createElement("button");
        applyBtn.className = "notebook-btn notebook-apply-btn";
        applyBtn.textContent = "Apply";
        applyBtn.addEventListener("click", () => {
            this.applyEdit(cell.state.id, textarea.value);
        });
        actions.appendChild(applyBtn);
        const cancelBtn = document.createElement("button");
        cancelBtn.className = "notebook-btn notebook-cancel-btn";
        cancelBtn.textContent = "Cancel";
        cancelBtn.addEventListener("click", () => this.cancelEdit(cell.state.id));
        actions.appendChild(cancelBtn);
        container.appendChild(actions);
    }
    renderAddCellButton(parent, insertIndex) {
        var _a;
        const btnClass = ((_a = this.config.cssClasses) === null || _a === void 0 ? void 0 : _a.addCellButton) || "";
        const btn = document.createElement("button");
        btn.className = `notebook-add-cell-btn ${btnClass}`;
        btn.textContent = "+ Add Cell";
        btn.addEventListener("click", () => {
            const newCell = this.insertCell(insertIndex, "");
            this.startEdit(newCell.state.id);
        });
        parent.appendChild(btn);
    }
    handleLayoutChange(event) {
        if (this.config.onLayoutChange) {
            this.config.onLayoutChange(event);
        }
        if (!event.columnWidthsChanged && !event.rowHeightsChanged) {
            return;
        }
    }
    startEdit(cellId) {
        const cell = (0, cellFactory_1.findCellById)(this.cells, cellId);
        if (!cell)
            return;
        const updatedCell = (0, cellFactory_1.updateCellState)(cell, { isEditing: true });
        this.replaceCellInTree(cell, updatedCell);
        this.rerenderCell(updatedCell);
    }
    applyEdit(cellId, newSource) {
        const cell = (0, cellFactory_1.findCellById)(this.cells, cellId);
        if (!cell)
            return;
        const updatedCell = Object.assign(Object.assign({}, cell), { source: newSource, state: Object.assign(Object.assign({}, cell.state), { isEditing: false, hasError: false, errorMessage: undefined }) });
        this.replaceCellInTree(cell, updatedCell);
        this.rerenderCell(updatedCell);
        if (this.config.onNotationChange) {
            this.config.onNotationChange(this.notationSource, this.notation);
        }
    }
    cancelEdit(cellId) {
        const cell = (0, cellFactory_1.findCellById)(this.cells, cellId);
        if (!cell)
            return;
        const updatedCell = (0, cellFactory_1.updateCellState)(cell, { isEditing: false });
        this.replaceCellInTree(cell, updatedCell);
        this.rerenderCell(updatedCell);
    }
    deleteCell(cellId) {
        const cell = (0, cellFactory_1.findCellById)(this.cells, cellId);
        if (!cell)
            return;
        if (cell.parent) {
            const index = cell.parent.children.indexOf(cell);
            if (index >= 0) {
                cell.parent.children.splice(index, 1);
            }
        }
        else {
            const index = this.cells.indexOf(cell);
            if (index >= 0) {
                this.cells.splice(index, 1);
            }
        }
        const element = this.cellElements.get(cellId);
        if (element) {
            element.remove();
            this.cellElements.delete(cellId);
        }
        this.cellNotationViews.delete(cellId);
    }
    moveCell(cellId, targetIndex) {
        const cell = (0, cellFactory_1.findCellById)(this.cells, cellId);
        if (!cell)
            return;
        if (cell.parent) {
            console.warn("Moving nested cells not yet supported");
            return;
        }
        const currentIndex = this.cells.indexOf(cell);
        if (currentIndex < 0 || currentIndex === targetIndex)
            return;
        this.cells.splice(currentIndex, 1);
        this.cells.splice(targetIndex, 0, cell);
        this.render();
    }
    insertCell(index, source) {
        const rawBlock = new block_1.RawBlock(source, "notation");
        const cell = {
            blockItem: rawBlock,
            state: {
                id: `cell-${Date.now()}`,
                type: "rawblock",
                depth: 0,
                isExpanded: true,
                isEditing: false,
                hasError: false,
            },
            source,
            children: [],
            parent: null,
        };
        this.cells.splice(index, 0, cell);
        this.render();
        return cell;
    }
    toggleExpanded(cellId) {
        const cell = (0, cellFactory_1.findCellById)(this.cells, cellId);
        if (!cell)
            return;
        const updatedCell = (0, cellFactory_1.updateCellState)(cell, {
            isExpanded: !cell.state.isExpanded,
        });
        this.replaceCellInTree(cell, updatedCell);
        this.rerenderCell(updatedCell);
    }
    replaceCellInTree(oldCell, newCell) {
        if (oldCell.parent) {
            const index = oldCell.parent.children.indexOf(oldCell);
            if (index >= 0) {
                oldCell.parent.children[index] = newCell;
                newCell.parent = oldCell.parent;
            }
        }
        else {
            const index = this.cells.indexOf(oldCell);
            if (index >= 0) {
                this.cells[index] = newCell;
            }
        }
    }
    rerenderCell(cell) {
        const element = this.cellElements.get(cell.state.id);
        if (!element || !element.parentElement)
            return;
        const parent = element.parentElement;
        const nextSibling = element.nextSibling;
        element.remove();
        this.cellElements.delete(cell.state.id);
        this.cellNotationViews.delete(cell.state.id);
        const tempContainer = document.createElement("div");
        this.renderCell(cell, tempContainer);
        const newElement = tempContainer.firstChild;
        if (nextSibling) {
            parent.insertBefore(newElement, nextSibling);
        }
        else {
            parent.appendChild(newElement);
        }
    }
    destroy() {
        if (this.layoutChangeUnsubscribe) {
            this.layoutChangeUnsubscribe();
            this.layoutChangeUnsubscribe = null;
        }
        this.rootElement.innerHTML = "";
        this.cellElements.clear();
        this.cellNotationViews.clear();
    }
}
exports.default = NotebookView;
//# sourceMappingURL=NotebookView.js.map