#! /usr/bin/env python

# Copyright C 2008-2011 by Isilon Systems, Inc. All rights not expressly
# granted herein are reserved.
# Created in the United States of America.
# 
# This digital media is protected by U.S. and international copyright and
# intellectual property laws. Unless otherwise specified, all information
# and screens appearing as part of this digital medium, including
# software, services, documents, text, images, icons, and logos design;
# the selection, assembly, arrangement, and design thereof; and the code
# that enables its presentation, are the sole property of Isilon Systems,
# Inc.
# 
# Except as otherwise required by applicable law, no part of any
# copyrighted material may be reproduced, modified, translated,
# distributed, published, or transmitted by any means, electronic or
# mechanical, for any purpose, without the prior written consent of Isilon
# Systems. 
#  
# Isilon and Isilon Systems are registered trademarks of Isilon Systems,
# Inc.  Legion is a trademark of Isilon Systems, Inc.  All other
# trademarks and registered trademarks are the property of their
# respective holders.
#
#####
#
#    Script to change node system configuration, serial numbers, and
#    install node-specific CTO receipts.
#

import getopt
import os
import os.path
import re
import sys

import isi.hw.check.mfg.options as options
import isi.hw.check.lib.cto as cto

mfg_options = options.get_options()

# These required options are automatically set on call to isi_mfg_check
# These required options are NOT displayed in --help output

required_mfg_options_keys = [
    'no_remote_logging',
    'no_remote_opts',
    'skip_identify',
    'chassisconfig',
    ]

# Track known VALID isi_mfg_check args.
# valid_mfg_options_dicts are grouped by functionality, options dicts
# valid_mfg_options_keys are additional discrete options, options dict keys

valid_mfg_options_dicts = [
    options.get_options_cto(),
    options.get_options_node(),
    options.get_options_cmdb(),
    options.get_options_net(),
    ]

valid_mfg_options_keys = [
    'newserial',
    ]

# Create options dictionaries for usage() and main()

required = {}
for opt in required_mfg_options_keys:
    required.update({opt: mfg_options[opt]})

valid = {}
for opt in valid_mfg_options_keys:
    valid.update({opt: mfg_options[opt]})
for opts in valid_mfg_options_dicts:
    valid.update(opts)

def usage(code):
    header = [
        'Usage: %s [OPTIONS]' % os.path.basename(sys.argv[0]),
        '',
        'All OPTIONS are passed through to the underlying tools.',
        'All OPTIONS are optional; Tool will prompt for inputs.',
        '',
        'OPTIONS include:',
        ]
    # Only display valid options; Do not display (internal) required options
    usage_options = valid_mfg_options_dicts
    for opt in valid_mfg_options_keys:
        usage_options.append({opt: mfg_options[opt]})
    orders = cto.VALID_ORDERS_STRINGS
    extras1 = [
        ('METHOD', cto.CMDB_ACCESS_VALID_METHODS_STRING2),
        ('USER', 'Suggested: node'),
        ('ORDER', orders[0]),
        ]
    extras1 += [('', order) for order in orders[1:]]
    extras2 = [
        (cto.CMDB_ACCESS_MOUNT,
         'Use NFS mount point (Suggested default)'),
        (cto.CMDB_ACCESS_SCP,
         'Use scp/ssh commands (Multiple password prompts)'),
        (cto.CMDB_ACCESS_LOCAL,
         'Use local file, no network'),
        ]
    width = max(map(len, zip(*(extras1+extras2))[0]))
    wstr = lambda (s1, s2): '  %-*s    %s' % (width, s1, s2)
    extra = [
        '',
        'Valid OPTIONS values include:',
        ]
    extra += map(wstr, extras1)
    extra += [
        '',
        'Valid METHOD values include:',
        ]
    extra += map(wstr, extras2)
    print >> sys.stderr, options.get_usage(header, usage_options, extra)
    sys.exit(code)

def main():

    # Create lists of option strings from option dicts
    required_options = [opt['opts'][0] for opt in required.itervalues()]
    valid_options = [opt['opts'][0] for opt in valid.itervalues()]
    all_options = required_options + valid_options + ['h','help']

    # Create short and long options for use with getopt
    is_short = lambda x: len(x.strip(':=')) == 1
    short_options = ''.join(filter(is_short, all_options))
    long_options = filter(lambda o: not is_short(o), all_options)

    try:
        opts, args = getopt.getopt(sys.argv[1:], short_options, long_options)
    except getopt.GetoptError, err:
        print str(err)
        usage(1)

    # Create '-o'/'--option' option strings for use with getopt results
    def option_string(s):
        s = s.strip(':=')
        if len(s) == 1:
            return '-%s' % s
        else:
            return '--%s' % s
    required_opts = map(option_string, required_options)
    valid_opts = map(option_string, valid_options)

    user_args = {}
    for opt, arg in opts:
        if opt == '-h':
            usage(0)
        elif opt in required_opts:
            pass
        elif opt in valid_opts:
            user_args[opt] = arg
        else:
            print 'Invalid option %s' % opt
            usage(1)

    user_options = reduce(
        lambda a, b: a + b,
        [[opt, arg] for (opt, arg) in user_args.iteritems()],
        [])

    cmd = '/usr/bin/isi_hwtools/isi_mfg_check'
    opts = [cmd] + required_opts + user_options
    os.execv(cmd, opts)

if __name__ == '__main__':
    status = main()
    sys.exit(status)
