#!/usr/bin/python3
# Version 1.8.1-1
import sys
import optparse
from nodes import Hierarchy, NodesException, numerically_sorted_entities, collect_name_hostlist

# MAIN

op = optparse.OptionParser(usage="usage: %prog [OPTION]... NODESPEC")
op.add_option("--to-nodes",
              action="store_true", 
              help="convert NODESPEC to nodes (default)")
op.add_option("-u", "--up",
              action="store",
              metavar="LEVEL",
              help="list groups where any node in NODESPEC is a member")
op.add_option("-f", "--fill",
              action="store",
              metavar="LEVEL",
              help="as --up, but then convert to nodes")
op.add_option("-r", "--representative",
              action="store",
              metavar="LEVEL",
              help="as --up, but then convert to a representative node per group")
op.add_option("-g", "--gather",
              action="store",
              metavar="LEVEL",
              help="list groups whose members are all in NODESPEC plus the individual nodes that are left over")
op.add_option("-i", "--index",
              action="store",
              metavar="LEVEL",
              help="list the nodes together with their index in their group at the specified LEVEL (--expand is implied)")
op.add_option("-I", "--index-separator",
              action="store", type="string",  default=": ",
              metavar="SEPARATOR",
              help="separator to use between node and index in --index (default is ': ')")
op.add_option("--convert-to-clustershell",
              action="store_true",
              help="convert to ClusterShell YAML")
op.add_option("-m", "--missing",
              action="store", 
              metavar="GROUP",
              help="when doing --up, pretend that nodes not in any group belong to GROUP")
op.add_option("-e", "--expand",
              action="store_true", 
              help="expand to list of names instead of collecting a hostlist")
op.add_option("--separator",
              action="store", type="string",  default="\n",
              help="separator to use between nodes when outputting an expanded list (default is newline)")
op.add_option("--prepend",
              action="store", type="string",  default="",
              help="string to prepend to each node when outputting an expanded list")
op.add_option("--append",
              action="store", type="string",  default="",
              help="string to append to each node when outputting an expanded list")
op.add_option("-n", "--count",
              action="store_true",
              help="output the number of names instead of the hostlist or expanded list")
op.add_option("-s", "--slurm",
              action="store_true", 
              help="create dynamic groups for SLURM jobs and users")
op.add_option("--config-file",
              action="store",
              default="/etc/nodes.conf",
              metavar="FILE",
              help="use FILE instead of /etc/nodes.conf")

(opts, args) = op.parse_args()

h = Hierarchy()
try:
    h.parse_file(opts.config_file)
except NodesException as e:
    print()
    sys.stderr.write("Config file error: %s\n" % e.msg)
    sys.exit(1)

if opts.slurm:
    try:
        h.parse_slurm()
    except NodesException as e:
        print()
        sys.stderr.write("SLURM error: %s\n" % e.msg)
        sys.exit(1)


if not opts.convert_to_clustershell:
    if len(args) != 1:
        sys.exit("Error: You need to provide a single node specifier!\n")
        sys.exit(1)
    else:
        arg = args[0]

modes_chosen = int(opts.to_nodes is not None) + \
    int(opts.up is not None) + \
    int(opts.fill is not None) + \
    int(opts.representative is not None) + \
    int(opts.gather is not None) + \
    int(opts.index is not None) + \
    int(opts.convert_to_clustershell is not None)

if modes_chosen > 1:
    sys.exit("Error: You cannot choose more than one mode at a time!\n")
    sys.exit(1)
elif modes_chosen == 0 or opts.to_nodes:
    func = lambda a: h.to_nodes(a)
else:
    if opts.up:
        func = lambda arg: h.up(opts.up, arg, missing_group = opts.missing)
    elif opts.fill:
        func = lambda arg: h.fill(opts.fill, arg)
    elif opts.representative:
        func = lambda arg: h.representative(opts.representative, arg)
    elif opts.gather:
        func = lambda arg: h.gather(opts.gather, arg)
    elif opts.index:
        func = lambda arg: h.index(opts.index, arg, separator = opts.index_separator)
    elif opts.convert_to_clustershell:
        h.convert_to_clustershell()
        sys.exit(0)

try:
    res = func(arg)
    if opts.count:
        print(len(res))
    elif opts.expand or opts.index:
        print(opts.separator.join([opts.prepend + x.name + opts.append for x in numerically_sorted_entities(res)]))
    else:
        print(collect_name_hostlist(res))

except NodesException as e:
    print()
    sys.stderr.write("Error: %s\n" % e.msg)
    sys.exit(1)

