# Source code for lookatme.utils

    """
    """

    import urwid

    def prefix_text(text: str, prefix: str, split: str = "\n") -> str:
        return split.join(prefix + part for part in text.split(split))

    def row_text(rendered_row):
        """Return all text joined together from the rendered row
        """
        return b"".join(x[-1] for x in rendered_row)

    def resolve_bag_of_text_markup_or_widgets(items):
        """Resolve the list of items into either contiguous urwid.Text() instances,
        or pre-existing urwid.Widget objects
        """
        res = []
        curr_text_markup = []
        for item in items:
            if isinstance(item, tuple) or isinstance(item, str):
                curr_text_markup.append(item)
            else:
                if len(curr_text_markup) > 0:
                    res.append(urwid.Text(curr_text_markup))
                    curr_text_markup = []
                res.append(item)

        if len(curr_text_markup) > 0:
            res.append(urwid.Text(curr_text_markup))

        return res

    def dict_deep_update(to_update, new_vals):
        """Deeply update the to_update dict with the new_vals
        """
        for key, value in new_vals.items():
            if isinstance(value, dict):
                node = to_update.setdefault(key, {})
                dict_deep_update(node, value)
            else:
                to_update[key] = value

    def spec_from_style(styles):
        """Create an urwid.AttrSpec from a {fg:"", bg:""} style dict. If styles
        is a string, it will be used as the foreground
        """
        if isinstance(styles, str):
            return urwid.AttrSpec(styles, "")
        else:
            return urwid.AttrSpec(styles.get("fg", ""), styles.get("bg", ""))

    def get_fg_bg_styles(style):
        if style is None:
            return [], []

        def non_empty_split(data):
            res = [x.strip() for x in data.split(",")]
            return list(filter(None, res))

        # from lookatme.config.get_style()
        if isinstance(style, dict):
            return non_empty_split(style["fg"]), non_empty_split(style["bg"])
        # just a str will only set the foreground color
        elif isinstance(style, str):
            return non_empty_split(style), []
        elif isinstance(style, urwid.AttrSpec):
            return non_empty_split(style.foreground), non_empty_split(style.background)
        else:
            raise ValueError("Unsupported style value {!r}".format(style))

    def overwrite_spec(orig_spec, new_spec):
        if orig_spec is None:
            orig_spec = urwid.AttrSpec("", "")
        if new_spec is None:
            new_spec = urwid.AttrSpec("", "")

        fg_orig = orig_spec.foreground.split(",")
        fg_orig_color = orig_spec._foreground_color()
        fg_orig.remove(fg_orig_color)

        bg_orig = orig_spec.background.split(",")
        bg_orig_color = orig_spec._background()
        bg_orig.remove(bg_orig_color)

        fg_new = new_spec.foreground.split(",")
        fg_new_color = new_spec._foreground_color()
        fg_new.remove(fg_new_color)

        bg_new = new_spec.background.split(",")
        bg_new_color = new_spec._background()
        bg_new.remove(bg_new_color)

        if fg_new_color == "default":
            fg_orig.append(fg_orig_color)
        else:
            fg_new.append(fg_new_color)

        if bg_new_color == "default":
            bg_orig.append(bg_orig_color)
        else:
            bg_new.append(bg_new_color)

        return urwid.AttrSpec(
            ",".join(set(fg_orig + fg_new)),
            ",".join(set(bg_orig + bg_new)),
        )

    def flatten_text(text, new_spec=None):
        """Return a flattend list of tuples that can be used as the first argument
        to a new urwid.Text().

        :param urwid.Text text: The text to flatten
        :param urwid.AttrSpec new_spec: A new spec to merge with existing styles
        :returns: list of tuples
        """
        text, chunk_stylings = text.get_text()

        res = []
        total_len = 0
        for spec, chunk_len in chunk_stylings:
            split_text = text[total_len:total_len + chunk_len]
            total_len += chunk_len

            split_text_spec = overwrite_spec(new_spec, spec)
            res.append((split_text_spec, split_text))

        if len(text[total_len:]) > 0:
            res.append((new_spec, text[total_len:]))

        return res

    def can_style_item(item):
        """Return true/false if ``style_text`` can work with the given item
        """
        return isinstance(item, (urwid.Text, list, tuple))

    def styled_text(text, new_styles, old_styles=None, supplement_style=False):
        """Return a styled text tuple that can be used within urwid.Text.

        .. note::

            If an urwid.Text instance is passed in as the ``text`` parameter,
            alignment values will be lost and must be explicitly re-added by the
            caller.
        """
        if isinstance(text, urwid.Text):
            new_spec = spec_from_style(new_styles)
            return flatten_text(text, new_spec)
        elif (isinstance(text, tuple)
                and isinstance(text[0], urwid.AttrSpec)
                and isinstance(text[1], urwid.Text)):
            text = text[1].text
            old_styles = text[0]

        new_fg, new_bg = get_fg_bg_styles(new_styles)
        old_fg, old_bg = get_fg_bg_styles(old_styles)

        def join(items):
            return ",".join(set(items))

        spec = urwid.AttrSpec(
            join(new_fg + old_fg),
            join(new_bg + old_bg),
        )
        return (spec, text)

    def pile_or_listbox_add(container, widgets):
        """Add the widget/widgets to the container
        """
        if isinstance(container, urwid.ListBox):
            return listbox_add(container, widgets)
        elif isinstance(container, urwid.Pile):
            return pile_add(container, widgets)
        else:
            raise ValueError("Container was not listbox, nor pile")

    def listbox_add(listbox, widgets):
        if not isinstance(widgets, list):
            widgets = [widgets]

        for w in widgets:
            if len(listbox.body) > 0 \
                    and isinstance(w, urwid.Divider) \
                    and isinstance(listbox.body[-1], urwid.Divider):
                continue
            listbox.body.append(w)

    def pile_add(pile, widgets):
        """
        """
        if not isinstance(widgets, list):
            widgets = [widgets]

        for w in widgets:
            if len(pile.contents) > 0 \
                    and isinstance(w, urwid.Divider) \
                    and isinstance(pile.contents[-1][0], urwid.Divider):
                continue
            pile.contents.append((w, pile.options()))

    def int_to_roman(integer):
        integer = int(integer)
        ints = [1000, 900,  500, 400, 100,  90, 50,  40, 10,  9,   5,  4,   1]
        nums = ["m",  "cm", "d", "cd", "c", "xc",
                "l", "xl", "x", "ix", "v", "iv", "i"]
        result = []
        for i in range(len(ints)):
            count = integer // ints[i]
            result.append(nums[i] * count)
            integer -= ints[i] * count
        return "".join(result)