"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Datum = void 0;
const DEFAULT_FONT_SIZE_1 = require("../../../../../client/DEFAULT_FONT_SIZE");
const element_1 = require("../../../../../client/element");
const custom_1 = require("../../../../../client/event/custom");
const parentElement_1 = require("../../../../../client/platform/web/parentElement");
const getFontSize_1 = require("../../../../../client/util/style/getFontSize");
const evaluate_1 = require("../../../../../spec/evaluate");
const parser_1 = require("../../../../../spec/parser");
const stringify_1 = require("../../../../../spec/stringify");
const keyUpdateTree_1 = require("../../../../../util/keyUpdateTree");
const f_1 = require("../../../../f/comparison/Equals/f");
const Component_1 = require("../DataTree/Component");
class Datum extends element_1.Element {
    constructor($props, $system) {
        super($props, $system);
        this._ignore_blur = false;
        this.focus = (options) => {
            this._data_tree.focus(options);
        };
        this.blur = () => {
            this._data_tree.blur();
        };
        this.focusChild = (path, options) => {
            this._data_tree.focusLeaf(path, options);
        };
        this.blurChild = (path) => {
            this._data_tree.blurLeaf(path);
        };
        this._onLeafKeyDown = ({ value, path, event, _event, }) => {
            // console.log('Datum', '_onLeafKeyDown')
            const { key, shiftKey } = event;
            const leaf = this._data_tree.getChildAtPath(path);
            const { start: selectionStart, end: selectionEnd } = leaf.getSelectionRange();
            const [preventDefault, { nextRoot, nextPath, nextSelectionStart, nextSelectionEnd, nextDirection: direction, },] = (0, keyUpdateTree_1._keyUpdateTree)(this._root, path, value, key, selectionStart, selectionEnd, shiftKey);
            const diffPath = !(0, f_1.default)(path, nextPath);
            if (preventDefault) {
                if (diffPath) {
                    this._ignore_blur = true;
                }
                _event.preventDefault();
                this._onChange(nextRoot, nextPath, nextSelectionStart, nextSelectionEnd, direction);
            }
            // const diffPath = !isEqual(path, nextPath)
            // const diffRoot = nextRoot.value !== this._root.value
            // const diffSelectionStart = !isEqual(selectionStart, nextSelectionStart)
            // const diffSelectionEnd = !isEqual(selectionEnd, nextSelectionEnd)
            // if (diffRoot || diffPath || diffSelectionStart || diffSelectionEnd) {
            //   if (diffPath) {
            //     this._ignore_blur = true
            //   }
            //   _event.preventDefault()
            //   this._onChange(
            //     nextRoot,
            //     nextPath,
            //     nextSelectionStart,
            //     nextSelectionEnd,
            //     direction
            //   )
            // }
        };
        this._onLeafFocus = ({ path, _event, }) => {
            // console.log('Datum', '_onLeafFocus', path)
            if (this._ignore_blur) {
                return;
            }
            const { relatedTarget } = _event;
            if (relatedTarget === null ||
                (relatedTarget &&
                    relatedTarget instanceof Node &&
                    !this._data_tree.$element.contains(relatedTarget))) {
                this.dispatchEvent('datumfocus', { data: this._root, path });
            }
        };
        this._onLeafBlur = ({ path, _event, }) => {
            // console.log('Datum', '_onLeafBlur', this._ignore_blur)
            if (this._ignore_blur) {
                return;
            }
            if (path.length > 0) {
                const parentPath = (0, parser_1.getParentPath)(path);
                const parent = (0, parser_1._getNodeAtPath)(this._root, parentPath);
                if (path[path.length - 1] === parent.children.length - 1) {
                    const data = (0, parser_1._getNodeAtPath)(this._root, path);
                    if (data.value === '') {
                        const nextRoot = (0, parser_1._removeNodeAt)(this._root, path);
                        this._onChange(nextRoot, []);
                    }
                }
            }
            const { relatedTarget } = _event;
            if (relatedTarget === null ||
                (relatedTarget &&
                    relatedTarget instanceof Node &&
                    !this._data_tree.$element.contains(relatedTarget))) {
                this.dispatchEvent('datumblur', { data: this._root, path });
            }
        };
        this._onLeafPaste = ({ value, path, text, }) => {
            // console.log('Datum', '_onLeafPaste', value, path, text, text.length)
            const leaf = this._data_tree.getChildAtPath(path);
            const { start: selectionStart, end: selectionEnd } = leaf.getSelectionRange();
            const nextValue = value.slice(0, selectionStart) +
                text +
                value.slice(selectionEnd, value.length);
            const nextLeaf = (0, parser_1.getTree)(nextValue);
            const nextRoot = (0, parser_1._updateNodeAt)(this._root, path, nextLeaf);
            const nextSelectionStart = selectionStart + text.length;
            const nextSelectionEnd = nextSelectionStart;
            let nextFocus = (0, parser_1._getLastLeafPath)(nextRoot);
            const nextFocusNode = (0, parser_1._getNodeAtPath)(nextRoot, nextFocus);
            // {} and [] first input should be focused
            if (nextFocusNode.type === parser_1.TreeNodeType.ObjectLiteral ||
                nextFocusNode.type === parser_1.TreeNodeType.ArrayLiteral) {
                nextFocus.push(0);
            }
            this._onChange(nextRoot, nextFocus, nextSelectionStart, nextSelectionEnd, 'forward');
        };
        this._onLeafInput = ({ value, path, }) => {
            // console.log('Datum', '_onLeafInput')
            const leaf = this._data_tree.getChildAtPath(path);
            const { start: selectionStart } = leaf.getSelectionRange();
            const parent = (0, parser_1._getParent)(this._root, path);
            const ignoreKeyword = !!(parent &&
                (parent.type === parser_1.TreeNodeType.KeyValue ||
                    parent.type === parser_1.TreeNodeType.ObjectLiteral));
            const tree = (0, parser_1.getTree)(value, false, ignoreKeyword);
            let nextRoot = (0, parser_1._updateNodeAt)(this._root, path, tree);
            let nextPath = path;
            this._onChange(nextRoot, nextPath, selectionStart, selectionStart);
        };
        this._onChange = (data, focus, selectionStart, selectionEnd, direction) => {
            // console.log(
            //   'Datum',
            //   '_onChange',
            //   data,
            //   focus,
            //   selectionStart,
            //   selectionEnd,
            //   direction
            // )
            this._root = data;
            this._ignore_blur = true;
            this._data_tree.setProp('data', data);
            this._data_tree.focusLeaf(focus);
            this._ignore_blur = false;
            if (selectionStart !== undefined && selectionEnd !== undefined) {
                this._data_tree.setLeafSelectionRange(focus, selectionStart, selectionEnd, direction);
            }
            this.dispatchEvent('datumchange', { data });
        };
        const { style = {}, data = (0, parser_1.getTree)(''), fontSize } = $props;
        const data_tree = new Component_1.default({
            style: { ...style, fontSize: `${fontSize !== null && fontSize !== void 0 ? fontSize : DEFAULT_FONT_SIZE_1.DEFAULT_FONT_SIZE}px` },
            data,
            path: [],
            parent: null,
            fontSize,
        }, this.$system);
        this._root = data;
        this._data_tree = data_tree;
        this._data_tree.addEventListener((0, custom_1.makeCustomListener)('leafkeydown', this._onLeafKeyDown));
        this._data_tree.addEventListener((0, custom_1.makeCustomListener)('leafinput', this._onLeafInput));
        this._data_tree.addEventListener((0, custom_1.makeCustomListener)('leaffocus', this._onLeafFocus));
        this._data_tree.addEventListener((0, custom_1.makeCustomListener)('leafblur', this._onLeafBlur));
        this._data_tree.addEventListener((0, custom_1.makeCustomListener)('leafpaste', this._onLeafPaste));
        const $element = (0, parentElement_1.parentElement)($system);
        this.$element = $element;
        this.$slot = data_tree.$slot;
        this.$subComponent = {
            data_tree,
        };
        this.registerRoot(data_tree);
    }
    onPropChanged(prop, current) {
        if (prop === 'data') {
            this._root = current;
            this._data_tree.setProp('data', current);
        }
        else if (prop === 'style') {
            const fontSize = (current.fontSize && (0, getFontSize_1.parseFontSize)(current.fontSize)) ||
                this.getFontSize();
            this._data_tree.setProp('style', current);
            this._data_tree.setProp('fontSize', fontSize);
        }
    }
}
exports.Datum = Datum;
class Datum_ extends element_1.Element {
    constructor($props, $system) {
        super($props, $system);
        this._get_tree = (value) => {
            const data_tree = (value !== undefined && (0, parser_1.getTree)((0, stringify_1.stringify)(value))) || (0, parser_1.getTree)('');
            return data_tree;
        };
        const { style = {}, value = undefined } = $props;
        const data = this._get_tree(value);
        const root = new Datum({ data, style, fontSize: 12 }, this.$system);
        root.addEventListener((0, custom_1.makeCustomListener)('datumchange', (event) => {
            const { data } = event;
            try {
                const data_ = (0, evaluate_1._evaluate)(data, this.$system.specs, this.$system.classes);
                this.set('value', data_);
                this.dispatchEvent('change', data_);
            }
            catch (err) {
                //
            }
        }));
        this._root = root;
        const $element = (0, parentElement_1.parentElement)($system);
        this.$element = $element;
        this.$slot = root.$slot;
        this.$unbundled = false;
        this.$subComponent = {
            root,
        };
        this.registerRoot(root);
    }
    onPropChanged(prop, current) {
        if (prop === 'value') {
            const data = this._get_tree(current);
            this._root.setProp('data', data);
        }
        else {
            this._root.setProp(prop, current);
        }
    }
}
exports.default = Datum_;
//# sourceMappingURL=Component.js.map