# -*- coding: utf-8 -*-
"""
Provides textual descriptions for :mod:`behave.model` elements.
"""


from six.moves import range     # pylint: disable=redefined-builtin
from six.moves import zip       # pylint: disable=redefined-builtin
from behave.textutil import indent


# -----------------------------------------------------------------------------
# FUNCTIONS:
# -----------------------------------------------------------------------------
def escape_cell(cell):
    """
    Escape table cell contents.
    :param cell:  Table cell (as unicode string).
    :return: Escaped cell (as unicode string).
    """
    cell = cell.replace('\\', '\\\\')
    cell = cell.replace('\n', '\\n')
    cell = cell.replace('|', '\\|')
    return cell


def escape_triple_quotes(text):
    """
    Escape triple-quotes, used for multi-line text/doc-strings.
    """
    return text.replace('"""', '\\"\\"\\"')


# -----------------------------------------------------------------------------
# CLASS:
# -----------------------------------------------------------------------------
class ModelDescriptor(object):

    @staticmethod
    def describe_table(table, indentation=None):
        """
        Provide a textual description of the table (as used w/ Gherkin).

        :param table:  Table to use (as :class:`behave.model.Table`)
        :param indentation:  Line prefix to use (as string, if any).
        :return: Textual table description (as unicode string).
        """
        # -- STEP: Determine output size of all cells.
        cell_lengths = []
        all_rows = [table.headings] + table.rows
        for row in all_rows:
            lengths = [len(escape_cell(c)) for c in row]
            cell_lengths.append(lengths)

        # -- STEP: Determine max. output size for each column.
        max_lengths = []
        for col in range(0, len(cell_lengths[0])):
            max_lengths.append(max([c[col] for c in cell_lengths]))

        # -- STEP: Build textual table description.
        lines = []
        for r, row in enumerate(all_rows):
            line = "|"
            for c, (cell, max_length) in enumerate(zip(row, max_lengths)):
                pad_size = max_length - cell_lengths[r][c]
                line += " %s%s |" % (escape_cell(cell), " " * pad_size)
            line += "\n"
            lines.append(line)

        if indentation:
            return indent(lines, indentation)
        # -- OTHERWISE:
        return "".join(lines)

    @staticmethod
    def describe_docstring(doc_string, indentation=None):
        """
        Provide a textual description of the multi-line text/triple-quoted
        doc-string (as used w/ Gherkin).

        :param doc_string:  Multi-line text to use.
        :param indentation:  Line prefix to use (as string, if any).
        :return: Textual table description (as unicode string).
        """
        text = escape_triple_quotes(doc_string)
        text = '"""\n' + text + '\n"""\n'

        if indentation:
            text = indent(text, indentation)
        return text


class ModelPrinter(ModelDescriptor):

    def __init__(self, stream):
        super(ModelPrinter, self).__init__()
        self.stream = stream

    def print_table(self, table, indentation=None):
        self.stream.write(self.describe_table(table, indentation))
        self.stream.flush()

    def print_docstring(self, text, indentation=None):
        self.stream.write(self.describe_docstring(text, indentation))
        self.stream.flush()
