"""
Code for the MCH2022 badge to control the 5 neopixels in the kite.

The buttons A and B can be used to cycle through the default colors provided by matplotlib.

Getting the Color List
----------------------
>>> import matplotlib
>>> print(matplotlib.colors.TABLEAU_COLORS)
>>> print(matplotlib.colors.BASE_COLORS)

>>> print(tuple(
...     (lambda s: tuple(int(f"0x{s[2 * i:2 * i + 2]}", 16)
...                      for i in range(3)))(c[1:])
...     for c in [matplotlib.colors.to_hex(f"C{j}")
...               for j in range(10)])


See Also
--------
[[https://www.badge.team/docs/badges/mch2022/software-development/micropython/neopixels/]]:
    The code is taken from there

"""
# imports
from machine import Pin
from neopixel import NeoPixel
import mch22
import buttons
import display


# Pin 19 controls the power supply to SD card and neopixels
powerPin = Pin(19, Pin.OUT)

# Pin 5 is the LED's data line
dataPin = Pin(5, Pin.OUT)

# create a neopixel object for 5 pixels
np = NeoPixel(dataPin, 5)

# turn on power to the LEDs
powerPin.on()


def reboot(pressed):
    """
    reboot on button press
    """
    if pressed:
        mch22.exit_python()


def convert_hexstring_to_int_tuple(color):
    """
    Convert color

    Example
    -------
    >>> convert_hexstring_to_int_tuple("#1f77b4")
    (31, 119, 180)
    """
    s = color[-6:]
    return tuple(int(f"0x{s[2 * i:2 * i + 2]}", 16)
                 for i in range(3))


BASE_COLORS = [
    ('b', (0, 0, 255)),
    ('g', (0, 127, 0)),
    ('r', (255, 0, 0)),
    ('c', (0, 192, 192)),
    ('m', (192, 0, 192)),
    ('y', (192, 192, 0)),
    ('k', (0, 0, 0)),
    ('w', (255, 255, 255))]

TABLEAU_COLORS = [
    (c_str, convert_hexstring_to_int_tuple(c))
    for (c_str, c) in [
            ('tab:blue', '#1f77b4'),
            ('tab:orange', '#ff7f0e'),
            ('tab:green', '#2ca02c'),
            ('tab:red', '#d62728'),
            ('tab:purple', '#9467bd'),
            ('tab:brown', '#8c564b'),
            ('tab:pink', '#e377c2'),
            ('tab:gray', '#7f7f7f'),
            ('tab:olive', '#bcbd22'),
            ('tab:cyan', '#17becf')]]

i = 0
color_list = TABLEAU_COLORS


def cycle_color(pressed):
    """
    Cycle through a list of colors
    """
    if not pressed:
        # if we don't add this, the function is also called on release
        return

    global i, color_list
    color_str, color = color_list[(i) % len(color_list)]
    color_hex = int("0x" + "".join([
        f"{n:02x}" for n in color]), 16)
    for pxl in [0, 1, 3]:
        # set some colors for the pixels (RGB)
        # (This is the center row of the kite)
        np[pxl] = color
    # pixel to the right
    np[4] = color_list[(i - 1) % len(color_list)][-1]
    # pixel to the left
    np[2] = color_list[(i + 1) % len(color_list)][-1]

    # send colors out to LEDs
    np.write()

    display.drawFill(color_hex)

    # Add what color we are displaying to the display
    text_color = 0xFFFFFF if color_str != 'w' else 0x000000
    font = "roboto_regular12"
    display.drawText(
        10, 10, f"Color: {color_str} - {color} - {hex(color_hex)}", text_color, font)

    display.drawText(
        10, 60, "Press <A> and <B> to cycle colors. \n<SELECT> to change color list.",
        text_color, font)
    display.drawText(
        10, 120, "Press <MENU> to quit", text_color, font)


    display.flush()
    i += 1

def cycle_backwards(pressed):
    """
    cycle the other way around
    """
    global i
    if pressed:
        i -= 2
        cycle_color(pressed)

def toggle(pressed):
    """
    switch between the two color lists
    """
    if not pressed:
        return
    global i, color_list
    if BASE_COLORS is color_list:
        color_list = TABLEAU_COLORS
    else:
        color_list = BASE_COLORS
    i -= 1
    cycle_color(pressed)

buttons.attach(buttons.BTN_MENU, reboot)
buttons.attach(buttons.BTN_A, cycle_color)
buttons.attach(buttons.BTN_B, cycle_backwards)
buttons.attach(buttons.BTN_SELECT, toggle)
# call function once for initialization
cycle_color(True)