#!/usr/bin/env python3

import os
import re
import sys

line_re = re.compile(r'^([0-9A-Fa-f]{4}):((?:[0-9A-Fa-f]{32}){1,2})$')
def parse(line):
    m = line_re.match(line)
    if not m:
        raise Exception('could not parse line: %r' % line)
    n = int(m.group(1), 16)
    data = m.group(2)
    return (n, data)

blank_line = ' '.join(['00'] * 16)

def split16(data):
    return ' '.join([data[i:i+2] for i in range(0, 32, 2)])

def split(data):
    if len(data) == 32:
        return (split16(data),)
    elif len(data) == 64:
        return (split16(data[0:32]), split16(data[32:64]))
    else:
        raise Exception('invalid data length: %d' % len(data))

def run(path, start):
    limit = start + 256
    widths = [8] * 256
    lines = []

    def emit(n, line1, line2):
        lines.append(('( %04x ) ' % n) + line1)
        lines.append('         ' + line2)

    with open(path, 'r') as f:
        seeking = start
        for line in f:
            n, data = parse(line.lower())
            if n < seeking:
                continue
            if n > seeking:
                for i in range(seeking, min(limit, seeking)):
                    emit(i, blank_line, blank_line)
            if n >= limit:
                break
            tpl = split(data)
            if len(tpl) == 1:
                emit(n, tpl[0], blank_line)
                widths[n - start] = 8
            else:
                emit(n, tpl[0], tpl[1])
                widths[n - start] = 16
            seeking = n + 1
        for i in range(seeking, limit):
            emit(i, blank_line, blank_line)

    print('( unifont: %04x to %04x )' % (start, limit - 1))
    print('')
    print('( widths )')
    for i in range(16):
        j = i * 16
        width_line = ' '.join([('%02x' % widths[k]) for k in range(j, j + 16)])
        print(('( %04x ) ' % j) + width_line)
    print('')
    print('( font data, 2x2 tiles )')
    for line in lines:
        print(line)

def usage(message=None):
    if message:
        print('ERROR: %s' % message)
        print('')
    print('USAGE: %s PATH START' % sys.argv[0])
    print('')
    print('  PATH is a hex file, e.g. /usr/share/unifont/unifont.hex')
    print('  START is a code point in hex, e.g. 0, 3c0, 7f00, etc.')
    print('')
    print('  each .uf2 file contains 256 characters, so the output')
    print('  will contains widths and data for all characters from')
    print('  START to START+255 (inclusive).')
    print('')
    sys.exit(1)

def main():
    args = sys.argv[1:]
    if len(args) != 2:
        return usage()
    path, start = args
    if not os.path.exists(path):
        return usage('could not read .hex file: %s' % path)

    try:
        n = int(start, 16)
    except:
        return usage('could not parse start character: %s' % start)

    if n < 0:
        return usage('start must be >= 0: %s' % start)
    if n > 65280:
        return usage('start must be <= ff00: %s' % start)

    run(path, n)

if __name__ == "__main__":
    main()