'''
Writer content to ztxt pdb file.
'''

__license__   = 'GPL v3'
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
__docformat__ = 'restructuredtext en'

import struct
import zlib

from calibre.ebooks.pdb.formatwriter import FormatWriter
from calibre.ebooks.pdb.header import PdbHeaderBuilder
from calibre.ebooks.txt.newlines import TxtNewlines, specified_newlines
from calibre.ebooks.txt.txtml import TXTMLizer

MAX_RECORD_SIZE = 8192


class Writer(FormatWriter):

    def __init__(self, opts, log):
        self.opts = opts
        self.log = log

    def write_content(self, oeb_book, out_stream, metadata=None):
        title = self.opts.title if self.opts.title else oeb_book.metadata.title[0].value if oeb_book.metadata.title != [] else _('Unknown')

        txt_records, txt_length = self._generate_text(oeb_book)

        crc32 = 0
        section_lengths = []
        compressor = zlib.compressobj(9)
        self.log.info('Compressing data...')
        for i in range(0, len(txt_records)):
            self.log.debug('\tCompressing record %i' % i)
            txt_records[i] = compressor.compress(txt_records[i])
            txt_records[i] = txt_records[i] + compressor.flush(zlib.Z_FULL_FLUSH)
            section_lengths.append(len(txt_records[i]))
            crc32 = zlib.crc32(txt_records[i], crc32) & 0xffffffff

        header_record = self._header_record(txt_length, len(txt_records), crc32)
        section_lengths.insert(0, len(header_record))

        out_stream.seek(0)
        hb = PdbHeaderBuilder('zTXTGPlm', title)
        hb.build_header(section_lengths, out_stream)

        for record in [header_record]+txt_records:
            out_stream.write(record)

    def _generate_text(self, oeb_book):
        writer = TXTMLizer(self.log)
        txt = writer.extract_content(oeb_book, self.opts)

        self.log.debug('\tReplacing newlines with selected type...')
        txt = specified_newlines(TxtNewlines('windows').newline,
                txt).encode(self.opts.pdb_output_encoding, 'replace')

        txt_length = len(txt)

        txt_records = []
        for i in range(0, (len(txt) / MAX_RECORD_SIZE) + 1):
            txt_records.append(txt[i * MAX_RECORD_SIZE : (i * MAX_RECORD_SIZE) + MAX_RECORD_SIZE])

        return txt_records, txt_length

    def _header_record(self, txt_length, record_count, crc32):
        record = b''

        record += struct.pack('>H', 0x012c)             # [0:2], version. 0x012c = 1.44
        record += struct.pack('>H', record_count)       # [2:4], Number of PDB records used for the text of the book.
        record += struct.pack('>L', txt_length)         # [4:8], Uncompressed length of the entire text of the book.
        record += struct.pack('>H', MAX_RECORD_SIZE)    # [8:10], Maximum size of each record containing text
        record += struct.pack('>H', 0)                  # [10:12], Number of bookmarks.
        record += struct.pack('>H', 0)                  # [12:14], Bookmark record. 0 if there are no bookmarks.
        record += struct.pack('>H', 0)                  # [14:16], Number of annotations.
        record += struct.pack('>H', 0)                  # [16:18], Annotation record. 0 if there are no annotations.
        record += struct.pack('>B', 1)                  # [18:19], Flags. Bitmask, 0x01 = Random Access. 0x02 = Non-Uniform text block size.
        record += struct.pack('>B', 0)                  # [19:20], Reserved.
        record += struct.pack('>L', crc32)              # [20:24], crc32
        record += struct.pack('>LL', 0, 0)              # [24:32], padding

        return record
