def create_toc(doctree, depth=9223372036854775807, writer_name='html',
               exclude_first_section=True, href_prefix=None, id_prefix='toc-ref-'):
    """
    Create a Table of Contents (TOC) from the given doctree

    Returns: (docutils.core.Publisher instance, output string)

    `writer_name`: represents a reST writer name and determines the type of
        output returned.

    Example:

        pub = blazeutils.rst.rst2pub(toc_rst)
        pub, html_output = blazeutils.rst.create_toc(pub.document)

        # a full HTML document (probably not what you want most of the time)
        print html_output

        # just the TOC
        print pub.writer.parts['body']
    """
    # copy the doctree since Content alters some settings on the original
    # document
    doctree = doctree.deepcopy()

    # we want to be able to customize ids to avoid clashes if needed
    doctree.settings.auto_id_prefix = id_prefix

    details = {
        'depth': depth,
    }

    # Assuming the document has one primary heading and then sub-sections, we
    # want to be able to give just the sub-sections
    startnode = None
    if exclude_first_section:
        nodes = doctree.traverse(docutils.nodes.section)
        if nodes:
            startnode = nodes[0]

    # use the Contents transform to build the TOC node structure from the
    # document
    c = Contents(doctree)
    # this startnode isn't really used as the start node, its only used for
    # to pull settings from
    c.startnode = BlankObject(details=details)
    # since this toc is detached from the rest of the document, we don't want
    # backlinks
    c.backlinks = 'none'
    # build the nodes
    toc_nodes = c.build_contents(startnode or doctree)

    # create a new document with the new nodes
    toc_doc = new_document(None)
    toc_doc += toc_nodes

    # fix fragements that reference the same page
    if href_prefix:
        prefix_refids(toc_doc, href_prefix)

    # setup a publisher and publish from the TOC document
    reader = docutils.readers.doctree.Reader(parser_name='null')
    pub = Publisher(
        reader, None, None,
        source=io.DocTreeInput(toc_doc),
        destination_class=io.StringOutput
    )
    pub.set_writer(writer_name)

    final_settings_overrides = default_rst_opts.copy()
    pub.process_programmatic_settings(
        None, final_settings_overrides, None)

    output = pub.publish()
    return pub, output