from colorama import Fore, Back, Style

# see http://xahlee.info/comp/unicode_drawing_shapes.html


def merge(color_string):
    """ Given a string of colorama ANSI, merge them if you can. """
    return color_string.replace("m\x1b[", ";")


class Boxes(object):
    """ Boxes makes nice ASCII graphic menus

    Example:

        c1 = merge(Style.BRIGHT + Fore.CYAN)
        c2 = merge(Style.NORMAL + Fore.CYAN)

        # Set the size of the box to 40  (Important!)
        box = Boxes(40, color=c1)

        self.queue_game.put(box.top())
        # format string "{0:^40}".format("Text Centered")
        # This centers the text into the size of the box.

        self.queue_game.put(box.row(c1 + "{0:^40}".format("Scripts")))

        # this draws the middle line.  (The line that goes across, but is
        # connected on both sides to the one above it).
        self.queue_game.put(box.middle())


        def menu_item(ch, desc):
            # Again we want the final string to be 40!
            # c1 and c2 (below) take 0 space.
            # We have " " + ch + " " + "-" + " " .. which equals 5
            # So desc needs {:35} to pad out string out to 40 print chars.

            row = " {0}{1} {2}-{3} {4:35}".format(c1, ch, c2, c1, desc)
            # self.queue_game.put(
            #     " " + c1 + ch + c2 + " - " + c1 + desc + self.nl
            # )
            self.queue_game.put(box.row(row))

        menu_item("1", "Ports (Trades between two sectors)")
        menu_item("2", "Explore (Strange new sectors)")
        menu_item("3", "Space... the final frontier...")
        menu_item("X", "eXit")
        self.queue_game.put(box.bottom())

    """

    box_styles = (
        # ┌──┐
        # │  │
        # ├──┤
        # └──┘
        {
            "tl": "\xda",
            "tr": "\xbf",
            "top": "\xc4",
            "side": "\xb3",
            "bl": "\xc0",
            "br": "\xd9",
            "ml": "\xc3",
            "mr": "\xb4",
        },
        # ╔══╗
        # ║  ║
        # ╠══╣
        # ╚══╝
        {
            "tl": "\xc9",
            "tr": "\xbb",
            "top": "\xcd",
            "side": "\xba",
            "bl": "\xc8",
            "br": "\xbc",
            "ml": "\xcc",
            "mr": "\xb9",
        },
        # ╒══╕
        # │  │
        # ╞══╡
        # ╘══╛
        {
            "tl": "\xd5",
            "tr": "\xb8",
            "top": "\xcd",
            "side": "\xb3",
            "bl": "\xd4",
            "br": "\xbe",
            "ml": "\xc6",
            "mr": "\xb5",
        },
        # ╓──╖
        # ║  ║
        # ╟──╢
        # ╙──╜
        {
            "tl": "\xd6",
            "tr": "\xb7",
            "top": "\xc4",
            "side": "\xba",
            "bl": "\xd3",
            "br": "\xbd",
            "ml": "\xc7",
            "mr": "\xb6",
        },
    )

    def __init__(self, size: int, color="", style=1, start_nl=True):
        """ Construct box

        size is width of text inside the box.
        (so actual width is size + 2).

        color = Style of color to use.  
        If color is blank, we don't use the RESET_ALL.

        style=0  Is double lines.  
        start_nl Should we start the top with a newline?
        """
        self.size = size
        self.style = style
        self.color = color
        self.start_nl = start_nl

        # default colors
        # self.c = merge(Style.BRIGHT + Fore.WHITE + Back.BLUE)
        # self.cp = merge(Style.BRIGHT + Fore.YELLOW + Back.BLUE)

        # useful consts
        self.r = Style.RESET_ALL
        self.nl = "\n\r"
        # self.bsb = "\b \b"

    def top(self):
        """ Output the TOP line. """
        if self.color == "":
            c = ""
            r = ""
        else:
            c = self.color
            r = self.r
        s = self.box_styles[self.style]
        if self.start_nl:
            n = self.nl
        else:
            n = ""
        return n + c + s["tl"] + s["top"] * self.size + s["tr"] + r + self.nl

    def middle(self):
        """ Output MIDDLE line.

        This solid line goes completely across.
        The edges connect to the top and bottom.
        """
        if self.color == "":
            c = ""
            r = ""
        else:
            c = self.color
            r = self.r
        s = self.box_styles[self.style]
        return c + s["ml"] + s["top"] * self.size + s["mr"] + r + self.nl

    def row(self, line):
        """ Output content line.

        NOTE:  the line length must match the box size.
        Use "{0:30}".format(content) to match size of 30.
        """
        if self.color == "":
            c = ""
            r = ""
        else:
            c = self.color
            r = self.r
        s = self.box_styles[self.style]
        return c + "{0}{1}{2}".format(s["side"], r + line + c, s["side"]) + r + self.nl

    def bottom(self):
        """ Output BOTTOM line. """
        if self.color == "":
            c = ""
            r = ""
        else:
            c = self.color
            r = self.r
        s = self.box_styles[self.style]
        return c + s["bl"] + s["top"] * self.size + s["br"] + r + self.nl

    @staticmethod
    def alert(message, length=0, pad=2, width=78, base="blue", style=1):
        """
        Display alert message

        Example:
        self.queue_game.put(Boxes.alert("Proxy done.", base="green"))

        length: the printable character length.
            If the string contains color codes, you'll need
            to use this so it will be centered properly.
            If not given, len(message) is used.
        pad:  The spaces at the front and back of the message.
        width:  Defaults to 78 chars wide.
        base: The background color to use for the alert.
        """
        if base == "red":
            color = merge(Style.BRIGHT + Fore.YELLOW + Back.RED)
        elif base == "blue":
            color = merge(Style.BRIGHT + Fore.YELLOW + Back.BLUE)
        elif base == "green":
            color = merge(Style.BRIGHT + Fore.YELLOW + Back.GREEN)
        elif base == "cyan":
            color = merge(Style.BRIGHT + Fore.YELLOW + Back.CYAN)
        elif base == "magenta":
            color = merge(Style.BRIGHT + Fore.YELLOW + Back.MAGENTA)
        else:
            # I don't know.
            color = Style.RESET_ALL

        if length == 0:
            length = len(message)
        box_size = length + pad * 2
        boxpad = " " * pad
        box = Boxes(box_size, color=color, style=style, start_nl=False)
        msg = "{0}{1}{2}{3}".format(color, boxpad, message, boxpad)

        # How much pad to add to the left side?
        left_pad = (width - box_size + 2) // 2
        pad = " " * left_pad
        return "{0}{1}{2}{3}{4}{5}".format(
            pad, box.top(), pad, box.row(msg), pad, box.bottom()
        )