// %pacpus:license{
// This file is part of the PACPUS framework distributed under the
// CECILL-C License, Version 1.0.
// %pacpus:license}
/// @file
/// @author  Gerald Dherbomez <firstname.surname@utc.fr>
/// @date    January, 2006
/// @version $Id: ComponentManager.h 76 2013-01-10 17:05:10Z kurdejma $
/// @copyright Copyright (c) UTC/CNRS Heudiasyc 2006 - 2013. All rights reserved.
/// @brief Brief description.
///
/// Purpose:     This class records the components and manages them
///              This class is a singleton
///              Use the static ComponentManager::create() function
///              to get a pointer on this object.

#ifndef DEF_PACPUS_COMPONENTMANAGER_H
#define DEF_PACPUS_COMPONENTMANAGER_H

#include <Pacpus/kernel/pacpus.h>
#include <Pacpus/kernel/ComponentFactoryBase.h>
#include <Pacpus/kernel/PacpusPluginInterface.h>
#include <Pacpus/kernel/XmlConfigFile.h>

#include <cstddef>
#include <QList>
#include <QMap>
#include <QPluginLoader>

namespace pacpus {

class ComponentBase;

/// @todo Documentation
typedef QMap<QString, ComponentBase *> ComponentMap;
/// @todo Documentation
typedef QMap<QString, ComponentFactoryBase *> FactoryMap;

/// Singleton recording the components and managing them.
class PACPUSLIB_API ComponentManager
{
    friend class ComponentBase;

public:
    /// @returns a pointer to the ComponentManager object
    /// @deprecated Use getInstance()
    PACPUS_DEPRECATED_MSG( static ComponentManager * create(), "use 'getInstance()'" );

    /// Returns an instance of the singleton ComponentManager class.
    /// @returns Pointer to the ComponentManager singleton.
    static ComponentManager* getInstance();

    /// Destroys the ComponentManager singleton.
    ///
    /// After this call, every pointer to the ComponentManager becomes invalid.
    static void destroy();

    /// Automatic deleter class.
    struct destroyer {
        /// Invokes ComponentManager::destroy() method if @b mgr pointer is not null.
        void operator()(ComponentManager * mgr) const
        {
            if (!mgr) {
                return;
            }
            mgr->destroy();
        }
    };

    /** Load the components included in the XML config file.
     * @param file Name of the XML file.
     * @return Number of components loaded by the manager.
     */
    std::size_t loadComponents(const QString& file);

    /** Start all the components
     * @return True if all the component has been started, otherwise false.
     */
    bool start();

    /** Start only the component passed in parameter.
     * @param component Component to start.
     * @return True if the component exists and has been started, otherwise false.
     */
    bool start(const QString& component);

    /** Stop all the components
     * @return True if all the component has been stopped, otherwise false.
     */
    bool stop();

    /** Stop only the component passed in parameter.
     * @param component Component to stop.
     * @return True if the component has been stopped, otherwise false.
     */
    bool stop(const QString& component);

    /** Get a pointer to the component referred by @em name.
     * @param name Name of the component.
     * @return Pointer to the component if it exists, otherwise @em NULL.
     */
    ComponentBase* getComponent(const QString& name);

    /** Get the list of all the names of the component known by the manager.
     * @return List of all the component's name.
     */
    QStringList getAllComponentsName() const;

    /** Load a new plugin from the file filename (it may be a .so/.dll file)
     * @param filename Name of the shared object or the dll.
     * @return True if the plugin has been loaded, otherwise false.
     */
    bool loadPlugin(const QString& filename);

private:
    bool stop(ComponentBase* component) const;

    /// Create a new component of type 'type' and with the name 'name'
    bool createComponent(const QString& type, const QString& name);

    bool createConnection(const QString& type, const QString& name, const QString& , int );

    bool registerComponent(ComponentBase* addr, const QString& name);
    bool registerComponentFactory(ComponentFactoryBase* addr, const QString& type);

    bool unregisterComponent(const QString& name);
    bool unregisterComponentFactory(const QString& type);

    // Allow 2 functions to access to private members of ComponentManager
    friend void ComponentFactoryBase::addFactory(ComponentFactoryBase* addr, const QString & type);
    friend void ComponentFactoryBase::addComponent(const QString & name);

    /// private constructor accessible only via static create() function
    ComponentManager();

    /// private destructor accessible only via static destroy() function
    ~ComponentManager();

private:
    /// The static pointer to this object (ComponentManager is a singleton)
    static ComponentManager * mInstance;

    /// The map of available factories of component
    FactoryMap factoryMap_;

    /// The map of loaded components
    ComponentMap componentMap_;

    /// a pointer on the xml interface
    pacpus::XmlConfigFile * xmlTree_;

    /// a list of QObject in which plugins are embedded
    QObjectList pluginList_;

    /// The object used to load the plugins
    QPluginLoader pluginLoader_;
};

} // namespace pacpus

#endif
