#!/usr/bin/env python3

# THIS FILE IS PART OF THE CYLC SUITE ENGINE.
# Copyright (C) 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 [prep] print [OPTIONS] [REGEX]

Print registered (installed) suites.

Note on result filtering:
  (a) The filter patterns are Regular Expressions, not shell globs, so
the general wildcard is '.*' (match zero or more of anything), NOT '*'.
  (b) For printing purposes there is an implicit wildcard at the end of
each pattern ('foo' is the same as 'foo/*'); use the string end marker
to prevent this ('foo$' matches only literal 'foo')."""

import sys
from cylc.flow.remote import remrun
if remrun():
    sys.exit(0)

import os
import re

from cylc.flow.network.scan import get_scan_items_from_fs
from cylc.flow.option_parsers import CylcOptionParser as COP
from cylc.flow.print_tree import print_tree
from cylc.flow.suite_files import REG_DELIM
from cylc.flow.terminal import cli_function


def get_padding(reglist):
    maxlen = 0
    for reg in reglist:
        items = reg[0].split(REG_DELIM)
        for i in range(0, len(items)):
            if i == 0:
                tmp = len(items[i])
            else:
                tmp = 2 * i + 1 + len(items[i])
            if tmp > maxlen:
                maxlen = tmp
    return maxlen * ' '


def get_option_parser():
    parser = COP(__doc__,
                 argdoc=[('[REGEX]', 'Suite name regular expression pattern')])

    parser.add_option(
        "-t", "--tree", help="Print suites in nested tree form.",
        action="store_true", default=False, dest="tree")

    parser.add_option(
        "-b", "--box",
        help="Use unicode box drawing characters in tree views.",
        action="store_true", default=False, dest="unicode")

    parser.add_option(
        "-a", "--align", help="Align columns.",
        action="store_true", default=False, dest="align")

    parser.add_option(
        "-x", help="don't print suite definition directory paths.",
        action="store_true", default=False, dest="x")

    parser.add_option(
        "-y", help="Don't print suite titles.",
        action="store_true", default=False, dest="y")

    parser.add_option(
        "--fail", help="Fail (exit 1) if no matching suites are found.",
        action="store_true", default=False, dest="fail")

    return parser


@cli_function(get_option_parser)
def main(parser, options, regfilter=None):
    if regfilter:
        try:
            regfilter = re.compile(regfilter)
        except re.error as exc:
            raise ValueError("%s: %s" % (regfilter, exc))
    allsuites = list(
        get_scan_items_from_fs(reg_pattern=regfilter, active_only=False))
    if options.fail and not allsuites:
        raise SystemExit('ERROR: no suites matched.')
    if not options.tree:
        if options.align:
            maxlen_suite = 0
            maxlen_title = 0
            for suite, dir_, title in allsuites:
                if len(suite) > maxlen_suite:
                    maxlen_suite = len(suite)
                if len(title) > maxlen_title:
                    maxlen_title = len(title)
            spacer_suite = maxlen_suite * ' '
            spacer_title = maxlen_title * ' '
        for suite, dir_, title in allsuites:
            dir_ = re.sub('^' + os.environ['HOME'], '~', dir_)
            if options.align:
                suite = suite + spacer_suite[len(suite):]
                title = title + spacer_title[len(title):]
            if not options.x and not options.y:
                line = suite + ' | ' + title + ' | ' + dir_
            elif not options.y:
                line = suite + ' | ' + title
            elif not options.x:
                line = suite + ' | ' + dir_
            else:
                line = suite
            print(line)
    else:
        tree = {}
        if options.align:
            maxlen_title = 0
            for suite, dir_, title in allsuites:
                if len(title) > maxlen_title:
                    maxlen_title = len(title)
            spacer_title = maxlen_title * ' '

        for suite, dir_, title in allsuites:
            dir_ = re.sub('^' + os.environ['HOME'], '~', dir_)
            if options.align:
                title = title + spacer_title[len(title):]
            regpath = suite.split(REG_DELIM)
            sub = tree
            for key in regpath[:-1]:
                if key not in sub:
                    sub[key] = {}
                sub = sub[key]
            if not options.x and not options.y:
                line = title + ' | ' + dir_
            elif not options.y:
                line = ' ' + title
            elif not options.x:
                line = ' ' + dir_
            else:
                line = ''
            sub[regpath[-1]] = line

        pad = get_padding(allsuites)
        print_tree(tree, pad, options.unicode)


if __name__ == "__main__":
    main()
