#!/usr/bin/env python3
import os
import sys
import argparse
import subprocess

# Support running from uninstalled package by adding parent dir to sys path
rootdir = os.path.abspath(os.path.realpath((os.path.dirname(
    os.path.dirname(__file__)))))
sys.path.insert(1, rootdir)

from emmo import World, onto_path
from emmo.ontodoc import (
    OntoDoc, get_format, get_style, get_figformat, get_maxwidth, get_docpp)

import owlready2


def main():
    parser = argparse.ArgumentParser(
        description='Tool for documenting ontologies.')
    parser.add_argument(
        'iri', metavar='IRI',
        help='File name or URI of the ontology to document.')
    parser.add_argument(
        'outfile', metavar='OUTFILE',
        help='Output file.')

    parser.add_argument(
        '--database', '-d', metavar='FILENAME', default=':memory:',
        help='Load ontology from Owlready2 sqlite3 database.  The `iri` '
        'argument should in this case be the IRI of the ontology you '
        'want to document.')
    parser.add_argument(
        '--local', '-l', action='store_true',
        help='Load imported ontologies locally.  Their paths are specified '
        'in Protègè catalog files or via the --path option.  The IRI should '
        'be a file name.')
    parser.add_argument(
        '--catalog-file', default='catalog-v001.xml',
        help='Name of Protègè catalog file in the same folder as the '
        'ontology.  This option is used together with --local and '
        'defaults to "catalog-v001.xml".')
    parser.add_argument(
        '--path', action='append', default=[],
        help='Paths where imported ontologies can be found.  May be provided '
        'as a comma-separated string and/or with multiple --path options.')
    parser.add_argument(
        '--reasoner', nargs='?', const='HermiT', choices=['HermiT', 'Pellet'],
        help='Run given reasoner on the ontology.  Valid reasoners are '
        '"HermiT" (default) and "Pellet".  Note: these reasoners doesn\'t '
        'work well with EMMO.')
    parser.add_argument(
        '--template', '-t', metavar='FILE',
        help='ontodoc input template.  If not provided, a simple default '
        'template will be used.  Don\'t confuse it with the pandoc templates.')
    parser.add_argument(
        '--format', '-f', metavar='FORMAT',
        help='Output format.  May be "md", "simple-html" or any other format '
        'supported by pandoc.  By default the format is inferred from '
        '--output.')
    parser.add_argument(
        '--figdir', '-D', metavar='DIR', default='genfigs',
        help='Default directory to store generated figures.  If a relative '
        'path is given, it is relative to the template (see --template), or '
        'the current directory, if --template is not given. Default: '
        '"genfigs"')
    parser.add_argument(
        '--figformat', '-F',
        help='Format for generated figures.  The default is inferred from '
        '--format."')
    parser.add_argument(
        '--max-figwidth', '-w',
        help='Maximum figure width.  The default is inferred from --format.')
    parser.add_argument(
        '--pandoc-option', '-p', metavar='STRING', action='append',
        dest='pandoc_options',
        help='Additional pandoc long options overriding those read from '
        '--pandoc-option-file.  It is possible to remove pandoc option --XXX '
        'with "--pandoc-option=no-XXX".  This option may be provided multiple '
        'times.')
    parser.add_argument(
        '--pandoc-option-file', '-P', metavar='FILE', action='append',
        dest='pandoc_option_files',
        help='YAML file with additional pandoc options.  Note, that default '
        'pandoc options are read from the files "pandoc-options.yaml" and '
        '"pandoc-FORMAT-options.yaml" (where FORMAT is format specified with '
        '--format).  This option allows to override the defaults and add '
        'additional pandoc options.  This option may be provided multiple '
        'times.')
    parser.add_argument(
        '--keep-generated', '-k', metavar='FILE', dest='genfile',
        help='Keep a copy of generated markdown input file for pandoc '
        '(for debugging).')
    args = parser.parse_args()

    # Append to onto_path
    for paths in args.path:
        for path in paths.split(','):
            if path not in onto_path:
                onto_path.append(path)

    # Load ontology
    world = World(filename=args.database)
    if args.database != ':memory:' and args.iri not in world.ontologies:
        parser.error('The IRI argument should be one of the ontologies in '
                     'the database:\n  ' +
                     '\n  '.join(world.ontologies.keys()))
    onto = world.get_ontology(args.iri)
    try:
        onto.load(only_local=args.local, catalog_file=args.catalog_file)
    except owlready2.OwlReadyOntologyParsingError as e:
        parser.error('error parsing %r: %s' % (args.iri, e))

    # Sync reasoner
    if args.reasoner:
        onto.sync_reasoner(reasoner=args.reasoner)

    # Instantiate ontodoc instance
    format = get_format(args.outfile, args.format)
    style = get_style(format)
    figformat = args.figformat if args.figformat else get_figformat(format)
    maxwidth = args.max_figwidth if args.max_figwidth else get_maxwidth(format)
    ontodoc = OntoDoc(onto, style=style)
    docpp = get_docpp(ontodoc, args.template, figdir=args.figdir,
                      figformat=figformat, maxwidth=maxwidth)
    docpp.process()

    try:
        docpp.write(args.outfile, format=args.format,
                    pandoc_option_files=args.pandoc_option_files,
                    pandoc_options=args.pandoc_options,
                    genfile=args.genfile)
    except subprocess.CalledProcessError as e:
        os._exit(e.returncode)  # Exit without traceback on pandoc errors

    return docpp


if __name__ == '__main__':
    docpp = main()
