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

#ifndef UNIVERSALDATAELEMENT_H_
#define UNIVERSALDATAELEMENT_H_

#include "DataElement.h"

/**
 *  Implementation of a DataElement as a "UniversalDataElement".
 *
 *  Universal DataElements essentially contain a list of
 *  DataElements with the same UniversalURI name.  When a DataValue
 *  is requested, the DataValue from the "best" DataElement is
 *  returned.
 *
 *  The determination of "best" is done whenever a DataElement changes
 *  in a significnat way, such as changing its accuracy, its failed state,
 *  or its orphaned state.
 *
 *  \ingroup data
 */
class UniversalDataElement : public DataElement
{
public:
    /// Constructor for a universal DataElement.
    ///
    /// \param name The UniversalURI for this universal.
    /// \param dataValue Initial dataValue used to define dataType & size, etc.
    UniversalDataElement( const UniversalURI& name, const DataValue* dataValue );

    /// Destructor
    virtual ~UniversalDataElement();

    // Get the DataValue for this DataElement.
    /// Implements the pure virtual from DataElement.
    ///
    /// \return Pointer to the the DataValue.
    virtual DataValue* getDataValue( void ) const;

    /// Get the current DataElement accuracy.
    /// Implements the pure virtual from DataElement.
    ///
    /// \return Current accuracy metric for the DataValue.
    virtual float getAccuracy( const Unit& unit ) const
#ifndef __GAZEBO
    throw( UninitializedException )
#endif
    ;
    virtual float getAccuracySI() const
#ifndef __GAZEBO
    throw( UninitializedException )
#endif
    ;

    /// Get the last written DataElement accuracy.
    /// Overrides the virtual from DataElement.
    ///
    /// \return Last written accuracy metric for the DataValue.
    virtual float getWrittenAccuracy( const Unit& unit ) const;

    /// Implements the UniversalDataElement's sense of "orphaned."
    /// A UniversalDataElement is orphaned if it has no DataElements registered
    /// to it.  It is not orphaned (it is failed) if it's unable to select
    /// a DataElement.
    ///
    /// \return true if this UniversalDataElement has no DataElements
    ///            registered to it.
    virtual bool isOrphaned( void ) const;

    //== Functions specific to the aggregator aspects of UniversalDataElement ==

    /// Adds the given DataElement to the list of participants in this Universal
    ///
    /// \param element The DataElement which is now checked for this Universal.
    void addElement( DataElement& element );

    virtual bool isUniversal( ) const
    {
        return true;
    }

    /// Causes the universal to be recalculated, if a change is pending.
    void notifyChangeDone( Component* notifier );
    void notifyChangeDone( DataWriter* notifier );

    /// Reevaluate all participants and choose a new best solution.
    /// The heart of the Universal, go through all registered DataElements,
    /// find the best (most accurate).
    void recalculate( void );

    DataElement* getBestElement( DataAccessor::RequestStrategy strategy = DataAccessor::MIN_ERROR ) const;

    /**
     * Returns true if the value was touched since the last run of the
     * indicated component.
     */
    virtual bool wasTouchedSinceLastRun( const Component* component );

    /// Returns the timestamp of last write
    virtual const Timestamp& getTimestamp() const;

    /// Returns true if one of the registered readers is requesting data
    /// and the indicated element is intended to provide the data
    bool isDataRequested( DataElement* element );

    /// Returns true if one of the registered readers is requesting data
    bool isAnyDataRequested();

protected:

    /// Protected function.  Shouldn't be able to set the Universal's accuracy.
    /// Does nothing.  Returns current value for accuracy.
    virtual float setAccuracy( const Unit& unit, float accuracy );

    virtual void setDataValue( DataValue* dataValue )
    {}

    /// The current "best" DataElement (minError and enabled).
    DataElement *bestElement_;

    /// The current "minPower" DataElement.
    DataElement *minPowerElement_;

    /// The current "minError" DataElement.
    DataElement *minErrorElement_;

    /// The current "minLatency" DataElement.
    DataElement *minLatencyElement_;

    /// The current "maxFrequency" DataElement.
    DataElement *maxFrequencyElement_;

    /// The defaultValue_ to use if there if the Universal can't find a "best value"
    //DataValue *defaultValue_;

    /// The current Universal accuracy.  Set either to the accuracy of the
    /// current "best value" or to DataElement::NoAccuracy_s if the Universal
    /// is failed.
    float accuracy_;

    /// List of participating DataElements.
    DataElementList elementList_;

    /// Returns the accuracy in base, unscaled SI units.
    virtual float getBaseAccuracy() const
    {
        return accuracy_;
    }

private:
    // Note that the copy constructor below is private and not given a body.
    // Any attempt to call it will return a compiler error.
    UniversalDataElement( const UniversalDataElement& old ); // disallow copy constructor

};

#endif /*UNIVERSALDATAELEMENT_H_*/
