"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 index_1 = require("../../../index");
const React = require("react");
const ReactDOM = require("react-dom");
const classNames = require("classnames");
const mobx_1 = require("mobx");
const PiUtils_1 = require("../../../util/PiUtils");
const DropdownComponent_1 = require("../dropdown/DropdownComponent");
const BehaviorUtils_1 = require("../../../util/BehaviorUtils");
const Keys = require("../../../util/Keys");
const Styles_1 = require("../styles/Styles");
const PiLogging_1 = require("../../../util/PiLogging");
const attachClickOutsideListener = require("click-outside");
const LOGGER = new PiLogging_1.PiLogger("AbstractChoiceComponent");
class AbstractChoiceComponent extends React.Component {
    constructor(props) {
        super(props);
        this.isEditing = false;
        this.text = "";
        this.selectedOptionId = "";
        this._dropdownIsOpen = false;
        this.OPEN = false;
        this.hasError = false;
        this.caretPosition = 0;
        this.element = null;
        this.setElement = (element) => {
            this.element = element;
        };
        this.dropdown = null;
        this.setDropdown = (drop) => {
            this.dropdown = drop;
        };
        this.setFocus = () => __awaiter(this, void 0, void 0, function* () {
            LOGGER.info(this, "!!!!!!!!!!!!!!!!!!!!!!!!! FOCUS");
            if (!!this.element) {
                this.element.focus();
            }
        });
        this.closeDropdown = () => {
            this.dropdownIsOpen = false;
        };
        this.handleSelected = (optionId) => {
            LOGGER.info(this, "handleSelected " + optionId);
            BehaviorUtils_1.executeBehavior(this.props.box, optionId, this.props.editor);
            this.dropdownIsOpen = false;
        };
        this.setSelectedOption = (id) => {
            this.selectedOptionId = id;
        };
        this.onClick = () => __awaiter(this, void 0, void 0, function* () {
            PiLogging_1.EVENT_LOG.info(this, "onClick");
            this.dropdownIsOpen = true;
            this.startEditing();
            if (!!this.element && this.element.innerText === this.props.box.placeholder) {
                this.setCaretToMostLeft();
            }
            this.props.box.caretPosition = this.getCaretPosition();
        });
        this.onBlur = (e) => __awaiter(this, void 0, void 0, function* () {
            PiLogging_1.EVENT_LOG.info(this, "onBlur: " + e.type);
            this.stopEditing();
            e.stopPropagation();
        });
        this.onInput = (e) => __awaiter(this, void 0, void 0, function* () {
            e.persist();
            PiLogging_1.EVENT_LOG.info(this, "onInput [" + this.element.innerText + "]");
            this.props.box.caretPosition = this.getCaretPosition();
            this.caretPosition = this.props.box.caretPosition;
            const aliasResult = yield this.handleStringInput(this.element.innerText);
            if (aliasResult === BehaviorUtils_1.BehaviorExecutionResult.NO_MATCH || aliasResult === BehaviorUtils_1.BehaviorExecutionResult.PARTIAL_MATCH) {
                this.dropdownIsOpen = true;
            }
            if (this.props.box.deleteWhenEmpty1() && this.element.innerText.length === 0) {
                this.props.editor.deleteBox(this.props.box);
            }
        });
        this.onKeyDown = (e) => __awaiter(this, void 0, void 0, function* () {
            PiLogging_1.EVENT_LOG.info(this, "onKeyDown: " + e.key + " for role " + this.props.box.role);
            if (Keys.isPrintable(e) && !e.ctrlKey) {
                LOGGER.info(this, "is printable");
                e.stopPropagation();
                return;
            }
            if (e.keyCode === Keys.DELETE) {
                e.stopPropagation();
            }
            if (!this.shouldPropagate(e)) {
                e.stopPropagation();
            }
            if (this.dropdownIsOpen && this.dropdown) {
                LOGGER.info(this, "Forwarding event to dropdown component");
                const x = this.dropdown.handleKeyDown(e);
                LOGGER.info(this, "handled result: " + x);
                if (x) {
                    e.preventDefault();
                    e.stopPropagation();
                    this.setCaretToMostRight();
                    this.props.box.caretPosition = this.getCaretPosition();
                    this.caretPosition = this.props.box.caretPosition;
                    LOGGER.info(this, "caret " + this.props.box.caretPosition);
                }
                switch (e.keyCode) {
                    case Keys.ENTER:
                        e.preventDefault();
                        break;
                }
            }
            else {
                switch (e.keyCode) {
                    case Keys.ENTER:
                        e.preventDefault();
                        const handled = false;
                        if (index_1.isAliasBox(this.props.box)) {
                            PiUtils_1.PiUtils.handleKeyboardShortcut(Keys.reactToKey(e), this.props.box, this.props.editor);
                            e.stopPropagation();
                        }
                        break;
                    case Keys.SPACEBAR:
                        LOGGER.info(this, "onKeyDown Keys.SPACEBAR");
                        if (e.ctrlKey) {
                            this.dropdownIsOpen = true;
                        }
                        break;
                }
            }
        });
        this.onKeyPress = (e) => {
            PiLogging_1.EVENT_LOG.info(this, "onKeyPress: " + e.key + "  " + this.props.box.actualWidth);
            this.props.box.caretPosition = this.getCaretPosition() + 1;
            e.stopPropagation();
        };
        this.subscribeToBoxEvents = (box) => {
            box.setCaret = this.setCaret;
            box.triggerKeyPressEvent = this.triggerKeyPressEvent;
            box.triggerKeyDownEvent = this.triggerKeyDownEvent;
            box.setSetFocus(this.setFocus);
        };
        this.triggerKeyPressEvent = (key) => __awaiter(this, void 0, void 0, function* () {
            LOGGER.info(this, "triggerKeyPressEvent " + key);
            const aliasResult = yield this.handleStringInput(key);
            if (aliasResult !== BehaviorUtils_1.BehaviorExecutionResult.EXECUTED) {
                if (this.element) {
                    this.element.innerText = key;
                    this.setCaretPosition(this.element.innerText.length);
                    this.dropdownIsOpen = true;
                }
            }
        });
        this.triggerKeyDownEvent = (key) => __awaiter(this, void 0, void 0, function* () {
            LOGGER.info(this, "triggerKeyDownEvent: " + key.keyCode);
            const result = yield PiUtils_1.PiUtils.handleKeyboardShortcut(key, this.props.box, this.props.editor);
        });
        this.handleStringInput = (s) => __awaiter(this, void 0, void 0, function* () {
            LOGGER.info(this, "handleStringInput for box " + this.props.box.role);
            const aliasResult = yield BehaviorUtils_1.executeBehavior(this.props.box, s, this.props.editor);
            switch (aliasResult) {
                case BehaviorUtils_1.BehaviorExecutionResult.EXECUTED:
                    if (this.element) {
                        this.element.innerText = "";
                    }
                    this.dropdownIsOpen = false;
                    this.hasError = false;
                    break;
                case BehaviorUtils_1.BehaviorExecutionResult.PARTIAL_MATCH:
                    LOGGER.info(this, "PARTIAL_MATCH");
                    this.hasError = false;
                    break;
                case BehaviorUtils_1.BehaviorExecutionResult.NO_MATCH:
                    LOGGER.info(this, "NO MATCH");
                    this.hasError = true;
                    break;
            }
            return aliasResult;
        });
        this.setCaret = (caret) => {
            LOGGER.info(this, "setCaret " + caret);
            switch (caret.position) {
                case BehaviorUtils_1.PiCaretPosition.RIGHT_MOST:
                    this.setCaretToMostRight();
                    break;
                case BehaviorUtils_1.PiCaretPosition.LEFT_MOST:
                    this.setCaretToMostLeft();
                    break;
                case BehaviorUtils_1.PiCaretPosition.INDEX:
                    this.setCaretPosition(caret.index);
                    break;
                case BehaviorUtils_1.PiCaretPosition.UNSPECIFIED:
                    break;
            }
        };
        this.setCaretToMostLeft = () => {
            this.startEditing();
            this.setCaretPosition(0);
        };
        this.setCaretToMostRight = () => {
            LOGGER.info(this, "setCaretToMostRight");
            this.startEditing();
            if (!this.element) {
                LOGGER.info(this, "setCaretToMostRight: empty element");
                return;
            }
            if (this.element.innerText === this.props.box.placeholder) {
                LOGGER.info(this, "setCaretToMostRight: set left for placeholder");
                this.setCaretPosition(0);
            }
            else {
                LOGGER.info(this, "setCaretToMostRight: position " + this.element.innerText.length);
                this.setCaretPosition(this.element.innerText.length);
            }
        };
        this.startEditing = () => {
            if (this.isEditing) {
                return;
            }
            this.isEditing = true;
        };
        this.stopEditing = () => {
            this.isEditing = false;
            this.props.box.caretPosition = -1;
            if (!!this.element) {
                this.element.innerText = "";
            }
            this.dropdownIsOpen = false;
            this.hasError = false;
            this.clearSelection();
        };
        this.setCaretPosition = (position) => {
            if (position === -1) {
                return;
            }
            this.clearSelection();
            const range = document.createRange();
            try {
                if (!!this.element && !!this.element.childNodes && this.element.childNodes[0]) {
                    range.setStart(this.element.childNodes[0], Math.min(position, this.element.innerText.length));
                }
                else {
                    if (!!this.element) {
                        range.setStart(this.element, position);
                    }
                }
            }
            catch (e) {
                console.log(e.toString());
            }
            range.collapse(true);
            window.getSelection().addRange(range);
        };
        this.setCaretPosition2 = (position) => {
            if (position === -1) {
                return;
            }
            if (!this.element.innerText) {
                return;
            }
            if (position > this.element.innerText.length) {
                console.log("ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR; ");
                console.log("TExtComponent.setCaretPosition >length: " + position + " > " + this.element.innerText.length);
            }
            this.clearSelection();
            const range = document.createRange();
            if (this.element.childNodes[0]) {
                range.setStart(this.element.childNodes[0], position);
            }
            else {
                range.setStart(this.element, position);
            }
            range.collapse(true);
            window.getSelection().addRange(range);
            this.caretPosition = position;
            this.props.box.caretPosition = position;
        };
        this.clearSelection = () => {
            window.getSelection().removeAllRanges();
        };
        this.getCaretPosition = () => {
            return window.getSelection().focusOffset;
        };
        this.shouldPropagate = (e) => {
            if (index_1.isMetaKey(e)) {
                if (e.keyCode === Keys.ARROW_UP || e.keyCode === Keys.ARROW_DOWN || e.keyCode === Keys.TAB) {
                    return true;
                }
            }
            if (e.keyCode === Keys.ENTER || e.keyCode === Keys.TAB) {
                return true;
            }
            if (e.keyCode === Keys.ARROW_UP || e.keyCode === Keys.ARROW_DOWN) {
                return true;
            }
            const caretPosition = this.getCaretPosition();
            if (e.keyCode === Keys.ARROW_LEFT || e.keyCode === Keys.BACKSPACE) {
                return caretPosition <= 0;
            }
            else if (e.keyCode === Keys.ARROW_RIGHT || e.keyCode === Keys.DELETE) {
                return caretPosition >= this.element.innerText.length;
            }
            else {
                return false;
            }
        };
        this.text = "";
        this.subscribeToBoxEvents(props.box);
    }
    set dropdownIsOpen(v) {
        this._dropdownIsOpen = v;
        this.OPEN = v;
        this.forceUpdate();
    }
    get dropdownIsOpen() {
        return this._dropdownIsOpen;
    }
    componentWillReceiveProps(nextProps) {
        this.subscribeToBoxEvents(nextProps.box);
    }
    componentDidMount() {
        this.element.setAttribute("contentEditable", "true");
        const node = ReactDOM.findDOMNode(this);
        this.disposeClickOutsideListener = attachClickOutsideListener(node, this.closeDropdown);
        this.subscribeToBoxEvents(this.props.box);
        this.checkSelected();
    }
    checkSelected() {
        const selectedBox = this.props.editor.selectedBox;
        const isSelected = !!this.props.box && !!selectedBox ? this.props.box.id === selectedBox.id : false;
        if (isSelected) {
            LOGGER.info(this, "checkSelected SELECTED position " + this.caretPosition);
            this.element.focus();
            this.setCaretPosition(this.caretPosition);
        }
        else {
        }
    }
    componentWillUnmount() {
        if (this.disposeClickOutsideListener) {
            this.disposeClickOutsideListener();
            this.disposeClickOutsideListener = null;
        }
    }
    componentDidUpdate() {
        this.props.box.setSetFocus(this.setFocus);
        this.checkSelected();
    }
    get myStyleClasses() {
        const box = this.props.box;
        let styleClasses;
        if (this.text === box.placeholder) {
            styleClasses = classNames(Styles_1.STYLES.alias, box.style);
        }
        else {
            styleClasses = classNames(box.style, Styles_1.STYLES.aliasSelected);
        }
        if (this.hasError) {
            styleClasses = classNames(Styles_1.STYLES.incorrect, styleClasses);
        }
        return styleClasses;
    }
    render() {
        PiLogging_1.RENDER_LOG.info(this, "AbstractChoiceComponent");
        const box = this.props.box;
        return (React.createElement("div", { id: this.props.box.id + "maindiv", onBlur: this.onBlur },
            React.createElement("div", { id: this.props.box.id + "textdiv", className: this.myStyleClasses, ref: this.setElement, tabIndex: 0, onInput: this.onInput, onKeyDown: this.onKeyDown, onKeyPress: this.onKeyPress, onClick: this.onClick, spellCheck: false, "data-placeholdertext": box.placeholder }, this.text),
            this.OPEN && (React.createElement(DropdownComponent_1.DropdownComponent, { handleSelectedOption: this.handleSelected, selectedOptionId: this.selectedOptionId, setSelectedOption: this.setSelectedOption, getOptions: this.getOptions, styleClasses: [], ref: this.setDropdown }))));
    }
    setCaret3(position) {
        const el = this.element;
        const range = document.createRange();
        const sel = window.getSelection();
        range.setStart(el.childNodes[0], position);
        range.collapse(true);
        sel.removeAllRanges();
        sel.addRange(range);
    }
}
__decorate([
    mobx_1.observable,
    __metadata("design:type", String)
], AbstractChoiceComponent.prototype, "text", void 0);
__decorate([
    mobx_1.observable,
    __metadata("design:type", Object)
], AbstractChoiceComponent.prototype, "selectedOptionId", void 0);
__decorate([
    mobx_1.observable,
    __metadata("design:type", Boolean)
], AbstractChoiceComponent.prototype, "_dropdownIsOpen", void 0);
__decorate([
    mobx_1.observable,
    __metadata("design:type", Boolean)
], AbstractChoiceComponent.prototype, "OPEN", void 0);
__decorate([
    mobx_1.observable,
    __metadata("design:type", Boolean)
], AbstractChoiceComponent.prototype, "hasError", void 0);
__decorate([
    mobx_1.computed,
    __metadata("design:type", String),
    __metadata("design:paramtypes", [])
], AbstractChoiceComponent.prototype, "myStyleClasses", null);
__decorate([
    mobx_1.action,
    __metadata("design:type", Object)
], AbstractChoiceComponent.prototype, "handleStringInput", void 0);
exports.AbstractChoiceComponent = AbstractChoiceComponent;
//# sourceMappingURL=AbstractChoiceComponent.js.map