/** \file
 *
 *  Contains the ComponentRegistry class declaration.
 *
 *  Copyright (c) 2007,2008,2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */

#ifndef BLOCKREGISTRY_H_
#define BLOCKREGISTRY_H_

#include "utils/Str.h"

#include "component/Component.h"
#include "process/Handler.h"
#include "process/ThreadHandler.h"
#include "supervisor/ControlThread.h"
#include "utils/FlexArray.h"

class Supervisor;

/**
 *  Keeps track of all Components currently loaded and their assignment to
 *  handlers.  It also "owns" the ControlThread.
 *
 *  In general, the ComponentRegistry does not handle Component destruction.
 *  It's critical, of course, that Components be unregistered from the registry
 *  before being deleted.
 *
 *  \ingroup supervisor
 */
class ComponentRegistry
{
    //===================================================================
    /// A structure for containing all the ComponentRegistry's "entry" about
    /// a component.
    struct ComponentRegistryEntry
    {
        /// Constructor.  Takes pointer to Component.
        ComponentRegistryEntry( Component *component = NULL,
                                Component::ComponentType handlerType = Component::COMPONENT_SYNC,
                                Handler *handler = NULL );

        /// Pointer to the Component.  Should always be valid.
        Component* component_;

        ///
        Component::ComponentType handlerType_;

        /// Pointer to the Component's handler.  May be NULL if component is not
        /// being handled.
        Handler *handler_;

    };

    typedef FlexArray<ComponentRegistry::ComponentRegistryEntry *> ListOfComponentRegistryEntries;

public:

    /// Initializes the list and logger.
    static void Initialize();

    /// Uninitializes the list.
    static void Uninitialize();

    /// Uninitializes the control thread
    static void UninitializeControlThread();

    /// Add the component to the registry.
    ///
    /// Uses the component's
    /// handler preferences to match it to a handler.
    ///
    /// \param component The component added to the registry.
    /// \param insertFront If true, the component is inserted at the front of the
    ///           list (first to start, last to be stopped) --- used to force
    ///           the Logger to the front of the list
    static Handler* Insert( Component* component, bool insertFront = false );

    /// Remove the given component from the registry.
    ///
    /// Does not delete the component, but does delete any handlers
    /// (uses purgeEntry)
    ///
    /// \param component The component to be removed from the registry.
    static void Remove( Component* component );

    /// Finds a component given its name.  Case sensitive.
    ///
    /// \param name Name of component to be found
    /// \return Pointer to component if found, or NULL if not found
    static Component* Find( const Str& name );

    /// Finds a component handler given its name.  Case sensitive.
    ///
    /// \param name Name of component handler to be found
    /// \return Pointer to handler if found, or NULL if not found
    static Handler* FindHandler( const Str& name );

    /// Returns the number of entries in the registry.
    ///
    /// \return Number of entries in the registry.
    static size_t Length();

    /// Start (spawn) all of the Components which run in their own ThreadHandlers.
    ///
    /// Threads are started in the order in which their Components were added
    /// to the registry.
    static void StartThreads( void );

    /// Stop all of the Components which run in their own ThreadHandlers.
    ///
    /// Goes in LIFO order, so the last threaded Component added is the first one
    /// shutdown.
    static void ShutdownThreads( void );

    /// Delete all contained components and handlers (cleanup).
    ///
    /// Goes in reverse order of component insertion.  Calls purgeEntry on each
    /// remaining entry, then delete the component (which purgeEntry and removeEntry
    /// do not do)
    static void DeleteAll( void );

    /**
     *  Gets the period of the ControlThread
     *  \return period of the ControlThread, in seconds
     */
    static const Timespan& GetControlThreadPeriod();

    /**
     *  Sets the period of the ControlThread
     *  \param period Period of the ControlThread, in seconds
     */
    static void SetControlThreadPeriod( const Timespan& period );

    /**
     *  Returns the number of Entries
     */
    static unsigned int GetEntryCount( void );

    /**
     *  Returns the component at the indexed position
     *  Returns NULL if there is no component at the indicated index
     */
    static const Component* GetIndexed( const unsigned int index );

protected:

    /// The actual "cleanup" function called by RemoveC and DeleteAll.
    /// Doesn't remove entry from list_, assumes caller will do that.
    ///
    /// \param entry Entry to clean up
    /// \return Component contained in the entry (or NULL), which isn't touched.
    static Component *PurgeEntry( ComponentRegistryEntry *entry );

private:

    /// Private Constructor for static class.
    ComponentRegistry()
    {};

    /// The list of ComponentRegistryEntries
    static ListOfComponentRegistryEntries* List_;

    /// Pointer to a Logger
    static Logger* Logger_;

    /// Pointer to the ControlThread
    static ControlThread* ControlThread_;

};


#endif /*BLOCKMAP_H_*/
