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

#ifndef SYNCCOMPONENT_H_
#define SYNCCOMPONENT_H_

#include "LcmMessagingComponent.h"

/** Abstract Base class for software components that run in the computation
 *  cycle. In most instances, this class should not be directly extended.
 *  Instead, daughter classes corresponding to each of the CycleOrder values
 *  should be used.
 *
 *  \ingroup component
 *
 */
class SyncComponent: public LcmMessagingComponent
{
public:

    friend class ScriptSyncComponent;
    friend class SyncStarterComponent;
    friend class SyncSimulatorComponent;
    friend class SyncSensorComponent;
    friend class SyncDerivationComponent;
    friend class SyncNavigationComponent;
    friend class SyncEstimationComponent;
    friend class SyncMissionComponent;
    friend class SyncControlComponent;
    friend class SyncMaintainerComponent;
    friend class SyncServoComponent;
    friend class SyncTestComponent;
    friend class SyncReporterComponent;
    friend class SyncLoggerComponent;

    /// These are enumerated to simplify sorting and ordering
    class CycleOrder
    {
    public:
        CycleOrder( int orderPreference ) :
            orderPreference_( orderPreference )
        {
        }
        operator int() const
        {
            return orderPreference_;
        }
        bool operator ==( const CycleOrder& otherPreference ) const
        {
            return orderPreference_ == otherPreference.orderPreference_;
        }
        bool operator !=( const CycleOrder& otherPreference ) const
        {
            return orderPreference_ != otherPreference.orderPreference_;
        }
        bool operator <( const CycleOrder& otherPreference ) const
        {
            return orderPreference_ < otherPreference.orderPreference_;
        }
    private:
        int orderPreference_;
    };

    static const int CYCLE_INCREMENT;
    static const int CYCLE_REPEAT_OFFSET;

    static const CycleOrder CYCLE_STARTER;
    static const CycleOrder CYCLE_SIMULATOR;
    static const CycleOrder CYCLE_SENSOR;
    static const CycleOrder CYCLE_DERIVATION;
    static const CycleOrder CYCLE_ESTIMATION;
    static const CycleOrder CYCLE_NAVIGATION;
    static const CycleOrder CYCLE_MISSION_MANAGER;
    static const CycleOrder CYCLE_MISSION;
    static const CycleOrder CYCLE_CONTROL;
    static const CycleOrder CYCLE_SERVO;
    static const CycleOrder CYCLE_TEST;
    static const CycleOrder CYCLE_REPORTER;
    static const CycleOrder CYCLE_LOGGER;

    /// Getter function for controlThreadOrderPreference
    CycleOrder getCycleOrder( void )
    {
        return cycleOrder_;
    }

    void setRepeating( bool repeating )
    {
        repeating_ = repeating;
    }

    int getDivisor( ) const
    {
        return divisor_;
    }

    int getModulo( ) const
    {
        return modulo_;
    }

    SyncComponent( const Str& name, const Module* module, CycleOrder cycleOrder,
                   int divisor = 1, int modulo = 0 )
        : LcmMessagingComponent( name, COMPONENT_SYNC, module ),
          cycleOrder_( cycleOrder ),
          repeater_( false ),
          repeating_( false ),
          divisor_( divisor ),
          modulo_( modulo )
    {
    }

private:

    CycleOrder cycleOrder_;
    bool repeater_;
    bool repeating_;

    int divisor_;
    int modulo_;

protected:
    void setRepeater( bool repeater )
    {
        repeater_ = repeater;
    }

public:
    bool isRepeater()
    {
        return repeater_;
    }

    bool isRepeating()
    {
        return repeating_;
    }

};

/** Abstract Base class for components that run in the start of the
** computation cycle.
**/
class SyncStarterComponent: public SyncComponent
{
protected:
    SyncStarterComponent( const Str& name, const Module* module )
        : SyncComponent( name, module, CYCLE_STARTER )
    {}
};

/** Abstract Base class for components that run towards the start of the
** computation cycle, simulating sensor inputs since the last cycle.
**/
class SyncSimulatorComponent: public SyncComponent
{
protected:
    SyncSimulatorComponent( const Str& name, const Module* module,
                            int divisor = 1, int modulo = 0 )
        : SyncComponent( name, module, CYCLE_SIMULATOR, divisor, modulo )
    {}
};

