#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4

# Copyright 2017 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


import os
import signal
import optparse
import sys

try:
    signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
    pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
    sys.path.append(path)

import confluent.client as client

class NullOpt(object):
    blame = None
    clear = None


def bailout(msg, code=1):
    sys.stderr.write(msg + '\n')
    sys.exit(code)


argparser = optparse.OptionParser()
(options, args) = argparser.parse_args()

cfgpaths = {
    'bmc.ipv4_address': (
        'configuration/management_controller/net_interfaces/management',
        'ipv4_address'),
    'bmc.ipv4_method': (
        'configuration/management_controller/net_interfaces/management',
        'ipv4_configuration'),
    'bmc.ipv4_gateway': (
        'configuration/management_controller/net_interfaces/management',
        'ipv4_gateway'),
}

autodeps = {
    'bmc.ipv4_address': (('bmc.ipv4_method', 'static'),)
}

try:
    noderange = args[0]
except IndexError:
    argparser.print_help()
    sys.exit(1)
client.check_globbing(noderange)
setmode = None
assignment = {}
queryparms = {}


if len(args) == 1:
    for candidate in cfgpaths:
        path, attrib = cfgpaths[candidate]
        path = '/noderange/{0}/{1}'.format(noderange, path)
        if path not in queryparms:
            queryparms[path] = {}
        queryparms[path][attrib] = candidate
for param in args[1:]:
    if '=' in param:
        if setmode is None:
            setmode = True
        if setmode != True:
            bailout('Cannot do set and query in same command')
        key, _, value = param.partition('=')
        if key not in cfgpaths:
            bailout('Unrecognized setting: {0}'.format(key))
        for depkey, depval in autodeps.get(key, []):
            assignment[depkey] = depval
        assignment[key] = value
    else:
        if setmode is None:
            setmode = False
        if setmode != False:
            bailout('Cannot do set and query in same command')
        if '.' not in param:
            matchedparms = False
            for candidate in cfgpaths:
                if candidate.startswith('{0}.'.format(param)):
                    matchedparms = True
                    path, attrib = cfgpaths[candidate]
                    path = '/noderange/{0}/{1}'.format(noderange, path)
                    if path not in queryparms:
                        queryparms[path] = {}
                    queryparms[path][attrib] = candidate
            if not matchedparms:
                bailout('Unrecognized settings category: {0}'.format(param))
        elif param not in cfgpaths:
            bailout('Unrecognized parameter: {0}'.format(param))
        else:
            path, attrib = cfgpaths[param]
            path = '/noderange/{0}/{1}'.format(noderange, path)
            if path not in queryparms:
                queryparms[path] = {}
            queryparms[path][attrib] = param
session = client.Command()
if setmode:
    updatebypath = {}
    attrnamebypath = {}
    for key in assignment:
        if key not in cfgpaths:
            bailout('Unknown settings key: {0}'.format(key))
        path, attrib = cfgpaths[key]
        if path not in updatebypath:
            updatebypath[path] = {}
            attrnamebypath[path] = {}
        updatebypath[path][attrib] = assignment[key]
        attrnamebypath[path][attrib] = key
    # well, we want to expand things..
    # check ipv4, if requested change method to static
    for path in updatebypath:
        for r in session.update('/noderange/{0}/{1}'.format(noderange, path),
                                updatebypath[path]):
            for node in r:
                keyval = r[node]['value']
                key, val = keyval.split('=')
                if key in attrnamebypath[path]:
                    key = attrnamebypath[path][key]
                print('{0}: {1}: {2}'.format(node, key, val))
else:
    for path in queryparms:
        client.print_attrib_path(path, session, list(queryparms[path]),
                                 NullOpt(), queryparms[path])