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

#ifndef SCRIPTCOMPONENT_H_
#define SCRIPTCOMPONENT_H_

#include "component/AsyncComponent.h"
#include "component/Behavior.h"
#include "component/SyncComponent.h"

/** \ingroup missionScript
 *
 *  Not really a component, but a class that can be merged with a Component
 *  to wrap code that is scripted.  See classes ScriptAsyncComponent,
 *  ScriptMissionComponent and ScriptSyncMissionComponent.
 */
class ScriptComponent
{
public:
    /// Destructor
    virtual ~ScriptComponent();

    /// Returns a "Script" version of AsyncComponent, Behavior, or
    /// SyncComponent, or NULL if the component can not be properly read.
    static Component* Instance( int index, Logger& logger );

    /// int index
    void setIndex( int index )
    {
        index_ = index;
    }

    void setModuleName( Str moduleName )
    {
        moduleName_ = moduleName;
    }

    /// Initialize function
    virtual void scriptInitialize( Logger& logger );

    /// The actual "payload" of the component
    virtual void scriptRun( Logger& logger );

    /// The satisfied method
    virtual bool scriptIsSatisfied( Logger& logger );

    /// Uninit function
    virtual void scriptUninitialize( Logger& logger );

protected:

    /// Protected constructor called through instance()
    ScriptComponent();

    Str moduleName_;

    int index_;

};

/** \ingroup missionScript
 *
 * Scripted software components that run independently from the computation
 * cycle. Use with care!
 */
class ScriptAsyncComponent: public ScriptComponent, public AsyncComponent
{
private:
    friend class ScriptComponent;

    /// Protected constructor for components that run in periodic asynchronous threads
    ScriptAsyncComponent( const Module* module, const Str& name,
                          const Timespan& period );

    /// Destructor
    ~ScriptAsyncComponent() {};

    /// Initialize the payload
    inline virtual void initialize()
    {
        scriptInitialize( logger_ );
    }

    /// Execute the payload
    inline virtual void run()
    {
        scriptRun( logger_ );
    }

    /// Uninitialize the payload
    inline virtual void uninitialize()
    {
        scriptUninitialize( logger_ );
    }

};

/** \ingroup missionScript
 *
 * Scripted software components that run as part of a mission script.
 *
 */
class ScriptMissionComponent: public ScriptComponent, public Behavior
{
private:
    friend class ScriptComponent;

    /// Constructor
    ScriptMissionComponent( const Module* module, const Str& name,
                            const bool runnable, const bool satisfiable );

    /// Destructor
    ~ScriptMissionComponent() {};

    /// Initialize the payload
    inline virtual void initialize()
    {
        scriptInitialize( logger_ );
    }

    /// Execute the payload
    inline virtual void run()
    {
        scriptRun( logger_ );
    }

    /// Check if satisfied
    inline virtual bool isSatisfied()
    {
        return scriptIsSatisfied( logger_ );
    }

    /// Uninitialize the payload
    inline virtual void uninitialize()
    {
        scriptUninitialize( logger_ );
    }
};

/** \ingroup missionScript
 *
 * Scripted software components that run in the computation cycle.
 * Must indicate where in the cycle the code will run
 */
class ScriptSyncComponent: public ScriptComponent, public SyncComponent
{
private:
    friend class ScriptComponent;

    /// Constructor
    ScriptSyncComponent( const Module* module, const Str& name,
                         CycleOrder cycleOrder );

    /// Destructor
    ~ScriptSyncComponent() {};

    /// Initialize the payload
    inline virtual void initialize()
    {
        scriptInitialize( logger_ );
    }

    /// Execute the payload
    inline virtual void run()
    {
        scriptRun( logger_ );
    }

    /// Uninitialize the payload
    inline virtual void uninitialize()
    {
        scriptUninitialize( logger_ );
    }
};

#endif /*SCRIPTCOMPONENT_H_*/
