'use strict';

const UIValue = Symbol('Displayed value in UI');
const UISelection = Symbol('Displayed selection in UI');
const InitialValue = Symbol('Initial value to compare on blur');
function isUIValue(value) {
    return typeof value === 'object' && UIValue in value;
}
function isUISelectionStart(start) {
    return !!start && typeof start === 'object' && UISelection in start;
}
function setUIValue(element, value) {
    if (element[InitialValue] === undefined) {
        element[InitialValue] = element.value;
    }
    element[UIValue] = value;
    // eslint-disable-next-line no-new-wrappers
    element.value = Object.assign(new String(value), {
        [UIValue]: true
    });
}
function getUIValue(element) {
    return element[UIValue] === undefined ? element.value : String(element[UIValue]);
}
/** Flag the IDL value as clean. This does not change the value.*/ function setUIValueClean(element) {
    element[UIValue] = undefined;
}
function clearInitialValue(element) {
    element[InitialValue] = undefined;
}
function getInitialValue(element) {
    return element[InitialValue];
}
function setUISelectionRaw(element, selection) {
    element[UISelection] = selection;
}
function setUISelection(element, { focusOffset: focusOffsetParam, anchorOffset: anchorOffsetParam = focusOffsetParam }, mode = 'replace') {
    const valueLength = getUIValue(element).length;
    const sanitizeOffset = (o)=>Math.max(0, Math.min(valueLength, o));
    const anchorOffset = mode === 'replace' || element[UISelection] === undefined ? sanitizeOffset(anchorOffsetParam) : element[UISelection].anchorOffset;
    const focusOffset = sanitizeOffset(focusOffsetParam);
    const startOffset = Math.min(anchorOffset, focusOffset);
    const endOffset = Math.max(anchorOffset, focusOffset);
    element[UISelection] = {
        anchorOffset,
        focusOffset
    };
    if (element.selectionStart === startOffset && element.selectionEnd === endOffset) {
        return;
    }
    // eslint-disable-next-line no-new-wrappers
    const startObj = Object.assign(new Number(startOffset), {
        [UISelection]: true
    });
    try {
        element.setSelectionRange(startObj, endOffset);
    } catch  {
    // DOMException for invalid state is expected when calling this
    // on an element without support for setSelectionRange
    }
}
function getUISelection(element) {
    var _element_selectionStart, _element_selectionEnd, _element_UISelection;
    const sel = (_element_UISelection = element[UISelection]) !== null && _element_UISelection !== undefined ? _element_UISelection : {
        anchorOffset: (_element_selectionStart = element.selectionStart) !== null && _element_selectionStart !== undefined ? _element_selectionStart : 0,
        focusOffset: (_element_selectionEnd = element.selectionEnd) !== null && _element_selectionEnd !== undefined ? _element_selectionEnd : 0
    };
    return {
        ...sel,
        startOffset: Math.min(sel.anchorOffset, sel.focusOffset),
        endOffset: Math.max(sel.anchorOffset, sel.focusOffset)
    };
}
function hasUISelection(element) {
    return !!element[UISelection];
}
/** Flag the IDL selection as clean. This does not change the selection. */ function setUISelectionClean(element) {
    element[UISelection] = undefined;
}

exports.clearInitialValue = clearInitialValue;
exports.getInitialValue = getInitialValue;
exports.getUISelection = getUISelection;
exports.getUIValue = getUIValue;
exports.hasUISelection = hasUISelection;
exports.isUISelectionStart = isUISelectionStart;
exports.isUIValue = isUIValue;
exports.setUISelection = setUISelection;
exports.setUISelectionClean = setUISelectionClean;
exports.setUISelectionRaw = setUISelectionRaw;
exports.setUIValue = setUIValue;
exports.setUIValueClean = setUIValueClean;
