import re


def wrap_line(line, breakable_regex, line_cont,
              base_indent=0, max_width=80, rewrap=False):
    """Wrap the given line within the given width.

    This function is going to be exported to be used by template writers in
    Jinja as a filter.

    Parameters
    ----------

    line
        The line to be wrapped.

    breakable_regex
        The regular expression giving the places where the line can be broke.
        The parts in the regular expression that needs to be kept can be put in
        a capturing parentheses.

    line_cont
        The string to be put by the end of line to indicate line continuation.

    base_indent
        The base indentation for the lines.

    max_width
        The maximum width of the lines to wrap the given line within.

    rewrap
        if the line is going to be rewrapped.

    Return
    ------
    A list of lines for the breaking of the given line.

    """

    # First compute the width that is available for actual content.
    avail_width = max_width - base_indent - len(line_cont)

    # Remove all the new lines and old line-continuation and indentation for
    # rewrapping.
    if rewrap:
        line = re.sub(
            line_cont + '\\s*\n\\s*', '', line
        )

    # Break the given line according to the given regular expression.
    trunks = re.split(breakable_regex, line)
    # Have a shallow check and issue warning.
    for i in trunks:
        if len(i) > avail_width:
            print('WARNING')
            print(
                'Trunk {} is longer than the given width of {}'.format(
                    i, max_width
                )
            )
            print('Longer width or finer partition can be given.')
        continue

    # Actually break the list of trunks into lines.
    lines = []
    curr_line = ''
    for trunk in trunks:

        if len(curr_line) == 0 or len(curr_line) + len(trunk) <= avail_width:
            # When we are able to add the trunk to the current line. Note that
            # when the current line is empty, the next trunk will be forced to
            # be added.
            curr_line += trunk
        else:
            # When the current line is already filled up.
            #
            # First dump the current line.
            lines.append(curr_line)
            # Then add the current trunk at the beginning of the next line. The
            # left spaces could be striped.
            curr_line = trunk.lstrip()

        # Go on to the next trunk.
        continue

    else:

        # We need to add the trailing current line after all the loop.
        lines.append(curr_line)

    # Before returning, we need to decorate the lines with indentation and
    # continuation suffix.
    decorated = [
        ''.join([
            ' ' * base_indent, v, line_cont if i != len(lines) - 1 else ''
        ])
        for i, v in enumerate(lines)
    ]
    return '\n'.join(decorated)