/*
 * Copyright (C) 2007-2023 Xagasoft, All rights reserved.
 *
 * This file is part of the libbu++ library and is released under the
 * terms of the license contained in the file LICENSE.
 */

#include "bu/client.h"
#include <stdlib.h>
#include <errno.h>
#include "bu/protocol.h"
#include "bu/clientlink.h"
#include "bu/clientlinkfactory.h"
#include "bu/mutexlocker.h"

#ifdef PROFILE_BU_SERVER
#define BU_PROFILE_START( x ) Bu::Profiler::getInstance().startEvent( x )
#define BU_PROFILE_END( x ) Bu::Profiler::getInstance().endEvent( x )
#else
#define BU_PROFILE_START( x ) (void)0
#define BU_PROFILE_END( x ) (void)0
#endif

Bu::Client::Client( int iId, const Bu::ServerInterface &rServer ) :
    pProto( NULL ),
    bWantsDisconnect( false ),
    iId( iId ),
    xServer( rServer )
{
}

Bu::Client::~Client()
{
}

int Bu::Client::getId() const
{
    return iId;
}

void Bu::Client::processInput()
{
    Bu::MutexLocker l( mProto );

    if( pProto && getInputSize() > 0 )
    {
        BU_PROFILE_START("client.process");
        pProto->onNewData( this );
        BU_PROFILE_END("client.process");
    }
}

void Bu::Client::outputReady()
{
    xServer.outputReady( iId );
}

void Bu::Client::setProtocol( Protocol *pProto )
{
    Bu::MutexLocker l( mProto );
    this->pProto = pProto;
    this->pProto->onNewConnection( this );
}

Bu::Protocol *Bu::Client::getProtocol()
{
    Bu::MutexLocker l( mProto );
    return pProto;
}

void Bu::Client::clearProtocol()
{
    Bu::MutexLocker l( mProto );
    pProto = NULL;
}

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

Bu::size Bu::Client::write( const Bu::String &sData )
{
    return cbBuffer.client().write( sData.getStr(), sData.getSize() );
}

Bu::size Bu::Client::write( const void *pData, Bu::size nBytes )
{
    return cbBuffer.client().write( pData, nBytes );
}

Bu::size Bu::Client::write( int8_t nData )
{
    return cbBuffer.client().write( (const char *)&nData, sizeof(nData) );
}

Bu::size Bu::Client::write( int16_t nData )
{
    return cbBuffer.client().write( (const char *)&nData, sizeof(nData) );
}

Bu::size Bu::Client::write( int32_t nData )
{
    return cbBuffer.client().write( (const char *)&nData, sizeof(nData) );
}

Bu::size Bu::Client::write( int64_t nData )
{
    return cbBuffer.client().write( (const char *)&nData, sizeof(nData) );
}

Bu::size Bu::Client::write( uint8_t nData )
{
    return cbBuffer.client().write( (const char *)&nData, sizeof(nData) );
}

Bu::size Bu::Client::write( uint16_t nData )
{
    return cbBuffer.client().write( (const char *)&nData, sizeof(nData) );
}

Bu::size Bu::Client::write( uint32_t nData )
{
    return cbBuffer.client().write( (const char *)&nData, sizeof(nData) );
}

Bu::size Bu::Client::write( uint64_t nData )
{
    return cbBuffer.client().write( (const char *)&nData, sizeof(nData) );
}

Bu::size Bu::Client::read( void *pData, Bu::size nBytes )
{
    return cbBuffer.client().read( pData, nBytes );
}


Bu::size Bu::Client::peek( void *pData, int nBytes, int nOffset )
{
    return cbBuffer.client().peek( pData, nBytes, nOffset );
}


Bu::size Bu::Client::getInputSize()
{
    return cbBuffer.client().getSize();
}

Bu::size Bu::Client::getOutputSize()
{
    return cbBuffer.server().getSize();
}

void Bu::Client::disconnect()
{
    Bu::MutexLocker l( mDisconnect );
    bWantsDisconnect = true;
}

bool Bu::Client::wantsDisconnect()
{
    Bu::MutexLocker l( mDisconnect );
    return bWantsDisconnect;
}

void Bu::Client::close()
{
}

Bu::ClientLink *Bu::Client::getLink()
{
    return NULL; //pfLink->createLink( this );
}

void Bu::Client::onMessage( const Bu::String &sMsg )
{
    Bu::MutexLocker l( mProto );
    if( pProto )
        pProto->onMessage( this, sMsg );
}

void Bu::Client::tick()
{
    Bu::MutexLocker l( mProto );
    if( pProto )
        pProto->onTick( this );
}

Bu::size Bu::Client::tell()
{
    return 0;
}

void Bu::Client::seek( Bu::size offset )
{
    return cbBuffer.client().seek( offset );
}

void Bu::Client::setPos( Bu::size )
{
    throw Bu::ExceptionBase();
}

void Bu::Client::setPosEnd( Bu::size )
{
    throw Bu::ExceptionBase();
}

bool Bu::Client::isEos()
{
    return true;
}

void Bu::Client::flush()
{
    cbBuffer.client().flush();
    outputReady();
}

bool Bu::Client::canRead()
{
    return cbBuffer.client().getSize() > 0;
}

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

bool Bu::Client::isReadable()
{
    return true;
}

bool Bu::Client::isWritable()
{
    return true;
}

bool Bu::Client::isSeekable()
{
    return false;
}

bool Bu::Client::isBlocking()
{
    return false;
}

void Bu::Client::setBlocking( bool )
{
    throw Bu::ExceptionBase();
}

void Bu::Client::setSize( Bu::size )
{
    throw Bu::ExceptionBase();
}

Bu::size Bu::Client::getSize() const
{
    return 0;
}

Bu::size Bu::Client::getBlockSize() const
{
    return 0;
    //return pSocket->getBlockSize();
}

Bu::String Bu::Client::getLocation() const
{
    return "???";
    //return pSocket->getLocation();
}

