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

# Copyright 2018 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 optparse
import os
import signal
import sys
import time

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
import confluent.screensqueeze as sq

exitcode = 0


def get_update_progress(session, url):
    for res in session.read(url):
        status = res['phase']
        percent = res['progress']
        detail = res['detail']
        if status == 'error':
            text = 'error!'
        else:
            text = '{0}: {1:3.0f}%'.format(status, percent)
    return text, status, detail


def printerror(res, node=None):
    global exitcode
    if 'errorcode' in res:
        exitcode = res['errorcode']
    if 'error' in res:
        if node:
            sys.stderr.write('{0}: {1}\n'.format(node, res['error']))
        else:
            sys.stderr.write('{0}\n'.format(res['error']))
        if 'errorcode' not in res:
            exitcode = 1
    for node in res.get('databynode', ()):
        printerror(res['databynode'][node], node)



def download_servicedata(noderange, media, options):
    global exitcode
    session = client.Command()
    output = sq.ScreenPrinter(noderange, session)
    filename = os.path.abspath(media)
    resource = '/noderange/{0}/support/servicedata/'.format(noderange)
    upargs = {'filename': filename}
    noderrs = {}
    nodeurls = {}
    session.stop_if_noderange_over(noderange, options.maxnodes)
    for res in session.create(resource, upargs):
        if 'created' not in res:
            for nodename in res.get('databynode', ()):
                output.set_output(nodename, 'error!')
                noderrs[nodename] = res['databynode'][nodename].get(
                    'error', 'Unknown Error')
            continue
        watchurl = res['created']
        currnode = watchurl.split('/')[1]
        nodeurls[currnode] = '/' + watchurl
    while nodeurls:
        for node in list(nodeurls):
            progress, status, err = get_update_progress(
                session, nodeurls[node])
            if status == 'error':
                exitcode = 1
                noderrs[node] = err
            if status in ('error', 'complete', 'pending'):
                list(session.delete(nodeurls[node]))
                del nodeurls[node]
            output.set_output(node, progress)
        time.sleep(2)
    allerrnodes = ','.join(noderrs)
    if noderrs:
        sys.stderr.write(
            'Nodes had errors retrieving service data ({0})!\n'.format(allerrnodes))
    for node in noderrs:
        sys.stderr.write('{0}: {1}\n'.format(node, noderrs[node]))

funmap = {
    'servicedata': download_servicedata,
}


class OptParser(optparse.OptionParser):

    def format_epilog(self, formatter):
        return self.expand_prog_name(self.epilog)

def main():
    argparser = OptParser(
        usage="Usage: %prog <noderange> servicedata "
              "<directory or filename>",
        epilog='\nservicedata will save service data to the given '
               'directory.  It is saved to the location on the relevant '
               'management server (the confluent server if running remote, '
               'and the collective.manager if in collective)\n'
               '\n\nSee `man %prog` for more info.\n')
    argparser.add_option('-m', '--maxnodes', type='int',
                     help='Specify a maximum number of '
                          'nodes to download diagnostic data from, '
                          'prompting if over the threshold') 
    (options, args) = argparser.parse_args()
    media = None
    try:
        noderange = args[0]
        operation = args[1]
        arglength = 2
        if operation == 'servicedata':
            media = args[2]
            arglength = 3
        if len(args) > arglength:
            argparser.print_help()
            sys.exit(1)
    except IndexError:
        argparser.print_help()
        sys.exit(1)
    client.check_globbing(noderange)
    try:
        handler = funmap[operation]
    except KeyError:
        argparser.print_help()
        sys.exit(1)
    handler(noderange, media, options)
if __name__ == '__main__':
    main()
