import re
from sphinx.util.compat import Directive
from docutils import nodes


class DialectDirective(Directive):
    has_content = True

    _dialects = {}

    def _parse_content(self):
        d = {}
        d['default'] = self.content[0]
        d['text'] = []
        idx = 0
        for line in self.content[1:]:
            idx += 1
            m = re.match(r'\:(.+?)\: +(.+)', line)
            if m:
                attrname, value = m.group(1, 2)
                d[attrname] = value
            else:
                break
        d["text"] = self.content[idx + 1:]
        return d

    def _dbapi_node(self):

        dialect_name, dbapi_name = self.dialect_name.split("+")

        try:
            dialect_directive = self._dialects[dialect_name]
        except KeyError:
            raise Exception(
                "No .. dialect:: %s "
                "directive has been established"
                % dialect_name)

        output = []

        content = self._parse_content()

        parent_section_ref = self.state.parent.children[0]['ids'][0]
        self._append_dbapi_bullet(
            dialect_name, dbapi_name,
            content['name'], parent_section_ref)

        p = nodes.paragraph(
            '', '',
            nodes.Text(
                "Support for the %s database via the %s driver." % (
                    dialect_directive.database_name,
                    content['name']
                ),
                "Support for the %s database via the %s driver." % (
                    dialect_directive.database_name,
                    content['name']
                )
            ),
        )

        self.state.nested_parse(content['text'], 0, p)
        output.append(p)

        if "url" in content or "driverurl" in content:
            sec = nodes.section(
                '',
                nodes.title("DBAPI", "DBAPI"),
                ids=["dialect-%s-%s-url" % (dialect_name, dbapi_name)]
            )
            if "url" in content:
                text = "Documentation and download information "\
                       "(if applicable) "\
                       "for %s is available at:\n" % content["name"]
                uri = content['url']
                sec.append(
                    nodes.paragraph(
                        '', '',
                        nodes.Text(text, text),
                        nodes.reference('', '',
                            nodes.Text(uri, uri),
                            refuri=uri,
                        )
                    )
                )
            if "driverurl" in content:
                text = "Drivers for this database are available at:\n"
                sec.append(
                    nodes.paragraph(
                        '', '',
                        nodes.Text(text, text),
                        nodes.reference('', '',
                            nodes.Text(
                                content['driverurl'],
                                content['driverurl']),
                            refuri=content['driverurl']
                        )
                    )
                )
            output.append(sec)

        if "connectstring" in content:
            sec = nodes.section(
                '',
                nodes.title("Connecting", "Connecting"),
                nodes.paragraph(
                    '', '',
                    nodes.Text("Connect String:", "Connect String:"),
                    nodes.literal_block(
                        content['connectstring'],
                        content['connectstring'])
                ),
                ids=["dialect-%s-%s-connect" % (dialect_name, dbapi_name)]
            )
            output.append(sec)

        return output

    def _dialect_node(self):
        self._dialects[self.dialect_name] = self

        content = self._parse_content()
        self.database_name = content['name']

        self.bullets = nodes.bullet_list()
        text = "The following dialect/DBAPI options are available.  "\
               "Please refer to individual DBAPI sections "\
               "for connect information."
        sec = nodes.section(
            '',
            nodes.paragraph(
                '', '',
                nodes.Text(
                    "Support for the %s database." % content['name'],
                    "Support for the %s database." % content['name']
                ),
            ),
            nodes.title("DBAPI Support", "DBAPI Support"),
            nodes.paragraph(
                '', '',
                nodes.Text(text, text),
                self.bullets
            ),
            ids=["dialect-%s" % self.dialect_name]
        )

        return [sec]

    def _append_dbapi_bullet(self, dialect_name, dbapi_name, name, idname):
        env = self.state.document.settings.env
        dialect_directive = self._dialects[dialect_name]
        try:
            relative_uri = env.app.builder.get_relative_uri(
                dialect_directive.docname, self.docname)
        except:
            relative_uri = ""
        list_node = nodes.list_item(
            '',
            nodes.paragraph(
                '', '',
                nodes.reference(
                    '', '',
                    nodes.Text(name, name),
                    refdocname=self.docname,
                    refuri=relative_uri + "#" + idname
                ),
                #nodes.Text(" ", " "),
                #nodes.reference('', '',
                #            nodes.Text("(connectstring)", "(connectstring)"),
                #            refdocname=self.docname,
                #            refuri=env.app.builder.get_relative_uri(
                #                    dialect_directive.docname, self.docname) +
                ##                        "#" + ("dialect-%s-%s-connect" %
                #                                (dialect_name, dbapi_name))
                #        )
            )
        )
        dialect_directive.bullets.append(list_node)

    def run(self):
        env = self.state.document.settings.env
        self.docname = env.docname

        self.dialect_name = dialect_name = self.content[0]

        has_dbapi = "+" in dialect_name
        if has_dbapi:
            return self._dbapi_node()
        else:
            return self._dialect_node()


def setup(app):
    app.add_directive('dialect', DialectDirective)

