/** \file
 *
 * LineReader class declaration.
 *
 *  Copyright (c) 2015 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */

#ifndef LINEREADER_H_
#define LINEREADER_H_

#include <iostream>

/**
 * Utility for the concrete concern of reading lines from
 * a given file descriptor in a non-blocking fashion.
 * A line is any sequence of characters ending with '\n'.
 * Although somewhat similar with functionality offered by other
 * classes, this separated module facilitates reuse in various scenarios.
 * For example, to do line reads from stdin in combination with reads from
 * sockets, etc. This class was added during the initial development
 * of the socket-based interface with the ESP.
 *
 * \ingroup io
 */
class LineReader
{
public:

    ///
    /// Constructor
    /// \param fd            file descriptor to read data from
    /// \param bufferSize    size for internal buffer; default: 1024
    /// \param debug         flag for ad hoc debug printing; default: false
    ///
    LineReader( int fd, size_t bufferSize = 1024, bool debug = false )
        : fd_( fd ),
          bufferSize_( bufferSize ),
          bufferRead_( 0 ),
          debug_( debug )
    {
        buffer_ = new char[bufferSize_];
    }

    ~LineReader()
    {
        delete[] buffer_;
    }

    ///
    /// Reads a line (or part of it depending on given output buffer size).
    /// The underlying read operation is non-blocking so multiple calls can be done
    /// until a complete line is received or until the size of data already received
    /// is equal or greater than the output buffer size.
    ///
    /// \param buf       output buffer
    /// \param bufSize   size of output buffer
    /// \return
    ///   0    : Nothing new received since last processed read. Call again later.
    ///   -1   : Some bytes have been received (in the internal buffer) but not a complete line yet and the
    ///          output buffer is large enough to continue waiting for the line. Call again later.
    ///          Nothing is transferred to output buffer just yet.
    ///   len  : positive integer indicating number of bytes received and transferred to output buffer.
    ///          Caller can simply use the condition buf[len - 1] == '\n' to verify complete line reception.
    ///          (Note that buf[len - 1] != '\n' implies len == bufSize.)
    ///   -2   : Some error has occurred.
    ///
    int readLine( char* buf, size_t bufSize ) ;

protected:
    int fd_;

private:
    // disallow copy constructor
    LineReader( const LineReader& old );

    char* buffer_;
    size_t bufferSize_;
    size_t bufferRead_;    // number of bytes read but not yet processed
    bool debug_;

    void adjustBuffer( size_t bufSize );
    int fillInBuffer();
    void updateBuffer( size_t processed );
    int nbRead( char* buffer, size_t bufferLength );

};

#endif /*LINEREADER_H_*/
