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

#ifndef DATAVALUE_H_
#define DATAVALUE_H_

#include "data/BinaryDataType.h"
#include "units/Unit.h"
#include "utils/Str.h"

class OutStream;

/**
 *  A DataValue is an abstract base class for a data value
 *  and associated engineering units of the value, where a "value"
 *  is a chunk of data that would be written in a single
 *  stroke -- such as an integer or floating point value -- or the pair
 *  of values associated with Latitude and Longitude, or even a 6-DOF
 *  location or rate.
 *
 *  Many dataValues have a native resolution that exceeds their serialized
 *  resolutions.  For example Float2 is handled internally as a 4-byte floating
 *  point number -- but is serialized as a two-byte floating point number.
 *  Likewise, a Location is handled internally as a pair of 8-byte doubles, but is
 *  serialized as a pair of 4-byte floats.
 *
 *  \ingroup data
 */
class DataValue
{

    friend class DataAccess;

public:

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

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

    /// Return a pointer to a new copy
    virtual DataValue* copy() const = 0;

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

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

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

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

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

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

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

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

    /// Copy value to another dataValue
    virtual bool copyTo( DataValue& assignTo ) const
    {
        return assignTo.setFrom( *this );
    }

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

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

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

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

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

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

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

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

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

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

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

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

    /// Returns true if the number is not a number
    virtual bool isNaN()
    {
        return false;
    }

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

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

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

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

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

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

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

    // as a Str with its unit
    virtual Str toString() const
    {
        return toString( getUnit() ) + " " + getUnit().getAbbreviation();
    }

    /// 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 = 0;

    /// 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 ) = 0;

    /// Returns the size of the internal storage type (i.e. sizeof(type))
    virtual size_t getTypeSize() const
    {
        return typeSize_;
    }

    /// Returns a constant (defined in BinaryDataType.h)
    /// representing the internal storage type
    virtual BinaryDataType getBinaryType( void ) const
    {
        return binaryType_;
    }

    const Unit& getUnit() const
    {
        return *unit_;
    }

    const Unit& getBaseUnit() const
    {
        return unit_->getBaseUnit();
    }

    void setUnit( const Unit& unit )
    {
        unit_ = &unit;
    }

    void clearType()
    {
        binaryType_ = NO_TYPE;
    }

protected:

    /// Protected Constructor for abstract base class
    DataValue( const Unit& unit, const size_t& typeSize, const BinaryDataType& binaryType )
        : unit_( &unit ),
          typeSize_( typeSize ),
          binaryType_( binaryType )
    {}
    ;

    /// Protected unitless constructor for use via DataEntry class
    DataValue( const size_t& typeSize, const BinaryDataType& binaryType )
        : unit_( NULL ),
          typeSize_( typeSize ),
          binaryType_( binaryType )
    {}
    ;

    // The base "ancestor" unit of the value stored in this DataValue
    // All values that are read to/from this DataValue must be convertable
    // to this unit.
    const Unit* unit_;

    /// size of the internal storage type (i.e. sizeof(type))
    size_t typeSize_;

    /// constant (defined in BinaryDataType.h)
    /// representing the internal storage type
    BinaryDataType binaryType_;

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

};

#endif /*DATAVALUE_H_*/
