// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.

#ifndef __MODULE_MANAGER_HPP__
#define __MODULE_MANAGER_HPP__

#include <list>
#include <mutex>
#include <string>
#include <vector>

#include <glog/logging.h>

#include <mesos/mesos.hpp>
#include <mesos/module.hpp>

#include <mesos/module/module.hpp>

#include <process/owned.hpp>

#include <stout/check.hpp>
#include <stout/dynamiclibrary.hpp>
#include <stout/hashmap.hpp>
#include <stout/nothing.hpp>
#include <stout/synchronized.hpp>
#include <stout/try.hpp>

#include "messages/messages.hpp"

namespace mesos {
namespace modules {

// Mesos module loading.
//
// Phases:

// 1. Load dynamic libraries that contain modules from the Modules
//    instance which may have come from a commandline flag.
// 2. Verify versions and compatibilities.
//   a) Library compatibility. (Module API version check)
//   b) Module compatibility. (Module Kind version check)
// 3. Instantiate singleton per module. (happens in the library)
// 4. Bind reference to use case. (happens in Mesos)


class ModuleManager
{
public:
  // Loads dynamic libraries, and verifies the compatibility of the
  // modules in them.
  //
  // NOTE: If loading fails at a particular library we don't unload
  // all of the already loaded libraries.
  static Try<Nothing> load(const Modules& modules)
  {
    return loadManifest(modules);
  }

  // NOTE: If loading fails at a particular library we don't unload
  // all of the already loaded libraries.
  static Try<Nothing> load(const std::string& modulesDir);

  // create() should be called only after load().
  template <typename T>
  static Try<T*> create(
      const std::string& moduleName,
      const Option<Parameters>& params = None())
  {
    synchronized (mutex) {
      if (!moduleBases.contains(moduleName)) {
        return Error(
            "Module '" + moduleName + "' unknown");
      }

      Module<T>* module = (Module<T>*) moduleBases[moduleName];
      if (module->create == nullptr) {
        return Error(
            "Error creating module instance for '" + moduleName + "': "
            "create() method not found");
      }

      std::string expectedKind = kind<T>();
      if (expectedKind != module->kind) {
        return Error(
            "Error creating module instance for '" + moduleName + "': "
            "module is of kind '" + module->kind + "', but the requested "
            "kind is '" + expectedKind + "'");
      }

      T* instance =
        module->create(
            params.isSome() ? params.get() : moduleParameters[moduleName]);
      if (instance == nullptr) {
        return Error("Error creating Module instance for '" + moduleName + "'");
      }
      return instance;
    }
  }

  template <typename T>
  static bool contains(const std::string& moduleName)
  {
    synchronized (mutex) {
      return (moduleBases.contains(moduleName) &&
              moduleBases[moduleName]->kind == stringify(kind<T>()));
    }
  }

  // Returns all module names that have been loaded that implement the
  // specified interface 'T'. For example:
  //
  //   std::vector<std::string> modules = ModuleManager::find<Hook>();
  //
  // Will return all of the module names for modules that implement
  // the Isolator interface.
  template <typename T>
  static std::vector<std::string> find()
  {
    std::vector<std::string> names;

    synchronized (mutex) {
      foreachpair (const std::string& name, ModuleBase* base, moduleBases) {
        if (base->kind == stringify(kind<T>())) {
          names.push_back(name);
        }
      }
    }

    return names;
  }

  // Exposed just for testing so that we can unload a given
  // module  and remove it from the list of ModuleBases.
  static Try<Nothing> unload(const std::string& moduleName);

private:
  static void initialize();

  static Try<Nothing> loadManifest(const Modules& modules);

  static Try<Nothing> verifyModule(
      const std::string& moduleName,
      const ModuleBase* moduleBase);

  // Allow multiple calls to `load()` by verifying that the modules with same
  // name are indeed identical. Thus, multiple loadings of a module manifest
  // are harmless.
  static Try<Nothing> verifyIdenticalModule(
      const std::string& libraryName,
      const Modules::Library::Module& module,
      const ModuleBase* base);

  static std::mutex mutex;

  static hashmap<std::string, std::string> kindToVersion;

  // Mapping from "module name" to the actual ModuleBase. If two
  // modules from different libraries have the same name then the last
  // one specified in the protobuf Modules will be picked.
  static hashmap<std::string, ModuleBase*> moduleBases;

  // Module-specific command-line parameters.
  static hashmap<std::string, Parameters> moduleParameters;

  // A list of dynamic libraries to keep the object from getting
  // destructed.
  // NOTE: We do leak loaded dynamic libraries. This is to allow
  // modules to make use of e.g., libprocess which otherwise could
  // lead to situations where libprocess (which we depend on ourself)
  // is unloaded before the destructor of below `static` is called.
  // Unloading the dynamic library could then lead to the linker
  // attempting to unload the libprocess loaded from the module which
  // is not there anymore.
  static hashmap<std::string, DynamicLibrary*> dynamicLibraries;

  // Module to library name mapping.
  static hashmap<std::string, std::string> moduleLibraries;
};

} // namespace modules {
} // namespace mesos {

#endif // __MODULE_MANAGER_HPP__
