/** \file
 *
 *  Contains the SendDestination class implementation.
 *
 *  Copyright (c) 2017 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */

#include "SendData.h"

FastMap<const Str, RingBuffer<SendData*>*> SendData::RingBuffers_;

RingBuffer<SendData*>* SendData::GetBuffer( const Str& scheme )
{
    RingBuffer<SendData*>* ringbuffer = RingBuffers_.get( scheme );
    if( !ringbuffer )
    {
        ringbuffer = new RingBuffer<SendData*>();
        RingBuffers_.put( scheme, ringbuffer );
    }
    return ringbuffer;
}

void SendData::Push( SendDestination* destination, DataValue* value, const Unit* unit, bool freeValue, Logger* logger )
{
    SendData* sendData = new SendData( destination, value, unit, freeValue );

    if( NULL != sendData )
    {
        RingBuffer<SendData*>* ringBuf = GetBuffer( destination->getScheme() );
        if( NULL != ringBuf )
        {
            ringBuf->push( sendData );
        }
        else if( NULL != logger )
        {
            logger->syslog( "Failed to get SendData ring buffer. " + sendData->destination_->getPath() + " will not be sent.", Syslog::ERROR );
        }
    }
    else if( NULL != logger )
    {
        logger->syslog( "Failed to construct SendData.", Syslog::ERROR );
    }
}

SendData* SendData::Pop( const Str& scheme )
{
    RingBuffer<SendData*>* ringbuffer = RingBuffers_.get( scheme );
    return ringbuffer ? ringbuffer->pop() : NULL;
}

bool SendData::DataToSend( const Str& scheme )
{
    RingBuffer<SendData*>* ringbuffer = RingBuffers_.get( scheme );;
    return ringbuffer && !ringbuffer->isEmpty();
}

SendData::~SendData()
{
    delete destination_;
    if( freeValue_ )
    {
        delete value_;
    }
}

SendData::SendData( SendDestination* destination, DataValue* value, const Unit* unit, bool freeValue )
    : destination_( destination ),
      value_( value ),
      unit_( unit ),
      freeValue_( freeValue )
{}

SendDestination::SendDestination( const Str& destinationUri, bool requirePath, Logger& logger, const Syslog::Severity logSeverity )
    : scheme_( Str::EMPTY_STR ),
      hostId_( 0 ),
      host_( Str::EMPTY_STR ),
      path_( Str::EMPTY_STR ),
      error_( true )
{
    size_t colonAt = destinationUri.find( ":" );
    if( colonAt == 0 || colonAt == destinationUri.length() - 1 || colonAt == Str::NO_POS )
    {
        logger.syslog( "Invalid or missing ':' characters in destination URI: " + destinationUri, logSeverity );
        return;
    }
    scheme_ = destinationUri.substr( 0, colonAt );
    bool schemeOk = false;
    if( scheme_ == "modem" )
    {
        schemeOk = true;
    }
    if( !schemeOk )
    {
        logger.syslog( "Unknown scheme: " + scheme_ + " in destination URI: " + destinationUri, logSeverity );
    }
    size_t colon2At = destinationUri.find( ":", colonAt + 1 );
    if( colon2At == colonAt + 1  || ( requirePath && ( colon2At == Str::NO_POS || colon2At == destinationUri.length() - 1 ) ) )
    {
        logger.syslog( "Invalid or missing ':' character between host and path in destination URI: " + destinationUri, logSeverity );
        return;
    }
    host_ = colon2At == Str::NO_POS ? destinationUri.substr( colonAt + 1 ) : destinationUri.substr( colonAt + 1, colon2At - colonAt - 1 );
    hostId_ = atoi( host_.cStr() );
    if( scheme_ == "modem" && ( hostId_ < 0 || hostId_ > 255 ) )
    {
        logger.syslog( "For the scheme 'modem', the host must be between 0 and 255 in destination URI: " + destinationUri, logSeverity );
        return;
    }
    path_ = colon2At == Str::NO_POS ? "" : destinationUri.substr( colon2At + 1 );
    error_ = false;
}

SendDestination::SendDestination( const SendDestination& destination )
    : scheme_( destination.scheme_ ),
      hostId_( destination.hostId_ ),
      host_( destination.host_ ),
      path_( destination.path_ ),
      error_( destination.error_ )
{}
