########################################################################
# Copyright (C) 2019 VMWare, Inc.                                      #
# All Rights Reserved                                                  #
########################################################################
#

'''
Define the data structure for base image.

Implement the functionalities such as construction, serializating to json,
and deserializing from json.
'''

from .Errors import BaseimageValidationError
from .ReleaseUnit import (ReleaseUnit, ESX_COMP_NAME)
try:
   from .Utils.JsonSchema import ValidateBaseImage
   HAVE_VALIDATE_BI = True
except Exception:
   HAVE_VALIDATE_BI = False


def GenerateReleaseID(version):
   return ESX_COMP_NAME + ':' + version


class BaseImage(ReleaseUnit):
   ''' A base image is a release unit that always contains the
       component "ESXi".
   '''

   # The common type for BaseImage objects
   releaseType = 'baseImage'

   # The schema version.
   SCHEMA_VERSION = "1.0"

   # Valid schema veriosn map to release version. Need to populate when bump
   # schema version.
   SCHEMA_VERSION_MAP = {"1.0": '7.0.0'}

   extraAttributes = []
   extraDefault = []
   extraMap = dict(zip(extraAttributes, extraDefault))

   @classmethod
   def FromJSON(cls, jsonString, validation=False):
      # Schema validation
      if validation and HAVE_VALIDATE_BI:
         valid, errMsg = ValidateBaseImage(jsonString)
         if not valid:
            raise BaseimageValidationError(errMsg)

      image = BaseImage(spec=jsonString)
      if validation:
         image.Validate()
      return image

   def ToJSON(self):
      self.Validate()
      jsonString = super(BaseImage, self).ToJSON()

      # Schema validation
      if HAVE_VALIDATE_BI:
         valid, errMsg = ValidateBaseImage(self.ToJSONDict())
         if not valid:
            raise BaseimageValidationError(errMsg)

      return jsonString

   def Validate(self, components=None, biVibs=None):
      """Validates base image schema, metadata, and components.

         Parameters:
            * components - ComponentCollection object having all base image
                           components
            * biVibs     - VibCollection object with VIBs that correspond to
                           all components in base image.
      """

      if ESX_COMP_NAME not in self._components:
         errMsg = 'Base Image must contain the ESXi component'
         raise BaseimageValidationError(errMsg)

      # Validate baseimage components
      if components and biVibs:
         problems = components.Validate(biVibs)
         if problems:
            errMsg = 'Failed to validate components in base image %s: %s' % \
                     (self.versionSpec.version.versionstring,
                      ','.join(p.msg for p in problems.values()))
            raise BaseimageValidationError(errMsg)

   def Copy(self):
      image = BaseImage()
      imageDict = self.ToJSONDict()
      image.FromJSONDict(imageDict)
      return image

   def _GenerateReleaseID(self):
      version = self._versionSpec.version.versionstring \
                if self._versionSpec else ''
      self._releaseID = GenerateReleaseID(version)
