"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const loader_1 = require("../../loader");
const carnatic_1 = require("../../carnatic");
const DEFAULT_CONFIG = {
    debounceDelay: 300,
    syncScroll: true,
};
class SideBySideEditor {
    constructor(config = {}) {
        this.notation = null;
        this.beatLayout = null;
        this.debounceTimer = null;
        this.isScrollSyncing = false;
        this.config = Object.assign(Object.assign({}, DEFAULT_CONFIG), config);
        this.editorElement = document.createElement("textarea");
        this.editorElement.className = "side-by-side-editor";
        if (this.config.editorClass) {
            this.editorElement.className += " " + this.config.editorClass;
        }
        this.editorElement.spellcheck = false;
        this.editorElement.placeholder = "Enter notation source...";
        if (this.config.initialSource) {
            this.editorElement.value = this.config.initialSource;
        }
        this.outputElement = document.createElement("div");
        this.outputElement.className = "side-by-side-output";
        if (this.config.outputClass) {
            this.outputElement.className += " " + this.config.outputClass;
        }
        this.notationView = new carnatic_1.NotationView(this.outputElement, {
            sharedGridLayoutGroup: this.config.sharedGridLayoutGroup,
            markdownParser: this.config.markdownParser,
        });
        this.setupEventListeners();
        if (this.config.initialSource) {
            this.render();
        }
    }
    get source() {
        return this.editorElement.value;
    }
    set source(value) {
        this.editorElement.value = value;
        this.render();
    }
    getNotation() {
        return this.notation;
    }
    getBeatLayout() {
        return this.beatLayout;
    }
    render() {
        var _a, _b, _c, _d;
        const source = this.editorElement.value;
        this.notationView.clear();
        const [notation, beatLayout, errors] = (0, loader_1.load)(source, { log: false });
        if (errors.length > 0) {
            this.notation = null;
            this.beatLayout = null;
            (_b = (_a = this.config).onParseError) === null || _b === void 0 ? void 0 : _b.call(_a, errors);
            return false;
        }
        this.notation = notation;
        this.beatLayout = beatLayout;
        this.notationView.renderNotation(notation, beatLayout);
        (_d = (_c = this.config).onNotationParsed) === null || _d === void 0 ? void 0 : _d.call(_c, notation, beatLayout);
        return true;
    }
    setupEventListeners() {
        this.editorElement.addEventListener("input", () => {
            var _a, _b;
            (_b = (_a = this.config).onSourceChange) === null || _b === void 0 ? void 0 : _b.call(_a, this.editorElement.value);
            if (this.config.debounceDelay && this.config.debounceDelay > 0) {
                if (this.debounceTimer) {
                    clearTimeout(this.debounceTimer);
                }
                this.debounceTimer = setTimeout(() => {
                    this.render();
                }, this.config.debounceDelay);
            }
        });
        if (this.config.syncScroll) {
            this.editorElement.addEventListener("scroll", () => {
                this.syncScrollToOutput();
            });
            this.outputElement.addEventListener("scroll", () => {
                this.syncScrollToEditor();
            });
        }
    }
    syncScrollToOutput() {
        if (this.isScrollSyncing)
            return;
        this.isScrollSyncing = true;
        const editor = this.editorElement;
        const output = this.outputElement;
        const maxScrollTop = editor.scrollHeight - editor.clientHeight;
        if (maxScrollTop <= 0) {
            this.isScrollSyncing = false;
            return;
        }
        const scrollPercent = editor.scrollTop / maxScrollTop;
        const outputMaxScroll = output.scrollHeight - output.clientHeight;
        output.scrollTop = scrollPercent * outputMaxScroll;
        this.isScrollSyncing = false;
    }
    syncScrollToEditor() {
        if (this.isScrollSyncing)
            return;
        this.isScrollSyncing = true;
        const editor = this.editorElement;
        const output = this.outputElement;
        const maxScrollTop = output.scrollHeight - output.clientHeight;
        if (maxScrollTop <= 0) {
            this.isScrollSyncing = false;
            return;
        }
        const scrollPercent = output.scrollTop / maxScrollTop;
        const editorMaxScroll = editor.scrollHeight - editor.clientHeight;
        editor.scrollTop = scrollPercent * editorMaxScroll;
        this.isScrollSyncing = false;
    }
    scrollToTop() {
        this.editorElement.scrollTop = 0;
        this.outputElement.scrollTop = 0;
    }
    scrollToBottom() {
        this.editorElement.scrollTop = this.editorElement.scrollHeight;
        this.outputElement.scrollTop = this.outputElement.scrollHeight;
    }
    scrollToLine(lineNumber) {
        const lines = this.editorElement.value.split("\n");
        const lineHeight = this.editorElement.scrollHeight / lines.length;
        this.editorElement.scrollTop = (lineNumber - 1) * lineHeight;
        this.syncScrollToOutput();
    }
    focus() {
        this.editorElement.focus();
    }
    insertAtCursor(text) {
        var _a, _b;
        const start = this.editorElement.selectionStart;
        const end = this.editorElement.selectionEnd;
        const value = this.editorElement.value;
        this.editorElement.value = value.substring(0, start) + text + value.substring(end);
        this.editorElement.selectionStart = start + text.length;
        this.editorElement.selectionEnd = start + text.length;
        (_b = (_a = this.config).onSourceChange) === null || _b === void 0 ? void 0 : _b.call(_a, this.editorElement.value);
    }
    getSelection() {
        return {
            start: this.editorElement.selectionStart,
            end: this.editorElement.selectionEnd,
            text: this.editorElement.value.substring(this.editorElement.selectionStart, this.editorElement.selectionEnd),
        };
    }
    setSelection(start, end) {
        this.editorElement.selectionStart = start;
        this.editorElement.selectionEnd = end;
    }
    destroy() {
        if (this.debounceTimer) {
            clearTimeout(this.debounceTimer);
        }
        this.editorElement.remove();
        this.outputElement.remove();
    }
}
exports.default = SideBySideEditor;
//# sourceMappingURL=SideBySideEditor.js.map