#!/usr/bin/env python2

# THIS FILE IS PART OF THE CYLC SUITE ENGINE.
# Copyright (C) 2008-2018 NIWA & British Crown (Met Office) & Contributors.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# 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, see <http://www.gnu.org/licenses/>.

"""cylc [info] documentation|browse [OPTIONS] [SUITE]

View documentation in browser or PDF viewer, as per Cylc global config.

% cylc doc [OPTIONS]
   View local or internet [--www] Cylc documentation URLs.

% cylc doc [-t TASK] SUITE
    View suite or task documentation, if URLs are specified in the suite. This
parses the suite definition to extract the requested URL. Note that suite
server programs also hold suite URLs for access from the Cylc GUI.

Arguments:
   [TARGET]    File, URL, or suite name"""

import sys

for arg in sys.argv[1:]:
    if arg.startswith('--host=') or arg.startswith('--user='):
        from cylc.remote import remrun
        if remrun(forward_x11=True):
            sys.exit(0)

import os
import re
from subprocess import call
from optparse import OptionParser

import cylc.flags
from cylc.cfgspec.glbl_cfg import glbl_cfg
from cylc.run_get_stdout import run_get_stdout


def main():
    parser = OptionParser(__doc__)

    parser.add_option(
        "-p", "--pdf", help="Open the PDF User Guide directly.",
        action="store_true", default=False, dest="pdf")

    parser.add_option(
        "-w", "--www", help="Open the cylc internet homepage",
        action="store_true", default=False, dest="www")

    parser.add_option(
        "-t", "--task", help="Browse task documentation URLs.",
        metavar="TASK_NAME", action="store", default=None, dest="task_name")

    parser.add_option(
        "-s", "--stdout", help="Just print the URL to stdout.",
        action="store_true", default=False, dest="stdout")

    parser.add_option(
        "--user",
        help="Other user account name. This results in "
             "command reinvocation on the remote account.",
        metavar="USER", action="store", dest="owner")

    parser.add_option(
        "--host",
        help="Other host name. This results in "
             "command reinvocation on the remote account.",
        metavar="HOST", action="store", dest="host")

    parser.add_option(
        "--debug",
        help="Print exception traceback on error.",
        action="store_true", default=False, dest="debug")

    parser.add_option(
        "--url",
        help="URL to view in your configured browser.",
        metavar="URL", default=None, action="store", dest="url")

    (options, args) = parser.parse_args()
    cylc.flags.debug = options.debug

    intranet_url = glbl_cfg().get(['documentation', 'urls', 'local index'])
    internet_url = glbl_cfg().get(['documentation', 'urls',
                                   'internet homepage'])
    html_file = glbl_cfg().get(['documentation', 'files', 'html index'])
    html_viewer = glbl_cfg().get(['document viewers', 'html'])
    pdf_file = glbl_cfg().get(['documentation', 'files', 'pdf user guide'])
    pdf_viewer = glbl_cfg().get(['document viewers', 'pdf'])
    if len(args) == 0:
        # Cylc documentation.
        if options.pdf:
            # Force PDF.
            viewer = pdf_viewer
            target = pdf_file
        elif options.url:
            viewer = html_viewer
            target = options.url
        else:
            # HTML documentation index.
            viewer = html_viewer
            if options.www:
                # Force internet.
                if internet_url is not None:
                    target = internet_url
                else:
                    sys.exit("ERROR: cylc internet URL not defined.")
            elif intranet_url is not None:
                # Intranet.
                target = intranet_url
            else:
                # Open in file:// mode as a last resort.
                print >> sys.stderr, ("WARNING: cylc intranet URL not "
                                      "defined, trying file mode.")
                target = html_file

    elif len(args) == 1:
        # Suite or task documentation.
        if options.pdf or options.www:
            print >> sys.stderr, (
                "(Note: --pdf and --www are ignored for suite documentation).")
        suite = args[0]
        if options.task_name:
            # Task documentation.
            res, stdout = run_get_stdout(
                "cylc get-suite-config -i [runtime][%s][meta]URL %s" % (
                    options.task_name, suite))
        else:
            # Suite documentation.
            res, stdout = run_get_stdout(
                "cylc get-suite-config -i [meta]URL %s" % suite)
        if not res:
            # (Illegal config item)
            sys.exit(stdout)
        elif len(stdout) == 0:
            if options.task_name is not None:
                sys.exit("ERROR: No URL defined for %s in %s." % (
                    options.task_name, suite))
            else:
                sys.exit("ERROR: No URL defined for %s." % suite)
        target = stdout[0]
        viewer = html_viewer
    else:
        parser.error("Too many arguments.")

    if target in [pdf_file, html_file] and not os.path.isfile(target):
        sys.exit("ERROR, file not found: %s (see your cylc admin)" % target)

    # viewer may have spaces (e.g. 'firefox --no-remote'):
    command = '%s %s' % (viewer, target)
    command_list = re.split(' ', command)

    if options.stdout:
        print target
        sys.exit(0)

    try:
        retcode = call(command_list, stdin=open(os.devnull))
    except OSError:
        print >> sys.stderr, 'ERROR, failed to execute: %s' % command
        if cylc.flags.debug:
            raise
    else:
        if retcode != 0:
            print >> sys.stderr, 'ERROR, command failed: %s' % command
        sys.exit(retcode)


if __name__ == "__main__":
    try:
        main()
    except Exception as exc:
        if cylc.flags.debug:
            raise
        sys.exit(str(exc))
