# Copyright 2015 VMware, Inc.  All rights reserved. -- VMware Confidential
#
'''
Module hiding the details about the execution patching script logic.
'''
import logging

from patch_errors import InternalError

from vmware_b2b.patching.executor.execution_factory import getExecutor
from vmware_b2b.patching.utils.reporting_utils import createReportingIdentifier, \
    createComponentReportingIdentifier

logger = logging.getLogger(__name__)

noneType = type(None)

def executeHook(scriptFile, hook, args, reportQueue, reportIdentifier=None,
                expectedResultType=noneType):
    '''Executes a component patch hook. The method creates an executor based
    on defined execution policy, and executes the patching hook.

    @param scriptFile: Python module where component patching hooks are defined at
    @type scriptFile: str

    @param hook: The patching hook which has to be executed. Allowed values are
      defined at extensions.Hook structure.
    @type hook: str

    @param args: The patching hooks input. The object will be passed to the
      the component patching hook.
    @type args: Serializable

    @param reportQueue: A queue to be used for reporting purposes by the patching
        hook
    @type reportQueue: multiprocessor.Queue

    @param reportIdentifier: The identifier for this component to be used for
        reporting. Use reporting_utils.createReportingIdentifier for creating it.
    @type reportIdentifier: str

    @param expectedResultType: The expected result type.
    @type expectedResultType: type or tuple of types

    @return: The result of the patching hook
    @rtype: Serializable

    @raise: patch_errors.BaseError or ComponentError: If the component fails to be executed in
      the provided contract.
    '''
    reportIdentifier = reportIdentifier or createReportingIdentifier(scriptFile, hook)
    executor = getExecutor()
    result = executor.executeHook(scriptFile, hook, args, reportQueue, reportIdentifier)

    if not isinstance(result, expectedResultType):
        error = "Expected result type to be %s, but got %s" % \
                        (expectedResultType, type(result))
        logger.error(error)
        raise InternalError(error)

    return result

def executeComponentHook(hook, ctx, c, userData, reportQueue, expectedResultType=noneType):
    '''Executes a component patch hook. The method creates an executor based
    on defined execution policy, and executes the patching hook. The method also
    extracts the subset of all given userData and pass only the data which
    the component hook is interested in(defined by its discovery hook).

    @param hook: The patching hook which has to be executed. Allowed values are
      defined at extensions.Hook structure.
    @type hook: str

    @param ctx: Global CPO patch phase context
    @type ctx: vmware.patching.data.model.PatchPhaseContext

    @param c: A component which has to be executed
    @type c: vmware.patching.data.model.Component

    @param userData: All customer input, as result of component questions
    @type userData: dict

    @param reportQueue: A queue to be used for reporting purposes by the patching
        hook
    @type reportQueue: multiprocessor.Queue

    @param expectedResultType: The expected result type.
    @type expectedResultType: type or tuple of types

    @return: The result of the patching hook
    @rtype: Serializable

    @raise: patch_errors.BaseError or ComponentError: If the component fails to be executed in
      the provided contract.
    '''
    args = ctx.buildComponentExecutionContext(c, userData)
    identifier = createComponentReportingIdentifier(c, hook)
    result = executeHook(c.patchScript, hook, args,
                         reportQueue, identifier, expectedResultType)

    return result
