define([
    "jquery",
    "underscore",
    "utils",
    "text!html/tocSettingsBloc.html",
], function($, _, utils, tocSettingsBlocHTML) {
    var toc = {
        extensionId: "toc",
        extensionName: "Table of Content",
        optional: true,
        defaultConfig: {
            marker: "\\[(TOC|toc)\\]"
        },
        settingsBloc: tocSettingsBlocHTML
    };
    toc.onLoadSettings = function() {
        utils.setInputValue("#input-toc-marker", toc.config.marker);
    };
    toc.onSaveSettings = function(newConfig, event) {
        newConfig.marker = utils.getInputRegExpValue("#input-toc-marker", event);
};
    // TOC element description
    function TocElement(tagName, anchor, text) {
        this.tagName = tagName;
        this.anchor = anchor;
        this.text = text;
        this.children = [];
    }
    TocElement.prototype.childrenToString = function() {
        if(this.children.length === 0) {
            return "";
        }
        var result = "
";
        _.each(this.children, function(child) {
            result += child.toString();
        });
        result += "
";
        return result;
    };
    TocElement.prototype.toString = function() {
        var result = "";
        if(this.anchor && this.text) {
            result += '' + this.text + '';
        }
        result += this.childrenToString() + "";
        return result;
    };
    // Transform flat list of TocElement into a tree
    function groupTags(array, level) {
        level = level || 1;
        var tagName = "H" + level;
        var result = [];
        var currentElement = undefined;
        function pushCurrentElement() {
            if(currentElement !== undefined) {
                if(currentElement.children.length > 0) {
                    currentElement.children = groupTags(currentElement.children, level + 1);
                }
                result.push(currentElement);
            }
        }
        _.each(array, function(element, index) {
            if(element.tagName != tagName) {
                if(currentElement === undefined) {
                    currentElement = new TocElement();
                }
                currentElement.children.push(element);
            }
            else {
                pushCurrentElement();
                currentElement = element;
            }
        });
        pushCurrentElement();
        return result;
    }
    // Build the TOC
    function buildToc() {
        var anchorList = {};
        function createAnchor(element) {
            var id = element.prop("id") || utils.slugify(element.text());
            var anchor = id;
            var index = 0;
            while (_.has(anchorList, anchor)) {
                anchor = id + "-" + (++index);
            }
            anchorList[anchor] = true;
            // Update the id of the element
            element.prop("id", anchor);
            return anchor;
        }
        var elementList = [];
        $("#wmd-preview > h1," + "#wmd-preview > h2," + "#wmd-preview > h3," + "#wmd-preview > h4," + "#wmd-preview > h5," + "#wmd-preview > h6").each(function() {
            elementList.push(new TocElement($(this).prop("tagName"), createAnchor($(this)), $(this).text()));
        });
        elementList = groupTags(elementList);
        return '' + elementList.toString() + '
 ';
    }
    toc.onEditorConfigure = function(editor) {
        // Run TOC generation when conversion is finished directly on HTML
        editor.hooks.chain("onPreviewRefresh", function() {
            var htmlToc = buildToc();
            var html = $("#wmd-preview").html();
            html = html.replace(new RegExp("" + toc.config.marker + "<\\/p>", "g"), htmlToc);
            $("#wmd-preview").html(html);
        });
    };
    return toc;
});