#!/bin/env python3
'''
This is a quick script to generate an SVG of a binary slide rule.
'''
import sys
import math

def my_write( val: str ):
    '''
    wrapper for printouts to allow for single point of modification or replacement
    '''
    sys.stdout.write(val+'\n')

WEB_WIDTH=10.5 #1920
WEB_UNITS="in"

MAX_DEPTH = 8
DEPTH_RANGE = 2 ** MAX_DEPTH
STROKE_WIDTH=10
X_WIDTH = 10.5*1200
Y_HEIGHT = X_WIDTH//10
HALF_ROW_HEIGHT = round(Y_HEIGHT/(MAX_DEPTH*4+2))
FONT_STYLE = 'font-family="monospace" font-weight="bold"'

my_write( '<?xml version="1.0" encoding="UTF-8"?>')
my_write(f'<svg width="{WEB_WIDTH}{WEB_UNITS}" height="{round(WEB_WIDTH*Y_HEIGHT/X_WIDTH,5)}'
         f'{WEB_UNITS}" viewBox="0 0 {X_WIDTH} {Y_HEIGHT}" xmlns="http://www.w3.org/2000/svg">')
my_write(f'  <rect width="{X_WIDTH/(2**(MAX_DEPTH+4))}" height="{4*MAX_DEPTH*HALF_ROW_HEIGHT}"'
         f' x="0" y="{HALF_ROW_HEIGHT}" fill="black" />')
my_write(f'  <text x="{X_WIDTH/(2**(MAX_DEPTH+4))}" y="{HALF_ROW_HEIGHT*MAX_DEPTH}" '
         f'font-size="{HALF_ROW_HEIGHT*2}" fill="black" {FONT_STYLE}>1._</text>')

for digit in range(0, MAX_DEPTH):
    step = 2 ** (MAX_DEPTH - (digit+1))
    for count in range(1, 2**(digit+1), 2):
        i = count * step
        prex = round(X_WIDTH * math.log2(1+(i-step)/DEPTH_RANGE))
        startx = round(X_WIDTH * math.log2(1+(i/DEPTH_RANGE)))
        stopx = round(X_WIDTH * math.log2(1+(i+step)/DEPTH_RANGE))
        my_write(f'  <rect width="{stopx-startx}" height="{2*HALF_ROW_HEIGHT}" x="{startx}" '
                 f'y="{HALF_ROW_HEIGHT*(2*digit+1)            }" fill="black" />')
        my_write(f'  <rect width="{stopx-startx}" height="{2*HALF_ROW_HEIGHT}" x="{startx}" '
                 f'y="{HALF_ROW_HEIGHT*(4*MAX_DEPTH-2*digit-1)}" fill="black" />')
        if digit % 4 == (MAX_DEPTH-1)%4:
            my_write(f'  <text x="{(stopx+startx)/2}" y="{HALF_ROW_HEIGHT*(2*digit+2)          }" '
                     f'font-size="{HALF_ROW_HEIGHT*1.25}" fill="white" dominant-baseline="middle" '
                     f'text-anchor="middle" {FONT_STYLE}>{hex(count%16)[-1:].upper()    }</text>')
            my_write(f'  <text x="{(prex+startx)/2 }" y="{HALF_ROW_HEIGHT*(2*digit+2)          }" '
                     f'font-size="{HALF_ROW_HEIGHT*1.25}" fill="black" dominant-baseline="middle" '
                     f'text-anchor="middle" {FONT_STYLE}>{hex((count-1)%16)[-1:].upper()}</text>')
            my_write(f'  <text x="{(stopx+startx)/2}" y="{HALF_ROW_HEIGHT*(4*MAX_DEPTH-2*digit)}" '
                     f'font-size="{HALF_ROW_HEIGHT*1.25}" fill="white" dominant-baseline="middle" '
                     f'text-anchor="middle" {FONT_STYLE}>{hex(count%16)[-1:].upper()    }</text>')
            my_write(f'  <text x="{(prex+startx)/2 }" y="{HALF_ROW_HEIGHT*(4*MAX_DEPTH-2*digit)}" '
                     f'font-size="{HALF_ROW_HEIGHT*1.25}" fill="black" dominant-baseline="middle" '
                     f'text-anchor="middle" {FONT_STYLE}>{hex((count-1)%16)[-1:].upper()}</text>')


table_data = [
    ['', '00', '01', '10', '11'],
    ['00', '0',  '4',  '8',  'C' ],
    ['01', '1',  '5',  '9',  'D' ],
    ['10', '2',  '6',  'A',  'E' ],
    ['11', '3',  '7',  'B',  'F' ] ]

TABLE_X = 625
TABLE_Y = HALF_ROW_HEIGHT*(MAX_DEPTH*2+10.125)
TABLE_CWIDTH = 100

my_write('  <g>')

row_shading = HALF_ROW_HEIGHT*1.25*(len(table_data)+0.5)
for x_pos in range(round(TABLE_X-(TABLE_CWIDTH/2)),
                   TABLE_X+TABLE_CWIDTH*len(table_data[0]), round(TABLE_CWIDTH*2)):
    my_write(f'    <rect x="{x_pos}" y="{TABLE_Y-HALF_ROW_HEIGHT}" width="{TABLE_CWIDTH}" '
             f'height="{row_shading}" fill="#CCC"/>')

y_pos=TABLE_Y
for row in table_data:
    x_pos=TABLE_X
    my_write(f'    <text x="{x_pos}" y="{y_pos}" font-size="{HALF_ROW_HEIGHT*1.25}" '
             f'text-anchor="middle" dominant-baseline="middle" fill="black" {FONT_STYLE} >')
    for item in row:
        my_write(f'      <tspan x="{x_pos}"> {item}</tspan>')
        x_pos=x_pos+TABLE_CWIDTH
    my_write('    </text>')
    y_pos=y_pos+(HALF_ROW_HEIGHT*1.25)
my_write('  </g>')

my_write('</svg>')
