#!/usr/bin/python

# as described in http://www.sven.de/librie/Librie/MgrTabFormat

# this is what goes in /mssony/librie/booklist/MgrTbl.dat

import sys
import os
import rfc822
import struct
import time
import LrfFile
import xml.dom.minidom

def pack_to(len, bytes):
    return (bytes + struct.pack("x" * len))[:len]

class xml_attrs:
    def __init__(self, s=None, node=None):
        if s:
            self.xpp = xml.dom.minidom.parseString(s)
        else:
            self.xpp = node
    def __getattr__(self, a):
        return xml_attrs(node=self.xpp.getElementsByTagName(a)[0])
    def Text(self):
        return self.xpp.childNodes[0].wholeText
    def unlink(self):
        return self.xpp.unlink()

# this lets "" encode to ""
def encode_utf16(s):
    if not s: return ""
    return s.encode("utf-16")

# "<" for all, little endian; "H" for all of these 2-byte fields
class MgrField:
    def __init__(self, lrfname):
        self.lrfname = os.path.basename(lrfname)
        self.title = u""
        self.titlereading = u""
        self.author = u""
        self.authorreading = u""
        self.publisher = u""
        self.location = ""
        lrf = LrfFile.LrfFile(lrfname)
        # this is the full cover - should thumbnail it
        # (use PIL, or double-pipe - avoid the tmpfile)
        # http://permalink.gmane.org/gmane.linux.hardware.sony.librie/1545
        # says "60x80" for the thumbnail...
        conv = os.popen("convert -scale 20% - /tmp/x.gif", "w")
        conv.write(lrf.gif)
        conv.close()
        self.cover_image_data = open("/tmp/x.gif").read()
        self.cover_image_type = 0x14
        # lrf.uinfo also has CreationDate, Title, Author, BookID, Publisher...
        xlrf = xml_attrs(lrf.uinfo.rstrip("\0"))
        xbook = xlrf.Info.BookInfo
        self.id = xbook.BookID.Text()
        self.publisher = xbook.Publisher.Text()
        self.author = xbook.Author.Text()
        self.title = xbook.Title.Text()
        xdoc = xlrf.Info.DocInfo
        self.when = xdoc.CreationDate.Text()
        xlrf.unlink()
    def import_fields(self, fields):
        for k,v in fields.items():
            setattr(self, k.lower(), v.decode("iso-8859-1"))
    def set_size(self, size):
        self.size = size
    def set_mtime(self, mtime):
        self.unixtime = mtime
    def prep(self):
        # some things are derived...
        if not hasattr(self, "id"):
            self.id = unicode(self.lrfname.replace(".lrf","",1))
            # self.id = "zdVnISprTxmeHKjx"
        if not hasattr(self, "when"):
            self.when = time.strftime("%Y-%m-%d", time.gmtime(self.unixtime))
        if not hasattr(self, "cover_image_data"):
            # read and convert, later
            self.cover_image_data = open("/usr/share/galeon/general.png", "r").read()
            # 0x11 for JPEG, 0x12 for PNG, 0x13 for BMP and 0x14 for GIF.
            self.cover_image_type = 0x12
        # if not self.titlereading:
        #     self.titlereading = self.title
        # if not self.authorreading:
        #     self.authorreading = self.author
        if not self.location:
            # BookListItem.cs makes this upper case
            self.location = "a:/ebook/bbeb/book/" + self.lrfname

    def marshall(self):
        bytes = []
        # emit the headerfields
        bytes.append(struct.pack("<H", 0)) # dummy recordlen
        bytes.append(struct.pack("<H", len(encode_utf16(self.title))))
        bytes.append(struct.pack("<H", len(encode_utf16(self.titlereading))))
        bytes.append(struct.pack("<H", len(encode_utf16(self.author))))
        bytes.append(struct.pack("<H", len(encode_utf16(self.authorreading))))
        bytes.append(struct.pack("<H", len(encode_utf16(self.publisher))))
        bytes.append(struct.pack("<H", len(self.location.encode("ascii"))))
        bytes.append(struct.pack("<H", len(self.cover_image_data)))
        bytes.append(struct.pack("<H", 0x60)) # unknown
        bytes.append(struct.pack("x" * 15))
        # now add the values
        bytes.append(pack_to(32, encode_utf16(self.id)))
        bytes.append(pack_to(15, self.when.encode("ascii")))
        bytes.append(encode_utf16(self.title))
        bytes.append(encode_utf16(self.titlereading))
        bytes.append(encode_utf16(self.author))
        bytes.append(encode_utf16(self.authorreading))
        bytes.append(encode_utf16(self.publisher))
        bytes.append(self.location.encode("ascii"))
        bytes.append(struct.pack("<L", self.size))
        bytes.append(struct.pack("x" * 16))
        bytes.append(struct.pack("B", self.cover_image_type))
        bytes.append(self.cover_image_data)
        # now fix the length
        bytes[0] = struct.pack("<H", len("".join(bytes)))
        return "".join(bytes)


def get_keys(lrfname):
    fp = open(lrfname.replace(".lrf", ".info", 1), "r")
    m = rfc822.Message(fp)
    return m.dict

def write_datafile(stickbase):
    mgrtbl_name = os.path.join(stickbase, "mssony/librie/booklist/MgrTbl.dat")
    mgrtbl = open(mgrtbl_name, "w")

    bookdir = os.path.join(stickbase, "ebook/bbeb/book")
    for lrfname in os.listdir(bookdir):
        if not lrfname.endswith(".lrf"): continue
        bookname = os.path.join(bookdir, lrfname)
        mgr = MgrField(bookname)
        # metadata = get_keys(bookname)
        # mgr.import_fields(metadata)
        mgr.set_size(os.path.getsize(bookname))
        mgr.set_mtime(os.path.getmtime(bookname))
        mgr.prep()
        mgrtbl.write(mgr.marshall())

    mgrtbl.close()

if __name__ == "__main__":
    prog, stickbase = sys.argv
    write_datafile(stickbase)