export function extractLeadingText(string, completeTag) {
    let tagIndex = string.indexOf(completeTag);
    let leadingText = undefined;
    let leadingTextRegExp = /\[(.+?)\]/g;
    let leadingTextInfo = leadingTextRegExp.exec(string);

    // did we find leading text, and if so, does it immediately precede the tag?
    while (leadingTextInfo && leadingTextInfo.length) {
        if (leadingTextInfo.index + leadingTextInfo[0].length === tagIndex) {
            string = string.replace(leadingTextInfo[0], '');
            leadingText = leadingTextInfo[1];
            break;
        }

        leadingTextInfo = leadingTextRegExp.exec(string);
    }

    return {
        leadingText: leadingText,
        string: string
    };
}

export function splitLinkText(text) {
    let linkText;
    let target;
    let splitIndex;

    // if a pipe is not present, we split on the first space
    splitIndex = text.indexOf('|');
    if (splitIndex === -1) {
        splitIndex = text.search(/\s/);
    }

    if (splitIndex !== -1) {
        linkText = text.substr(splitIndex + 1);
        // Normalize subsequent newlines to a single space.
        linkText = linkText.replace(/\n+/, ' ');
        target = text.substr(0, splitIndex);
    }

    return {
        linkText: linkText,
        target: target || text
    };
}

export let LinkParser = (function() {
    let processTheLink = function(string, tagInfo, leadingText) {
        let leading = extractLeadingText(string, tagInfo.completeTag),
            linkText,
            split,
            target,
            stringtoReplace;

        linkText = leadingText ? leadingText : leading.leadingText || '';

        split = splitLinkText(tagInfo.text);
        target = split.target;

        if (leading.leadingText !== undefined) {
            stringtoReplace = '[' + leading.leadingText + ']' + tagInfo.completeTag;
        } else if (typeof split.linkText !== 'undefined') {
            stringtoReplace = tagInfo.completeTag;
            linkText = split.linkText;
        }
        if (linkText === '' || linkText == null || target == null) {
            return string;
        }

        return string.replace(stringtoReplace, '[' + linkText + '](' + target + ')');
    };

    /**
     * Convert
     * {@link http://www.google.com|Google} or {@link https://github.com GitHub} or [Github]{@link https://github.com} to [Github](https://github.com)
     */

    let replaceLinkTag = function(str: string) {
        if (typeof str === 'undefined') {
            return {
                newString: ''
            };
        }

        // new RegExp('\\[((?:.|\n)+?)]\\{@link\\s+((?:.|\n)+?)\\}', 'i').exec('ee [TO DO]{@link Todo} fo') -> "[TO DO]{@link Todo}", "TO DO", "Todo"
        // new RegExp('\\{@link\\s+((?:.|\n)+?)\\}', 'i').exec('ee [TODO]{@link Todo} fo') -> "{@link Todo}", "Todo"

        let tagRegExpLight = new RegExp('\\{@link\\s+((?:.|\n)+?)\\}', 'i'),
            tagRegExpFull = new RegExp('\\{@link\\s+((?:.|\n)+?)\\}', 'i'),
            tagRegExp,
            matches,
            previousString,
            tagInfo = [];

        tagRegExp = str.indexOf(']{') !== -1 ? tagRegExpFull : tagRegExpLight;

        function replaceMatch(replacer, tag, match, text, linkText?) {
            let matchedTag = {
                completeTag: match,
                tag: tag,
                text: text
            };
            tagInfo.push(matchedTag);
            if (linkText) {
                return replacer(str, matchedTag, linkText);
            } else {
                return replacer(str, matchedTag);
            }
        }

        do {
            matches = tagRegExp.exec(str);
            if (matches) {
                previousString = str;
                if (matches.length === 2) {
                    str = replaceMatch(processTheLink, 'link', matches[0], matches[1]);
                }
                if (matches.length === 3) {
                    str = replaceMatch(processTheLink, 'link', matches[0], matches[2], matches[1]);
                }
            }
        } while (matches && previousString !== str);

        return {
            newString: str
        };
    };

    let _resolveLinks = function(str: string) {
        return replaceLinkTag(str).newString;
    };

    return {
        resolveLinks: _resolveLinks
    };
})();
