# This Python 3 script reads a single documentation.html file generated by Sigasi
# Studio, and rewrites it into separate files per entity or module. Multiple
# libraries are not supported.
#
# This script reads its input from a file named documentation.html, which is assumed
# to be in the current directory.
# The generated index document is index.html, the separate files with a single
# design unit are named after the design unit.
#
#
# Note that the structure of the generated documentation is not fixed like an API.
# Sigasi may change the way it generates documentation, and this may break the
# functionality of this script (and your adaptations).  This script was made for
# Sigasi Studio 4.12.
#
# Copyright (c) 2021, Sigasi. All rights reserved.
#
# This script is provided under the BSD license:
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
#   Redistributions of source code must retain the above copyright notice, this
#   list of conditions and the following disclaimer.
#
#   Redistributions in binary form must reproduce the above copyright notice, this
#   list of conditions and the following disclaimer in the documentation and/or
#   other materials provided with the distribution.
#
#   Neither the name of the Sigasi nor the names of its
#   contributors may be used to endorse or promote products derived from
#   this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

from htmldom import htmldom


def bare_design_unit_name(text):
    result = text.replace("&#8203;", "")  # Zero width space
    if "." in result:
        return result.split(".")[1].strip()
    return result.strip()


def rewrite_documentation():
    # Read and parse the documentation generated by Sigasi Studio, and save the header for later
    dom = htmldom.HtmlDom("file:documentation.html").createDom()
    head = dom.find("head")

    # Create a list of entities and modules. VHDL architectures are appended to their respective architectures
    design_units = {}

    entity_length = len("entity ")
    for entity in dom.find("div.entity"):
        design_units[bare_design_unit_name(entity.find("h2").text()[entity_length:])] = entity

    architecture_length = len("architecture ")
    for architecture in dom.find("div.architecture"):
        arch_name = bare_design_unit_name(architecture.find("h2").text()[architecture_length:])
        entity_name = arch_name.split("(")[0]
        if entity_name in design_units:
            design_units[entity_name].append(architecture)
        else:
            print("*Warning* unmatched architecture " + arch_name + " of " + entity_name)

    module_length = len("module ")
    for module in dom.find("div.module"):
        design_units[bare_design_unit_name(module.find("h2").text()[module_length:])] = module

    # Look up which design units are instantiated i.e. which are not top levels
    non_top_level = []

    for design_unit_name, design_unit in design_units.items():
        for h3 in design_unit.find('h3'):
            if h3.text() == "Instantiations":
                for insta in h3.nextUntil('h3'):
                    insta_li = insta.find('li').first()
                    insta_li_textbits = insta_li.text().split(" : ")
                    insta_name = bare_design_unit_name(insta_li_textbits[1])
                    non_top_level.append(insta_name)
                    # While we're here, add a link to instantiations
                    text_with_link = insta_li_textbits[0] + " : " + '<a href="' + insta_name + '.html">' + \
                                     insta_li_textbits[1] + '</a>'
                    insta_li.text(text_with_link)

    # Create a new index document and set up some headers and titles.
    index_document = htmldom.HtmlDom().createDom("<html><body></body></html>").find('html')
    index_document.prepend(head)
    index_body = index_document.find('body')
    # Copy the H1 title from the original document to the index document.
    index_body.prepend(dom.find('h1'))
    # One may want to append some high-level information on the project at this point.
    index_body.append("<h2>Top level modules and entities:</h2><ul></ul>")
    index_body.append("<h2>Other modules and entities:</h2><ul></ul>")

    # Generate an HTML file for each design unit, and add a link in the index document
    for design_unit_name, design_unit in design_units.items():
        print('Design unit: ' + design_unit_name)
        new_document = htmldom.HtmlDom().createDom("<html><body></body></html>").find('html')
        new_document.prepend(head)
        # Copy the full HTML describing the design unit from the original document into the single design unit document
        new_document.find('body').append(design_unit)
        # Add the link to the index document
        link = '<li><a href="' + design_unit_name + '.html">' + design_unit_name + '</a></li>'
        if design_unit_name not in non_top_level:
            design_unit.find('p').first().after("<p>This is a top level module/entity</p>")
            index_body.find('ul').first().append(link)
        else:
            index_body.find('ul').last().append(link)
        # Save the single design unit document
        with open(design_unit_name + ".html", 'w') as f:
            f.write(new_document.html())

    # Save the index document
    with open('index.html', 'w') as f:
        f.write(index_document.html())


if __name__ == '__main__':
    rewrite_documentation()
