# -*- coding: utf-8 -*-
"""
    htmlhelp2
    ~~~~~~~~~

    Build HTML help support files with [ALIAS] and [MAP] sections
    Note: Replaces original HTMLHelp builder!

    :copyright: Copyright 2012 David Motl
    :license: GNU GPL v.2
    
    $Id: htmlhelp2.py,v 1.1 2015/07/06 08:19:57 dmotl Exp $
"""

import os
import subprocess

from sphinx.builders.htmlhelp import HTMLHelpBuilder
from sphinx.errors import ExtensionError
from sphinx.util import logging
from sphinx.util.console import bold, darkgreen  # type: ignore
from sphinx.errors import SphinxError

class HTMLHelpCompilerFailed(SphinxError):
    category = 'HTML Help compiler failed'

class HTMLHelpExtBuilder(HTMLHelpBuilder):
    name = 'htmlhelp'
    
    def init(self):
        HTMLHelpBuilder.init(self)
        epilog = ''
        
    def build_map(self, filename):
        """ Parse ctxhelp.h and make a dictionary which maps topics -> (num_id, label) """
        mmap = {}
        f = open(filename, "r")
        try:
           for line in f:
                x = line.split(None, 3)
                if len(x)==4 and x[0]=='#define' and x[2].isnumeric():
                    """ Get topic name """
                    start = x[3].find("/*");
                    if (start>=0):
                       end = x[3].find("*/", start+2);
                       if (end>=0):
                             topic = x[3][start+3:end].strip();
                             if len(topic)>0:
                                  mmap[topic] = (int(x[2]), x[1], None)
        finally:
           f.close()
        return mmap
        
    def update_hhp(self, outdir, outname, topics):
        f = self.open_file(outdir, outname+'.hhp', 'a')
        try:
            f.write('\n[ALIAS]\n')
            for topic in iter(topics):
                val = topics[topic]
                if val[1] and val[2]:
                    f.write(val[1] + ' = ' + val[2] + '\n')
                else:
                    logger = logging.getLogger(__name__)
                    logger.warn("Missing topic: %s" % val[1])
            f.write('\n')
            f.write('[MAP]\n')
            for topic in iter(topics):
                val = topics[topic]
                if val[1] and val[2]:
                    f.write('#define ' + val[1] + ' ' + str(val[0]) + '\n')
        finally:
            f.close()
        
    def get_outdated_docs(self):    
        if self.config.ctxhelp_file:
            mapfile = os.path.join(self.srcdir, self.config.ctxhelp_file)
            try:
                mapmtime = os.path.getmtime(mapfile)
            except Exception:
                raise ExtensionError('File not found: %s' % mapfile)
            for docname in self.env.found_docs:        
                targetname = self.get_outfilename(docname)
                try:
                    targetmtime = os.path.getmtime(targetname)
                except Exception:
                    targetmtime = 0                
                if mapmtime > targetmtime:
                    return self.env.found_docs
        return HTMLHelpBuilder.get_outdated_docs(self)
        
    def update_project(self, outdir, outname):
        if self.config.ctxhelp_file:
            # Read map list of tuples (id, symbol, label)
            logger = logging.getLogger(__name__)
            logger.info(bold('updating project file...'), nonl=True)
            
            mmap = self.build_map(os.path.join(self.srcdir, self.config.ctxhelp_file))
            if mmap:
                # Resolve links
                for obj in self.env.domains['std'].get_objects():
                    label = obj[0]
                    if obj[2]=='label' and (label in mmap):
                        val = mmap[label]
                        mmap[label] = (val[0], val[1], obj[3] + self.out_suffix)
                # Update project file        
                self.update_hhp(outdir, outname, mmap)
            else:
                logger.warn("No topics found in %s" % self.config.ctxhelp_file)
            
            logger.info('done')

    def compile_chm(self, outdir, outname):
        # Read map list of tuples (id, symbol, label)
        logger = logging.getLogger(__name__)
        logger.info(bold('building chm file...'), nonl=True)
        
        args = [ 'hhc', os.path.join(outdir, outname+'.hhp') ]
        try:
            p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
            output = p.communicate()[0]
            if p.returncode != 1:
                raise HTMLHelpCompilerFailed(output)
        except OSError:
            raise AppleHelpIndexerFailed(__('Command not found: %s') % args[0])        
    
        logger.info('done')
                    
    def handle_finish(self):
        HTMLHelpBuilder.handle_finish(self)
        self.update_project(self.outdir, self.config.htmlhelp_basename)
        self.compile_chm(self.outdir, self.config.htmlhelp_basename)
        
def setup(app):
    # Replace original HTML Help builder
    app.add_builder(HTMLHelpExtBuilder, override=True)
