import struct
BPS, SPC = 512, 128
RESV, NFATS = 1, 2
ROOTENTS = 400
NDIRS = 400
NCLUST = 24200
ROOTSEC = (ROOTENTS * 32 + BPS - 1) // BPS      # 25
FATSEC = ((NCLUST + 2) * 2 + BPS - 1) // BPS    # 95
while (RESV + NFATS * FATSEC + ROOTSEC) % 8 != 4:
    FATSEC += 1                                  # 97
FIRST = RESV + NFATS * FATSEC + ROOTSEC
assert FIRST % 8 == 4
TOTSEC = FIRST + NCLUST * SPC

def dirent(name, attr, clus, size=0):
    e = bytearray(32)
    n, ext = (name.split('.') + [''])[:2]
    e[0:8] = n.upper().ljust(8).encode(); e[8:11] = ext.upper().ljust(3).encode()
    e[11] = attr
    struct.pack_into('<H', e, 26, clus & 0xFFFF); struct.pack_into('<I', e, 28, size)
    return bytes(e)

f = open('/tmp/opencode/df2675/chain4.img', 'wb')
f.truncate(TOTSEC * BPS)
bs = bytearray(512)
bs[0:3] = b'\xEB\x3C\x90'; bs[3:11] = b'MSDOS5.0'
struct.pack_into('<H', bs, 11, BPS); bs[13] = SPC
struct.pack_into('<H', bs, 14, RESV); bs[16] = NFATS
struct.pack_into('<H', bs, 17, ROOTENTS)
struct.pack_into('<H', bs, 19, 0); bs[21] = 0xF8
struct.pack_into('<H', bs, 22, FATSEC)
struct.pack_into('<H', bs, 24, 63); struct.pack_into('<H', bs, 26, 255)
struct.pack_into('<I', bs, 32, TOTSEC)
bs[36] = 0x80; bs[38] = 0x29
struct.pack_into('<I', bs, 39, 0x2675F1F1)
bs[43:54] = b'NO NAME    '; bs[54:62] = b'FAT16   '
bs[510:512] = b'\x55\xAA'
f.write(bs)
fat = bytearray(FATSEC * BPS)
struct.pack_into('<H', fat, 0, 0xFFF8); struct.pack_into('<H', fat, 2, 0xFFFF)
for c in range(2, 2 + NDIRS): struct.pack_into('<H', fat, c*2, 0xFFFF)   # dirs
for c in range(2 + NDIRS, 6335): struct.pack_into('<H', fat, c*2, 0xFFFF)  # blocked
# 6335 free (g2's data cluster = 0x18BF)
for c in range(6336, 24148): struct.pack_into('<H', fat, c*2, 0xFFFF)   # blocked
# 24148 free (g3's data cluster = 0x5E54)
for i in range(NFATS):
    f.seek((RESV + i * FATSEC) * BPS)
    f.write(fat)
root = bytearray(ROOTSEC * BPS)
for i in range(NDIRS):
    root[i*32:(i+1)*32] = dirent('D%03d' % i, 0x10, 2+i)
f.seek((RESV + NFATS * FATSEC) * BPS)
f.write(root)
tmpl = bytearray(65536)
tmpl[0:32] = dirent('.', 0x10, 2)
tmpl[32:64] = dirent('..', 0x10, 0)
for s in range(2, 1984):
    tmpl[s*32:(s+1)*32] = dirent('F%04d' % (s-2), 0x20, 0)
tmpl[1984*32] = 0x00
for i in range(NDIRS):
    f.seek((FIRST + i * SPC) * BPS)
    f.write(tmpl)
f.close()
print(f"chain4.img: FIRST {FIRST} FATSEC {FATSEC} {NDIRS} dirs, "
      f"free@6335,24148; {TOTSEC*BPS/1e9:.2f} GB sparse")
