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

#include "DataReader.h"
#include "DataElement.h"

#include "component/Component.h"

DataReader::DataReader( Component* owner,
                        DataElement& element,
                        const DataValue* defaultValue,
                        bool deleteDefaultValue )
    : DataAccessor( owner, element, DATA_READER, NULL, Logger::TIME_PRECISION_MILLIS ),
      requestStrategy_( NO_STRATEGY ),
      defaultValue_( defaultValue ),
      defaultUnit_( NULL == defaultValue_ ? Units::NONE : defaultValue_->getUnit() ),
      deleteDefaultValue_( deleteDefaultValue ),
      implementor_( false )
{
    element.registerReader( this );
    owner->registerReader( this );
}

DataReader::DataReader( Component* owner,
                        DataElement& element,
                        const Unit& defaultUnit )
    : DataAccessor( owner, element, DATA_READER, NULL ),
      requestStrategy_( NO_STRATEGY ),
      defaultValue_( NULL ),
      defaultUnit_( defaultUnit ),
      deleteDefaultValue_( false ),
      implementor_( false )
{
    element.registerReader( this );
    owner->registerReader( this );
}

DataReader::~DataReader()
{
    element_.unregisterReader( this );
    owner_->unregisterReader( this );
    if( deleteDefaultValue_ && NULL != defaultValue_ )
    {
        delete defaultValue_;
        defaultValue_ = NULL;
    }
}

const Unit* DataReader::getDefaultUnit()
{
    return &defaultUnit_;
}

//-------------------------------------------------------------------
/// Status and state functions
bool DataReader::isUnavailable( void )
{
    return element_.isUnavailable();
}
bool DataReader::isInvalid( void )
{
    return element_.isInvalid();
}
bool DataReader::isOrphaned( void )
{
    return element_.isOrphaned();
}
bool DataReader::isActive( void )
{
    return element_.isActive();
}


//-------------------------------------------------------------------
/// Get functions
bool DataReader::read( const Unit& unit, unsigned char& readTo )
{
    if( false == element_.isActive() )
    {
        return NULL == defaultValue_ ? false : defaultValue_->copyTo( unit, readTo );
    }
    else
    {
        try
        {
            return element_.get( *this, unit, readTo );
        }
        catch( DataElement::UninitializedException & deui )
        {
            return NULL == defaultValue_ ? false : defaultValue_->copyTo( unit, readTo );
        }
    }
}

bool DataReader::read( const Unit& unit, double& readTo )
{
    if( false == element_.isActive() )
    {
        return NULL == defaultValue_ ? false : defaultValue_->copyTo( unit, readTo );
    }
    else
    {
        try
        {
            return element_.get( *this, unit, readTo );
        }
        catch( DataElement::UninitializedException & deui )
        {
            return NULL == defaultValue_ ? false : defaultValue_->copyTo( unit, readTo );
        }
    }
}

bool DataReader::read( const Unit& unit, float& readTo )
{
    if( false == element_.isActive() )
    {
        return NULL == defaultValue_ ? false : defaultValue_->copyTo( unit, readTo );
    }
    else
    {
        try
        {
            return element_.get( *this, unit, readTo );
        }
        catch( DataElement::UninitializedException & deui )
        {
            return NULL == defaultValue_ ? false : defaultValue_->copyTo( unit, readTo );
        }
    }
}

bool DataReader::read( const Unit& unit, int& readTo )
{
    if( false == element_.isActive() )
    {
        return NULL == defaultValue_ ? false : defaultValue_->copyTo( unit, readTo );
    }
    else
    {
        try
        {
            return element_.get( *this, unit, readTo );
        }
        catch( DataElement::UninitializedException & deui )
        {
            return NULL == defaultValue_ ? false : defaultValue_->copyTo( unit, readTo );
        }
    }
}

bool DataReader::read( bool& readTo )
{
    if( false == element_.isActive() )
    {
        return NULL == defaultValue_ ? false : defaultValue_->copyTo( Units::BOOL, readTo );
    }
    else
    {
        try
        {
            return element_.get( *this, Units::BOOL, readTo );
        }
        catch( DataElement::UninitializedException & deui )
        {
            return NULL == defaultValue_ ? false : defaultValue_->copyTo( Units::BOOL, readTo );
        }
    }
}

bool DataReader::read( Timespan& readTo )
{

    bool retval = false;
    double seconds = 0.0;
    if( false == element_.isActive() )
    {
        retval = ( ( NULL == defaultValue_ ) ? false : defaultValue_->copyTo( Units::SECOND, seconds ) );
    }
    else
    {
        try
        {
            // return element_.get( *this, unit, readTo );
            retval = element_.get( *this, Units::SECOND, seconds );
        }
        catch( DataElement::UninitializedException & deui )
        {
            retval = ( ( NULL == defaultValue_ ) ? false : defaultValue_->copyTo( Units::SECOND, seconds ) );
        }
    }
    if( retval ) readTo = Timespan::Seconds( seconds );
    return retval;
}


bool DataReader::read( DataValue& readTo )
{
    if( false == element_.isActive() )
    {
        return NULL == defaultValue_ ? false : defaultValue_->copyTo( readTo );
    }
    else
    {
        try
        {
            return element_.get( *this, readTo );
        }
        catch( DataElement::UninitializedException & deui )
        {
            return NULL == defaultValue_ ? false : defaultValue_->copyTo( readTo );
        }
    }
}

int DataReader::asInt( const Unit& unit )
{
    int value( 0 );
    if( false == element_.isActive() )
    {
        if( NULL != defaultValue_ )
        {
            defaultValue_->copyTo( unit, value );
        }
    }
    else
    {
        try
        {
            value = element_.asInt( *this, unit );
        }
        catch( DataElement::UninitializedException & deui )
        {
            if( NULL != defaultValue_ )
            {
                defaultValue_->copyTo( unit, value );
            }
        }
    }
    return value;
}

double DataReader::asDouble( const Unit& unit )
{
    double value = nan( "" );
    if( false == element_.isActive() )
    {
        if( NULL != defaultValue_ )
        {
            defaultValue_->copyTo( unit, value );
        }
    }
    else
    {
        try
        {
            value = element_.asDouble( *this, unit );
        }
        catch( DataElement::UninitializedException & deui )
        {
            if( NULL != defaultValue_ )
            {
                defaultValue_->copyTo( unit, value );
            }
        }
    }
    return value;
}

Str DataReader::asString( const Unit& unit )
{
    Str retVal( Str::EMPTY_STR );
    if( false == element_.isActive() )
    {
        owner_->getLogger().syslog( "data element is not active.", Syslog::ERROR );
        if( NULL != defaultValue_ ) retVal = defaultValue_->toString( unit );
    }
    else
    {
        try
        {
            retVal = element_.asString( *this, unit );
        }
        catch( DataElement::UninitializedException & deui )
        {
            owner_->getLogger().syslog( "caught uninitialized data element exception.", Syslog::ERROR );
            if( NULL != defaultValue_ ) retVal = defaultValue_->toString( unit );
        }
    }
    return retVal;
}

const Timestamp& DataReader::getTimestamp( void ) const
{
    return element_.getTimestamp();
}

bool DataReader::wasTouchedSinceLastRun( const Component* component )
{
    return element_.wasTouchedSinceLastRun( component );
}



