"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const mobx_1 = require("mobx");
const InternalBehavior_1 = require("./InternalBehavior");
const BehaviorUtils_1 = require("../util/BehaviorUtils");
const AliasBox_1 = require("./boxes/AliasBox");
const SelectBox_1 = require("./boxes/SelectBox");
const TextBox_1 = require("./boxes/TextBox");
const Box_1 = require("./boxes/Box");
const PiLogging_1 = require("../util/PiLogging");
const PiUtils_1 = require("../util/PiUtils");
const LOGGER = new PiLogging_1.PiLogger("PiEditor").mute();
class PiEditor {
    constructor(projection, actions) {
        this.behaviors = [];
        this.keyboardActions = [];
        this.selectedElement = null;
        this.selectedPosition = BehaviorUtils_1.PiCaret.UNSPECIFIED;
        this.selectedRole = null;
        this.actions = actions;
        this.projection = projection;
        this.initializeAliases(actions);
    }
    initializeAliases(actions) {
        if (!actions) {
            return;
        }
        actions.expressionCreators.forEach(ea => this.behaviors.push(new InternalBehavior_1.InternalExpressionBehavior(ea)));
        actions.binaryExpressionCreators.forEach(ba => this.behaviors.push(new InternalBehavior_1.InternalBinaryBehavior(ba)));
        actions.customBehaviors.forEach(ca => this.behaviors.push(new InternalBehavior_1.InternalCustomBehavior(ca)));
        this.keyboardActions = actions.keyboardActions;
    }
    get projectedElement() {
        return this.$projectedElement;
    }
    set projectedElement(e) {
        this.$projectedElement = e;
    }
    selectElement(element, role, caretPosition) {
        return __awaiter(this, void 0, void 0, function* () {
            this.selectedElement = element;
            this.selectedRole = role;
            this.selectedPosition = caretPosition;
            PiUtils_1.wait(0);
            LOGGER.info(this, "==> selectElement " + (!!element && element) + " Role: " + role);
            const rootBox = this.rootBox;
            const box = rootBox.findBox(element.piId(), role);
            LOGGER.info(this, "-==> selectElement found box " + (!!box && box.kind));
            if (box) {
                yield this.selectBox(box, caretPosition);
            }
            else {
                if (!!role) {
                    LOGGER.info(this, "Trying without role");
                    yield this.selectElement(element);
                    this.selectedRole = role;
                    this.selectedPosition = caretPosition;
                }
            }
        });
    }
    selectBox(box, caretPosition) {
        return __awaiter(this, void 0, void 0, function* () {
            if (box === this.selectedBox) {
                return;
            }
            this.selectedBox = box;
            this.$projectedElement.focus();
            if (box === null) {
                return;
            }
            LOGGER.info(this, "==> select box " + box.role + " caret position: " + caretPosition);
            if (TextBox_1.isTextBox(box) || AliasBox_1.isAliasBox(box) || SelectBox_1.isSelectBox(box)) {
                if (caretPosition) {
                    LOGGER.info(this, "caret position is " + caretPosition);
                    box.setCaret(caretPosition);
                }
                else {
                    LOGGER.info(this, "caret position is empty");
                    box.setCaret(BehaviorUtils_1.PiCaret.RIGHT_MOST);
                }
                LOGGER.info(this, "setting focus on box " + box.role);
                yield box.setFocus();
            }
        });
    }
    get selectedBox() {
        return this.$selectedBox;
    }
    set selectedBox(box) {
        LOGGER.info(this, " ==> set selected box: " + (!!box ? box.role : "null"));
        this.$selectedBox = box;
        if (!!box) {
            this.selectedElement = box.element;
            this.selectedRole = box.role;
        }
    }
    get rootBox() {
        LOGGER.info(this, "RECALCULATING ROOT [" + this.rootElement + "]");
        return this.projection.getBox(this.rootElement);
    }
    selectParentBox() {
        LOGGER.info(this, "==> SelectParent");
        const parent = this.selectedBox.parent;
        if (parent) {
            if (parent.selectable) {
                this.selectBox(parent);
                parent.setFocus();
            }
            else {
                this.selectBox(parent);
                this.selectParentBox();
            }
        }
    }
    selectFirstLeafChildBox() {
        const first = this.selectedBox.firstLeaf;
        if (first) {
            this.selectBox(first);
        }
    }
    selectNextLeaf() {
        const next = this.selectedBox.nextLeafRight;
        if (next) {
            this.selectBox(next);
            next.setFocus();
            if (TextBox_1.isTextBox(next) || SelectBox_1.isSelectBox(next)) {
                next.setCaret(BehaviorUtils_1.PiCaret.LEFT_MOST);
            }
        }
    }
    selectPreviousLeaf() {
        return __awaiter(this, void 0, void 0, function* () {
            const previous = this.selectedBox.nextLeafLeft;
            if (previous) {
                yield this.selectBox(previous);
                previous.setFocus();
                if (TextBox_1.isTextBox(previous) || SelectBox_1.isSelectBox(previous)) {
                    LOGGER.info(this, "selectPreviousLeaf set caret to RIGHT_MOST");
                    previous.setCaret(BehaviorUtils_1.PiCaret.RIGHT_MOST);
                }
            }
        });
    }
    deleteBox(box) {
        return __awaiter(this, void 0, void 0, function* () {
            LOGGER.info(this, "deleteBox");
            const exp = box.element;
            const container = exp.piContainer();
            if (container !== null) {
                LOGGER.info(this, "remove from parent splice " + [container.propertyIndex] + ", 1");
                const propertyIndex = container.propertyIndex;
                const parentElement = container.container;
                if (propertyIndex !== undefined) {
                    let arrayProperty = container.container[container.propertyName];
                    arrayProperty.splice(propertyIndex, 1);
                    let length = arrayProperty.length;
                    if (length === 0) {
                        yield this.selectElement(parentElement, `${container.container.piLanguageConcept()}-${container.propertyName}`);
                    }
                    else if (length <= propertyIndex) {
                        yield this.selectElement(arrayProperty[propertyIndex - 1]);
                    }
                    else {
                        yield this.selectElement(arrayProperty[propertyIndex]);
                    }
                }
                else {
                    container.container[container.propertyName] = null;
                    yield this.selectElement(container.container, (container.container.piIsBinaryExpression() ? `PiBinaryExpression-${container.propertyName}` : `${container.container.piLanguageConcept()}-${container.propertyName}`));
                }
            }
        });
    }
    selectFirstEditableChildBox() {
        return __awaiter(this, void 0, void 0, function* () {
            const first = this.selectedBox.firstEditableChild;
            LOGGER.info(this, "selectFirstEditableChildBox: " + first.kind + " elem: " + first.element + "  role " + first.role);
            if (first) {
                LOGGER.info(this, "selectFirstEditableChildBox: first found with role " + first.role);
                this.selectBox(first);
            }
        });
    }
    set rootElement(exp) {
        this._rootElement = exp;
    }
    get rootElement() {
        return this._rootElement;
    }
}
__decorate([
    mobx_1.observable,
    __metadata("design:type", Object)
], PiEditor.prototype, "_rootElement", void 0);
__decorate([
    mobx_1.observable,
    __metadata("design:type", Box_1.Box)
], PiEditor.prototype, "$selectedBox", void 0);
__decorate([
    mobx_1.computed,
    __metadata("design:type", Box_1.Box),
    __metadata("design:paramtypes", [])
], PiEditor.prototype, "rootBox", null);
__decorate([
    mobx_1.action,
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Box_1.Box]),
    __metadata("design:returntype", Promise)
], PiEditor.prototype, "deleteBox", null);
exports.PiEditor = PiEditor;
//# sourceMappingURL=PiEditor.js.map