/* Network-Integrated Multimedia Middleware (NMM)
 * http://www.motama.com/nmm.html
 *  
 * Copyright (C) 2006-2007
 * Motama GmbH, Saarbruecken, Germany
 * http://www.motama.com
 *  
 * This file is part of NMM. 
 * 
 * NMM is free software; you can redistribute it and/or modify it    
 * under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; only version 2 of the License.      
 * 
 * NMM is distributed in the hope that it will be useful, but WITHOUT 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 
 * License for more details.  
 * 
 * You should have received a copy of the GNU General Public License 
 * along with NMM; if not, write to the Free Software Foundation,    
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */

#ifndef NMM_BUFFER_HPP
#define NMM_BUFFER_HPP NMM_BUFFER_HPP

#include "nmm/nmm_prefix.hpp"

#include "Message.hpp"

#include "visibility.hpp"

namespace NMM {
  
  class BufferManager;
  
  /** This class represents a multimedia buffer.
   *
   * A multimedia buffer is merely a continuous block of memory with some
   * header information.
   */
  class DLLEXPORT Buffer : public Message {
  public:
    /** The main constructor.
     *
     * A buffer is passed its size and
     * a pointer to the Allocator object which allocated
     * (i.e. created) it.
     *
     * @param newsize The size of the buffer in bytes.
     * @param master The Allocator object in charge of this buffer.
     */
    Buffer (const nmm_uint32 newsize, const BufferManager *master);

    /** A constructor to reuse a given memory area. 
     *
     * Same as the main constructor, except that no memory is allocated for the data.
     * Instead, the char array passed is used.
     *
     * @param newsize The size of the buffer in bytes.
     * @param initial_data The actual buffer.
     * @param master The Allocator object in charge of this buffer.
     */
    Buffer (const nmm_uint32 newsize,char* initial_data,
	    const BufferManager *master);

    /** Copy constructor.
     *
     * @param buffer buffer to copy
     */
    Buffer(const Buffer& buffer);

    /** Default destructor.
     */
    ~Buffer ();  

    /** Resets internal state of this buffer.
     *
     * Use this method to reset the internal state of the buffer
     * This means the mandatory bit will be set to false;
     * the used size will be set to the total size of the buffer;
     * and the buffer is set to be a data buffer
     * This method should be called by the BufferManager before 
     * an already used buffer is returned.
     */
    void reset(); 

    /** Returns writeable instance of this buffer.
     *
     * This method returns a writeable instance of the buffer.
     * Since Buffer-objects can be shared along the flowgraph, 
     * an operation, which modifies the data of the Buffer-object,
     * must call this method before getData().
     * Typical use: 
     * myBuffer = myBuffer->getWritableInstance(); 
     * char *data = myBuffer->getData();
     *
     * @return pointer to writeable instance of this buffer
     */
    Buffer *getWriteableInstance();

    /** Returns a pointer to the data field.
     * The data field is a simple byte array.
     *
     * @return A pointer to the byte-array used.
     */
    char* getData () const;

    /** Attempts to set data field to etxernal memory area. 
     *
     * Attempts to set the data field to an etxernal memory
     * area. Only use if you own the Buffer (reference counter <= 1)! 
     *
     * @param size size of new data array
     * @param data pointer to data array
     * @return FAILURE if reference counter > 1, SUCCESS otherwise
     */
    Result setData (const nmm_uint32 size, char *data);

    /** Returns the size of this buffer.
     * 
     * @return The size of this buffer.
     */
    nmm_uint32 getSize () const;

    /** Returns used bytes of buffer.
     *
     * Returns the used bytes of this buffer. Buffers should
     * be filled from the beginning.
     *
     * @return The used bytes of this buffer.
     */
    nmm_uint32 getUsed () const;


    /** Sets used bytes of buffer.
     *
     * Sets the used bytes of this buffer. The used byte count is
     * automatically clipped to the range between 0 and size inclusive.
     *
     * @param actused the new used byte count.
     */
    void setUsed (const nmm_uint32 actused);

    /** Assignment operator.
     *
     * Copy data from buffer b to this buffer.
     *
     * @param b Buffer to assign from
     * @return reference to this buffer
     */
    const Buffer& operator=(const Buffer& b);

    /** Returns a non-writeable copy of the current buffer.
     *
     * This method returns a non-writeable copy of the current buffer and increases the ref-count
     *
     * @return pointer to non-writeable copy of this buffer
     */
    virtual Buffer* copy() const;
    
  protected:
    /** Releases Buffer.
     *
     * Calls releaseBuffer on BufferManager given on construction of this buffer.
     */
    virtual void erase() const;
    
  private:
    const BufferManager *manager;  ///< The BufferManager of this buffer.
    TValue<nmm_uint32> size;       ///< The size in bytes of this buffer.
    TValue<nmm_uint32> realsize;   ///< The number of bytes actually used.
    TValue<nmm_char*> data;        ///< The actual data field.
    TValue<nmm_bool>  own_data;    ///< True if constructor allocated the data.
    
    void registerAttributes();
    
    ThreadMutex op_mutex;  ///< Mutex to protect operations like getWriteableInstance(), increaseCount() and release()
  };
}

#include "nmm/nmm_suffix.hpp"

#endif
