#include "bu/myriadstream.h"

#include "bu/mutexlocker.h"

Bu::MyriadStream::MyriadStream( Bu::Myriad &rMyriad,
        Bu::Myriad::Stream *pStream, Bu::Myriad::Mode eMode ) :
    rMyriad( rMyriad ),
    pStream( pStream ),
    eMode( eMode ),
    iPos( 0 )
{
    if( (eMode&Bu::Myriad::ReadWrite) == 0 )
    {
        throw Bu::MyriadException( Bu::MyriadException::invalidParameter,
                "MyriadStream must be opened Read or Write or both.");
    }
    Bu::MutexLocker l( mAccess );
    pStream->open();

    if( (eMode&Bu::Myriad::Write) != 0 )
    {
        // Writing mode, what other options do we deal with?
        if( (eMode&Bu::Myriad::Truncate) != 0 )
        {
            // Truncate, set size to zero before starting.
            pStream->setSize( 0 );
        }
        else if( (eMode&Bu::Myriad::Append) != 0 )
        {
            iPos = pStream->getSize();
        }
    }
}

Bu::MyriadStream::~MyriadStream()
{
    close();
}

void Bu::MyriadStream::close()
{
    Bu::MutexLocker l( mAccess );
    if( eMode )
    {
        pStream->close();
        eMode = Bu::Myriad::None;
    }
}

Bu::size Bu::MyriadStream::read( void *pBuf, size iBytes )
{
    Bu::MutexLocker l( mAccess );
    int32_t iRead = pStream->read( iPos, pBuf, iBytes );
    iPos += iRead;
    return iRead;
}

Bu::size Bu::MyriadStream::write( const void *pBuf, size iBytes )
{
    Bu::MutexLocker l( mAccess );
    int32_t iWrite = pStream->write( iPos, pBuf, iBytes );
    iPos += iWrite;
    return iWrite;
}

Bu::size Bu::MyriadStream::tell()
{
    Bu::MutexLocker l( mAccess );
    return iPos;
}

void Bu::MyriadStream::seek( size offset )
{
    Bu::MutexLocker l( mAccess );
    iPos += offset;
}

void Bu::MyriadStream::setPos( size pos )
{
    Bu::MutexLocker l( mAccess );
    iPos = pos;
}

void Bu::MyriadStream::setPosEnd( size pos )
{
    Bu::MutexLocker l( mAccess );
    iPos = pStream->getSize()-pos;
}

bool Bu::MyriadStream::isEos()
{
    Bu::MutexLocker l( mAccess );
    return iPos == pStream->getSize();
}

bool Bu::MyriadStream::isOpen()
{
    return true;
}

void Bu::MyriadStream::flush()
{
    // Does this make sense?
}

bool Bu::MyriadStream::canRead()
{
    return true;
}

bool Bu::MyriadStream::canWrite()
{
    return true;
}

bool Bu::MyriadStream::isReadable()
{
    Bu::MutexLocker l( mAccess );
    return (eMode&Bu::Myriad::Read) != 0;
}

bool Bu::MyriadStream::isWritable()
{
    Bu::MutexLocker l( mAccess );
    return (eMode&Bu::Myriad::Write) != 0;
}

bool Bu::MyriadStream::isSeekable()
{
    return true;
}

bool Bu::MyriadStream::isBlocking()
{
    return true;
}

void Bu::MyriadStream::setBlocking( bool /*bBlocking*/ )
{
    // Dunno what this would even mean here.
}

void Bu::MyriadStream::setSize( size iSize )
{
    Bu::MutexLocker l( mAccess );
    pStream->setSize( iSize );
    if( iPos > iSize )
        iPos = iSize;
}

Bu::size Bu::MyriadStream::getSize() const
{
    Bu::MutexLocker l( mAccess );
    return pStream->getSize();
}

Bu::size Bu::MyriadStream::getBlockSize() const
{
    Bu::MutexLocker l( mAccess );
    return pStream->getBlockSize();
}

Bu::String Bu::MyriadStream::getLocation() const
{
    Bu::MutexLocker l( mAccess );
    return pStream->getLocation();
}

Bu::Myriad::StreamId Bu::MyriadStream::getId() const
{
    Bu::MutexLocker l( mAccess );
    return pStream->getStreamId();
}

