# -*- coding: utf-8 -*-
#
# Copyright (C) tkornuta, IBM Corporation 2019
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

__author__ = "Tomasz Kornuta"

import inspect

import ptp

from ptp.configuration.configuration_error import ConfigurationError


class ComponentFactory(object):
    """
    Class instantiating the components using the passed config.
    """

    @staticmethod
    def check_inheritance(class_obj, parent_class_name):
        """
        Checks whether given class inherits (even indirectly) from parent class.
        """
        # Check if class is derived (even indirectly) from Component.
        for c in inspect.getmro(class_obj):
            if c.__name__ == parent_class_name:
                return True
        return False



    @staticmethod
    def build(name, config):
        """
        Method creates a single component on the basis of configuration section.
        Raises ConfigurationError exception when encountered issues.

        :param name: Name of the section/component.

        :param config: Parameters used to instantiate all components.
        :type config: :py:class:`ptp.configuration.ConfigInterface`

        :return: tuple (component, component class).
        """

        # Check presence of type.
        if 'type' not in config:
            raise ConfigurationError("Section {} does not contain the key 'type' defining the component type".format(name))

        # Get the class type.
        c_type = config["type"]

        # Get class object.
        if c_type.find("ptp.") != -1:
            # Try to evaluate it directly.
            class_obj = eval(c_type)
        else:
            try:
                # Try to find it in the main "ptp" namespace.
                class_obj = getattr(ptp, c_type)
            except AttributeError:
                raise ConfigurationError("Class '{}' not found in the list of Component classes".format(c_type))

        # Check if class is derived (even indirectly) from Component.
        if not ComponentFactory.check_inheritance(class_obj, ptp.Component.__name__):
            raise ConfigurationError("Class '{}' is not derived from the Component class".format(c_type))

        # Instantiate component.
        component = class_obj(name, config)

        return component, class_obj