/** Abstract Base class for components that collect data for use later in the
** computation cycle.
**/
class SyncSensorComponent: public SyncComponent
{
protected:
    SyncSensorComponent( const Str& name, const Module* module,
                         int divisor = 1, int modulo = 0 )
        : SyncComponent( name, module, CYCLE_SENSOR, divisor, modulo )
    {}
};

/** Abstract Base class for components that run after sensors, deriving
 * other measurements.
**/
class SyncDerivationComponent: public SyncComponent
{
protected:
    SyncDerivationComponent( const Str& name, const Module* module,
                             int divisor = 1, int modulo = 0 )
        : SyncComponent( name, module, CYCLE_DERIVATION, divisor, modulo )
    {}
};

/** Abstract Base class for components that generate navigation estimates.
**/
class SyncNavigationComponent: public SyncComponent
{
protected:
    SyncNavigationComponent( const Str& name, const Module* module,
                             int divisor = 1, int modulo = 0 )
        : SyncComponent( name, module, CYCLE_NAVIGATION, divisor, modulo )
    {}
};

/** Abstract Base class for components that generate other estimates.
**/
class SyncEstimationComponent: public SyncComponent
{
protected:
    SyncEstimationComponent( const Str& name, const Module* module,
                             int divisor = 1, int modulo = 0 )
        : SyncComponent( name, module, CYCLE_ESTIMATION, divisor, modulo )
    {}
};

/** Abstract Base class for components that manage mission components.
**/
class SyncMissionComponent: public SyncComponent
{
protected:
    SyncMissionComponent( const Str& name, const Module* module )
        : SyncComponent( name, module, CYCLE_MISSION )
    {}
};

/** Abstract Base class for components that compute settings to be
 * communicated to SyncServoComponent instances.
**/
class SyncControlComponent: public SyncComponent
{
protected:
    SyncControlComponent( const Str& name, const Module* module,
                          int divisor = 1, int modulo = 0 )
        : SyncComponent( name, module, CYCLE_CONTROL, divisor, modulo )
    {}
};

/** Abstract Base class for components that run before the servos
** allowing command-line overrides of guidance and control outputs.
**/
class SyncMaintainerComponent: public SyncComponent
{
protected:
    SyncMaintainerComponent( const Str& name, const Module* module,
                             CycleOrder cycleOrder, int divisor = 1, int modulo = 0 )
        : SyncComponent( name, module, cycleOrder, divisor, modulo )
    {}
};

/** Abstract Base class for components that run towards the end of the
** computation cycle, communicating with controllers.
**/
class SyncServoComponent: public SyncComponent
{
protected:
    SyncServoComponent( const Str& name, const Module* module,
                        int divisor = 1, int modulo = 0 )
        : SyncComponent( name, module, CYCLE_SERVO, divisor, modulo )
    {}
};

/** Abstract Base class for components that run towards the end of the
** computation cycle, evaluating how well everything performed.
**/
class SyncTestComponent: public SyncComponent
{
protected:
    SyncTestComponent( const Str& name, const Module* module,
                       int divisor = 1, int modulo = 0 )
        : SyncComponent( name, module, CYCLE_TEST, divisor, modulo )
    {}
};

/** Abstract Base class for components that run in the end of the
** computation cycle, doing logging.
**/
class SyncReporterComponent: public SyncComponent
{
protected:
    SyncReporterComponent( const Str& name, const Module* module,
                           int divisor = 1, int modulo = 0 )
        : SyncComponent( name, module, CYCLE_REPORTER, divisor, modulo )
    {}
};

/** Abstract Base class for components that run in the end of the
** computation cycle, doing logging.
**/
class SyncLoggerComponent: public SyncComponent
{
protected:
    SyncLoggerComponent( const Str& name, const Module* module )
        : SyncComponent( name, module, CYCLE_LOGGER )
    {}
};

/// Define a type for a "list of component pointers".  Used in a number of
/// different places.
typedef FlexArray<SyncComponent*> ListOfSyncComponents;


#endif /* SYNCCOMPONENT_H_ */
