#!/usr/bin/env python

import re
import sys

import isi.app.lib.cluster as clusterlib
import isi.net.flexnet as flx
import isi.hw.check.lib.args as argslib
import isi.hw.check.lib.filenames as files
import isi.hw.check.lib.net as net
import isi.hw.check.safe.id.ethernet as eth

files.init()
d = None

FMT = '%-5s %-11s %-6s %-16s %-6s %-4s %-7s'
FMT_MORE = '%-5s %-11s %-6s %-16s %-6s %-4s %-7s %-10s %-24s'

def print_header():
    if d is None:
        print FMT % ('name', 'flags', 'index', 'address', 'active',
                     'up', 'enabled')
    else:
        print FMT_MORE % ('name', 'flags', 'index', 'address', 'active', 'up',
                          'enabled', 'itype', 'media')

def print_iface(iface, address, python_mode):
    flags = '0x%08x' % iface.flags
    if d is None:
        vals = (iface.nic.name, flags, iface.index, address,
                iface.nic.active, iface.nic.up, iface.enabled)
        if python_mode:
            print ("{'name':'%s','flags':%s,'index':%d,'address':'%s'," +
                   "'active':%d,'up':%d,'enabled':%d}") % vals
        else:
            print FMT % vals
    else:
        if iface.flags == flx.IFFLAG_INTERNAL:
            m = 'Infiniband'
        else:
            m = d[iface.nic.name]['info']
        vals = (iface.nic.name, flags, iface.index, address,
                iface.nic.active, iface.nic.up, iface.enabled, str(iface), m)
        if python_mode:
            print ("{'name':'%s','flags':%s,'index':%d,'address':'%s'," +
                   "'active':%d,'up':%d,'enabled':%d,'itype':'%s'," +
                   "'media':'%s'}") % vals
        else:
            print FMT_MORE % vals

def main(options):
    global d
    args = argslib.Args(options)
    non_opts = args.process(sys.argv[1:])

    IFLAGS = flx.IFFLAG_INTERNAL
    XFLAGS = flx.IFFLAG_EXTERNAL
    IXFLAGS = IFLAGS | XFLAGS

    cluster = clusterlib.Cluster()
    node = cluster.local()
    config = flx.config_load_local()

    if args['moreinfo']:
        d = eth.get_ifconfig_info()
    if args['showheader']:
        print_header()
    
    if non_opts == []:
        # print all external interfaces
        try:
            query_ifaces = flx.lni_query(node, flx.LNI_ANY_IDX, XFLAGS)
        except Exception, e:
            print "Error: %s %s" % (e.message, e.args)
            return
        for iface in query_ifaces:
            # must match against iface name
            addrs = config.get_node_iface_addrs(iface.name, node,
                                                flx.AllocMethod.static)
            if len(addrs):
                print_iface(iface, addrs[0], args['pymode'])
                
        # print all internal interfaces
        try:
            query_ifaces = flx.lni_query(node, flx.LNI_ANY_IDX, IFLAGS)
        except Exception, e:
            print "Error: %s %s" % (e.message, e.args)
            return
        for iface in query_ifaces:
            # must match against index of internal interface
            addrs = config.get_node_addrs(node, flx.AllocMethod.static, iface.index,
                                          IFLAGS)
            if len(addrs):
                print_iface(iface, addrs[0], args['pymode'])

    else:
        # print only specific interfaces
        # XXX PAT: Note that printing specific interface FlexNet info is 
        # currently broken with FlexNet V2.  Fixin this requires changes to
        # import isi.hw.check.lib.net as well as this section of code.  For now
        # there is no way to populate the ext_ifaces and int_ifaces lists
        # correctly, because isi.hw.check.lib.net isn't even correctly parsing
        # the IfaceName argument correctly given the new FlexNet V2 convention.
        # This will not affect the general case however.  This feature of
        # isi_flexnet_info doesn't seem to be used currently, but should be
        # fixed for completeness.
        ifaces = []
        ext_ifaces = []
        int_ifaces = []
        for name in non_opts:
            try:
                iface = net.IfaceName(name)
            except net.IfaceError, e:
                raise argslib.Error(e)
            if iface:
                flags = iface.itype() == 'ext' and XFLAGS or IFLAGS
                ifaces.append((flags, iface.index()))

        try:
            query_ifaces = flx.lni_query(node, flx.LNI_ANY_IDX, IXFLAGS)
        except Exception, e:
            print "Error: %s %s" % (e.message, e.args)
            return
        # print all matching external interfaces
        for iface in filter(lambda x: (x.flags & IXFLAGS, x.index) in ext_ifaces,
                            flx.lni_query(node, flx.LNI_ANY_IDX, IXFLAGS)):
            addrs = config.get_node_iface_addrs(iface.name, node,
                                                flx.AllocMethod.static)
            if len(addrs):
                print_iface(iface, addrs[0], args['pymode'])
        # print all matching internal interfaces
        for iface in filter(lambda x: (x.flags & IXFLAGS, x.index) in int_ifaces,
                            flx.lni_query(node, flx.LNI_ANY_IDX, IXFLAGS)):
            addrs = config.get_node_iface_addrs(iface.name, node,
                                                flx.AllocMethod.static)
            if len(addrs):
                print_iface(iface, addrs[0], args['pymode'])
        
    
if __name__ == '__main__':
    usage = \
"""Usage: %s [OPTIONS] [<interfaces>]

OPTIONS:
  <interfaces>       : Print information for the given interfaces, specified
                       as (ext|int)([1-9][0-9]|[A-Z]) (e.g. ext1, intA,
                       or int2, etc)
  -n, --noheader     : Suppres table headers
  -h, --help         : Show this text

Prints out the interface name, flags, index, and ip address for
external and internal network interfaces.""" % argslib.appname()
    
    options = {
        'showheader':
        {'opts'    : ['n', 'noheader'],
         'default' : True,
         'func'    : argslib.false_func(),
         },

        'pymode':
        {'opts'    : ['p', 'pymode'],
         'default' : False,
         'func'    : argslib.true_func(),
         },
        
        'help':
        {'opts'    : ['h', 'help'],
         'func'    : argslib.help_func(usage),
         },

        'moreinfo':
        {'opts'    : ['m', 'moreinfo'],
         'func'    : argslib.true_func(),
         },
        }

    sys.exit(argslib.run(lambda :main(options), usage))
             
