#!/usr/bin/env python

#
# Copyright 2017-2021 VMware, Inc.  All rights reserved. -- VMware Confidential
#
"""
Contains the base class for all patch scripts.
"""

from distutils.version import LooseVersion

from ..version_util import is_patch_executed, \
    is_patch_executed_during_current_upgrade, \
    is_patch_expanded_during_current_upgrade


class PatchBase:
    """
    Abstract base class for all patches.
    """

    def __init__(self, name, version, summary):
        """
        Constructor

        :param name: Name of the patch
        :type name: String

        :param version: Version of the patch
        :type version: LooseVersion

        :param summary: Patch description
        :type summary: LocalizableMessage
        """
        if not isinstance(version, LooseVersion):
            raise TypeError('Wrong type of version parameter')

        self.name = name
        self.version = version
        self.summary = summary


    def get_name(self):
        """
        :return: Patch name
        :rtype: String
        """
        return self.name

    def get_version(self):
        """
        :return: Patch version
        :rtype: LooseVersion
        """
        return self.version

    def get_summary(self):
        """
        :return: Patch description string
        :rtype: LocalizableMessage
        """
        return self.summary

    def should_expand(self, patch_context):
        """
        :param patch_context: Context given by the patch framework
        :type patch_context: patch_specs.PatchContext

        :return: Whether the patch should be expanded or not
        :rtype: bool
        """
        return False

    def should_patch(self, patch_context):
        """
        :param patch_context: Context given by the patch framework
        :type patch_context: patch_specs.PatchContext

        :return: Whether the patch should be executed or not
        :rtype: bool
        """
        return not is_patch_executed(self.name, self.version)

    def do_expand(self, patch_context):
        """
        :param patch_context: Context given by the patch framework
        :type patch_context: patch_specs.PatchContext
        """
        pass

    def do_revert(self, patch_context):
        """
        :param patch_context: Context given by the patch framework
        :type patch_context: patch_specs.PatchContext
        """
        raise NotImplementedError()

    def do_contract(self, patch_context):
        """
        :param patch_context: Context given by the patch framework
        :type patch_context: patch_specs.PatchContext
        """
        pass

    def do_patching(self, patch_context):
        """
        Abstract method to be implemented in descendant classes.
        Perform incremental patching.

        :param patch_context: Context given by the patch framework
        :type patch_context: PatchContext

        :raise UserError: Error that will be reported to the user.
        """
        raise NotImplementedError()

    def is_expanded(self, patch_context):
        """
        :param patch_context: Context given by the patch framework
        :type patch_context: PatchContext

        :return: Whether the patch was expanded during the current upgrade
        :rtype: bool
        """
        return is_patch_expanded_during_current_upgrade(self.name, self.version, patch_context)

    def is_patched(self, patch_context):
        """
        :param patch_context: Context given by the patch framework
        :type patch_context: PatchContext

        :return: Whether the patch was executed during the current upgrade
        :rtype: bool
        """
        return is_patch_executed_during_current_upgrade(self.name, self.version, patch_context)

    def on_success(self, patch_context):
        """
        To be executed at OnSuccess phase after the patch has been
        successfully executed

        :param patch_context: Context given by the patch framework
        :type patch_context: PatchContext
        """
