import buttons
import defines
import math
import random
import rgb
import virtualtimers

pixels = [
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ],
]

new_char_frequency = 100


def new_char():
    coord_x = random.randint(0, 31)
    pixels[0][coord_x] = 255

    run_again_in = new_char_frequency  # time until this function should run again, in ms
    return run_again_in


def core_loop():
    frame = []
    for x in range(31, -1, -1):
        for y in range(7, -1, -1):
            prev_brightness = pixels[y][x]
            new_brightness = decrease_brightness(prev_brightness)

            # prevent endlessly trailing display of almost 0 values
            if new_brightness < 20:
                new_brightness = 0

            if trail_should_be_aborted(y, prev_brightness):
                prev_brightness = 250

            write_pixel(new_brightness, x, y)

            if trail_should_extend_a_pixel_down(prev_brightness, y):
                write_pixel(prev_brightness, x, y + 1)

    for y in range(7, -1, -1):
        for x in range(31, -1, -1):
            brightness = pixels[y][x]
            frame_val = build_color_value(brightness)

            if pixel_is_tip_of_a_trail(brightness):
                frame_val = 0xaaaaaaff

            frame.append(frame_val)

    rgb.enablecomp()
    rgb.frame(frame)
    rgb.disablecomp()

    run_again_in = 71  # time until this function should run again, in ms
    return run_again_in


# internal/"private" functions, used by the core loop


def build_color_value(brightness):
    color_r = 0 * brightness * pow(16, 6)
    color_g = 1 * brightness * pow(16, 4)
    color_b = 0 * brightness * pow(16, 2)
    color_l = 255
    frame_val = color_r + color_g + color_b + color_l
    return frame_val


def decrease_brightness(prev_brightness):
    return max(0, math.ceil(prev_brightness * (random.randint(60, 99)/100)))


def trail_should_be_aborted(y, prev_brightness):
    return y > 3 and random.randint(0, 100) > 95 and prev_brightness >= 255


def write_pixel(brightness, x, y):
    pixels[y][x] = brightness


def trail_should_extend_a_pixel_down(prev_brightness, y):
    return y < 7 and prev_brightness >= 255


def pixel_is_tip_of_a_trail(brightness):
    return brightness >= 250

# Button callbacks


def brightness_increase(button_is_down):
    if button_is_down:
        new_brightness = min(32, rgb.getbrightness()+4)
        rgb.setbrightness(new_brightness)
        pass


def brightness_decrease(button_is_down):
    if button_is_down:
        new_brightness = max(0, rgb.getbrightness()-4)
        rgb.setbrightness(new_brightness)
        pass


def char_frequency_increase(button_is_down):
    global new_char_frequency
    if button_is_down:
        new_char_frequency = min(1000, new_char_frequency+100)
        pass


def char_frequency_decrease(button_is_down):
    global new_char_frequency
    if button_is_down:
        new_char_frequency = max(10, new_char_frequency-100)
        pass


# Register button callbacks

buttons.register(defines.BTN_DOWN, brightness_increase)
buttons.register(defines.BTN_UP, brightness_decrease)
buttons.register(defines.BTN_LEFT, char_frequency_increase)
buttons.register(defines.BTN_RIGHT, char_frequency_decrease)

# Start processes

rgb.setbrightness(16)
virtualtimers.begin(100)
virtualtimers.new(0, core_loop)
virtualtimers.new(0, new_char)