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

#include "StrValue.h"

#include <math.h>

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

/// Default constructior
StrValue::StrValue()
    : DataValue( Units::NONE, 0, MULTIVALUE ),
      value_()
{
}

/// Two or three value constructior
StrValue::StrValue( const char* value, size_t length, const Unit& unit )
    : DataValue( unit, length == Str::NO_POS ? strlen( value ) : length, MULTIVALUE ),
      value_( value, length )
{
}

/// Single value constructior
StrValue::StrValue( const Str value )
    : DataValue( Units::NONE, value.length(), MULTIVALUE ),
      value_( value )
{
}

/// Copy constructior
StrValue::StrValue( const StrValue& value )
    : DataValue( value.getUnit(), value.value_.size(), MULTIVALUE ),
      value_( value.value_ )
{
}

/// Override new
void* StrValue::operator new( size_t size )
{
    return malloc( size );
}

/// Override delete
void StrValue::operator delete( void* p )
{
    ( ( DataValue* )p )->clearType();
    free( p );
}

/// Return a pointer to a new copy
StrValue* StrValue::copy() const
{
    return new StrValue( value_ );
}

/// Return the absolute value of this difference from another DataValue
double StrValue::absDiff( const DataValue* rhs ) const
{
    return __builtin_nan( "" );
}

/// Copy n-dimensional value to double
/*bool StrValue::copyTo( const Unit& unit, double& assignTo, unsigned int dim ) const
{
    if( dim >= value_.length() )
    {
        assignTo = 0;
        return false;
    }
    assignTo = value_.cStr()[dim];
    return true;
}*/

/// Comparison with another DataValue
int StrValue::compare( const DataValue& compareTo ) const
{
    if( compareTo.getBinaryType() == binaryType_ )
    {
        return value_.compare( ( ( StrValue * ) & compareTo )->value_ );
    }
    return -1;
}

/// Equality test with another DataValue
bool StrValue::equals( const DataValue& compareTo ) const
{
    if( compareTo.getTypeSize() == typeSize_ && compareTo.getBinaryType() == binaryType_ )
    {
        return value_ == ( ( ( StrValue * ) & compareTo )->value_ );
    }
    return false;
}

/// set DataValue value
bool StrValue::setFrom( const DataValue& value )
{
    if( value.equals( *this ) )
    {
        return true;
    }
    switch( value.getBinaryType() )
    {
    case NO_TYPE:
        break;
    case MULTIVALUE:
        value_ = ( ( StrValue * ) & value )->value_;
        typeSize_ = value_.length();
        return true;
    case UCHAR1:
    case SHORT2:
    case USHORT2:
    case INT4:
    case FLOAT2:
    case FLOAT3:
    case FLOAT4:
    case DOUBLE4:
    case DOUBLE6:
    case DOUBLE8:
        value_ = value.toString();
        typeSize_ = value_.length();
        return true;
    }
    return false;
};

// as a Str
const Str& StrValue::asString() const
{
    return value_;
}

void StrValue::setString( const Str& str )
{
    value_ = str;
}

// as a Str
Str StrValue::toString() const
{
    return value_;
}

// as a Str
Str StrValue::toString( const Unit& unit ) const
{
    return value_;
}

/// Send the data value to the indicated stream.
/// Return the number of bytes written.
/// For now, assume little-endian.
unsigned int StrValue::toStream( OutStream& outStream ) const
{
    unsigned short length = value_.length();
    outStream.writeShort( length );
    return outStream.write( value_.cStr(), length ).bytesWritten() + 2;
}

/// Load the data from the a binary representation in the buffer
/// Typically just a memcopy of the variable, though endianness
/// may come into it.
void StrValue::fromBinary( const void *buffer, unsigned short typeSize )
{
    typeSize_ = typeSize;
    fromBinary( buffer );
}

/// Load the data from the a binary representation in the buffer
/// Typically just a memcopy of the variable, though endianness
/// may come into it.
void StrValue::fromBinary( const void *buffer )
{
    value_ = Str( ( char * )buffer, typeSize_ );
}

