import * as React from 'react';
import { classes } from 'typestyle';
import { EN_US } from '@lumino/keyboard';
import { InputBoxHiddenStyle, InputBoxNewStyle, InputBoxStyle, InputSelectedTextStyle, InputStyle, InputTextStyle, InputUnavailableStyle, InputWaitingStyle, SubmitConflictStyle, SubmitNonFunctionalStyle, SubmitStyle } from '../componentStyle/ShortcutInputStyle';
/** Object for shortcut items */
export class ShortcutObject {
    constructor() {
        this.commandName = '';
        this.label = '';
        this.keys = {};
        this.source = '';
        this.selector = '';
        this.category = '';
        this.id = '';
        this.numberOfShortcuts = 0;
        this.hasConflict = false;
    }
    get(sortCriteria) {
        if (sortCriteria === 'label') {
            return this.label;
        }
        else if (sortCriteria === 'selector') {
            return this.selector;
        }
        else if (sortCriteria === 'category') {
            return this.category;
        }
        else if (sortCriteria === 'source') {
            return this.source;
        }
        else {
            return '';
        }
    }
}
/** Object for conflicting shortcut error messages */
export class ErrorObject extends ShortcutObject {
    constructor() {
        super();
        this.takenBy = new TakenByObject();
    }
}
/** Object for showing which shortcut conflicts with the new one */
export class TakenByObject {
    constructor(shortcut) {
        if (shortcut) {
            this.takenBy = shortcut;
            this.takenByKey = '';
            this.takenByLabel = shortcut.category + ': ' + shortcut.label;
            this.id = shortcut.commandName + '_' + shortcut.selector;
        }
        else {
            this.takenBy = new ShortcutObject();
            this.takenByKey = '';
            this.takenByLabel = '';
            this.id = '';
        }
    }
}
export class ShortcutInput extends React.Component {
    constructor(props) {
        super(props);
        this.handleUpdate = () => {
            let keys = this.state.keys;
            keys.push(this.state.currentChain);
            this.setState({ keys: keys });
            this.props.handleUpdate(this.props.shortcut, this.state.keys);
        };
        this.handleOverwrite = async () => {
            this.props
                .deleteShortcut(this.state.takenByObject.takenBy, this.state.takenByObject.takenByKey)
                .then(this.handleUpdate());
        };
        this.handleReplace = async () => {
            let keys = this.state.keys;
            keys.push(this.state.currentChain);
            this.props.toggleInput();
            await this.props.deleteShortcut(this.props.shortcut, this.props.shortcutId);
            this.props.handleUpdate(this.props.shortcut, keys);
        };
        /** Parse user input for chained shortcuts */
        this.parseChaining = (event, value, userInput, keys, currentChain) => {
            let key = EN_US.keyForKeydownEvent(event.nativeEvent);
            const modKeys = ['Shift', 'Control', 'Alt', 'Meta', 'Ctrl', 'Accel'];
            if (event.key === 'Backspace') {
                userInput = '';
                value = '';
                keys = [];
                currentChain = '';
                this.setState({
                    value: value,
                    userInput: userInput,
                    keys: keys,
                    currentChain: currentChain
                });
            }
            else if (event.key !== 'CapsLock') {
                const lastKey = userInput
                    .substr(userInput.lastIndexOf(' ') + 1, userInput.length)
                    .trim();
                /** if last key was not a modefier then there is a chain */
                if (modKeys.lastIndexOf(lastKey) === -1 && lastKey != '') {
                    userInput = userInput + ',';
                    keys.push(currentChain);
                    currentChain = '';
                    /** check if a modefier key was held down through chain */
                    if (event.ctrlKey && event.key != 'Control') {
                        userInput = (userInput + ' Ctrl').trim();
                        currentChain = (currentChain + ' Ctrl').trim();
                    }
                    if (event.metaKey && event.key != 'Meta') {
                        userInput = (userInput + ' Accel').trim();
                        currentChain = (currentChain + ' Accel').trim();
                    }
                    if (event.altKey && event.key != 'Alt') {
                        userInput = (userInput + ' Alt').trim();
                        currentChain = (currentChain + ' Alt').trim();
                    }
                    if (event.shiftKey && event.key != 'Shift') {
                        userInput = (userInput + ' Shift').trim();
                        currentChain = (currentChain + ' Shift').trim();
                    }
                    /** if not a modefier key, add to user input and current chain */
                    if (modKeys.lastIndexOf(event.key) === -1) {
                        userInput = (userInput + ' ' + key).trim();
                        currentChain = (currentChain + ' ' + key).trim();
                        /** if a modefier key, add to user input and current chain */
                    }
                    else {
                        if (event.key === 'Meta') {
                            userInput = (userInput + ' Accel').trim();
                            currentChain = (currentChain + ' Accel').trim();
                        }
                        else if (event.key === 'Control') {
                            userInput = (userInput + ' Ctrl').trim();
                            currentChain = (currentChain + ' Ctrl').trim();
                        }
                        else if (event.key === 'Shift') {
                            userInput = (userInput + ' Shift').trim();
                            currentChain = (currentChain + ' Shift').trim();
                        }
                        else if (event.key === 'Alt') {
                            userInput = (userInput + ' Alt').trim();
                            currentChain = (currentChain + ' Alt').trim();
                        }
                        else {
                            userInput = (userInput + ' ' + event.key).trim();
                            currentChain = (currentChain + ' ' + event.key).trim();
                        }
                    }
                    /** if not a chain, add the key to user input and current chain */
                }
                else {
                    /** if modefier key, rename */
                    if (event.key === 'Control') {
                        userInput = (userInput + ' Ctrl').trim();
                        currentChain = (currentChain + ' Ctrl').trim();
                    }
                    else if (event.key === 'Meta') {
                        userInput = (userInput + ' Accel').trim();
                        currentChain = (currentChain + ' Accel').trim();
                    }
                    else if (event.key === 'Shift') {
                        userInput = (userInput + ' Shift').trim();
                        currentChain = (currentChain + ' Shift').trim();
                    }
                    else if (event.key === 'Alt') {
                        userInput = (userInput + ' Alt').trim();
                        currentChain = (currentChain + ' Alt').trim();
                        /** if not a modefier key, add it regularly */
                    }
                    else {
                        userInput = (userInput + ' ' + key).trim();
                        currentChain = (currentChain + ' ' + key).trim();
                    }
                }
            }
            /** update state of keys and currentChain */
            this.setState({
                keys: keys,
                currentChain: currentChain
            });
            return [userInput, keys, currentChain];
        };
        /**
         * Check if shorcut being typed will work
         * (does not end with ctrl, alt, command, or shift)
         * */
        this.checkNonFunctional = (shortcut) => {
            const dontEnd = ['Ctrl', 'Alt', 'Accel', 'Shift'];
            const shortcutKeys = this.state.currentChain.split(' ');
            const last = shortcutKeys[shortcutKeys.length - 1];
            this.setState({
                isFunctional: !(dontEnd.indexOf(last) !== -1)
            });
            return dontEnd.indexOf(last) !== -1;
        };
        /** Check if shortcut being typed is already taken */
        this.checkShortcutAvailability = (userInput, keys, currentChain) => {
            /** First, check whole shortcut */
            let isAvailable = Object.keys(this.props.keyBindingsUsed).indexOf(keys.join(' ') + currentChain + '_' + this.props.shortcut.selector) === -1 || userInput === '';
            let takenByObject = new TakenByObject();
            if (isAvailable) {
                /** Next, check each piece of a chain */
                for (let binding of keys) {
                    if (Object.keys(this.props.keyBindingsUsed).indexOf(binding + '_' + this.props.shortcut.selector) !== -1 &&
                        binding !== '') {
                        isAvailable = false;
                        takenByObject = this.props.keyBindingsUsed[binding + '_' + this.props.shortcut.selector];
                        break;
                    }
                }
                /** Check current chain */
                if (isAvailable &&
                    Object.keys(this.props.keyBindingsUsed).indexOf(currentChain + '_' + this.props.shortcut.selector) !== -1 &&
                    currentChain !== '') {
                    isAvailable = false;
                    takenByObject = this.props.keyBindingsUsed[currentChain + '_' + this.props.shortcut.selector];
                }
                /** If unavailable set takenByObject */
            }
            else {
                takenByObject = this.props.keyBindingsUsed[keys.join(' ') + currentChain + '_' + this.props.shortcut.selector];
            }
            /** allow to set shortcut to what it initially was if replacing */
            if (!isAvailable) {
                if (takenByObject.takenBy.id === this.props.shortcut.id &&
                    this.props.newOrReplace === 'replace') {
                    isAvailable = true;
                    takenByObject = new TakenByObject();
                }
            }
            this.setState({ isAvailable: isAvailable });
            return takenByObject;
        };
        /** Parse and normalize user input */
        this.handleInput = (event) => {
            event.preventDefault();
            this.setState({ selected: false });
            const parsed = this.parseChaining(event, this.state.value, this.state.userInput, this.state.keys, this.state.currentChain);
            const userInput = parsed[0];
            const keys = parsed[1];
            const currentChain = parsed[2];
            const value = this.props.toSymbols(userInput);
            let takenByObject = this.checkShortcutAvailability(userInput, keys, currentChain);
            this.checkConflict(takenByObject, keys);
            this.setState({
                value: value,
                userInput: userInput,
                takenByObject: takenByObject,
                keys: keys,
                currentChain: currentChain
            }, () => this.checkNonFunctional(this.state.userInput));
        };
        this.handleBlur = (event) => {
            if (event.relatedTarget === null ||
                (event.relatedTarget.id !== 'no-blur' &&
                    event.relatedTarget.id !== 'overwrite')) {
                this.props.toggleInput();
                this.setState({
                    value: '',
                    userInput: ''
                });
                this.props.clearConflicts();
            }
        };
        this.state = {
            value: this.props.placeholder,
            userInput: '',
            isAvailable: true,
            isFunctional: this.props.newOrReplace === 'replace',
            takenByObject: new TakenByObject(),
            keys: new Array(),
            currentChain: '',
            selected: true
        };
    }
    checkConflict(takenByObject, keys) {
        if (takenByObject.id !== '' &&
            takenByObject.takenBy.id !== this.props.shortcut.id) {
            this.props.sortConflict(this.props.shortcut, takenByObject, takenByObject.takenByLabel, '');
        }
        else {
            this.props.clearConflicts();
        }
    }
    render() {
        const trans = this.props.translator.load('jupyterlab');
        let inputClassName = InputStyle;
        if (!this.state.isAvailable) {
            inputClassName = classes(inputClassName, InputUnavailableStyle);
        }
        return (React.createElement("div", { className: this.props.displayInput
                ? this.props.newOrReplace === 'new'
                    ? classes(InputBoxStyle, InputBoxNewStyle)
                    : InputBoxStyle
                : InputBoxHiddenStyle, onBlur: event => this.handleBlur(event) },
            React.createElement("div", { tabIndex: 0, id: "no-blur", className: inputClassName, onKeyDown: this.handleInput, ref: input => input && input.focus() },
                React.createElement("p", { className: this.state.selected && this.props.newOrReplace === 'replace'
                        ? classes(InputTextStyle, InputSelectedTextStyle)
                        : this.state.value === ''
                            ? classes(InputTextStyle, InputWaitingStyle)
                            : InputTextStyle }, this.state.value === ''
                    ? trans.__('press keys')
                    : this.state.value)),
            React.createElement("button", { className: !this.state.isFunctional
                    ? classes(SubmitStyle, SubmitNonFunctionalStyle)
                    : !this.state.isAvailable
                        ? classes(SubmitStyle, SubmitConflictStyle)
                        : classes(SubmitStyle), id: 'no-blur', disabled: !this.state.isAvailable || !this.state.isFunctional, onClick: () => {
                    if (this.props.newOrReplace === 'new') {
                        this.handleUpdate();
                        this.setState({
                            value: '',
                            keys: [],
                            currentChain: ''
                        });
                        this.props.toggleInput();
                    }
                    else {
                        /** don't replace if field has not been edited */
                        if (this.state.selected) {
                            this.props.toggleInput();
                            this.setState({
                                value: '',
                                userInput: ''
                            });
                            this.props.clearConflicts();
                        }
                        else {
                            void this.handleReplace();
                        }
                    }
                } }),
            !this.state.isAvailable && (React.createElement("button", { hidden: true, id: "overwrite", onClick: () => {
                    void this.handleOverwrite();
                    this.props.clearConflicts();
                    this.props.toggleInput();
                } }, trans.__('Overwrite')))));
    }
}
//# sourceMappingURL=ShortcutInput.js.map