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

import Ark
import Cell
import PyClient
import optparse # pylint: disable=deprecated-module
import sys

usage = """Usage:
dumpSatScdRegisters [<options>] [<scd-name>]

   Dumps out Scd satellite debug registers, if specified in the FDL.

   <scd-name> is the name of the Scd. This defaults to "FixedSystem"
      in the case of a fixed system or Supervisor1 in the case of
      a modular system. The default is Supervisor2 if the cellId
      specified is 2.

   Options:
      -c, --cellId <cell-id> - specifies the cell id of the Scd
      -s, --sliceId <slice-id> - specifies the slice id of the Scd

   cell-id and slice-id are only valid on modular systems.
   cell-id and slice-id are mutually exclusive.
"""

parser = optparse.OptionParser( usage=usage )
parser.add_option( '-c', '--cellId', action="store", type="string",
                   default=None, help="Cell id" )
parser.add_option( '-s', '--sliceId', action="store", type="string",
                   default=None, help="Slice id" )
options, args = parser.parse_args()

cellId = options.cellId
sliceId = options.sliceId
scdName = None if len( args ) < 1 else args[ 0 ]

def handleError( msg, printUsage=True ):
   print( msg )
   if printUsage:
      print( usage )
   sys.exit( 1 )

modular = Cell.cellType() == 'supervisor'

if modular:
   if cellId and sliceId:
      handleError( 'Error: cell-id and slice-id are mutually exclusive' )
else:
   if cellId:
      handleError( 'Error: cell-id is only valid on a modular system' )
   if sliceId:
      handleError( 'Error: slice-id is only valid on a modular system' )

if not cellId and not sliceId:
   cellId = "1"

if not scdName:
   if modular:
      if cellId:
         scdName = 'Supervisor' + cellId
      else:
         scdName = '0'
   else:
      scdName = 'FixedSystem'

root = PyClient.PyClient( 'ar', 'Sysdb' ).agentRoot()

hwdir = root.entity[ 'hardware' ]

if sliceId:
   scdconfigslicedir = hwdir[ 'scd' ][ 'config' ][ 'slice' ]
   if sliceId not in scdconfigslicedir:
      # pylint: disable-next=consider-using-f-string
      handleError( 'Could not find slice %s in %s' % ( sliceId,
         scdconfigslicedir ), printUsage=False)
   scdconfigdir = scdconfigslicedir[ sliceId ]

   scdstatusslicedir = hwdir[ 'archer' ][ 'scd' ][ 'status'][ 'slice' ]
   assert sliceId in scdstatusslicedir
   scdstatusdir = scdstatusslicedir[ sliceId ]

else:
   scdconfigcelldir = hwdir[ 'cell' ]
   if cellId not in scdconfigcelldir:
      # pylint: disable-next=consider-using-f-string
      handleError( 'Could not find cell %s in %s' % ( cellId,
         scdconfigcelldir ), printUsage=False)
   scdconfigdir = scdconfigcelldir[ cellId ][ 'scd' ][ 'config' ]
   scdstatuscelldir = hwdir[ 'archer' ][ 'scd' ][ 'status'][ 'cell' ]
   assert cellId in scdstatuscelldir
   scdstatusdir = scdstatuscelldir[ cellId ]

assert scdconfigdir
assert scdstatusdir

if scdName not in scdconfigdir.scdConfig:
   # pylint: disable-next=consider-using-f-string
   handleError( 'Could not find Scd %s in %s' % ( scdName,
      scdconfigdir.scdConfig ), printUsage=False)
assert scdName in scdstatusdir.scdStatus

scdconfig = scdconfigdir.scdConfig[ scdName ]
scdstatus = scdstatusdir.scdStatus[ scdName ]

for satScd in sorted( scdconfig.satelliteScd.values() ):
   # pylint: disable-next=consider-using-f-string
   print( '%s register values:' % satScd.name )

   debugBlock = satScd.debugBlock
   if satScd.name not in scdstatus.satelliteScd:
      print( 'No values collected' )
      print()
      continue
   debugVals = scdstatus.satelliteScd[ satScd.name ].debugVals

   colltimeStr = Ark.timestampToStr( debugVals.timestamp, relative=False )
   print( 'Last collection time: ' + colltimeStr )

   if not debugVals.val:
      print( 'No values collected' )
      print()
      continue

   keywidth = len( max( list( debugVals.val ), key=len ) )
   valwidth = 10

   blockOffsetIdx = {}
   for key in debugBlock:
      blockOffsetIdx[ debugBlock[ key ].offset ] = key

   for offset in sorted( blockOffsetIdx ):
      key = blockOffsetIdx[ offset ]
      assert key in debugVals.val
      # pylint: disable-next=consider-using-f-string
      print( '%s - %s: %s' % ( hex( offset ).rjust( 7 ),
         key.ljust( keywidth )[ : keywidth ],
         hex( debugVals.val[ key ] )[ : valwidth ].rjust( valwidth ) ) )
   print()
