// ---------------------------------------------------------------------------
// - Buffer.hpp                                                              -
// - standard object library - character buffer class definition             -
// ---------------------------------------------------------------------------
// - This program is free software;  you can redistribute it  and/or  modify -
// - it provided that this copyright notice is kept intact.                  -
// -                                                                         -
// - This program  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.  In no event shall -
// - the copyright holder be liable for any  direct, indirect, incidental or -
// - special damages arising in any way out of the use of this software.     -
// ---------------------------------------------------------------------------
// - copyright (c) 1999-2013 amaury darsch                                   -
// ---------------------------------------------------------------------------

#ifndef  AFNIX_BUFFER_HPP
#define  AFNIX_BUFFER_HPP

#ifndef  AFNIX_ENCODING_HPP
#include "Encoding.hpp"
#endif

namespace afnix {

  /// The Buffer class is a byte buffer which can be used to accumulate
  /// characters. By default, the class automatically resize itself when full.
  /// However, a flag controls whther or not this operation can proceed. If
  /// the buffer is full, an exception is raised. Standard methods to read 
  /// or write or extract data is provided. 
  /// @author amaury darsch

  class Buffer : public virtual Object {
  public:
    /// generate a random buffer by size
    /// @param size the number of bytes
    static Buffer random (const long size);

  protected:
    /// the buffer data
    char* p_data;
    /// the buffer size
    long  d_size;
    /// the buffer length
    long  d_blen;
    /// the resize flag
    bool  d_rflg;
    /// the buffer encoding
    Encoding::t_emod d_emod;

  public:
    /// create a default buffer
    Buffer (void);

    /// create a new buffer with a default size.
    /// @param size the buffer size
    Buffer (const long size);

    /// create a new buffer with a mode
    /// @param emod the encoding mode
    Buffer (const Encoding::t_emod emod);

    /// create a new buffer by size with a mode
    /// @param size the buffer size
    /// @param emod the encoding mode
    Buffer (const long size, const Encoding::t_emod emod);
    
    /// create a new buffer and initialize it with a c string
    /// @param value the c string to initialize
    Buffer (const char* value);

    /// create a new buffer and initialize it with a string
    /// @param value the string to initialize
    Buffer (const String& value);

    /// create a new buffer by size and content, no copy, no resize
    /// @param size the buffer size
    /// @param blen the buffer length
    /// @param data the buffer data
    Buffer (const long size, const long blen, char* data);

    /// copy construct a buffer
    Buffer (const Buffer& that);

    /// destroy this buffer
    ~Buffer (void);

    /// @return the class name
    String repr (void) const;

    /// @return a clone of this object
    Object* clone (void) const;

    /// assign a buffer to this one
    /// @param that the buffer to assign
    Buffer& operator = (const Buffer& that);

    /// reset this buffer 
    virtual void reset (void);
    
    /// @return the size of this buffer
    virtual long getsize (void) const;

    /// @return the length of this buffer
    virtual long length (void) const;

    /// set the buffer encoding mode
    /// param emod the encoding mode to set
    virtual void setemod (const Encoding::t_emod emod);

    /// @return the buffer encoding
    virtual Encoding::t_emod getemod (void) const;

    /// set the resize flag
    /// @param rflg the resize flag
    virtual void setrflg (const bool rflg);

    /// @return the resize flag
    virtual bool getrflg (void) const;

    /// @return true if the buffer is empty
    virtual bool empty (void) const;

    /// @return true if the buffer is full
    virtual bool full (void) const;

    /// add a character to this buffer
    /// @param value the character to add to this buffer
    virtual long add (const char value);

    /// add a unicode character to this buffer
    /// @param value the unicode character to add to this buffer
    virtual long add (const t_quad value);

    /// add a c-string to this buffer
    /// @param s the c-string to add
    virtual long add (const char* s);

    /// add a character buffer in this buffer
    /// @param cbuf the character buffer to add
    /// @param size the character buffer size
    virtual long add (const char* cbuf, const long size);

    /// add a string to this buffer
    /// @param s the string to add to this buffer
    virtual long add (const String& s);

    /// add a buffer object to this buffer
    /// @param buf the buffer to add
    virtual long add (const Buffer& buf);
    
    /// @return the next available character
    virtual char read (void);

    /// @return the next character but do not remove it
    virtual char get (void) const;

    /// @return a character by index
    virtual char get (const long index) const;

    /// @return the last character
    virtual char pop (void);

    /// shift the buffer by a certain amount
    /// @param asl the amount of left shift
    virtual void shl (const long asl);

    /// @return a line from this buffer
    virtual String readln (void);

    /// pushback a character in this buffer
    /// @param value the character to push back
    virtual long pushback (const char value);

    /// pushback a unicode character in this buffer
    /// @param value the character to push back
    virtual long pushback (const t_quad value);

    /// pushback a c-string in this buffer
    /// @param s the string to pushback
    virtual long pushback (const char* value);

    /// pushback a c-string in this buffer
    /// @param s    the string to pushback
    /// @param size the string size
    virtual long pushback (const char* s, const long size);

    /// pushback a string in this buffer
    /// @param value the string to push back
    virtual long pushback (const String& value);

    /// pushback a buffer in this buffer
    /// @param buffer the buffer to push back
    virtual long pushback (const Buffer& value);

    /// @return the buffer content as quad buffer
    virtual t_quad* toquad (void) const;

    /// @return the buffer contents as a string
    virtual String tostring (void) const;

    /// @return the buffer content as an octet string
    virtual String format (void) const;

    /// map this buffer to an anonymous data structure
    /// @param data the data structure to map
    /// @param size the data size to map
    virtual long tomap (void* data, const long size) const;

    /// add a natural word to this buffer
    /// @param wval the word to add
    virtual void addnw (const t_word wval);

    /// add a natural quad to this buffer
    /// @param qval the quad to add
    virtual void addnq (const t_quad qval);

    /// add a natural octa to this buffer
    /// @param oval the octa to add
    virtual void addno (const t_octa oval);

    /// @return a word in natural format from this buffer 
    virtual t_word getnw (void);

    /// @return a quad in natural format from this buffer 
    virtual t_quad getnq (void);

    /// @return an octa in natural format from this buffer 
    virtual t_octa getno (void);

    /// @return a word in host format from this buffer 
    virtual t_word gethw (void);

    /// @return a quad in host format from this buffer 
    virtual t_quad gethq (void);

    /// @return a octa in host format from this buffer 
    virtual t_octa getho (void);

    /// copy a buffer upto a boudary string
    /// @param bnds the boundary string
    virtual Buffer* cpbnds (const String& bnds);

  public:
    /// create a new object in a generic way
    /// @param argv the argument vector
    static Object* mknew (Vector* argv);

    /// @return true if the given quark is defined
    bool isquark (const long quark, const bool hflg) const;

    /// apply this object with a set of arguments and a quark
    /// @param robj  the current runnable
    /// @param nset  the current nameset    
    /// @param quark the quark to apply these arguments
    /// @param argv  the arguments to apply
    Object* apply (Runnable* robj, Nameset* nset, const long quark,
		   Vector* argv);    
  };
}

#endif
