#!/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.
"""

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)

    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=[r".*\.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()
