"""
HTML-TOC-adding transform.
"""
from ebook_converter import constants as const
from ebook_converter.ebooks.oeb import base


DEFAULT_TITLE = 'Table of Contents'
STYLE_CSS = {'nested': '.calibre_toc_header {\n  text-align: center;\n}\n'
             '.calibre_toc_block {\n  margin-left: 1.2em;\n  text-indent: '
             '-1.2em;\n}\n.calibre_toc_block .calibre_toc_block {\n  '
             'margin-left: 2.4em;\n}\n.calibre_toc_block .calibre_toc_block '
             '.calibre_toc_block {\n  margin-left: 3.6em;\n}\n',

             'centered': '.calibre_toc_header {\n  text-align: center;\n}\n'
             '.calibre_toc_block {\n  text-align: center;\n}\nbody > '
             '.calibre_toc_block {\n  margin-top: 1.2em;\n}\n'}


class HTMLTOCAdder(object):

    def __init__(self, title=None, style='nested', position='end'):
        self.title = title
        self.style = style
        self.position = position

    @classmethod
    def config(cls, cfg):
        group = cfg.add_group('htmltoc', 'HTML TOC generation options.')
        group('toc_title', ['--toc-title'], default=None,
              help='Title for any generated in-line table of contents.')
        return cfg

    @classmethod
    def generate(cls, opts):
        return cls(title=opts.toc_title)

    def __call__(self, oeb, context):
        has_toc = getattr(getattr(oeb, 'toc', False), 'nodes', False)

        if 'toc' in oeb.guide:
            # Ensure toc pointed to in <guide> is in spine
            from ebook_converter.ebooks.oeb.base import urlnormalize
            href = urlnormalize(oeb.guide['toc'].href)
            if href in oeb.manifest.hrefs:
                item = oeb.manifest.hrefs[href]
                if (hasattr(item.data, 'xpath') and
                        base.XPath('//h:a[@href]')(item.data)):
                    if oeb.spine.index(item) < 0:
                        if self.position == 'end':
                            oeb.spine.add(item, linear=False)
                        else:
                            oeb.spine.insert(0, item, linear=True)
                    return
                elif has_toc:
                    oeb.guide.remove('toc')
            else:
                oeb.guide.remove('toc')
        if not has_toc:
            return
        oeb.logger.info('Generating in-line TOC...')
        title = self.title or oeb.translate(DEFAULT_TITLE)
        style = self.style
        if style not in STYLE_CSS:
            oeb.logger.error('Unknown TOC style %r', style)
            style = 'nested'
        id, css_href = oeb.manifest.generate('tocstyle', 'tocstyle.css')
        oeb.manifest.add(id, css_href, base.CSS_MIME, data=STYLE_CSS[style])
        language = str(oeb.metadata.language[0])
        contents = base.element(None, base.tag('xhtml', 'html'),
                                nsmap={None: const.XHTML_NS},
                                attrib={base.tag('xml', 'lang'): language})
        head = base.element(contents, base.tag('xhtml', 'head'))
        htitle = base.element(head, base.tag('xhtml', 'title'))
        htitle.text = title
        base.element(head, base.tag('xhtml', 'link'), rel='stylesheet',
                     type=base.CSS_MIME, href=css_href)
        body = base.element(contents, base.tag('xhtml', 'body'),
                            attrib={'class': 'calibre_toc'})
        h1 = base.element(body, base.tag('xhtml', 'h2'),
                          attrib={'class': 'calibre_toc_header'})
        h1.text = title
        self.add_toc_level(body, oeb.toc)
        id, href = oeb.manifest.generate('contents', 'contents.xhtml')
        item = oeb.manifest.add(id, href, base.XHTML_MIME, data=contents)
        if self.position == 'end':
            oeb.spine.add(item, linear=False)
        else:
            oeb.spine.insert(0, item, linear=True)
        oeb.guide.add('toc', 'Table of Contents', href)

    def add_toc_level(self, elem, toc):
        for node in toc:
            block = base.element(elem, base.tag('xhtml', 'div'),
                                 attrib={'class': 'calibre_toc_block'})
            line = base.element(block, base.tag('xhtml', 'a'),
                                attrib={'href': node.href,
                                        'class': 'calibre_toc_line'})
            line.text = node.title
            self.add_toc_level(block, node)
