#!/usr/bin/env python3
# Copyright (c) 2007 Arastra, Inc.  All rights reserved.
# Arastra, Inc. Confidential and Proprietary.

# pylint: disable=consider-using-f-string


import sys, optparse, os, Tac # pylint: disable=deprecated-module

usageStr = ("usage: PhyEthtoolConfig add interface [interface...]\n"
            "       PhyEthtoolConfig remove interface [interface...]\n"
            "       PhyEthtoolConfig list\n\n"
            "This script configures PhyEthtool to manage interfaces.\n"
            "It is an alternative to having Fru/fdl configure PhyEthtool.\n"
            "It is useful in your workspace, so you can run:\n\n"
            "   % Sysdb &\n"
            "   % PhyEthtoolConfig add eth0\n"
            "   % PhyEthtool &\n" )
def usage():
   sys.stderr.write( usageStr )
   sys.exit( 1 )

phyConfig_ = None
ethIntfStatus_ = None

def mountStuff():
   global phyConfig_
   global ethIntfStatus_
   import EntityManager # pylint: disable=import-outside-toplevel
   em = EntityManager.Sysdb( sysname=opts.sysname )
   root = em.root() # pylint: disable=unused-variable
   import Cell # pylint: disable=import-outside-toplevel
   cellId = Cell.cellId()
   mg = em.mountGroup()
   # pylint: disable-next=unused-variable
   hwCell = mg.mount( 'hardware/cell', 'Tac::Dir', 'r' )
   mg.close( blocking=True )
   mg = em.mountGroup()
   hwCellDir = mg.mount( 'hardware/cell/%d' % cellId, 'Tac::Dir', 'w' )
   ethIntfStatus_ = mg.mount( 'interface/status/eth/phy',
          'Interface::EthPhyIntfStatusDir', 'w' )

   mg.close( blocking=True )

   try:
      hwCellDir['phy']['ethtool']['config']
   except KeyError:
      peDir = hwCellDir.mkdir( "phy/ethtool" )
      peDir.newEntity( 'Hardware::Phy::EthtoolConfig', 'config', mountPoint=True )
      
   mg = em.mountGroup()
   phyConfig_ = mg.mount( 'hardware/cell/%s/phy/ethtool/config' % cellId,
                          'Hardware::Phy::EthtoolConfig', 'w' )
   mg.close( blocking=True )


def phyConfig():
   if not phyConfig_: mountStuff() # pylint: disable=multiple-statements
   return phyConfig_

def ethIntfStatus():
   if not ethIntfStatus_: mountStuff() # pylint: disable=multiple-statements
   return ethIntfStatus_


def findEthIntfStatus( deviceName ):
   eis = ethIntfStatus()
   for intf in eis:
      if eis[intf].deviceName == deviceName:
         return intf
   return None


def addCmd( args ): # pylint: disable=redefined-outer-name
   pc = phyConfig()
   eis = ethIntfStatus()
   for deviceName in args:
      addrName = '/sys/class/net/%s/address' % deviceName
      if not os.path.exists( addrName ):
         sys.stderr.write( "%s: no such interface\n" % deviceName )
         continue
      addr = open( addrName ).read().strip() # pylint: disable=consider-using-with
      eintf = findEthIntfStatus( deviceName )
      if not eintf:
         for i in range( 1, 255 ):
            intfName = 'Management%d' % i
            if intfName not in eis: break # pylint: disable=multiple-statements
         eintf = eis.newIntfStatus( intfName, None, eis.genIdMarker, addr )
         eintf.deviceName = deviceName
      else:
         assert eintf.burnedInAddr == addr
      pc.newPhy( eintf.name, eintf )
   Tac.flushEntityLog()
   
def listCmd():
   pc = phyConfig()
   for m in pc.phy.members():
      print( pc.phy[ m ].ethIntfStatus.deviceName, "(interface name: %s)" % m )
   
def removeCmd( args ): # pylint: disable=redefined-outer-name
   pc = phyConfig()
   for deviceName in args:
      eintf = findEthIntfStatus( deviceName )
      if not eintf:
         sys.stderr.write( "%s: EthIntfStatus not found\n" % deviceName )
         continue
      if intf.name not in pc.phy: # pylint: disable=undefined-variable
         sys.stderr.write( "%s (interface %s): not being managed by PhyEthtool\n" %(
            deviceName, intf.name )) # pylint: disable=undefined-variable
         continue
      del pc.phy[intf.name] # pylint: disable=undefined-variable
   Tac.flushEntityLog()
   
op = optparse.OptionParser( usage=usageStr )
op.add_option( '--sysname', action='store', default='ar',
               help='Set system name (default: %default)' )
opts, args = op.parse_args()

args = sys.argv[1:]
if not args: usage() # pylint: disable=multiple-statements


cmd = args.pop( 0 )
if cmd == 'add':
   addCmd( args )
elif cmd == 'remove':
   removeCmd( args )
elif cmd == 'list':
   if args: usage() # pylint: disable=multiple-statements
   listCmd()
else:
   usage()
   
