// ---------------------------------------------------------------------------
// - Strbuf.cpp                                                              -
// - standard object library - string buffer class implementation            -
// ---------------------------------------------------------------------------
// - 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-2006 amaury darsch                                   -
// ---------------------------------------------------------------------------

#include "Ascii.hpp"
#include "Strbuf.hpp"
#include "Unicode.hpp"

namespace afnix {

  // -------------------------------------------------------------------------
  // - private section                                                       -
  // -------------------------------------------------------------------------

  // default buffer size
  const long BUFFER_SIZE = 1024;

  // -------------------------------------------------------------------------
  // - class section                                                         -
  // -------------------------------------------------------------------------

  // create a new buffer

  Strbuf::Strbuf (void) {
    p_buffer = new t_quad[BUFFER_SIZE];
    d_size   = BUFFER_SIZE;
    d_length = 0;
  }

  // create a new buffer with a predefined size

  Strbuf::Strbuf (const long size) {
    d_size   = (size <= 0) ? BUFFER_SIZE : size;
    p_buffer = new t_quad[d_size];
    d_length = 0;
  }

  // create a new buffer and initialize it with a c-string

  Strbuf::Strbuf (const char* value) {
    // get the c-string size
    long size = Ascii::strlen (value);
    d_size    = (size > 0) ? size : BUFFER_SIZE;
    // initialize the class
    p_buffer  = new t_quad[d_size];
    d_length  = 0;
    add (value);
  }

  // create a new buffer and initialize it with a string

  Strbuf::Strbuf (const String& value) {
    // get the string size
    long size = value.length ();
    d_size    = (size > 0) ? size : BUFFER_SIZE;
    // initialize the class
    p_buffer = new t_quad[d_size];
    d_length = 0;
    add (value);
  }
  
  // destroy this strbuf
  
  Strbuf::~Strbuf (void) {
    delete [] p_buffer;
  }
  
  // return the class name

  String Strbuf::repr (void) const {
    return "Strbuf";
  }

  // reset this buffer
  
  void Strbuf::reset (void) {
    wrlock ();
    d_length = 0;
    unlock ();
  }

  // return the length of this buffer
  
  long Strbuf::length (void) const {
    rdlock ();
    long result = d_length;
    unlock ();
    return result;
  }

  // add a character in this buffer

  void Strbuf::add (const char value) {
    wrlock ();
    try {
      add (Unicode::toquad (value));
      unlock ();
    } catch (...) {
      unlock ();
      throw;
    }
  }

  // add a unicode character in this buffer
  
  void Strbuf::add (const t_quad value) {
    wrlock ();
    // check for overflow
    if (d_length == d_size) resize (d_size * 2);
    // add the characater
    p_buffer[d_length++] = value;
    unlock ();
  }

  // add a character string in this buffr

  void Strbuf::add (const char* value) {
    wrlock ();
    try {
      long size = Ascii::strlen (value);
      add (value, size);
      unlock ();
    } catch (...) {
      unlock ();
      throw;
    }
  }

  // add a buffer in this buffer
  
  void Strbuf::add (const char* buffer, const long size) {
    if ((buffer == nilp) || (size == 0)) return;
    wrlock ();
    for (long i = 0; i < size; i++) add (buffer[i]);
    unlock ();
  }

  // add a unicode character string in this buffer

  void Strbuf::add (const t_quad* value) {
    wrlock ();
    try {
      long size = Unicode::strlen (value);
      add (value, size);
      unlock ();
    } catch (...) {
      unlock ();
      throw;
    }
  }

  // add a quad buffer in this buffer
  
  void Strbuf::add (const t_quad* buffer, const long size) {
    if ((buffer == nilp) || (size == 0)) return;
    wrlock ();
    for (long i = 0; i < size; i++) add (buffer[i]);
    unlock ();
  }

  // add a string in this buffer
  
  void Strbuf::add (const String& value) {
    wrlock ();
    try {
      t_quad* sbuf = value.toquad ();
      add (sbuf);
      delete [] sbuf;
    } catch (...) {
      unlock ();
      throw;
    }
    unlock ();
  }
    
  // return the corresponding string accumulated in this buffer
  
  String Strbuf::tostring (void) const {
    rdlock ();
    // create a temporary buffer to hold the characters
    t_quad* buf = new t_quad[d_length+1];
    // build the result string
    try {
      for (long i = 0; i < d_length; i++) buf[i] = p_buffer[i];
      buf[d_length] = nilq;
      // create the result string and clean the buffer
      String result = buf;
      delete [] buf;
      unlock ();
      return result;
    } catch (...) {
      delete [] buf;
      unlock ();
      throw;
    }
  }

  // resize this buffer

  void Strbuf::resize (const long size) {
    wrlock ();
    if ((size < 0) || (size < d_length)) {
      unlock ();
      return;
    }
    // allocate and copy the new buffer
    t_quad* buf = new t_quad[size];
    for (long i = 0; i < d_length; i++) buf[i] = p_buffer[i];
    delete [] p_buffer;
    // restore new buffer
    d_size   = size;
    p_buffer = buf;
    unlock ();
  }
}
