import utime
from machine import I2C, Pin

from liquid_crystal_i2c import LiquidCrystal_I2C


class CustomNumber:
    FONT_BIT_MAP = (
        (0x07, 0x0F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F),  # TR: 0
        (0x1F, 0x1F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00),  # TS: 1
        (0x1C, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F),  # TL: 2
        (0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F),  # SS: 3
        (0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x0F, 0x07),  # LL: 4
        (0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x1F),  # LS: 5
        (0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1C),  # LR: 6
        (0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F),  # SLS: 7
    )

    RAM_MAP = (
        ((0, 1, 2), (4, 5, 6)),  # Number: 0
        ((1, 2, 255), (5, 255, 5)),  # Number: 1
        ((1, 3, 2), (0, 7, 5)),  # Number: 2
        ((1, 3, 2), (5, 7, 6)),  # Number: 3
        ((0, 7, 255), (255, 255, 255)),  # Number: 4
        ((0, 3, 1), (5, 7, 6)),  # Number: 5
        ((0, 3, 1), (4, 7, 6)),  # Number: 6
        ((1, 1, 2), (255, 0, 255)),  # Number: 7
        ((0, 3, 2), (4, 7, 6)),  # Number: 8
        ((0, 3, 2), (5, 7, 6)),  # Number: 9
    )

    def __init__(self, lcd):
        self.__lcd = lcd
        for ram_addr, bit_map in enumerate(self.FONT_BIT_MAP):
            self.__lcd.custom_character(ram_addr=ram_addr, bit_map=bit_map)

    def print_number(self, num, x, y):
        num_str = str(num)
        num_width = 4
        for index, num_char in enumerate(num_str):
            top_row, low_row = self.RAM_MAP[int(num_char)]
            for col_index, (top_row_chr, low_row_chr) in enumerate(zip(top_row, low_row)):
                self.__lcd.set_cursor(y + col_index, x + index * num_width)
                self.__lcd.print(chr(top_row_chr))
                self.__lcd.set_cursor(y + 1 + col_index, x + index * num_width)
                self.__lcd.print(chr(low_row_chr))


def main():
    i2c = I2C(0, scl=Pin(1), sda=Pin(0), freq=100000)
    lcd = LiquidCrystal_I2C(port=i2c, row=4, col=20)
    num = CustomNumber(lcd)
    lcd.backlight(True)
    lcd.clear_display()
    while True:
        for i in range(100):
            num.print_number(num=i, x=0, y=0)
            utime.sleep_ms(500)


if __name__ == "__main__":
    main()