#!/usr/bin/env python3
from PIL import BdfFontFile, Image
import os
import serial
import argparse

compiled_output_path = 'compiled_eeprom'
header_path = 'eeprom_address.h'
eeprom_length = 131072 # 128 kib

data_path = "./eeprom_data"

output = open(compiled_output_path, 'wb')
header = open(header_path, 'w')

page_bit_width = 128
page_bit_height = 8
page_cnt = 4


#fonts
# for some reason BdfFontFile.BdfFontFile.bitmap doesn't have proper spacing
# so we'll just manually go through each character ourselves
# it's expected I'll rename fonts to how I think they should be refrenced beorehand
# also note we have no protection from using unsed chars, I can't let this project
# get to big for litteraly no reason

header.write("/**     GENERATED BY EEPROM COMPILER SCRIPT    **/\r\n\r\n")
header.write("#include \"paint.h\"\r\n")
header.write("// FONTS\r\n")

for file in os.listdir("{}/fonts/".format(data_path)):
    path = "{}/fonts/{}".format(data_path, file)
    if os.path.isfile(path) and path.split('.')[-1] == 'bdf':
        with open(path, 'rb') as font_fd:
            font_bdf = BdfFontFile.BdfFontFile(font_fd)
            font_name = file.split('.')[0].capitalize()

            #header.write("#define FONT_{}_ADDR\t0x{:04x}\r\n".format(font_name, output.tell()))
            header.write("font_t FONT_{} = {{ \r\n".format(font_name))

            first_char = False
            for char in enumerate(font_bdf.glyph):
                if char[1]:
                    if not first_char:
                        first_char = True
                        header.write((
                        "   .FONT_{}_WIDTH\t{}\r\n"
                        "   .FONT_{}_HEIGHT\t{}\r\n").format(
                            font_name, char[0],
                            font_name, char[1][-1].size[0],
                            font_name, char[1][-1].size[1]))
#                        header.write(("#define FONT_{}_FIRST_CHAR\t{}\r\n"
#                                "#define FONT_{}_WIDTH\t{}\r\n"
#                                "#define FONT_{}_HEIGHT\t{}\r\n").format(
#                            font_name, char[0],
#                            font_name, char[1][-1].size[0],
#                            font_name, char[1][-1].size[1]))
                    output.write(char[1][-1].tobytes('raw'))
            header.write("}\r\n")

header.write("\r\n\r\n// IMAGES\r\n#define IMG_BEGIN\t0x{:04x}\r\n".format(output.tell()))

image_cnt = 0

# images
for file in os.listdir("{}/images/".format(data_path)):
    path = "{}/images/{}".format(data_path, file)
    if os.path.isfile(path) and path.split('.')[-1] == 'png':
        with open(path, 'rb') as image_fd:
            image_cnt += 1
            image_bitmap = []
            image_bitmap_remapped = []
            image = Image.open(image_fd)
            if not image.mode == 'RGB':
                print("this script only compiles RGB formatted photos! (I'm lazy\r\n")
                exit(1)
            header.write("#define IMG_{}_ADDR\t0x{:04x}\r\n".format(
                file.split('.')[0].capitalize(),
                output.tell()))
            for byte in range(0, len(image.tobytes()), 3):
                if (byte / 3) % 8 == 0:
                    image_bitmap.append(0) 
                if sum(image.tobytes()[byte:byte+3]) > 0:
                    image_bitmap[-1] |= (int(byte / 3)) % 8

            # is this supposed to be big endian?
            image_bitmap_remapped = [0] * len(image_bitmap)
            for bit in range(0, page_bit_width * page_bit_height * page_cnt):
                w = page_bit_width
                h = page_bit_height
                i = bit
                #I am so sorry.
                extract_bit = (((i % w) * page_bit_height) + 
                                       (int(i / w) % page_bit_height) + 
                                       (int(i / (w * page_bit_height)) * 
                                       (w * page_bit_height)))

                if (extract_bit % 8) - (bit % 8) >= 0:
                    image_bitmap_remapped[int(bit / 8)] |= \
                    (image_bitmap[int(extract_bit / 8)] & (extract_bit % 8)) >> \
                    ((extract_bit % 8) - (bit % 8)) 
                else:
                    image_bitmap_remapped[int(bit / 8)] |= \
                    (image_bitmap[int(extract_bit / 8)] & (extract_bit % 8)) << \
                    ((bit % 8) - (extract_bit % 8)) 
            [output.write(byte.to_bytes(1, 'big')) for byte in image_bitmap_remapped]

header.write("#define IMG_COUNT\t{}\r\n\r\n".format(image_cnt))
            


print("EEPROM used: {}% ({} out of {} bits)".format(
    (output.tell() / eeprom_length) * 100, 
    output.tell(), eeprom_length))

if(output.tell() > eeprom_length):
    print("WARNING: You've used more eeprom then there is available!\r\n")

output.close()
header.close()
                    


