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


import argparse
import re
import sys
import Cell
import ModularGenprefdlLib

description = """Read from or write to a device's seeprom.

modularseeprom read [options]
   Read seeprom contents of [device_name] and write to stdout

   All numeric arguments must be specified in decimal.

Examples:
   modularseeprom read --device=Supervisor1 
   modularseeprom read --device=Midplane --seeprom-id=1

These combinations are currently unsupported:
   modularseeprom read --device=Supervisor1 [data1] write [data]

"""

### EXECUTABLE CODE SECTION ###############################################

deviceNames = [ 'Supervisor', 'Linecard', 'Fabric', 'Midplane', 'Switchcard',
                'SupervisorUplink' ]

def parseDevice( args ):
   deviceType = None
   deviceId = None
   # pylint: disable-next=consider-using-f-string
   deviceInvalidStr = "Device type must be one of %s" % str( deviceNames ) 
   deviceRe = re.search( r'([a-zA-Z]+)(\d*)', args.device, re.IGNORECASE )
   if deviceRe:
      deviceType = deviceRe.group( 1 )
      if deviceType not in deviceNames:
         parser.error( deviceInvalidStr )
      deviceType = "Chassis" if deviceType == "Midplane" else deviceType
      if deviceType == "Chassis":
         if args.seeprom_id:
            deviceId = int( args.seeprom_id )
         else:
            parser.error( "Mandatory --seeprom-id option missing." )
      elif deviceType == deviceNames[ 0 ]:
         deviceId = Cell.cellId()
      elif deviceRe.group( 2 ):
         deviceId = int( deviceRe.group( 2 ) )
   else:
      parser.error( deviceInvalidStr )

   return ( deviceType, deviceId )

def read( args ):
   ( deviceType, deviceId ) = parseDevice( args )
   offset_ = args.offset

   if args.length:
      length_ = int( args.length )
   else:
      length_ = 0 

   try:
      modPrefdlReader = ModularGenprefdlLib.ModularPrefdlReader()
   except ModularGenprefdlLib.UnsupportedException as e:
      print( e )
      sys.exit( 1 )
   data_ = modPrefdlReader.readDeviceSeeprom( deviceType=deviceType, 
                                              deviceId=deviceId, 
                                              length=length_, 
                                              offset=offset_, 
                                              section=args.section, 
                                              uncompressed=args.uncompressed )
      
   if data_:
      if args.output_file:
         f = open( args.output_file, "wb" ) # pylint: disable=consider-using-with
         f.write( data_ )
         f.close()
      else:
         print( data_ )
   else:
      # pylint: disable-next=consider-using-f-string
      print( "Could not read seeprom of device {}{}".format( deviceType,
            ( deviceId or '' ) ) )

# Shared options
parent_parser = argparse.ArgumentParser( add_help=False )
parent_parser.add_argument( "-d", "--device", dest="device", required=True, 
      help="Specify device name (e.g. Fabric1, Linecard3, Midplane, Switchcard, "
           "Supervisor1, SupervisorUplink2)" )
parent_parser.add_argument( "-n", "--seeprom-id", dest="seeprom_id", default=None,
      help="Seeprom id (1, 2, 3, etc.) to be read from/written to" )
parent_parser.add_argument( "-e", "--offset", dest="offset", default=0, type=int,
      help="Offset within seeprom to start from" )
parent_parser.add_argument( "-p", "--section", dest="section", default="all", 
      help="Specify the section to be read or write from/to: 'prefdl', 'fdl', " + 
           ", 'header', or 'all'" )
parent_parser.add_argument( "-u", "--uncompressed", dest="uncompressed",
      default=False, action="store_true", 
      help="Specify that the section to be read or write from/to is " + 
           "uncompressed (in case --section=fdl), or decoded (in case " + 
           "--section=prefdl), or both uncompressed and decoded (in case " + 
           "--section=all)." )

parser = argparse.ArgumentParser( 
      formatter_class=argparse.RawDescriptionHelpFormatter,
      description=description )
subparsers = parser.add_subparsers()

# Read subcommand
parser_read = subparsers.add_parser( 'read', parents=[ parent_parser ] )
parser_read.add_argument( "-o", "--output-file", dest="output_file", default=None, 
      help="Specify the file to be written to" )
parser_read.add_argument( "-l", "--length", dest="length", default=None, type=int,
      help="Length, in bytes, to read" )
parser_read.set_defaults( func=read )

arguments = parser.parse_args()

arguments.func( arguments )

sys.exit( 0 )
