#!/usr/bin/env python

# documentation.conf update script
#
# Author: Paul Eggleton <paul.eggleton@linux.intel.com>
#
# Copyright (C) 2015 Intel Corporation
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.


import sys
import os
import argparse
import re
from lxml import etree
import logging

def logger_create(name):
    logger = logging.getLogger(name)
    loggerhandler = logging.StreamHandler()
    loggerhandler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
    logger.addHandler(loggerhandler)
    logger.setLevel(logging.INFO)
    return logger
logger = logger_create('docconfupdater')

def main():
    parser = argparse.ArgumentParser(description="documentation.conf updater")
    parser.add_argument('basepath', help='Path to OE-Core base directory')
    parser.add_argument('-q', '--quiet', help='Print only warnings/errors', action='store_true')

    args = parser.parse_args()

    if args.quiet:
        logger.setLevel(logging.WARN)

    if not os.path.isdir(args.basepath):
        logger.error('Specified base path %s not found')
        return 1

    doc_conf = os.path.join(args.basepath, 'meta', 'conf', 'documentation.conf')
    if not os.path.exists(doc_conf):
        logger.error('Unable to find %s' % doc_conf)
        return 1

    allowed_flags = ['doc']
    flag_re = re.compile(r'\[(.+?)\]')

    infos = {}
    tree = etree.parse('ref-manual/ref-variables.xml')
    root = tree.getroot()
    for glossary in root.findall('glossary'):
        for glossdiv in glossary.findall('glossdiv'):
            for glossentry in glossdiv.findall('glossentry'):
                info = glossentry.find('info')
                if info is not None:
                    infoline = ' '.join(info.text.split())
                    infolinesplit = infoline.split('=', 1)
                    if len(infoline) < 2:
                        logger.warn('Invalid info line (no = character), ignoring: %s' % infoline)
                        continue
                    flags = flag_re.findall(infolinesplit[0])
                    if not flags:
                        logger.warn('Invalid info line (no varflag), ignoring: %s' % infoline)
                        continue
                    for flag in flags:
                        if flag not in allowed_flags:
                            logger.warn('Invalid info line (varflag %s not in allowed list), ignoring: %s' % (flag, infoline))
                            continue
                    infos[infolinesplit[0].rstrip()] = infolinesplit[1].lstrip()

    if not infos:
        logger.error('ERROR: Unable to find any info tags in the glossary')
        return 1

    def sortkey(key):
        # Underscores sort undesirably, so replace them
        return key.split('[')[0].replace('_', '-')

    changed = False
    lines = []
    invars = False
    lastletter = None
    added = []
    with open(doc_conf, 'r') as dcf:
        for line in dcf:
            if not invars:
                if line.startswith('#') and 'DESCRIPTIONS FOR VARIABLES' in line:
                    invars = True
            elif not line.startswith('#'):
                linesplit = line.split('=', 1)
                if len(linesplit) > 1:
                    key = linesplit[0].rstrip()
                    lastletter = key[0]
                    # Find anything in the dict that should come before the current key
                    for dkey in sorted(infos.keys()):
                        if sortkey(dkey) < sortkey(key):
                            lines.append('%s = %s\n' % (dkey, infos[dkey]))
                            added.append(dkey)
                            del infos[dkey]
                            changed = True
                    newvalue = infos.get(key, None)
                    if newvalue:
                        del infos[key]
                        if newvalue != linesplit[1].strip():
                            lines.append('%s = %s\n' % (key, newvalue))
                            changed = True
                            continue
                    elif key in added:
                        # We already added a new value for this key, so skip it
                        continue
                elif lastletter:
                    # Ensure we write out anything anything left over for this letter
                    for dkey in sorted(infos.keys()):
                        if dkey[0] == lastletter:
                            lines.append('%s = %s\n' % (dkey, infos[dkey]))
                            del infos[dkey]
                            changed = True
                        elif dkey[0] > lastletter:
                            # List is sorted, so we're done
                            break
                    lastletter = None
            lines.append(line)

    if not invars:
        logger.error('ERROR: Unable to find variables section in documentation.conf')
        return 1

    if infos:
        changed = True
        # Write out anything left over
        lines.append('\n\n')
        for key in sorted(infos.keys()):
            lines.append('%s = %s\n' % (key, infos[key]))

    if changed:
        logger.info('Updating %s' % doc_conf)
        with open(doc_conf, 'w') as dcf:
            for line in lines:
                dcf.write(line)
    else:
        logger.info('No changes required')

    return 0


if __name__ == "__main__":
    try:
        ret = main()
    except Exception:
        ret = 1
        import traceback
        traceback.print_exc(5)
    sys.exit(ret)


