import binascii

import badger2040w
import badger_os

# **** Put your list title here *****
list_title = "Checklist"
list_file = "checklist.txt"


# Global Constantsu
WIDTH = badger2040w.WIDTH
HEIGHT = badger2040w.HEIGHT

ARROW_THICKNESS = 3
ARROW_WIDTH = 18
ARROW_HEIGHT = 14
ARROW_PADDING = 2

MAX_ITEM_CHARS = 26
TITLE_TEXT_SIZE = 0.7
ITEM_TEXT_SIZE = 0.6
ITEM_SPACING = 20

LIST_START = 40
LIST_PADDING = 2
LIST_WIDTH = WIDTH - LIST_PADDING - LIST_PADDING - ARROW_WIDTH
LIST_HEIGHT = HEIGHT - LIST_START - LIST_PADDING - ARROW_HEIGHT


# Default list items - change the list items by editing checklist.txt
list_items = ["Badger", "Badger", "Badger", "Badger", "Badger", "Mushroom", "Mushroom", "Snake"]
save_checklist = False

try:
    with open("checklist.txt", "r") as f:
        raw_list_items = f.read()

    if raw_list_items.find(" X\n") != -1:
        # Have old style checklist, preserve state and note we should resave the list to remove the Xs
        list_items = []
        state = {
            "current_item": 0,
            "checked": []
        }
        for item in raw_list_items.strip().split("\n"):
            if item.endswith(" X"):
                state["checked"].append(True)
                item = item[:-2]
            else:
                state["checked"].append(False)
            list_items.append(item)
        state["items_hash"] = binascii.crc32("\n".join(list_items))

        badger_os.state_save("list", state)
        save_checklist = True
    else:
        list_items = [item.strip() for item in raw_list_items.strip().split("\n")]

except OSError:
    save_checklist = True

if save_checklist:
    with open("checklist.txt", "w") as f:
        for item in list_items:
            f.write(item + "\n")


# ------------------------------
#      Drawing functions
# ------------------------------

