#!/usr/bin/env python2

# THIS FILE IS PART OF THE CYLC SUITE ENGINE.
# Copyright (C) 2008-2019 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] ARGS

View documentation in the browser, 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."""

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
import shlex
from subprocess import call, check_call, CalledProcessError

from cylc.cfgspec.glbl_cfg import glbl_cfg
from cylc.option_parsers import CylcOptionParser as COP
from cylc.run_get_stdout import run_get_stdout


def main():
    parser = COP(
        __doc__, argdoc=[('[TARGET]', 'File or suite name')])

    parser.add_option(
        "-g", "--guides",
        help="Open the HTML (User & Suite Design) Guides directly.",
        action="store_true", default=False, dest="guides")

    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(remove_opts=['--host', '--user'])

    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 user guides'])
    html_viewer = glbl_cfg().get(['document viewers', 'html'])
    if len(args) == 0:
        # Cylc documentation.
        if options.guides:
            viewer = html_viewer
            target = html_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.guides or options.www:
            print >> sys.stderr, ("(Note: --guides 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 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 = shlex.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__":
    main()
