import { MaskBlockList } from "./blocks";
export class AbstractMask {
    constructor(blocks = []) {
        this.inputMode = 'text';
        this.locale = 'de-CH';
        this.blocks = new MaskBlockList(blocks);
    }
    /**
     * ABSTRACT EVENT METHODS
     * ------------------------------------------------------
     */
    onLocaleChange(context, _oldLocale, oldBlocks) {
        if (context.target) {
            const value = context.value;
            const chars = value.split('');
            for (let index = 0; index < chars.length; index++) {
                const char = chars[index];
                const newBlock = this.blocks.findByIndex(index);
                const oldBlock = oldBlocks.findByIndex(index);
                if (newBlock && oldBlock) {
                    if (newBlock.isSeparator) {
                        chars[index] = newBlock.mask;
                    }
                    else if (char === oldBlock.mask) {
                        chars[index] = newBlock.mask;
                    }
                }
            }
            context.value = chars.join('');
        }
    }
    onFocus(_context) {
        // empty placeholder
    }
    onBlur(_context) {
        // empty placeholder
    }
    onChange(context) {
        context.submit('change', this.onParseValue(context.value));
    }
    onNavigationDown(_context, _block, _index) {
        // empty placeholder
    }
    onSelectAll(_context, _block, _index) {
        // empty placeholder
    }
    onPaste(context, _block, _index) {
        const value = context.clipboardData || '';
        context.value = value;
        context.position.toEnd();
    }
    onBlockChange(context, block, index) {
        context.setChar();
        context.position.next();
        const nextBlock = this.blocks.list[index + 1];
        if (context.position.value === block.to && nextBlock && nextBlock.isSeparator) {
            context.position.next();
        }
    }
    onBackspaceDown(context, block, index) {
        context.position.previous();
        if (!block.isSeparator) {
            context.setChar(block.mask);
            const previousBlock = this.blocks.list[index - 1];
            if (context.position.value === block.from && previousBlock && previousBlock.isSeparator) {
                context.position.previous();
            }
        }
    }
    onDeleteDown(context, block, index) {
        context.setChar(block.mask);
        context.position.next();
        const nextBlock = this.blocks.list[index + 1];
        if (context.position.value === block.to && nextBlock && nextBlock.isSeparator) {
            context.position.next();
        }
    }
    onValueChanged(context) {
        const formattedValue = this.onFormatValue(context.newValue);
        const inputValue = context.focused && formattedValue === '' ? this.blocks.getPlaceholderMask() : formattedValue;
        context.value = inputValue;
        context.position.toEnd();
    }
    onParseValue(inputValue, options = { allowInvalidValue: false }) {
        if (inputValue) {
            return inputValue.trim();
        }
        return inputValue || '';
    }
    onFormatValue(rawValue) {
        if (rawValue) {
            return rawValue.trim();
        }
        return rawValue || '';
    }
    /**
     * UTILS
     * ------------------------------------------------------
     */
    toParsedValue(inputValue) {
        return this.onParseValue(inputValue);
    }
    toFormattedValue(inputValue) {
        return this.onFormatValue(inputValue);
    }
    /**
     * FIRE EVENT METHODS
     * ------------------------------------------------------
     */
    fireI18nChange(context) {
        const oldBlocks = this.blocks.clone();
        const oldLocale = `${context.locale}`;
        this.locale = context.locale;
        this.blocks.list.forEach(block => block.onI18nChange(context.locale));
        this.onLocaleChange(context, oldLocale, oldBlocks);
    }
    fireValueChanged(context) {
        if (context.didValueChange) {
            this.onValueChanged(context);
        }
    }
    firePaste(context) {
        const index = this.blocks.getBlockIndexFromPosition(context.position.value);
        if (index !== undefined) {
            const currentBlock = this.blocks.list[index];
            this.onPaste(context, currentBlock, index);
            this.onChange(context);
        }
    }
    fireClick(context) {
        const maskPlaceholder = this.blocks.getPlaceholderMask();
        if (maskPlaceholder === context.value) {
            context.position.toStart();
        }
    }
    fireFocus(context) {
        if (context.target && context.isValueEmpty()) {
            this.resetInputValueWithMask(context);
        }
        this.onFocus(context);
    }
    fireBlur(context) {
        if (context.target) {
            if (this.isValueEmptyMask(context)) {
                this.emptyInputValue(context);
            }
            else {
                this.onBlur(context);
                context.submit('blur', this.onParseValue(context.value, { allowInvalidValue: context.component.allowInvalidValue }));
            }
        }
    }
    fireKeyDown(context) {
        const position = context.isBackspaceKey ? Math.max(0, context.position.value - 1) : context.position.value;
        const index = this.blocks.getBlockIndexFromPosition(position);
        // prevent of adding more chars than possible
        if (position >= this.blocks.lastPosition && !context.isNavigationKey && !context.isSelectAllCommand) {
            context.preventDefault();
            context.stopPropagation();
            return;
        }
        if (index !== undefined && !context.position.isRangeSelection) {
            const currentBlock = this.blocks.list[index];
            //
            // Navigation keys like arrows and tabs
            if (context.isNavigationKey) {
                this.onNavigationDown(context, currentBlock, index);
                //
                // Select the whole value of the input
            }
            else if (context.isSelectAllCommand) {
                this.onSelectAll(context, currentBlock, index);
                //
                // On copy a the value
            }
            else if (context.isCopyCommand) {
                // this.onCopy(context, currentBlock, index)
                //
                // On paste a new value into
            }
            else if (context.isPasteCommand) {
                //
                // On backspace to remove a previous char
            }
            else if (context.isBackspaceKey) {
                context.preventDefault();
                this.onBackspaceDown(context, currentBlock, index);
                //
                // On delete to remove a next char
            }
            else if (context.isDeleteKey) {
                context.preventDefault();
                this.onDeleteDown(context, currentBlock, index);
                //
                // On double space key hit only happens on mac
            }
            else if (context.isWhiteSpaceKey) {
                context.preventDefault();
                const lastWrittenChar = context.value[context.position.value];
                if (lastWrittenChar === '.') {
                    context.stopPropagation();
                    const value = context.value;
                    context.value = value.substring(0, context.position.value) + '_' + value.substring(context.position.value + 1);
                }
                //
                // On a normal key down with the allowed key hits
            }
            else if (currentBlock.verifyAllowedKeyHits(context.key)) {
                context.preventDefault();
                this.onBlockChange(context, currentBlock, index);
                //
                // if the user hits the next separator we jump to the next user block
            }
            else if (this.blocks.verifyCallOfNextSeparator(context.key, index)) {
                context.preventDefault();
                const activeBlock = this.blocks.list[index];
                if (context.position.value > activeBlock.from) {
                    const nextBlock = this.blocks.list[index + 1];
                    const value = context.value;
                    const blockValue = currentBlock.getValueOfTheBlock(value);
                    const newBlockValue = currentBlock.format(blockValue);
                    context.value = value.substring(0, currentBlock.from) + newBlockValue + value.substring(currentBlock.to);
                    context.position.value = nextBlock.to;
                }
            }
            //
            // format all blocks where the cursor is not active
            const newIndex = this.blocks.getBlockIndexFromPosition(context.position.value);
            if (newIndex && !context.isBackspaceKey) {
                const newFormattedValue = this.blocks.formatBlocks(context.value, newIndex);
                const position = context.position.value;
                context.value = newFormattedValue;
                context.position.value = position;
            }
            //
            // hit a range of chars
        }
        else {
            if (!context.isTabKey) {
                context.preventDefault();
            }
            if (context.isBackspaceKey || context.isDeleteKey) {
                this.resetInputValueWithMask(context);
            }
            else if (this.blocks.list[0].verifyAllowedKeyHits(context.key)) {
                this.onBlockChange(context, this.blocks.list[0], 0);
            }
        }
    }
    /**
     * PROTECTED HELPER METHODS
     * ------------------------------------------------------
     */
    resetInputValueWithMask(context) {
        context.value = this.blocks.getPlaceholderMask();
        context.position.toStart();
    }
    isValueEmptyMask(context) {
        const placeholder = this.blocks.getPlaceholderMask();
        return placeholder === context.value;
    }
    emptyInputValue(context) {
        context.value = '';
        context.submit('blur', context.value);
    }
}