# Draw the list of items
def draw_list(items, item_states, start_item, highlighted_item, x, y, width, height, item_height, columns):
    item_x = 0
    item_y = 0
    current_col = 0
    for i in range(start_item, len(items)):
        if i == highlighted_item:
            display.set_pen(12)
            display.rectangle(item_x, item_y + y - (item_height // 2), width // columns, item_height)
        display.set_pen(0)
        display.text(items[i], item_x + x + item_height, item_y + y, WIDTH, ITEM_TEXT_SIZE)
        draw_checkbox(item_x, item_y + y - (item_height // 2), item_height, 15, 0, 2, item_states[i], 2)
        item_y += item_height
        if item_y >= height - (item_height // 2):
            item_x += width // columns
            item_y = 0
            current_col += 1
            if current_col >= columns:
                return


# Draw a upward arrow
def draw_up(x, y, width, height, thickness, padding):
    border = (thickness // 4) + padding
    display.line(x + border, y + height - border,
                 x + (width // 2), y + border)
    display.line(x + (width // 2), y + border,
                 x + width - border, y + height - border)


# Draw a downward arrow
def draw_down(x, y, width, height, thickness, padding):
    border = (thickness // 2) + padding
    display.line(x + border, y + border,
                 x + (width // 2), y + height - border)
    display.line(x + (width // 2), y + height - border,
                 x + width - border, y + border)


# Draw a left arrow
def draw_left(x, y, width, height, thickness, padding):
    border = (thickness // 2) + padding
    display.line(x + width - border, y + border,
                 x + border, y + (height // 2))
    display.line(x + border, y + (height // 2),
                 x + width - border, y + height - border)


# Draw a right arrow
def draw_right(x, y, width, height, thickness, padding):
    border = (thickness // 2) + padding
    display.line(x + border, y + border,
                 x + width - border, y + (height // 2))
    display.line(x + width - border, y + (height // 2),
                 x + border, y + height - border)


# Draw a tick
def draw_tick(x, y, width, height, thickness, padding):
    border = (thickness // 2) + padding
    display.line(x + border, y + ((height * 2) // 3),
                 x + (width // 2), y + height - border)
    display.line(x + (width // 2), y + height - border,
                 x + width - border, y + border)


# Draw a cross
def draw_cross(x, y, width, height, thickness, padding):
    border = (thickness // 2) + padding
    display.line(x + border, y + border, x + width - border, y + height - border)
    display.line(x + width - border, y + border, x + border, y + height - border)


# Draw a checkbox with or without a tick
def draw_checkbox(x, y, size, background, foreground, thickness, tick, padding):
    border = (thickness // 2) + padding
    display.set_pen(background)
    display.rectangle(x + border, y + border, size - (border * 2), size - (border * 2))
    display.set_pen(foreground)
    display.line(x + border, y + border, x + size - border, y + border)
    display.line(x + border, y + border, x + border, y + size - border)
    display.line(x + size - border, y + border, x + size - border, y + size - border)
    display.line(x + border, y + size - border, x + size - border, y + size - border)
    if tick:
        draw_tick(x, y, size, size, thickness, 2 + border)


# ------------------------------
#        Program setup
# ------------------------------

changed = not badger2040w.woken_by_button()
state = {
    "current_item": 0,
}
badger_os.state_load("list", state)
items_hash = binascii.crc32("\n".join(list_items))
if "items_hash" not in state or state["items_hash"] != items_hash:
    # Item list changed, or not yet written reset the list
    state["current_item"] = 0
    state["items_hash"] = items_hash
    state["checked"] = [False] * len(list_items)
    changed = True

# Global variables
items_per_page = 0

# Create a new Badger and set it to update FAST
display = badger2040w.Badger2040W()
display.led(128)
display.set_font("sans")
display.set_thickness(2)
if changed:
    display.set_update_speed(badger2040w.UPDATE_FAST)
else:
    display.set_update_speed(badger2040w.UPDATE_TURBO)

# Find out what the longest item is
longest_item = 0
for i in range(len(list_items)):
    while True:
        item = list_items[i]
        item_length = display.measure_text(item, ITEM_TEXT_SIZE)
        if item_length > 0 and item_length > LIST_WIDTH - ITEM_SPACING:
            list_items[i] = item[:-1]
        else:
            break
    longest_item = max(longest_item, display.measure_text(list_items[i], ITEM_TEXT_SIZE))


# And use that to calculate the number of columns we can fit onscreen and how many items that would give
list_columns = 1
while longest_item + ITEM_SPACING < (LIST_WIDTH // (list_columns + 1)):
    list_columns += 1

items_per_page = ((LIST_HEIGHT // ITEM_SPACING) + 1) * list_columns


# ------------------------------
#       Main program loop
# ------------------------------

while True:
    if len(list_items) > 0:
        if display.pressed(badger2040w.BUTTON_A):
            if state["current_item"] > 0:
                page = state["current_item"] // items_per_page
                state["current_item"] = max(state["current_item"] - (items_per_page) // list_columns, 0)
                if page != state["current_item"] // items_per_page:
                    display.update_speed(badger2040w.UPDATE_FAST)
                changed = True
        if display.pressed(badger2040w.BUTTON_B):
            state["checked"][state["current_item"]] = not state["checked"][state["current_item"]]
            changed = True
        if display.pressed(badger2040w.BUTTON_C):
            if state["current_item"] < len(list_items) - 1:
                page = state["current_item"] // items_per_page
                state["current_item"] = min(state["current_item"] + (items_per_page) // list_columns, len(list_items) - 1)
                if page != state["current_item"] // items_per_page:
                    display.update_speed(badger2040w.UPDATE_FAST)
                changed = True
        if display.pressed(badger2040w.BUTTON_UP):
            if state["current_item"] > 0:
                state["current_item"] -= 1
                changed = True
        if display.pressed(badger2040w.BUTTON_DOWN):
            if state["current_item"] < len(list_items) - 1:
                state["current_item"] += 1
                changed = True

    if changed:
        badger_os.state_save("list", state)

        display.set_pen(15)
        display.clear()

        display.set_pen(12)
        display.rectangle(WIDTH - ARROW_WIDTH, 0, ARROW_WIDTH, HEIGHT)
        display.rectangle(0, HEIGHT - ARROW_HEIGHT, WIDTH, ARROW_HEIGHT)

        y = LIST_PADDING + 12
        display.set_pen(0)
        display.text(list_title, LIST_PADDING, y, WIDTH, TITLE_TEXT_SIZE)

        y += 12
        display.set_pen(0)
        display.line(LIST_PADDING, y, WIDTH - LIST_PADDING - ARROW_WIDTH, y)

        if len(list_items) > 0:
            page_item = 0
            if items_per_page > 0:
                page_item = (state["current_item"] // items_per_page) * items_per_page

            # Draw the list
            display.set_pen(0)
            draw_list(list_items, state["checked"], page_item, state["current_item"], LIST_PADDING, LIST_START,
                      LIST_WIDTH, LIST_HEIGHT, ITEM_SPACING, list_columns)

            # Draw the interaction button icons
            display.set_pen(0)

            # Previous item
            if state["current_item"] > 0:
                draw_up(WIDTH - ARROW_WIDTH, (HEIGHT // 4) - (ARROW_HEIGHT // 2),
                        ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)

            # Next item
            if state["current_item"] < (len(list_items) - 1):
                draw_down(WIDTH - ARROW_WIDTH, ((HEIGHT * 3) // 4) - (ARROW_HEIGHT // 2),
                          ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)

            # Previous column
            if state["current_item"] > 0:
                draw_left((WIDTH // 7) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT,
                          ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)

            # Next column
            if state["current_item"] < (len(list_items) - 1):
                draw_right(((WIDTH * 6) // 7) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT,
                           ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)

            if state["checked"][state["current_item"]]:
                # Tick off item
                draw_cross((WIDTH // 2) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT,
                           ARROW_HEIGHT, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
            else:
                # Untick item
                draw_tick((WIDTH // 2) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT,
                          ARROW_HEIGHT, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
        else:
            # Say that the list is empty
            empty_text = "Nothing Here"
            text_length = display.measure_text(empty_text, ITEM_TEXT_SIZE)
            display.text(empty_text, ((LIST_PADDING + LIST_WIDTH) - text_length) // 2, (LIST_HEIGHT // 2) + LIST_START - (ITEM_SPACING // 4), WIDTH, ITEM_TEXT_SIZE)

        display.update()
        display.set_update_speed(badger2040w.UPDATE_TURBO)
        changed = False

    display.halt()
