window.EditorLists = (function () {

    function detectListPrefix(lineText) {
        var m;
        m = lineText.match(/^(\s*)(- \[[ x]\] )/);
        if (m) return { indent: m[1], prefix: m[2], type: 'task' };
        m = lineText.match(/^(\s*)([-*+] )/);
        if (m) return { indent: m[1], prefix: m[2], type: 'unordered' };
        m = lineText.match(/^(\s*)(\d+)\. /);
        if (m) return { indent: m[1], prefix: m[2] + '. ', type: 'ordered', num: parseInt(m[2], 10) };
        m = lineText.match(/^(\s*)(> )/);
        if (m) return { indent: m[1], prefix: m[2], type: 'blockquote' };
        return null;
    }

    function continuationPrefix(info) {
        if (info.type === 'task') return info.indent + '- [ ] ';
        if (info.type === 'ordered') return info.indent + (info.num + 1) + '. ';
        return info.indent + info.prefix;
    }

    function renumberOrderedList(text, fromLineIndex, indent, startNum) {
        var lines = text.split('\n');
        var re = new RegExp('^' + indent.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '(\\d+)\\. ');
        var num = startNum !== undefined ? startNum : null;
        for (var i = fromLineIndex; i < lines.length; i++) {
            var m = lines[i].match(re);
            if (!m) break;
            if (num === null) num = parseInt(m[1], 10);
            var newNumStr = String(num);
            if (m[1] !== newNumStr) {
                lines[i] = indent + newNumStr + '. ' + lines[i].slice(m[0].length);
            }
            num++;
        }
        return lines.join('\n');
    }

    function handleEnterKey(text, cursorPos) {
        var before = text.slice(0, cursorPos);
        var after = text.slice(cursorPos);
        var lineStart = before.lastIndexOf('\n') + 1;
        var lineEnd = text.indexOf('\n', cursorPos);
        if (lineEnd === -1) lineEnd = text.length;
        var fullLine = text.slice(lineStart, lineEnd);
        var info = detectListPrefix(fullLine);
        if (!info) return null;

        var contentAfterPrefix = fullLine.slice(info.indent.length + info.prefix.length);
        if (contentAfterPrefix.trim() === '') {
            var newText = text.slice(0, lineStart) + '\n' + after;
            var newCursor = lineStart + 1;
            if (info.type === 'ordered') {
                var lineIndex = text.slice(0, lineStart).split('\n').length;
                newText = renumberOrderedList(newText, lineIndex, info.indent);
            }
            return { text: newText, cursor: newCursor };
        }

        var cont = continuationPrefix(info);
        var newText = before + '\n' + cont + after;
        var newCursor = cursorPos + 1 + cont.length;
        if (info.type === 'ordered') {
            var insertedLineIndex = before.split('\n').length;
            newText = renumberOrderedList(newText, insertedLineIndex, info.indent);
        }
        return { text: newText, cursor: newCursor };
    }

    function deleteOrderedLine(text, cursorPos) {
        var lineStart = text.lastIndexOf('\n', cursorPos - 1) + 1;
        var lineEnd = text.indexOf('\n', cursorPos);
        if (lineEnd === -1) lineEnd = text.length;
        var fullLine = text.slice(lineStart, lineEnd);
        var info = detectListPrefix(fullLine);
        if (!info || info.type !== 'ordered') return null;

        var newText = text.slice(0, lineStart) + text.slice(lineEnd === text.length ? lineEnd : lineEnd + 1);
        var newCursor = lineStart;
        var fromLineIndex = text.slice(0, lineStart).split('\n').length - 1;
        newText = renumberOrderedList(newText, fromLineIndex, info.indent, info.num);
        return { text: newText, cursor: Math.min(newCursor, newText.length) };
    }

    return { handleEnterKey: handleEnterKey, deleteOrderedLine: deleteOrderedLine };
})();
