# -*- coding: utf-8 -*-
#
# Copyright Grégory Soutadé 2015

# This file is part of iwla

# iwla is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# iwla is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with iwla.  If not, see <http://www.gnu.org/licenses/>.
#

import importlib
import inspect
import logging

#
# IWLA Plugin interface
#

class IPlugin(object):
    
    def __init__(self, iwla):
        self.iwla = iwla
        self.requires = []
        self.conf_requires = []
        self.API_VERSION = 1
        self.ANALYSIS_CLASS = 'HTTP'

    def isValid(self, analysis_class, api_version):
        if analysis_class != self.ANALYSIS_CLASS: return False

        # For now there is only version 1
        if self.API_VERSION != api_version:
            return False

        return True
    
    def getRequirements(self):
        return self.requires

    def getConfRequirements(self):
        return self.conf_requires

    def load(self):
        return True

    def hook(self):
        pass

def validConfRequirements(conf_requirements, iwla, plugin_path):
    for r in conf_requirements:
        if iwla.getConfValue(r, None) is None:
            print('\'%s\' conf value required for %s' % (r, plugin_path))
            return False

    return True

def preloadPlugins(plugins, iwla):
    cache_plugins = {}

    logger = logging.getLogger(__name__)

    logger.info("==> Preload plugins")

    for (root, plugins_filenames) in plugins:
        for plugin_filename in plugins_filenames:
            plugin_path = root + '.' + plugin_filename
            try:
                mod = importlib.import_module(plugin_path)
                classes = [c for _,c in inspect.getmembers(mod)\
                               if inspect.isclass(c) and \
                               issubclass(c, IPlugin) and \
                               c.__name__ != 'IPlugin' and \
                               not c.__subclasses__()
                           ]

                if not classes:
                    logger.warning('No plugin defined in %s' % (plugin_path))
                    continue

                if len(classes) > 1:
                    logger.warning('More than one class found in %s, loading may fail. Selecting %s' % (plugin_path, classes[0]))
                    print(classes)
                    continue

                plugin = classes[0](iwla)
                plugin_name = plugin.__class__.__name__

                if not plugin.isValid(iwla.ANALYSIS_CLASS, iwla.API_VERSION):
                    #print 'Plugin not valid %s' % (plugin_filename)
                    continue
                
                #print 'Load plugin %s' % (plugin_name)

                conf_requirements = plugin.getConfRequirements()
                if not validConfRequirements(conf_requirements, iwla, plugin_path):
                    continue

                requirements = plugin.getRequirements()

                requirement_validated = False
                for r in requirements:
                    for p in cache_plugins.values():
                        if p.__class__.__name__ == r:
                            requirement_validated = True
                            break
                    if not requirement_validated:
                        logger.error('Missing requirements \'%s\' for plugin %s' % (r, plugin_path))
                        break
                if requirements and not requirement_validated: continue

                if not plugin.load():
                    logger.error('Plugin %s load failed' % (plugin_path))
                    continue

                logger.info('\tRegister %s' % (plugin_path))
                cache_plugins[plugin_path] = plugin
            except Exception as e:
                logger.exception('Error loading %s => %s' % (plugin_path, e))

    return cache_plugins