import wave
import array
import struct
import sys

import gameduino.compress
import gameduino.prep as gdprep

import Image

fmt = "<12sHI"

class Flash(object):
    def __init__(self):
        self.memory = array.array('B', [0xff] * 264 * 1024)
    def add(self, ptr, data):
        s = len(data)
        self.memory[ptr:ptr+s] = array.array('B', data)
        return ptr + s
    def dump(self, filename):
        open(filename, "w").write(self.memory.tostring())

class Asset(object):
    def __len__(self):
        return len(str(self))
    def dirent(self, ptr):
        pg = (ptr / 264)
        of = (ptr % 264)
        addr = 512 * pg + of
        return struct.pack(fmt, self.name, len(self), addr)
    def lay(self, flash, ptr):
        return flash.add(ptr, str(self))
    def portray(self, indent = 0):
        print "  " * indent, self.name, len(self)

class BinaryAsset(Asset):
    def __init__(self, name):
        self.name = name
        self.s = open(self.name).read()
    def __str__(self):
        return self.s

class ArrayAsset(Asset):
    def __init__(self, name, a):
        self.name = name
        self.a = a
    def __str__(self):
        return self.a.tostring()

class SampleAsset(Asset):
    prefix = ""
    def __init__(self, name):
        self.name = name
        src = wave.open("%s%s.wav" % (self.prefix, self.name))
        raw16 = array.array('h', src.readframes(src.getnframes()))
        self.raw8 = array.array('b', [v / 256 for v in raw16]).tostring()
        print "%s: len=%x sum=%x" % (name, len(self.raw8), sum([ord(c) for c in self.raw8]))
    def __str__(self):
        return self.raw8

class SampleAsset8(SampleAsset):
    prefix = "8"

class DirectoryAsset(Asset):
    def __init__(self, name, contents):
        self.name = name
        self.contents = contents
    def dirsize(self):
        return (len(self.contents) + 1) * struct.calcsize(fmt) 
    def __len__(self):
        return self.dirsize() + sum([len(e) for e in self.contents])
    def __str__(self):
        assert False, "Cannot convert directory to string"
    def lay(self, flash, ptr):
        optr = ptr # original ptr
        o = ptr + self.dirsize()
        for e in self.contents:
            ptr = flash.add(ptr, e.dirent(o))
            o += len(e)
        ptr = flash.add(ptr, [0] * struct.calcsize(fmt))    # terminator
        for e in self.contents:
            ptr = e.lay(flash, ptr)
        assert ptr == o # Check calculation worked
        return ptr
    def portray(self, indent = 0):
        print "  " * indent, self.name
        for c in self.contents:
            c.portray(indent + 1)

def SpriteDir(name, im, ir):
    return DirectoryAsset(name, [
        ArrayAsset("pal", gdprep.getpal(im)),
        ArrayAsset("img", ir.used())])

pickups2 = gdprep.palettize(Image.open("../pickups2.png"), 256)
pickups2ir = gdprep.ImageRAM(open("hdr.h", "w"))
pickups2ir.addsprites("pickups2", (16, 16), pickups2, gdprep.PALETTE256A, center = (8,8))

font16 = gdprep.palettize(Image.open("font16.png").convert("RGB"), 4)
font16ir = gdprep.ImageRAM(open("hdr.h", "w"))
font16ir.addsprites("font16", (16, 16), font16, gdprep.PALETTE4A, center = (8,8))
print "font16:", len(font16ir.used())
print gdprep.getpal(font16).tolist()

blocks = {}
assetroot = \
    DirectoryAsset("assetlib", [
        SpriteDir("pickups", pickups2, pickups2ir),
        DirectoryAsset("voice", [
            SampleAsset("ar"),
            SampleAsset("duino"),
            SampleAsset("game"),
            SampleAsset("go"),
            SampleAsset("nice"),
            SampleAsset("ohdear"),
            SampleAsset("over"),
            SampleAsset("ready"),
            ]),
        DirectoryAsset("fonts", [
            BinaryAsset("font8x8"),
            ArrayAsset("font16", font16ir.used())]),
        DirectoryAsset("drumkit", [
            SampleAsset8("bassdrum2"),
            SampleAsset8("bassdrum4"),
            SampleAsset8("clap"),
            SampleAsset8("conga2"),
            SampleAsset8("conga3"),
            SampleAsset8("cowbell1"),
            SampleAsset8("cymbal1"),
            SampleAsset8("cymbal3"),
            SampleAsset8("hihat1"),
            SampleAsset8("hihat2"),
            SampleAsset8("snaredrum2"),
            SampleAsset8("snaredrum3")
            ]),
        ])
assetroot.portray()

m = Flash()
ptr0 = 640 * 264 # Start of data
ptr1 = assetroot.lay(m, ptr0)
assets = m.memory[ptr0:ptr1]
print ptr1 - ptr0

dd = open("flashdump", "w")
dd.write(assets.tostring())

# dd = open("flashdump", "w")

cd = gameduino.compress.Codec(b_off = 7, b_len = 3)
cdd = open("../../assetlib.h", "w")
PG128 = 264 * 128
n2k = len(assets) / (8 * 264)
s0 = (8 * 264) * (n2k / 3)
s1 = (8 * 264) * (2 * n2k / 3)
chunks = [assets[:s0].tostring(), assets[s0:s1].tostring(), assets[s1:].tostring()]
o = 640
for i,chunk in enumerate(chunks):
    print len(chunk)
    while (len(chunk) % 264) != 0:
        chunk += chr(0)
    comp = cd.toarray(chunk)
    print "compressed to", len(comp)
    print >>cdd, "#define ASSET%d_PAGE %d" % (i, o)
    print >>cdd, "#define ASSET%d_SUM %dL" % (i, sum([ord(c) for c in chunk]))
    print >>cdd, "#define ASSET%d_LEN %d" % (i, len(chunk) / 264)
    gdprep.dump(cdd, "assetlib%d" % i, comp)
    o += len(chunk) / 264

sys.exit(0)
