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

#include "Double4.h"
#include "io/OutStream.h"
#include "utils/AuvMath.h"
#include "utils/RingBuffer.h"

#include <cfloat>

/// Constructor for non-array storage
Double4::Double4( const Unit& unit, double value, bool scaleValue )
    : Double( unit, value, scaleValue )
{
    typeSize_ = 4;
    binaryType_ = DOUBLE4;
}

/// Constructor from binary
Double4::Double4( const Unit& unit, const void *binary )
    : Double( unit, 0, false )
{
    typeSize_ = 4;
    binaryType_ = DOUBLE4;
    fromBinary( binary );
}

/// Return a pointer to a new copy
Double4* Double4::copy() const
{
    return new Double4( *unit_, value_, false );
}

/// A quick equality check used to see if value has changed enough
/// to matter in logging (useful for reduced resolution data storage
bool Double4::equalsForStorage( const double& compareTo ) const
{
    //printf("In Double4::equalsForStorage with %g and %g\n", value_, compareTo );
    return DoubleToFloat( value_ ) == DoubleToFloat( compareTo )
           || ( isnan( value_ ) && isnan( compareTo ) );
}

/// Send the data value to the indicated stream.
/// Return the number of bytes written.
/// For now, assume little-endian.
unsigned int Double4::toStream( OutStream& outStream ) const
{
    return outStream.writeFloat( DoubleToFloat( value_ ) ).bytesWritten();
}

void Double4::fromBinary( const void *buffer )
{
    float tempValue;
    memcpy( ( ( void* ) & tempValue ), buffer, typeSize_ );
    value_ = tempValue;
}

/// Protected Empty constructor for use bya DataEntry class
Double4::Double4()
    : Double()
{
    typeSize_ = 4;
    binaryType_ = DOUBLE4;
}

/// Cast to float without floating point errors
float Double4::DoubleToFloat( const double& theDouble )
{
    if( isnan( theDouble ) )
    {
        return nanf( "" );
    }
    if( theDouble > FLT_MAX )
    {
        return INFINITY;
    }
    if( theDouble < -FLT_MAX )
    {
        return -INFINITY;
    }
    if( ( theDouble > 0 && theDouble < FLT_MIN )
            || ( theDouble < 0 && theDouble > -FLT_MIN ) )
    {
        return 0.0f;
    }
    return theDouble;
}


