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

#ifndef FLOAT_H_
#define FLOAT_H_

#ifndef NANF
#define NANF ( nanf( "" ) )
#endif

#include "DataValue.h"
#include "utils/Mutex.h"

class RingBufferVoid;

/**
 *  Wraps a single precision (4-byte) floating point number and unit for
 *  storage in a DataElement.  (Storage is in the most canonical
 *  form of the specified unit).  Provides methods for reading and
 *  writing the value to and from other DataValues, performing
 *  unit conversions as needed.
 *
 *  Note: since these DataValues are created and destructed
 *  frequently, the new and delete operators have been overridden,
 *  so that objects can be re-used as needed.
 *
 *  Float::MallocRing_  stores deleted objects.
 *
 * \ingroup data
 */
class Float : public DataValue
{
public:

    /// Constructor for non-array storage
    Float( const Unit& unit, float value, bool scaleValue = true );

    /// Constructor from binary
    Float( const Unit& unit, const void *binary );

    /// Destructor
    virtual ~Float()
    {}
    ;

    /// Override new
    void* operator new( size_t size );

    /// Override delete
    void operator delete( void* p );

    /// Return a pointer to a new copy
    Float* copy() const;

    /// Subtraction of another DataValue to yield another DataValue
    virtual void minus( const DataValue* rhs, DataValue* assignTo ) const;

    /// Multiplication by a double to yield another DataValue
    virtual void times( const double rhs, DataValue* assignTo ) const;

    /// Return the absolute value of this difference from another DataValue
    virtual double absDiff( const DataValue* rhs ) const;

    /// Copy value to unsigned char
    virtual bool copyTo( const Unit& unit, unsigned char& assignTo ) const;

    /// Copy value to double
    virtual bool copyTo( const Unit& unit, double& assignTo ) const;

    /// Copy n-dimensional value to double
    virtual bool copyTo( const Unit& unit, double& assignTo, unsigned int dim ) const
    {
        return copyTo( unit, assignTo );
    }

    /// Copy value to float
    virtual bool copyTo( const Unit& unit, float& assignTo ) const;

    /// Copy value to unsigned int
    virtual bool copyTo( const Unit& unit, int& assignTo ) const;

    /// Comparison with unsigned char
    virtual int compare( const Unit& unit, const unsigned char& compareTo ) const;

    /// Comparison with double
    virtual int compare( const Unit& unit, const double& compareTo ) const;

    /// Comparison with float
    virtual int compare( const Unit& unit, const float& compareTo ) const;

    /// Comparison with int
    virtual int compare( const Unit& unit, const int& compareTo ) const;

    /// Comparison with another DataValue
    virtual int compare( const DataValue& compareTo ) const;

    /// Equality test with with unsigned char
    virtual bool equals( const Unit& unit, const unsigned char& compareTo ) const;

    /// Equality test with double
    virtual bool equals( const Unit& unit, const double& compareTo ) const;

    /// Equality test with float
    virtual bool equals( const Unit& unit, const float& compareTo ) const;

    /// Equality test with int
    virtual bool equals( const Unit& unit, const int& compareTo ) const;

    /// Equality test with another DataValue
    virtual bool equals( const DataValue& compareTo ) const;

    /// A quick equality check used to see if value has changed enough
    /// to matter in logging (useful for reduced resolution data storage
    virtual bool equalsForStorage( const float& compareTo ) const;

    /// Returns true if the number is not a number
    virtual bool isNaN();

    /// set from unsigned char value
    virtual bool setFrom( const Unit& unit, unsigned char value );

    /// set from double value
    virtual bool setFrom( const Unit& unit, double value );

    /// set from float value
    virtual bool setFrom( const Unit& unit, float value );

    /// set int value
    virtual bool setFrom( const Unit& unit, int value );

    /// set DataValue value
    virtual bool setFrom( const DataValue& value );

    // as a Str
    virtual Str toString( const Unit& unit ) const;

    /// Send the data value to the indicated stream.
    /// Return the number of bytes written.
    /// For now, assume little-endian.
    virtual unsigned int toStream( OutStream& outStream ) const;

    /// Convert the specified value to a binary representation in the buffer
    /// Typically just a memcopy of the variable, though endianness
    /// may come into it.
    static unsigned int ToBinary( const float& value, unsigned char *buffer, unsigned int maxlen );

    /// Load the data from the a binary representation in the buffer
    /// Typically just a memcopy of the variable, though endianness
    /// may come into it.
    virtual void fromBinary( const void *buffer );

protected:

    /// Protected Empty constructor for use by DataEntry class
    Float();

    float value_;

    /// Declared as a pointer to avoid including RingBuffer.h header here.
    static RingBufferVoid* MallocRing_;

    /// Makes sure that mallocRing_s is deleted on shutdown
    class StaticDestructor
    {
    public:
        virtual ~StaticDestructor();
    };

    /// Static instance of StaticDestructor
    static Float::StaticDestructor StaticDestructor_;

    /// Used for free/delete operations
    static Mutex Mutex_;
};

#endif /*FLOAT_H_*/
