########################################################################
# Copyright (C) 2010-2023 VMware, Inc.
# All Rights Reserved
########################################################################

"""'Misc utility functions
"""
import sys
import tarfile

_configStoreLogInit = False

def isPython3OrLater():
   """Return True if pyhton 3.0 or newer.
   """
   return sys.version_info[0] >= 3

def isString(objInstance):
   """Check whether the given object is a string.
   """
   if isPython3OrLater():
      return isinstance(objInstance, str)
   else:
      return isinstance(objInstance, basestring)

def byteToStr(byteString):
   """Convert an ascii byte string into a python native string.
   """
   return "".join(['%c' % c for c in byteString])

def seekable(fobj):
   """Check whether a file object supports '.seek()'.
   """
   try:
      return fobj.seekable()
   except AttributeError:
      # Python2 does not support .seekable(). Resort to calling .tell(),
      # which will raise an AttributeError if .seek() is not supported.
      try:
         _ = fobj.tell()
      except AttributeError:
         return False
      else:
         return True

def configStoreLogInit():
   """Initialize configstore logging
   """
   from libconfigstorepy import LogInit
   global _configStoreLogInit
   if not _configStoreLogInit:
      LogInit()
      _configStoreLogInit = True

def LogLargeBuffer(data, logger):
   """LogLargeBuffer takes params data of type optparse or
      string and the logger. If data is a optparse type it
      converts them to a dict and starts to log the contents.
      If the string is too long it logs them in chunks not
      exceeding MAX_CHUNK_SIZE
   """

   MAX_CHUNK_SIZE = 800

   def GetChunks(s):
      start = 0
      end = 0
      while start + MAX_CHUNK_SIZE < len(s):
         end = s.rfind(" ", start, start + MAX_CHUNK_SIZE + 1)
         if end == -1:
            yield s[start : start + MAX_CHUNK_SIZE]
            start += MAX_CHUNK_SIZE
         else:
            yield s[start:end]
            start = end + 1
      yield s[start:]

   if type(data) == str:
      if len(data) <= MAX_CHUNK_SIZE:
         logger(data)
      else:
         chunks = GetChunks(data)
         for c in chunks:
            logger(c)
   else:
      try:
         options_dict = vars(data)
      except Exception as e:
         raise

      for key, value in options_dict.items():
         strValue = str(value)
         if len(strValue) <= MAX_CHUNK_SIZE:
            logger('%s = %s' % (key, strValue))
         else:
            logger('%s =' % (key))
            chunks = GetChunks(strValue)
            for c in chunks:
               logger(c)

def toDepotProductList(platforms):
   """Convert a collection of platforms to a list of products.
      The method will ensure that 'embeddedEsx' will always be
      the first one in the returned list.
   """
   from ..Vib import SoftwarePlatform
   products = None
   if isinstance(platforms, set):
      products = list(platforms)
   elif isinstance(platforms, list):
      products = platforms
   else:
      raise ValueError('Invalid type of platforms argument.'
                       ' It must be either of type list or set.')

   # Make sure 'embeddedEsx' be the first one in the
   # list of supported products. This will fullfill the
   # requirement to upload content to VMware portal.
   if SoftwarePlatform.PRODUCT_EMBEDDEDESX in products and \
      products[0] != SoftwarePlatform.PRODUCT_EMBEDDEDESX:
      products.remove(SoftwarePlatform.PRODUCT_EMBEDDEDESX)
      products.insert(0, SoftwarePlatform.PRODUCT_EMBEDDEDESX)

   return products

def extractTar(tarPath, dest, mode='r', exception=Exception):
   """Extracts the contents of a tarfile to provided destination

      tarpath     : Path of the tarfile to be extracted
      dest        : Path where the contents are to be extracted
      mode        : tarfile.open mode
      exception   : Exception class that will be raised in case of any
                    suspicious files found in the tarfile
   """
   with tarfile.open(tarPath, mode=mode, format=tarfile.GNU_FORMAT) as tar:
      # Check for suspicious file names
      # TODO Remove this once Python version is >= 3.11.4 for all supported
      # versions. tarfile.open can then just use extraction filter.
      for f in tar.getmembers():
         if f.name.startswith("/") or ".." in f.name:
            raise exception('Potentially unsafe file %s in archive %s, '
                            'extraction will not proceed' % (f.name, tarPath))
      tar.extractall(path=dest)
