#!/usr/bin/env python

#############################################################################
##
# This file is part of Taurus, a Tango User Interface Library
##
# http://www.tango-controls.org/static/taurus/latest/doc/html/index.html
##
# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
##
# Taurus is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
##
# Taurus 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 Lesser General Public License for more details.
##
# You should have received a copy of the GNU Lesser General Public License
# along with Taurus.  If not, see <http://www.gnu.org/licenses/>.
##
#############################################################################

"""
This script is designed to provide taurus developers with a fast way to test
sphinx documentation from source code files or RST files.
"""

from __future__ import print_function

import sys
import os
import shutil
import argparse

from sphinx.application import Sphinx


def abspath(*path):
    """A method to determine absolute path for a given relative path to the
    directory where this script is located"""
    taurusdoc_dir = os.path.dirname(os.path.abspath(__file__))
    return os.path.join(taurusdoc_dir, *path)


sys.path.append(abspath('..', 'doc'))

try:
    import auto_rst4api
except ImportError:
    print("taurusdoc can only be run from a source distribution of taurus")
    sys.exit(1)

__INDEX = """
TaurusDoc
---------

This document has been autogenerated by taurusdoc for test purposes.
Any modifications will be lost.

.. toctree::

    {name}
"""


class RstCreator(auto_rst4api.Auto_rst4API_Creator):

    def documentClass(self, module, classname, docparentpath):
        """Documents a single class

        :param module: (module) python module where class resides
        :param classname: (str) class name
        :docparentpath: (str) path to the directory in which the documentation
                        files will be written
        """
        ofname = os.path.join(docparentpath, "_%s.rst" % classname)

        if self.verbose:
            print('creating "%s" ...' % ofname, )
        info = dict(modulename=module.__name__,
                    basemodulename=module.__name__.split('.')[-1],
                    modulepath=module.__path__,
                    submodulenames=[],
                    localclassnames=[classname],
                    localfunctionnames=[],
                    localenumerationnames=[],
                    externalmembernames=[],
                    submodules=[],
                    warnings=[])
        if not os.path.exists(ofname) or self.overwrite_old:
            text = self.classtemplate.render(info=info, classname=classname)
            with open(ofname, "w") as f:
                f.write('\n'.join((self.AUTOGEN_SIGNATURE,
                                   self.AUTOGEN_MESSAGE,
                                   text))
                        )
            if self.verbose:
                print(' ok.')
        else:
            if self.verbose:
                print(' skipping (file already exists)')


def main():
    description = "a tool to help developers preview the documentation " \
                  "generated by their code"
    parser = argparse.ArgumentParser(description=description)

    parser.add_argument("-v", "--verbose", dest="verbose",
                        action="store_true",
                        help="display a lot of information [default]",
                        default=True)
    parser.add_argument("-q", "--quiet", dest="verbose", action="store_false",
                        help="be really silent")
    parser.add_argument("--build-dir", dest="build_dir",
                        help="build directory [default=./build]")
    parser.add_argument("-a", "--all-files", dest="all_files", default=True,
                        action="store_true",
                        help="generate from scratch [default]")
    parser.add_argument("--cache", dest="all_files", action="store_false",
                        help="use previously generated files")
    parser.add_argument("--format", dest="builder", default="html",
                        help="output format [default=html]")
    parser.add_argument("--prefix", dest="prefix",
                        help="output directory")
    parser.add_argument("--class", dest="klass", default=None,
                        help=("full class name to generate doc for "
                              + "(ex.: taurus.qt.qtgui.display.TaurusLabel"))
    parser.add_argument("--package", dest="package", default=None,
                        help=("full package name to generate doc for "
                              + "(ex.: taurus.qt.qtgui.display)"))
    parser.add_argument("--file", dest="filename", default=None,
                        help="RST file")

    args = parser.parse_args()

    if not args.klass and not args.package and not args.filename:
        parser.error("must give one of --class or --package or --file")

    if int(bool(args.klass)) + int(bool(args.package)) + int(
            bool(args.filename)) > 1:
        parser.error(
            "options --class and --package and --file are mutually exclusive")

    fromlist = []

    if args.klass:
        package_name, class_name = args.klass.rsplit(".", 1)
        if package_name.find(".") >= 0:
            fromlist.append(package_name.split(".", 1)[0])
        mod = __import__(package_name, fromlist=fromlist)
    elif args.package:
        package_name = args.package
        mod = __import__(package_name, fromlist=fromlist)
    else:
        filename = args.filename

    if args.build_dir is None:
        args.build_dir = os.path.join(
            os.path.abspath(os.path.curdir), "build")

    # clean build dir
    if args.all_files:
        if os.path.isdir(args.build_dir):
            shutil.rmtree(args.build_dir)

    if not os.path.isdir(args.build_dir):
        os.makedirs(args.build_dir)

    if args.prefix is None:
        args.prefix = os.path.join(
            os.path.abspath(os.path.curdir), "sphinx")

    if not os.path.isdir(args.prefix):
        os.makedirs(args.prefix)

    doc_dir = abspath("..", "doc")

    if args.verbose:
        out = sys.stdout
    else:
        import StringIO
        out = StringIO.StringIO()

    if not args.filename:
        rstCreator = RstCreator(exclude_patterns=['.*\.ui'],
                                templatespath=doc_dir,
                                overwrite_old=True,
                                verbose=args.verbose,
                                classtemplate='api_class_simple.rst')

        rstCreator.cleanAutogenerated(args.build_dir)

    # create index.rst
    index_rst = os.path.join(args.build_dir, 'index.rst')
    with open(index_rst, "w") as f:
        if args.klass:
            rstCreator.documentClass(mod, class_name, args.build_dir)
            txt = __INDEX.format(name="_%s" % class_name)
        elif args.package:
            rstCreator.documentModule(package_name, args.build_dir)
            txt = __INDEX.format(name=package_name.rsplit(".", 1)[-1])
        else:
            shutil.copy(args.filename, args.build_dir)
            txt = __INDEX.format(name=os.path.basename(args.filename))
        f.write(txt)

    # directory where conf.py resides
    config_dir = os.path.join(doc_dir, 'source')
    doctree_dir = os.path.join(args.build_dir, 'doctrees')

    app = Sphinx(args.build_dir, config_dir, args.prefix,
                 doctree_dir, args.builder,
                 confoverrides=None, status=out, warning=sys.stderr,
                 freshenv=False, warningiserror=False, tags=None)

    app.build()


if __name__ == "__main__":
    main()
