from __future__ import absolute_import

import logging
import textwrap

from rstcloth.cloth import Cloth


logger = logging.getLogger("rstcloth")


def fill(string, first=0, hanging=0, wrap=True):
    first_indent = " " * first
    hanging_indent = " " * hanging

    if wrap is True:
        return textwrap.fill(
            string,
            width=72,
            break_on_hyphens=False,
            break_long_words=False,
            initial_indent=first_indent,
            subsequent_indent=hanging_indent,
            replace_whitespace=False,
        )  # https://docs.python.org/2/library/textwrap.html#textwrap.TextWrapper.replace_whitespace
    else:
        content = string.split("\n")
        if first == hanging:
            return "\n".join([first_indent + line for line in content])
        elif first > hanging:
            indent_diff = first - hanging
            o = indent_diff * " "
            o += "\n".join([hanging_indent + line for line in content])
            return o
        elif first < hanging:
            indent_diff = hanging - first
            o = "\n".join([hanging_indent + line for line in content])
            return o[indent_diff:]


def _indent(content, indent):
    if indent == 0:
        return content
    else:
        indent = " " * indent
        if isinstance(content, list):
            return ["".join([indent, line]) for line in content]
        else:
            return "".join([indent, content])


class RstCloth(Cloth):
    def __init__(self):
        self._data = []

    def _add(self, content):
        if isinstance(content, list):
            self._data.extend(content)
        else:
            self._data.append(content)

    def newline(self, count=1):
        if isinstance(count, int):
            if count == 1:
                self._add("")
            else:
                # subtract one because every item gets one \n for free.
                self._add("\n" * (count - 1))
        else:
            raise Exception("Count of newlines must be a positive int.")

    def directive(self, name, arg=None, fields=None, content=None, indent=0, wrap=True):
        o = []

        o.append(".. {0}::".format(name))

        if arg is not None:
            o[0] += " " + arg

        if fields is not None:
            for k, v in fields:
                o.append(_indent(":" + k + ": " + str(v), 3))

        if content is not None:
            o.append("")

            if isinstance(content, list):
                o.extend(_indent(content, 3))
            else:
                o.append(_indent(content, 3))

        self._add(_indent(o, indent))

    @staticmethod
    def role(name, value, text=None):
        if isinstance(name, list):
            name = ":".join(name)

        if text is None:
            return ":{0}:`{1}`".format(name, value)
        else:
            return ":{0}:`{2} <{1}>`".format(name, value, text)

    @staticmethod
    def bold(string):
        return "**{0}**".format(string)

    @staticmethod
    def emph(string):
        return "*{0}*".format(string)

    @staticmethod
    def pre(string):
        return "``{0}``".format(string)

    @staticmethod
    def inline_link(text, link):
        return "`{0} <{1}>`_".format(text, link)

    @staticmethod
    def footnote_ref(name):
        return "[#{0}]".format(name)

    @staticmethod
    def _paragraph(content, wrap=True):
        return [i.rstrip() for i in fill(content, wrap=wrap).split("\n")]

    def replacement(self, name, value, indent=0):
        output = ".. |{0}| replace:: {1}".format(name, value)
        self._add(_indent(output, indent))

    def codeblock(self, content, indent=0, wrap=True, language=None):
        if language is None:
            o = ["::", _indent(content, 3)]
            self._add(_indent(o, indent))
        else:
            self.directive(name="code-block", arg=language, content=content, indent=indent)

    def footnote(self, ref, text, indent=0, wrap=True):
        self._add(fill(".. [#{0}] {1}".format(ref, text), indent, indent + 3, wrap))

    def definition(self, name, text, indent=0, wrap=True, bold=False):
        o = []

        if bold is True:
            name = self.bold(name)

        o.append(_indent(name, indent))
        o.append(fill(text, indent + 3, indent + 3, wrap=wrap))

        self._add(o)

    def li(self, content, bullet="-", indent=0, wrap=True):
        bullet = bullet + " "
        hanging_indent_len = indent + len(bullet)

        if isinstance(content, list):
            content = "\n".join(bullet + item for item in content)
            self._add(fill(content, indent, indent + hanging_indent_len, wrap))
        else:
            content = bullet + fill(content, 0, len(bullet), wrap)
            self._add(fill(content, indent, indent, wrap))

    def field(self, name, value, indent=0, wrap=True):
        output = [":{0}:".format(name)]

        if len(name) + len(value) < 60:
            output[0] += " " + value
            final = True
        else:
            output.append("")
            final = False

        if wrap is True and final is False:
            content = fill(value, wrap=wrap).split("\n")
            for line in content:
                output.append(_indent(line, 3))

        if wrap is False and final is False:
            output.append(_indent(value, 3))

        for line in output:
            self._add(_indent(line, indent))

    def ref_target(self, name, indent=0):
        o = ".. _{0}:".format(name)
        self._add(_indent(o, indent))

    def content(self, content, indent=0, wrap=True):
        if isinstance(content, list):
            for line in content:
                self._add(_indent(line, indent))
        else:
            lines = self._paragraph(content, wrap)

            for line in lines:
                self._add(_indent(line, indent))

    def title(self, text, char="=", indent=0):
        line = char * len(text)
        self._add(_indent([line, text, line], indent))

    def heading(self, text, char, indent=0):
        self._add(_indent([text, char * len(text)], indent))

    def h1(self, text, indent=0):
        self.heading(text, char="=", indent=indent)

    def h2(self, text, indent=0):
        self.heading(text, char="-", indent=indent)

    def h3(self, text, indent=0):
        self.heading(text, char="~", indent=indent)

    def h4(self, text, indent=0):
        self.heading(text, char="+", indent=indent)

    def h5(self, text, indent=0):
        self.heading(text, char="^", indent=indent)

    def h6(self, text, indent=0):
        self.heading(text, char=";", indent=indent)
