var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
import { isNullOrUndefined, isUndefined } from '@syncfusion/ej2-base';
import { WCharacterFormat } from '../index';
import { defaultFont } from '../../index';
import { HelperMethods } from '../editor/editor-helper';
import { CharacterRangeType, FontScriptType } from '../../index';
/**
 * @private
 */
var TextHelper = /** @class */ (function () {
    function TextHelper(documentHelper) {
        this.paragraphMarkInfo = {};
        this._position = 0;
        this.documentHelper = documentHelper;
        if (!isNullOrUndefined(documentHelper)) {
            this.context = documentHelper.containerContext;
        }
    }
    Object.defineProperty(TextHelper.prototype, "position", {
        /**
         * @private
         * Current position of the fulltext
         */
        get: function () {
            return this._position;
        },
        set: function (value) {
            this._position = value;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(TextHelper.prototype, "paragraphMark", {
        get: function () {
            return '¶';
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(TextHelper.prototype, "lineBreakMark", {
        get: function () {
            return '↲';
        },
        enumerable: true,
        configurable: true
    });
    TextHelper.prototype.getEnSpaceCharacter = function () {
        return String.fromCharCode(8194);
    };
    TextHelper.prototype.repeatChar = function (char, count) {
        var text = '';
        for (var i = 0; i < count; i++) {
            text += char;
        }
        return text;
    };
    TextHelper.prototype.getParagraphMarkWidth = function (characterFormat) {
        return this.getParagraphMarkSize(characterFormat).Width;
    };
    TextHelper.prototype.getParagraphMarkSize = function (characterFormat) {
        var format = this.getFormatText(characterFormat);
        if (this.paragraphMarkInfo["" + format]) {
            return this.paragraphMarkInfo["" + format];
        }
        // Gets the text element's width;
        var width = this.getWidth(this.paragraphMark, characterFormat);
        // Calculate the text element's height and baseline offset.
        var textHelper = this.getHeight(characterFormat);
        var textSizeInfo = {
            'Width': width, 'Height': textHelper.Height, 'BaselineOffset': textHelper.BaselineOffset
        };
        if (characterFormat.hidden) {
            return textSizeInfo;
        }
        return this.paragraphMarkInfo["" + format] = textSizeInfo;
    };
    TextHelper.prototype.getTextSize = function (elementBox, characterFormat) {
        // Gets the text element's width;
        var textTrimEndWidth = 0;
        var isRTL = characterFormat.bidi || this.isRTLText(elementBox.text);
        var text = this.setText(elementBox.text, isRTL, characterFormat.bdo);
        if (text === '\r') {
            text = String.fromCharCode(182);
        }
        var nextElement = elementBox.nextElement;
        if (nextElement && elementBox.scriptType !== FontScriptType.Hebrew &&
            this.documentHelper.render.checkFormatToCombineText(elementBox.characterFormat, nextElement.characterFormat)
            && !HelperMethods.startsWith(elementBox.text, ' ') && !HelperMethods.endsWith(nextElement.text)
            && elementBox.characterFormat.bidi && nextElement.characterFormat.bidi
            && elementBox.characterRange === CharacterRangeType.RightToLeft
            && nextElement.characterRange === CharacterRangeType.RightToLeft) {
            text += '\u200D';
            textTrimEndWidth = this.getWidthWithZWJ(text, '\u200D', nextElement.text, characterFormat, elementBox.scriptType);
        }
        else {
            textTrimEndWidth = this.getWidth(text, characterFormat, elementBox.scriptType);
        }
        elementBox.width = textTrimEndWidth;
        // Calculate the text element's height and baseline offset.
        var textHelper = this.getHeight(characterFormat, elementBox.scriptType);
        if (!(this.documentHelper.compatibilityMode === 'Word2003' && elementBox.isColumnBreak)) {
            elementBox.height = textHelper.Height;
        }
        elementBox.baselineOffset = textHelper.BaselineOffset;
        if (elementBox.text[elementBox.text.length - 1] === ' ') {
            textTrimEndWidth = this.getWidth(HelperMethods.trimEnd(elementBox.text), characterFormat, elementBox.scriptType);
        }
        elementBox.trimEndWidth = textTrimEndWidth;
        return textTrimEndWidth;
    };
    TextHelper.prototype.getHeight = function (characterFormat, scriptType) {
        var fontToRender = this.getFontNameToRender(scriptType, characterFormat);
        // Get character format property as  below predefined structure to make it easy to check and retrieve
        // Predefined static structure `[FontName];[FontSize];bold;italic` to maintain as key in the collection
        var key = this.getFormatText(characterFormat, fontToRender);
        if (!isNullOrUndefined(this.documentHelper.heightInfoCollection["" + key])) {
            if (characterFormat.hidden) {
                var heightInfo = __assign({}, this.documentHelper.heightInfoCollection["" + key]);
                if (heightInfo.Height) {
                    heightInfo.Height = 0;
                }
                return heightInfo;
            }
            return this.documentHelper.heightInfoCollection["" + key];
        }
        var sizeInfo = this.documentHelper.owner.textMeasureHelper.getHeightInternal(characterFormat, fontToRender);
        this.documentHelper.heightInfoCollection["" + key] = __assign({}, sizeInfo);
        if (characterFormat.hidden) {
            sizeInfo.Height = 0;
        }
        return sizeInfo;
    };
    TextHelper.prototype.getFormatText = function (characterFormat, fontToRender) {
        var formatText = '';
        if (!isNullOrUndefined(fontToRender)) {
            formatText = fontToRender.toLocaleLowerCase();
        }
        else {
            formatText = characterFormat.fontFamily.toLocaleLowerCase();
        }
        var isBidi = characterFormat.bidi || characterFormat.complexScript;
        var font = isBidi ? characterFormat.fontSizeBidi : characterFormat.fontSize;
        var bold = isBidi ? characterFormat.boldBidi : characterFormat.bold;
        var italic = isBidi ? characterFormat.italicBidi : characterFormat.italic;
        formatText += ';' + font;
        if (bold) {
            formatText += ';' + 'bold';
        }
        if (italic) {
            formatText += ';' + 'italic';
        }
        return formatText;
    };
    TextHelper.prototype.measureTextExcludingSpaceAtEnd = function (text, characterFormat, scriptType) {
        return this.getWidth(HelperMethods.trimEnd(text), characterFormat, scriptType);
    };
    TextHelper.prototype.getWidth = function (text, characterFormat, scriptType) {
        if (characterFormat.hidden) {
            return 0;
        }
        if (text.match('\v')) {
            text.replace('\v', this.lineBreakMark);
        }
        var bold = '';
        var italic = '';
        var fontFamily = '';
        var isBidi = characterFormat.bidi || characterFormat.complexScript;
        var fontSize = isBidi ? characterFormat.fontSizeBidi : characterFormat.fontSize;
        bold = isBidi ? (characterFormat.boldBidi ? 'bold' : '') : (characterFormat.bold ? 'bold' : '');
        italic = isBidi ? (characterFormat.italicBidi ? 'italic' : '') : (characterFormat.italic ? 'italic' : '');
        fontFamily = this.getFontNameToRender(scriptType, characterFormat);
        fontSize = fontSize === 0 ? 0.5 : fontSize / (characterFormat.baselineAlignment === 'Normal' ? 1 : 1.5);
        this.context.font = bold + ' ' + italic + ' ' + fontSize + 'pt' + ' ' + '"' + fontFamily + '"';
        this.context.letterSpacing = characterFormat.characterSpacing + 'pt';
        var scaleFactor = (characterFormat.scaling / 100);
        if (characterFormat.allCaps) {
            text = text.toUpperCase();
        }
        //ES-853789:For combine character we need  to add the base character to get the width of the text.
        if (text === '\u0336') {
            text += 'A';
        }
        return Math.abs(this.context.measureText(text).width * scaleFactor);
    };
    TextHelper.prototype.getWidthWithZWJ = function (firstText, zwj, nextText, characterFormat, scriptType) {
        if (characterFormat.hidden) {
            return 0;
        }
        // Measure the combined text (accounts for proper Arabic shaping)
        var combinedWidth = this.getWidth(firstText + zwj + nextText, characterFormat, scriptType);
        // Measure only the next text in its isolated form
        var nextTextWidth = this.getWidth(nextText, characterFormat, scriptType);
        // The width of firstText + ZWJ is the difference // This accounts for the connection context
        return combinedWidth - nextTextWidth;
    };
    TextHelper.prototype.setText = function (textToRender, isBidi, bdo, isRender) {
        if (isNullOrUndefined(isRender)) {
            isRender = false;
        }
        if (textToRender.length === 0) {
            return '';
        }
        var isRtlText = isBidi;
        if ((!isRtlText && (bdo === 'RTL')) || (isRtlText && (bdo === 'LTR'))) {
            textToRender = HelperMethods.reverseString(textToRender);
        }
        else if (isRender && isRtlText && HelperMethods.endsWith(textToRender)) {
            var spaceCount = textToRender.length - HelperMethods.trimEnd(textToRender).length;
            textToRender = HelperMethods.addSpace(spaceCount) + HelperMethods.trimEnd(textToRender);
        }
        return textToRender;
    };
    TextHelper.prototype.measureText = function (text, characterFormat, scriptType) {
        // Gets the text element's width;
        var width = this.getWidth(text, characterFormat, scriptType);
        // Calculate the text element's height and baseline offset.
        var textHelper = this.getHeight(characterFormat, scriptType);
        return {
            'Width': width, 'Height': textHelper.Height, 'BaselineOffset': textHelper.BaselineOffset
        };
    };
    TextHelper.prototype.updateTextSize = function (elementBox, paragraph) {
        if (elementBox.characterFormat.hidden && paragraph.height === 0) {
            return;
        }
        var format = new WCharacterFormat(undefined, this.documentHelper.owner);
        var listCharacterFormat = elementBox.listLevel.characterFormat;
        var breakCharacterFormat = paragraph.characterFormat;
        format.fontSize = listCharacterFormat.hasValue('fontSize') ? listCharacterFormat.fontSize : breakCharacterFormat.fontSize;
        format.fontFamily = listCharacterFormat.hasValue('fontFamily') ? listCharacterFormat.fontFamily : breakCharacterFormat.fontFamily;
        var bold = '';
        var italic = '';
        var baselineAlignment = listCharacterFormat.baselineAlignment === 'Normal' ?
            breakCharacterFormat.baselineAlignment : listCharacterFormat.baselineAlignment;
        bold = listCharacterFormat.hasValue('bold') ? listCharacterFormat.bold ? 'bold' : '' : breakCharacterFormat.bold ? 'bold' : '';
        italic = listCharacterFormat.hasValue('italic') ? listCharacterFormat.italic ? 'italic' : ''
            : breakCharacterFormat.italic ? 'italic' : '';
        format.baselineAlignment = baselineAlignment;
        if (bold) {
            format.bold = true;
        }
        if (italic) {
            format.italic = true;
        }
        var isRTL = format.bidi || this.isRTLText(elementBox.text);
        var text = this.setText(elementBox.text, isRTL, format.bdo);
        elementBox.width = this.getWidth(text, format);
        // Calculate the text element's height and baseline offset.
        var textHelper = this.getHeight(format);
        elementBox.height = textHelper.Height;
        elementBox.baselineOffset = textHelper.BaselineOffset;
        format.destroy();
    };
    TextHelper.prototype.containsSpecialCharAlone = function (text) {
        /* eslint-disable */
        var specialChars = '*|.\:[]{}-`\;()@&$#%!~?,' + ' ' + "'";
        for (var i = 0; i < text.length; i++) {
            if (specialChars.indexOf(text.charAt(i)) === -1) {
                return false;
            }
        }
        return true;
    };
    TextHelper.prototype.containsNumberAlone = function (text) {
        /* eslint-disable */
        var number = '0123456789';
        if (text === '') {
            return false;
        }
        for (var i = 0; i < text.length; i++) {
            if (number.indexOf(text.charAt(i)) === -1) {
                return false;
            }
        }
        return true;
    };
    TextHelper.prototype.containsCombinationText = function (element) {
        /* eslint-disable */
        if (element.text.match(/^[0-9]+$/) && element.paragraph.bidi) {
            return true;
        }
        else {
            return false;
        }
    };
    TextHelper.prototype.inverseCharacter = function (ch) {
        if (isNullOrUndefined(ch) || ch.length === 0) {
            return ch;
        }
        // If single character, keep existing behavior
        if (ch.length === 1) {
            switch (ch) {
                case '(':
                    return ')';
                case ')':
                    return '(';
                case '<':
                    return '>';
                case '>':
                    return '<';
                case '{':
                    return '}';
                case '}':
                    return '{';
                case '[':
                    return ']';
                case ']':
                    return '[';
                default:
                    return ch;
            }
        }
        // For multi-character strings: only inverse when all characters are word-split characters
        var allWordSplit = true;
        for (var i = 0; i < ch.length; i++) {
            if (!this.isWordSplitChar(ch[i])) {
                allWordSplit = false;
                break;
            }
        }
        if (!allWordSplit) {
            return ch;
        }
        // Map each character using single-char inverse and combine
        var result = '';
        for (var i = ch.length - 1; i >= 0; i--) {
            result += this.inverseCharacter(ch[i]);
        }
        return result;
    };
    TextHelper.prototype.containsSpecialChar = function (text) {
        var specialChars = '*|.\:[]{}-`\;()@&$#%!~?' + ' ';
        for (var i = 0; i < text.length; i++) {
            if (specialChars.indexOf(text.charAt(i)) !== -1) {
                return true;
            }
        }
        return false;
    };
    /**
     * @private
     * @param {string} text - Specifies the text
     * @returns {boolean} - Returns true if given text it right to left.
     */
    TextHelper.prototype.isRTLText = function (text) {
        var isRTL = false;
        if (!isNullOrUndefined(text)) {
            for (var i = 0; i < text.length; i++) {
                var temp = text[i];
                if ((temp >= String.fromCharCode(1424) && temp <= String.fromCharCode(1535)) ////Script-Hebr, Hebrew characters https://en.wikipedia.org/wiki/Hebrew_alphabet#Unicode_and_HTML (https://en.wikipedia.org/wiki/Hebrew_(Unicode_block))
                    || (temp >= String.fromCharCode(64285) && temp <= String.fromCharCode(64335)) //Script-Hebr, Hebrew Alphabetic Presentation Forms characters https://en.wikipedia.org/wiki/Alphabetic_Presentation_Forms 
                    || (temp >= String.fromCharCode(1536) && temp <= String.fromCharCode(1791)) //Arabic - Urdu characters
                    || (temp >= String.fromCharCode(1872) && temp <= String.fromCharCode(1919)) //Arabic - Urdu characters
                    || (temp >= String.fromCharCode(2208) && temp <= String.fromCharCode(2303)) //Arabic characters
                    || (temp >= String.fromCharCode(64336) && temp <= String.fromCharCode(65023)) //Arabic - Urdu characters
                    || (temp >= String.fromCharCode(65136) && temp <= String.fromCharCode(65279)) //Arabic - Urdu characters
                    || (temp >= String.fromCharCode(43392) && temp <= String.fromCharCode(43487)) //Javanese characters
                    || (temp >= String.fromCharCode(1792) && temp <= String.fromCharCode(1871)) //Syriac characters
                    || (temp >= String.fromCharCode(1920) && temp <= String.fromCharCode(1983)) //Thaana characters
                    || (temp >= String.fromCharCode(2112) && temp <= String.fromCharCode(2143)) //Mandiac characters
                    || (temp >= String.fromCharCode(1984) && temp <= String.fromCharCode(2047)) //N'Ko characters
                    || (temp >= String.fromCharCode(2048) && temp <= String.fromCharCode(2111)) //Samaritan characters
                    //Tifinag characters 
                    || (temp >= String.fromCharCode(11568) && temp <= String.fromCharCode(11647))) {
                    isRTL = true;
                    break;
                }
            }
        }
        return isRTL;
    };
    /**
     * @private
     * @param {string} text - Specifies the text
     * @param {FontScriptType} scriptType - Specifies the script type
     * @returns {boolean} - Returns true if given text is unicode text.
     */
    TextHelper.prototype.isUnicodeText = function (text, scriptType, isWordBreak) {
        if (isWordBreak === void 0) { isWordBreak = false; }
        var isUnicode = false;
        if (!isNullOrUndefined(text)) {
            for (var i = 0; i < text.length; i++) {
                var temp = text[i];
                if ((temp >= '\u3000' && temp <= '\u30ff') // Japanese characters
                    || (temp >= '\uff00' && temp <= '\uffef') // Full-width roman characters and half-width katakana
                    || (temp >= '\u4e00' && temp <= '\u9faf') //CJK unifed ideographs - Common and uncommon kanji
                    || (temp >= '\u3400' && temp <= '\u4dbf') //CJK unified ideographs Extension A - Rare kanji
                    || (temp >= '\uac00' && temp <= '\uffef') //Korean Hangul characters
                    || (temp >= '\u0d80' && temp <= '\u0dff') //Sinhala characters
                    || (isWordBreak && ((temp >= '\u0590' && temp <= '\u05FF') // Hebrew characters
                        || (temp >= '\u0400' && temp <= '\u04FF') // Cyrillic characters
                        || (temp >= '\u00C0' && temp <= '\u00FF') // Accented Latin characters (Latin-1 Supplement)
                        || (temp >= '\u0100' && temp <= '\u017F') // Latin Extended-A
                        || (temp >= '\u0180' && temp <= '\u024F') // Latin Extended-B
                        || (temp >= '\u1E00' && temp <= '\u1EFF')
                        || (temp >= '\u0E00' && temp <= '\u0E7F') // Thai
                        || (temp >= '\u0600' && temp <= '\u06FF')))) { // Arabic characters
                    if (isWordBreak || scriptType !== 0) {
                        isUnicode = true;
                        break;
                    }
                }
            }
        }
        return isUnicode;
    };
    /**
     * @private
     * @param {string} text - Specifies the text
     * @param {Dictionary<TextElementBox, number>} elements - Elements of the text
     * @param {boolean} isAutoWidth
     * @param {boolean} isAllColumnHasAutoWidthType
     */
    TextHelper.prototype.readWord = function (text, elements, isAutoWidth, isAllColumnHasAutoWidthType) {
        var pos = this._position;
        var length = text.length;
        var char = '';
        while (pos < length) {
            char = text[pos];
            var isSplitChar = false;
            var code = char.charCodeAt(0);
            // \u2002 -- En Space, \u200C -- Zero Width Non-Joiner 
            if (char === '\u2002' || char === '\u200C' || (char === '\u00A0' && !isAutoWidth) || (isAllColumnHasAutoWidthType && (code >= 0x4E00 && code <= 0x9FFF))) {
                isSplitChar = true;
            }
            if ((char === '/' || char === '.' || char === ',' || char === '=' || char === '*' || char === '«' || char === '»' || char === '?' || char === '>' || char === '<') && !isAllColumnHasAutoWidthType) {
                isSplitChar = true;
            }
            switch (char) {
                case ' ':
                case '\t':
                case '\n':
                case '\r':
                case '\v':
                case '\f':
                case '\\':
                case ':':
                case '-':
                    isSplitChar = true;
            }
            if (isSplitChar) {
                if (char === ' ' && pos < HelperMethods.trimEnd(text).length && this.isTextContainsNonBreakingSpaceCharacter(text)
                    && this.isNonBreakingCharacterCombinedWithSpace(text, pos)) {
                    pos++;
                    continue;
                }
                if (pos === this._position || char === '-') {
                    pos++;
                }
                var text2 = text.substring(this._position, pos);
                this._position = pos;
                return text2;
            }
            var elementBox = this.getElementBoxOfChar(pos, elements);
            //Check whether character is unicode if it is unicode it reads character from text
            if (this.isUnicodeText(char, elementBox.scriptType, !isAllColumnHasAutoWidthType)) {
                if (pos === this._position) {
                    pos++;
                }
                if (pos > this._position) {
                    var unicodeText = text.substring(this._position, pos);
                    this._position = pos;
                    return unicodeText;
                }
            }
            pos++;
        }
        // The remaining text.
        if (pos > this._position) {
            var remainingText = text.substring(this._position, pos);
            this._position = pos;
            return remainingText;
        }
        return '';
    };
    /**
    * @private
    * @param {number} pos - Current text position
    * @param {Dictionary<TextElementBox, number>} elements - Elements of the text
    */
    TextHelper.prototype.getElementBoxOfChar = function (pos, elements) {
        var keys = elements.keys;
        var values = elements.values;
        var low = 0;
        var high = values.length - 1;
        while (low <= high) {
            var mid = Math.floor((low + high) / 2);
            var start = values[mid];
            var element = keys[mid];
            if (pos >= start && pos < start + element.text.length) {
                return element;
            }
            else if (pos < start) {
                high = mid - 1;
            }
            else {
                low = mid + 1;
            }
        }
        return undefined;
    };
    /**
     * @private
     * @param {string} text - Text which contains non-breaking space character.
     */
    TextHelper.prototype.isTextContainsNonBreakingSpaceCharacter = function (text) {
        return (this.documentHelper.compatibilityMode === 'Word2013' || this.documentHelper.compatibilityMode === 'Word2010') && text.indexOf('\u00A0') >= 0;
    };
    /**
     * @private
     * @param {string} text - Text which contains non-breaking space character.
     * @param {number} pos - Position of the empty space character
     */
    TextHelper.prototype.isNonBreakingCharacterCombinedWithSpace = function (text, pos) {
        for (var i = pos + 1; i < text.length; i++) {
            if (text[i] == '\u00A0')
                return true;
            else if (text[i] == ' ')
                continue;
            else
                break;
        }
        for (var i = pos - 1; i >= 0; i--) {
            if (text[i] == '\u00A0')
                return true;
            else if (text[i] == ' ')
                continue;
            else
                return false;
        }
        return false;
    };
    /**
     * @private
     * @param {string} text - Specifies the text
     * @returns {RtlInfo} - Returns the text info.
     */
    TextHelper.prototype.getRtlLanguage = function (text) {
        if (isNullOrUndefined(text) || text === '') {
            return { isRtl: false, id: 0 };
        }
        if (text >= String.fromCharCode(1424) && text <= String.fromCharCode(1535)) {
            return { isRtl: true, id: 1 };
            //Arabic - Urdu characters
        }
        else if ((text >= String.fromCharCode(1536) && text <= String.fromCharCode(1791))
            || (text >= String.fromCharCode(1872) && text <= String.fromCharCode(1919))
            || (text >= String.fromCharCode(2208) && text <= String.fromCharCode(2303))
            || (text >= String.fromCharCode(64336) && text <= String.fromCharCode(65023))
            || (text >= String.fromCharCode(65136) && text <= String.fromCharCode(65279))) {
            return { isRtl: true, id: 2 };
        }
        else if (text >= String.fromCharCode(43392) && text <= String.fromCharCode(43487)) {
            return { isRtl: true, id: 3 };
        }
        else if (text >= String.fromCharCode(1792) && text <= String.fromCharCode(1871)) {
            return { isRtl: true, id: 4 };
        }
        else if (text >= String.fromCharCode(1920) && text <= String.fromCharCode(1983)) {
            return { isRtl: true, id: 5 };
        }
        else if (text >= String.fromCharCode(2112) && text <= String.fromCharCode(2143)) {
            return { isRtl: true, id: 6 };
        }
        else if (text >= String.fromCharCode(1984) && text <= String.fromCharCode(2047)) {
            return { isRtl: true, id: 7 };
        }
        else if (text >= String.fromCharCode(2048) && text <= String.fromCharCode(2111)) {
            return { isRtl: true, id: 8 };
        }
        else if (text >= String.fromCharCode(11568) && text <= String.fromCharCode(11647)) {
            return { isRtl: true, id: 9 };
        }
        return { isRtl: false, id: 0 };
    };
    /**
     * @private
     */
    TextHelper.prototype.splitTextByConsecutiveLtrAndRtl = function (text, isTextBidi, isRTLLang, characterRangeTypes, isPrevLTRText, hasRTLCharacter, isPrevLTRBidi) {
        var charTypeIndex = characterRangeTypes.length;
        var splittedText = [];
        if (isNullOrUndefined(text) || text === '') {
            return splittedText;
        }
        var lastLtrIndex = -1;
        var ltrText = '';
        var rtlText = '';
        var wordSplitChars = '';
        var numberText = '';
        var hasNumberWithSeparatorPattern = !isNullOrUndefined(isPrevLTRText.value) && isPrevLTRText.value && isTextBidi && /^\d+(\.\d+)+$/.test(text);
        for (var i = 0; i < text.length; i++) {
            var currentCharacterType = 0;
            var separateEachWordSplitChars = false;
            if ((!isNullOrUndefined(isPrevLTRText.value) ? (!isPrevLTRText.value || (!isNullOrUndefined(isPrevLTRBidi.value) && !isPrevLTRBidi.value && isTextBidi && !hasNumberWithSeparatorPattern)) : isTextBidi) && this.isNumber(text[i])) {
                numberText += text[i];
                currentCharacterType = 4;
            }
            else if (this.isWordSplitChar(text[i])) {
                currentCharacterType = 2;
                if (separateEachWordSplitChars = (isTextBidi || (text.charCodeAt(i) == 32 && wordSplitChars == ''))) {
                    wordSplitChars += text[i];
                }
                else {
                    wordSplitChars += text[i];
                }
            }
            else if (this.isRTLText(text[i]) && !this.isNumber(text[i])) {
                isPrevLTRText.value = false;
                hasRTLCharacter.value = true;
                rtlText += text[i];
                currentCharacterType = 1;
            }
            else {
                isPrevLTRText.value = true;
                isPrevLTRBidi.value = isTextBidi;
                ltrText += text[i];
            }
            if (numberText != '' && currentCharacterType != 4) {
                splittedText.push(numberText);
                characterRangeTypes.push(CharacterRangeType.Number);
                numberText = '';
            }
            if (rtlText != '' && currentCharacterType != 1) {
                splittedText.push(rtlText);
                characterRangeTypes.push(CharacterRangeType.RightToLeft);
                rtlText = '';
            }
            if (ltrText != '' && currentCharacterType != 0) {
                splittedText.push(ltrText);
                lastLtrIndex = splittedText.length - 1;
                characterRangeTypes.push(CharacterRangeType.LeftToRight);
                ltrText = '';
            }
            if (wordSplitChars != '' && (currentCharacterType != 2 || separateEachWordSplitChars)) {
                splittedText.push(wordSplitChars);
                characterRangeTypes.push(CharacterRangeType.WordSplit);
                wordSplitChars = '';
            }
        }
        if (numberText != '') {
            splittedText.push(numberText);
            characterRangeTypes.push(CharacterRangeType.Number);
        }
        else if (rtlText != '') {
            splittedText.push(rtlText);
            characterRangeTypes.push(CharacterRangeType.RightToLeft);
        }
        else if (ltrText != '') {
            splittedText.push(ltrText);
            lastLtrIndex = splittedText.length - 1;
            characterRangeTypes.push(CharacterRangeType.LeftToRight);
        }
        else if (wordSplitChars != '') {
            splittedText.push(wordSplitChars);
            characterRangeTypes.push(CharacterRangeType.WordSplit);
        }
        if (hasRTLCharacter.value || (!isNullOrUndefined(isPrevLTRText.value) && !isPrevLTRText.value)) {
            for (var i = 1; i < splittedText.length; i++) {
                //Combines the consecutive LTR, RTL, and Number (Number get combined only if it's splitted by non reversing characters (.,:)) 
                //along with single in-between word split character.
                var charType = characterRangeTypes[i + charTypeIndex];
                if (charType == CharacterRangeType.WordSplit && splittedText[i].length == 1
                    && i + charTypeIndex + 1 < characterRangeTypes.length
                    && characterRangeTypes[i + charTypeIndex - 1] != CharacterRangeType.WordSplit
                    && (characterRangeTypes[i + charTypeIndex - 1] != CharacterRangeType.Number
                        //Else handled to combine consecutive number when text bidi is false and middle word split character is not white space.
                        || TextHelper.isNumberNonReversingCharacter(splittedText[i], isTextBidi))
                    && characterRangeTypes[i + charTypeIndex - 1] == characterRangeTypes[i + charTypeIndex + 1]) {
                    splittedText[i - 1] = splittedText[i - 1] + splittedText[i] + splittedText[i + 1];
                    splittedText.splice(i, 1);
                    splittedText.splice(i, 1);
                    characterRangeTypes.splice(i + charTypeIndex, 1);
                    characterRangeTypes.splice(i + charTypeIndex, 1);
                    i--;
                }
            }
        }
        else if (lastLtrIndex != -1) {
            if (isTextBidi) {
                for (var i = 1; i < lastLtrIndex; i++) {
                    //Combines the first and last LTR along with all in-between splited text's.
                    var charType = characterRangeTypes[i + charTypeIndex];
                    if (charType == CharacterRangeType.WordSplit && i < lastLtrIndex
                        && characterRangeTypes[i + charTypeIndex - 1] == CharacterRangeType.LeftToRight) {
                        ltrText = '';
                        for (var j = i + 1; j <= lastLtrIndex; j++) {
                            ltrText += splittedText[j];
                            splittedText.splice(j, 1);
                            characterRangeTypes.splice(j + charTypeIndex, 1);
                            j--;
                            lastLtrIndex--;
                        }
                        splittedText[i - 1] = splittedText[i - 1] + splittedText[i] + ltrText;
                        splittedText.splice(i, 1);
                        characterRangeTypes.splice(i + charTypeIndex, 1);
                        i--;
                        lastLtrIndex--;
                    }
                }
            }
            else {
                //Return the input text if text bidi is false.
                splittedText.length = 0;
                splittedText.push(text);
            }
        }
        else if (!isTextBidi) {
            //Return the input text if text bidi is false.
            splittedText.length = 0;
            splittedText.push(text);
        }
        if (isTextBidi) {
            for (var i = 1; i < splittedText.length; i++) {
                //Combines the consecutive LTR, RTL, and Number (Number get combined only if it's splitted by non reversing characters (.,:)
                //or if it's lang attribute is represent a RTL language)
                //along with single in-between number non reversing word split character.
                var charType = characterRangeTypes[i + charTypeIndex];
                if (charType == CharacterRangeType.WordSplit && splittedText[i].length == 1
                    && i + charTypeIndex + 1 < characterRangeTypes.length
                    && characterRangeTypes[i + charTypeIndex - 1] != CharacterRangeType.WordSplit
                    && (characterRangeTypes[i + charTypeIndex - 1] != CharacterRangeType.Number
                        || TextHelper.isNumberNonReversingCharacter(splittedText[i], isTextBidi) || !isRTLLang)
                    && characterRangeTypes[i + charTypeIndex - 1] == characterRangeTypes[i + charTypeIndex + 1]) {
                    splittedText[i - 1] = splittedText[i - 1] + splittedText[i] + splittedText[i + 1];
                    splittedText.splice(i, 1);
                    splittedText.splice(i, 1);
                    characterRangeTypes.splice(i + charTypeIndex, 1);
                    characterRangeTypes.splice(i + charTypeIndex, 1);
                    i--;
                }
                //Combines the Number along with single non-word split characters (% $ #).
                else if (charType == CharacterRangeType.WordSplit
                    && characterRangeTypes[i + charTypeIndex - 1] == CharacterRangeType.Number
                    && this.isNonWordSplitCharacter(splittedText[i]) && !isRTLLang) {
                    splittedText[i - 1] = splittedText[i - 1] + splittedText[i];
                    splittedText.splice(i, 1);
                    characterRangeTypes.splice(i + charTypeIndex, 1);
                    i--;
                }
                //Combines the consecutive LTR and Number
                else if (charType == CharacterRangeType.LeftToRight
                    && (characterRangeTypes[i + charTypeIndex - 1] == CharacterRangeType.Number
                        || characterRangeTypes[i + charTypeIndex - 1] == CharacterRangeType.LeftToRight)) {
                    splittedText[i - 1] = splittedText[i - 1] + splittedText[i];
                    characterRangeTypes[i + charTypeIndex - 1] = CharacterRangeType.LeftToRight;
                    splittedText.splice(i, 1);
                    characterRangeTypes.splice(i + charTypeIndex, 1);
                    i--;
                }
            }
        }
        return splittedText;
    };
    /**
     * @private
     */
    TextHelper.prototype.isRightToLeftLanguage = function (lang) {
        return (lang == 14337 || lang == 15361 || lang == 5121 || lang == 3073 || lang == 2049 ||
            lang == 11265 || lang == 13313 || lang == 12289 || lang == 4097 || lang == 8193 ||
            lang == 16385 || lang == 1025 || lang == 10241 || lang == 7169 || lang == 9217 || lang == 10655);
    };
    TextHelper.prototype.isNumber = function (ch) {
        if (!isNaN(parseInt(ch, 10))) {
            //This logic works for universal digits 0 to 9.
            return true;
        }
        else if (ch >= String.fromCharCode(1632) && ch <= String.fromCharCode(1641)) {
            //This logic works for ARABIC-INDIC DIGIT
            return true;
        }
        else if (ch >= String.fromCharCode(1776) && ch <= String.fromCharCode(1785)) {
            //This logic works for EXTENDED ARABIC-INDIC DIGIT
            return true;
        }
        else {
            //TODO: Extend this for language specific 
            return false;
        }
    };
    /**
     * @private
     */
    TextHelper.prototype.isWordSplitChar = function (character) {
        for (var i = 0; i < TextHelper.wordSplitCharacters.length; i++) {
            if (TextHelper.wordSplitCharacters[i] === character) {
                return true;
            }
        }
        return false;
    };
    /**
     * @private
     */
    TextHelper.isNumberNonReversingCharacter = function (character, isTextBidi) {
        for (var i = 0; i < TextHelper.numberNonReversingCharacters.length; i++) {
            var ch = TextHelper.numberNonReversingCharacters[i];
            if (character[0] == ch && (ch.charCodeAt(0) == 47 ? !isTextBidi : true)) {
                return true;
            }
        }
        return false;
    };
    /**
     * @private
     */
    TextHelper.prototype.isNonWordSplitCharacter = function (character) {
        var isNonWordSplitChar = false;
        for (var i = 0; i < character.length; i++) {
            var charCode = character.charCodeAt(i);
            //Consider a (% $ #) as non-word split characters
            if (charCode == 35 || charCode == 36 || charCode == 37) {
                isNonWordSplitChar = true;
            }
            else {
                isNonWordSplitChar = false;
                break;
            }
        }
        return isNonWordSplitChar;
    };
    TextHelper.prototype.getFontNameToRender = function (scriptType, charFormat) {
        if (!isNullOrUndefined(scriptType)) {
            if (charFormat.bidi || charFormat.complexScript) {
                return this.getFontNameBidiToRender(scriptType, charFormat);
            }
            else {
                if ((this.isEastAsiaScript(scriptType) || (charFormat.fontHintType === 'EastAsia' && scriptType === FontScriptType.SpecialCharacter)) && !isNullOrUndefined(charFormat.fontFamilyFarEast))
                    return this.getFontNameEAToRender(scriptType, charFormat);
                else
                    return this.getFontNameAsciiToRender(scriptType, charFormat);
            }
        }
        else {
            return charFormat.fontFamily;
        }
    };
    /// <summary>
    /// Check whether specified script is EastAsia script or not.
    /// </summary>
    /// <param name="scriptType">Represent a FontScriptType to check.</param>
    /// <returns></returns>
    TextHelper.prototype.isEastAsiaScript = function (scriptType) {
        return scriptType == FontScriptType.Japanese || scriptType == FontScriptType.Korean
            || scriptType == FontScriptType.Chinese;
    };
    /// <summary>
    /// Get the font name East Asia to render
    /// </summary>
    /// <param name="scriptType">Represent a CharacterRangeType.</param>
    /// <returns>Returns a eastAsia font name to draw the text.</returns>
    TextHelper.prototype.getFontNameEAToRender = function (scriptType, charFormat) {
        var fontName = charFormat.fontFamilyFarEast;
        if (isNullOrUndefined(fontName) || HelperMethods.isThemeFont(fontName))
            return this.getFontNameFromTheme(charFormat, fontName, scriptType, "EastAsia");
        else
            return fontName;
    };
    TextHelper.prototype.getFontNameAsciiToRender = function (scriptType, charFormat) {
        var fontName = charFormat.fontFamilyAscii;
        if (HelperMethods.isThemeFont(fontName))
            return this.getFontNameFromTheme(charFormat, fontName, scriptType, "Default");
        else
            return charFormat.fontFamily;
    };
    TextHelper.prototype.getFontNameBidiToRender = function (scriptType, charFormat) {
        //If CharacterFormat.Bidi is true, then font is determined in the order: FontNameBidi, Script-Arab, font scheme(latin, ea, cs), default font (Times New Roman)
        //CharacterRangeType of a text and FontHintType (IdctHint) has no impact in this behavior.
        //Note: Behavior is traced using Word version 1808 (build 10730.20304)
        //Determines the font nmae to used for RTL characters based on its script from direct or font scheme (Document theme file)
        var fontName = charFormat.fontFamilyBidi;
        if (!isNullOrUndefined(fontName) || HelperMethods.isThemeFont(fontName))
            return this.getFontNameFromTheme(charFormat, fontName, scriptType, "CS");
        else
            return fontName;
    };
    TextHelper.prototype.getFontNameFromTheme = function (charFormat, fontName, scriptType, hintType) {
        var fontScheme;
        if (this.documentHelper.hasThemes && !isNullOrUndefined(this.documentHelper.themes) && !isUndefined(this.documentHelper.themes.fontScheme))
            fontScheme = this.documentHelper.themes.fontScheme;
        if (fontName == "majorAscii" || fontName == "majorBidi" || fontName == "majorEastAsia" || fontName == "majorHAnsi") {
            var majorFontScheme = void 0;
            if (fontScheme != null && fontScheme.majorFontScheme != null) {
                majorFontScheme = fontScheme.majorFontScheme;
            }
            fontName = this.updateFontNameFromTheme(charFormat, majorFontScheme, scriptType, fontName, hintType);
        }
        else if (fontName == "minorAscii" || fontName == "minorBidi" || fontName == "minorEastAsia" || fontName == "minorHAnsi") {
            var minorFontScheme = void 0;
            if (fontScheme != null && fontScheme.majorFontScheme != null) {
                minorFontScheme = fontScheme.minorFontScheme;
            }
            fontName = this.updateFontNameFromTheme(charFormat, minorFontScheme, scriptType, fontName, hintType);
        }
        if (isNullOrUndefined(fontName) || HelperMethods.isThemeFont(fontName))
            //Gets the default font (Times New Roman)
            fontName = defaultFont;
        return fontName;
    };
    /// <summary>
    /// Update a font name from theme, based on FontHintType.
    /// </summary>
    /// <param name="majorMinorFontScheme"></param>
    /// <param name="scriptType"></param>
    /// <param name="fontName"></param>
    /// <param name="hintType"></param>
    TextHelper.prototype.updateFontNameFromTheme = function (charFormat, majorMinorFontScheme, scriptType, fontName, hintType) {
        //Script-Arab, font scheme(latin, ea, cs), default font (Times New Roman)
        var fontNameFromTheme = "";
        //Gets font from font scheme(latin, ea, cs) of document theme.
        if (majorMinorFontScheme != null && majorMinorFontScheme.fontSchemeList != null
            && majorMinorFontScheme.fontSchemeList.length > 0) {
            majorMinorFontScheme.fontSchemeList.forEach(function (fontSchemeStruct) {
                if (fontSchemeStruct.name == "cs" && (fontName == "majorBidi" || fontName == "minorBidi"))
                    fontNameFromTheme = fontSchemeStruct.typeface;
                else if (fontSchemeStruct.name == "ea" && (fontName == "majorEastAsia" || fontName == "minorEastAsia"))
                    fontNameFromTheme = fontSchemeStruct.typeface;
                else if (fontSchemeStruct.name == "latin" && (fontName == "majorAscii" || fontName == "majorHAnsi"
                    || fontName == "minorAscii" || fontName == "minorHAnsi"))
                    fontNameFromTheme = fontSchemeStruct.typeface;
            });
        }
        if (majorMinorFontScheme != null && majorMinorFontScheme.fontTypeface != null) {
            if (hintType == "CS") {
                // //If it's an complex script and "themeFontLang" element has a "bidi" attribute, then we need to locate the font name
                // //from the "theme.xml" for the language specified by the bidi attribute
                // if (charFormat.complexScript && Document != null && Document.Settings.ThemeFontLanguages != null &&
                //     Document.Settings.ThemeFontLanguages.HasValue(WCharacterFormat.LidBiKey))
                // {
                //     fontName = this.getFontNameWithFontScript(majorMinorFontScheme, Document.Settings.ThemeFontLanguages.LocaleIdBidi, hintType);
                //     if (fontName != null)
                //         fontNameFromTheme = fontName;
                // }
                //If the font name is mentioned as Ascii or HAnsi, then we need to get the font name from Latin.
                if (!charFormat.complexScript && (!charFormat.bidi && (fontName === "majorAscii" || fontName === "majorHAnsi" || fontName === "minorAscii" || fontName === "minorHAnsi"))
                    || (charFormat.bidi && (fontName === "majorHAnsi" || fontName === "minorHAnsi"))) {
                    fontName = fontNameFromTheme;
                }
                //To-Do: Have to implement the font name retrieval behavior, when a bidi attribute is not available in theme.
                else if (majorMinorFontScheme.fontTypeface.containsKey('Arab')) {
                    //map(object => object.id).indexOf('c');
                    //Gets the Arab-script (language) based font from font scheme (theme)
                    fontNameFromTheme = majorMinorFontScheme.fontTypeface.get('Arab');
                }
            }
            else if (hintType == "EastAsia") {
                if (!isNullOrUndefined(this.documentHelper.themeFontLanguage)) {
                    fontName = this.getFontNameWithFontScript(majorMinorFontScheme, this.documentHelper.themeFontLanguage.localeIdFarEast, hintType);
                    if (!isNullOrUndefined(fontName)) {
                        fontNameFromTheme = fontName;
                    }
                    //When font information is not available at the file level, Microsoft Word uses the following fonts as the default font for the respective language.
                    // else if (isNullOrUndefined(fontNameFromTheme))
                    // {
                    //     LocaleIDs lang = (LocaleIDs)Document.Settings.ThemeFontLanguages.LocaleIdFarEast;
                    //     if (lang == LocaleIDs.zh_CN)
                    //         fontNameFromTheme = "SimSun";
                    //     else if (lang == LocaleIDs.ko_KR)
                    //         fontNameFromTheme = "Batang";
                    //     else if (lang == LocaleIDs.ja_JP)
                    //         fontNameFromTheme = "MS Mincho";
                    // }
                }
            }
            else if (isNullOrUndefined(fontNameFromTheme) && !isNullOrUndefined(this.documentHelper.themeFontLanguage) && (fontName === "minorBidi" || fontName === "majorBidi")) {
                return fontName = this.getFontNameWithFontScript(majorMinorFontScheme, this.documentHelper.themeFontLanguage.localeIdBidi, hintType);
            }
        }
        if (isNullOrUndefined(fontNameFromTheme))
            //Gets the default font (Times New Roman)
            fontNameFromTheme = defaultFont;
        fontName = fontNameFromTheme;
        return fontName;
    };
    // /// <summary>
    // /// Gets the font name from a theme part for the specified font script.
    // /// </summary>
    TextHelper.prototype.getFontNameWithFontScript = function (majorMinorFontScheme, localeID, hintType) {
        var fontName = null;
        //To-Do: Should extend this behavior deponds on the localeID.
        var lang = localeID.toString();
        var fontTypeFaces = majorMinorFontScheme.fontTypeface;
        //Gujarati
        //If lang script is "gu-IN" or "gu", we should retrive the "Gujr" font from a theme part.
        if ((lang == 'gu_IN' || localeID == 1095) && fontTypeFaces.containsKey("Gujr"))
            fontName = fontTypeFaces.get("Arab");
        //Hindi
        //If lang script is "hi-IN" or "hi", we should retrive the "Deva" font from a theme part.
        //Marathi
        //If lang script is "mr-IN" or "mr", we should retrive the "Deva" font from a theme part.
        else if ((lang == 'hi_IN' || lang == 'mr_IN' || localeID == 1081 || localeID == 1102)
            && fontTypeFaces.containsKey("Deva"))
            fontName = fontTypeFaces.get("Arab");
        //Korean
        //If lang script is "ko-KR" or "ko", we should retrive the "Hang" font from a theme part.
        else if ((lang == 'ko_KR' || localeID == 1042) && fontTypeFaces.containsKey("Hang"))
            fontName = fontTypeFaces.get("Arab");
        //Chinese - Simplified
        //If lang script is "zh-CN", "zh-SG" or "zh", we should retrive the "Hans" font from a theme part.
        else if ((lang == 'zh_CN' || lang == 'zh_SG' || localeID == 2052) && fontTypeFaces.containsKey("Hans"))
            fontName = fontTypeFaces.get("Hans");
        //Chinese - Traditional
        //If lang script is "zh-TW", "zh-HK", or "zh-MO", we should retrive the "Hant" font from a theme part.
        else if ((lang == 'zh_TW' || lang == 'zh_HK' || lang == 'zh_MO')
            && fontTypeFaces.containsKey("Hant"))
            fontName = fontTypeFaces.get("Arab");
        //Japanese
        //If lang script is "ja-JP" or "ja", we should retrive the "Jpan" font from a theme part.
        else if ((lang == 'ja_JP' || localeID == 1041) && fontTypeFaces.containsKey("Jpan"))
            fontName = fontTypeFaces.get("Arab");
        //Tamil
        //If lang script is "ta-IN" or "ta", we should retrive the "Taml" font from a theme part.
        else if ((lang == 'ta_IN' || localeID == 1097) && fontTypeFaces.containsKey("Taml"))
            fontName = fontTypeFaces.get("Arab");
        //Telugu
        //If lang script is "te-IN" or "te", we should retrive the "Telu" font from a theme part.
        else if ((lang == 'te_IN' || localeID == 1098) && fontTypeFaces.containsKey("Telu"))
            fontName = fontTypeFaces.get("Arab");
        //Hebrew
        //If lang script is "he-IL" or "he", we should retrive the "Hebr" font from a theme part.
        else if ((lang == 'he_IL' || lang == 'yi_Hebr' || localeID == 1037) && fontTypeFaces.containsKey("Hebr"))
            fontName = fontTypeFaces.get("Arab");
        //Thai
        //If lang script is "th_TH" or "th", we should retrive the "Thai" font from a theme part.
        else if ((lang == 'th_TH' || localeID == 1054) && fontTypeFaces.containsKey("Thai"))
            fontName = fontTypeFaces.get("Thai");
        //Arabic
        else if (hintType == "CS" && fontTypeFaces.containsKey("Arab"))
            fontName = fontTypeFaces.get("Arab");
        return fontName;
    };
    TextHelper.prototype.destroy = function () {
        this.documentHelper = undefined;
        this.context = undefined;
        this.paragraphMarkInfo = {};
        this.paragraphMarkInfo = undefined;
    };
    TextHelper.wordSplitCharacters = [String.fromCharCode(32), String.fromCharCode(33), String.fromCharCode(34),
        String.fromCharCode(35), String.fromCharCode(36), String.fromCharCode(37), String.fromCharCode(38), String.fromCharCode(39),
        String.fromCharCode(40), String.fromCharCode(41), String.fromCharCode(42), String.fromCharCode(43), String.fromCharCode(44),
        String.fromCharCode(45), String.fromCharCode(46), String.fromCharCode(47), String.fromCharCode(58), String.fromCharCode(59),
        String.fromCharCode(60), String.fromCharCode(61), String.fromCharCode(62), String.fromCharCode(63), String.fromCharCode(64),
        String.fromCharCode(91), String.fromCharCode(92), String.fromCharCode(93), String.fromCharCode(94), String.fromCharCode(95),
        String.fromCharCode(96), String.fromCharCode(123), String.fromCharCode(124), String.fromCharCode(125), String.fromCharCode(126),
        String.fromCharCode(1548), String.fromCharCode(1563), String.fromCharCode(8211), String.fromCharCode(8212),
        String.fromCharCode(8216), String.fromCharCode(8217), String.fromCharCode(8221), String.fromCharCode(12288),
        String.fromCharCode(8207), String.fromCharCode(169), String.fromCharCode(160)];
    TextHelper.numberNonReversingCharacters = [String.fromCharCode(44), String.fromCharCode(46), String.fromCharCode(47),
        String.fromCharCode(58), String.fromCharCode(1548)];
    return TextHelper;
}());
export { TextHelper };
