from pathlib import Path
import os
import textwrap
import xml.etree.ElementTree as ET


def main():
    dstpath = Path('src/inline_doc.h')
    app = Application(dstpath)
    app.run()

"""
THis script requires a docutils and pygments installation either with:
- pip install docutils pygments
- apt install python3-docutils
- or similar
"""


HEADER = """#pragma once
// DO NOT EDIT. File generated by script update_inlinedoc.py.
"""


class Application(object):
    def __init__(self, dstpath):
        self.dstpath = dstpath


    def run(self):
        content = HEADER
        for path, name in self.__get_files():
            content += '\n' + self.__format_file(path, name)

        oldcontent = None
        if self.dstpath.exists():
            oldcontent = self.dstpath.read_text()

        if content != oldcontent:
            print("Creating %s" % self.dstpath)
            self.dstpath.write_text(content)


    def __format_file(self, path, name):
        print("Parsing %s" % path)
        cmd = 'rst2xml.py %s' % path
        xml = os.popen(cmd).read()
        f = Formatter(xml, name)
        return f.format()


    def __get_files(self):
        rootdir = Path('docs')
        for path in sorted(rootdir.glob("*.rst")):
            if path.name != 'index.rst':
                name = path.stem + '_doc'
                yield (path, name)


WIDTH = 60


class Formatter(object):
    def __init__(self, xml_string, name):
        self.xml  = ET.fromstring(xml_string)
        self.name = name


    def format(self):
        self.lines = []
        for node in next(self.xml.iter('document')):
            if node.tag == 'title':
                self.format_title(node)
            elif node.tag == 'paragraph':
                self.format_paragraph(node)
            elif node.tag == 'bullet_list':
                self.format_bullet_list(node)
            elif node.tag == 'section':
                break # do not add extra sections
            else:
                raise ValueError("tag '%s' not supported" % node.tag)


        return self.format_c_define()


    def format_title(self, node):
        self.lines.append(node.text)


    def format_paragraph(self, node):
        self.lines.append('')
        self.lines.extend(textwrap.wrap(self.normalize(node), width=WIDTH))


    def format_bullet_list(self, node):
        for list_item in node.iter('list_item'):
            for paragraph in list_item.iter('paragraph'):

                text = self.normalize(paragraph)
                lines = textwrap.wrap(text, width=(WIDTH - 2))
                for i, line in enumerate(lines):
                    if i == 0:
                        prefix = '- '
                    else:
                        prefix = '  '

                    self.lines.append(prefix + line)


    def normalize(self, node):
        t = ET.tostring(node, method='text', encoding='unicode')
        t = t.split()
        return ' '.join(t)


    def format_c_define(self):
        lines = []
        prevline = ''

        # 1. do preformatting
        for line in self.lines:
            line = line.rstrip()
            if line == '' and prevline == '':
                continue # compress multiple empty lines

            prevline = line

            line = line.replace(r'\\', r'\\\\')
            line = line.replace('"', r'\"')

            lines.append(line)

        # 2. remove empty lines from the end
        while lines:
            if lines[-1] == '':
                del lines[-1]
            else:
                break


        # 3. add qutations
        n = len(lines)
        indent = '\t'
        result = '#define %s \\\n' % self.name
        for i, line in enumerate(lines):
            result += indent
            if i < n - 1:
                result += '"%s\\n" \\\n' % line
            else:
                result += '"%s"\n' % line

        return result


if __name__ == '__main__':
    main()
