"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);
};
Object.defineProperty(exports, "__esModule", { value: true });
const mobx_1 = require("mobx");
const PiModel_1 = require("../language/PiModel");
const PiLogging_1 = require("./PiLogging");
const Box_1 = require("../editor/boxes/Box");
const PiModel_2 = require("../language/PiModel");
const PiEditor_1 = require("../editor/PiEditor");
const PiUtils_1 = require("./PiUtils");
exports.BEFORE_BINARY_OPERATOR = "binary-pre";
exports.AFTER_BINARY_OPERATOR = "binary-post";
exports.LEFT_MOST = "exp-left";
exports.RIGHT_MOST = "exp-right";
exports.EXPRESSION_PLACEHOLDER = "expression-placeholder";
exports.BINARY_OPERATOR = "binary-operator";
exports.BINARY_EXPRESSION = "binary-expression";
exports.EXPRESSION = "expression";
exports.EXPRESSION_SYMBOL = "symbol";
const LOGGER = new PiLogging_1.PiLogger("BalanceTree");
class BTree {
    isRightMostChild(exp) {
        PiUtils_1.PiUtils.CHECK(!exp.piIsBinaryExpression(), "isRightMostChild expects a non-binary expression");
        let currentExp = exp;
        let expContainer = currentExp.piContainer();
        while (expContainer && PiModel_2.isPiBinaryExpression(expContainer.container)) {
            if (expContainer.container.piRight() === currentExp) {
                currentExp = expContainer.container;
                expContainer = expContainer.container.piContainer();
            }
            else {
                return false;
            }
        }
        return true;
    }
    isLeftMostChild(exp) {
        PiUtils_1.PiUtils.CHECK(!exp.piIsBinaryExpression(), "isLeftMostChild expects a non-binary expression");
        let currentExp = exp;
        let expContainer = currentExp.piContainer();
        while (expContainer && PiModel_2.isPiBinaryExpression(expContainer.container)) {
            if (expContainer.container.piLeft() === currentExp) {
                currentExp = expContainer.container;
                expContainer = expContainer.container.piContainer();
            }
            else {
                return false;
            }
        }
        return true;
    }
    setRightExpression(exp, newExp, editor) {
        const right = exp.piRight();
        exp.piSetRight(newExp);
        newExp.piSetRight(right);
        this.balanceTree(newExp, editor);
    }
    setLeftExpression(exp, newExp, editor) {
        const left = exp.piLeft();
        exp.piSetLeft(newExp);
        newExp.piSetLeft(left);
        this.balanceTree(newExp, editor);
    }
    insertBinaryExpression(newBinExp, box, editor) {
        LOGGER.log("insertBinaryExpression for " + box.element);
        let selectedElement = null;
        PiUtils_1.PiUtils.CHECK(PiModel_1.isPiExpression(box.element), "insertBinaryExpression: current element should be a PiExpression, but it isn't");
        const exp = box.element;
        switch (box.role) {
            case exports.LEFT_MOST:
                selectedElement = { element: newBinExp, boxRoleToSelect: "PiBinaryExpression-left" };
                PiUtils_1.PiUtils.replaceExpression(exp, newBinExp, editor);
                newBinExp.piSetRight(exp);
                this.balanceTree(newBinExp, editor);
                break;
            case exports.RIGHT_MOST:
                selectedElement = { element: newBinExp, boxRoleToSelect: "PiBinaryExpression-right" };
                PiUtils_1.PiUtils.replaceExpression(exp, newBinExp, editor);
                newBinExp.piSetLeft(exp);
                this.balanceTree(newBinExp, editor);
                break;
            case exports.BEFORE_BINARY_OPERATOR:
                PiUtils_1.PiUtils.CHECK(PiModel_2.isPiBinaryExpression(exp), "Operator alias only allowed in binary operator");
                selectedElement = { element: newBinExp, boxRoleToSelect: "PiBinaryExpression-right" };
                const left = exp.piLeft();
                exp.piSetLeft(newBinExp);
                newBinExp.piSetLeft(left);
                this.balanceTree(newBinExp, editor);
                break;
            case exports.AFTER_BINARY_OPERATOR:
                PiUtils_1.PiUtils.CHECK(PiModel_2.isPiBinaryExpression(exp), "Operator alias only allowed in binary operator");
                selectedElement = { element: newBinExp, boxRoleToSelect: "PiBinaryExpression-left" };
                const right = exp.piRight();
                exp.piSetRight(newBinExp);
                newBinExp.piSetRight(right);
                this.balanceTree(newBinExp, editor);
                break;
            case exports.EXPRESSION_PLACEHOLDER:
                PiUtils_1.PiUtils.replaceExpression(exp, newBinExp, editor);
                selectedElement = { element: newBinExp, boxRoleToSelect: "PiBinaryExpression-left" };
                this.balanceTree(newBinExp, editor);
                break;
            default:
                throw Error("Cannot insert binary expression");
        }
        return selectedElement;
    }
    balanceTree(exp, editor) {
        const expContainer = exp.piContainer();
        const left = exp.piLeft();
        if (PiModel_2.isPiBinaryExpression(left)) {
            LOGGER.log("Rule 1: prio parent <= prio left");
            if (exp.piPriority() > left.piPriority()) {
                const leftRight = left.piRight();
                left.piSetRight(exp);
                exp.piSetLeft(leftRight);
                PiUtils_1.PiUtils.setContainer(left, expContainer, editor);
                this.balanceTree(exp, editor);
                return;
            }
        }
        const right = exp.piRight();
        if (PiModel_2.isPiBinaryExpression(right)) {
            LOGGER.log("Rule 2: prio parent < prio right");
            if (exp.piPriority() >= right.piPriority()) {
                const rightLeft = right.piLeft();
                right.piSetLeft(exp);
                exp.piSetRight(rightLeft);
                PiUtils_1.PiUtils.setContainer(right, expContainer, editor);
                this.balanceTree(exp, editor);
                return;
            }
        }
        if (expContainer && PiModel_2.isPiBinaryExpression(expContainer.container)) {
            const parent = expContainer.container;
            if (parent.piLeft() === exp) {
                LOGGER.log("Rule 3: exp is a left child");
                if (exp.piPriority() < parent.piPriority()) {
                    const parentProContainer = parent.piContainer();
                    const expRight = exp.piRight();
                    exp.piSetRight(parent);
                    parent.piSetLeft(expRight);
                    PiUtils_1.PiUtils.setContainer(exp, parentProContainer, editor);
                    this.balanceTree(exp, editor);
                    return;
                }
            }
            else {
                PiUtils_1.PiUtils.CHECK(parent.piRight() === exp, "should be the right child");
                LOGGER.log("Rule 4: exp is a right child, parent is " + parent);
                if (exp.piPriority() <= parent.piPriority()) {
                    const parentProContainer = parent.piContainer();
                    const expLeft = exp.piLeft();
                    exp.piSetLeft(parent);
                    parent.piSetRight(expLeft);
                    PiUtils_1.PiUtils.setContainer(exp, parentProContainer, editor);
                    this.balanceTree(exp, editor);
                    return;
                }
            }
        }
    }
}
__decorate([
    mobx_1.action,
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Object, PiEditor_1.PiEditor]),
    __metadata("design:returntype", void 0)
], BTree.prototype, "setRightExpression", null);
__decorate([
    mobx_1.action,
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Object, PiEditor_1.PiEditor]),
    __metadata("design:returntype", void 0)
], BTree.prototype, "setLeftExpression", null);
__decorate([
    mobx_1.action,
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Box_1.Box, PiEditor_1.PiEditor]),
    __metadata("design:returntype", Object)
], BTree.prototype, "insertBinaryExpression", null);
exports.BTREE = new BTree();
//# sourceMappingURL=BalanceTreeUtils.js.map