Buffer::Buffer(void)
  : buffer_(NULL)
  , length_(0)
  , storage_(kDefaultStorage)
{
}

Buffer::~Buffer(void)
{
  Destroy();
}

bool 
Buffer::Init(int storage)
{
  storage_ = (storage > kDefaultStorage ? storage : kDefaultStorage);

  buffer_ = (char*)malloc(storage_);
  if (NULL == buffer_) {
    LOG_FAIL("malloc failed\n");
    return false;
  }
  length_ = 0;

  return true;
}

void 
Buffer::Destroy(void)
{
  if (NULL != buffer_) {
    free(buffer_);
    buffer_ = NULL;
  }
  length_ = 0;
  storage_ = kDefaultStorage;
}

int 
Buffer::Put(const char* buffer, int bytes)
{
  if (NULL == buffer || bytes <= 0)
    return -1;

  if (length_ + bytes > storage_) {
    if (!Regrow())
      return -1;
  }

  memcpy(buffer_ + length_, buffer, bytes);
  length_ += bytes;

  return bytes;
}

int 
Buffer::Get(int bytes, char* buffer)
{
  if (bytes <= 0 || NULL == buffer)
    return -1;

  int copy_bytes = (length_ <=  bytes ? length_ : bytes);
  if (0 == copy_bytes)
    return 0;

  memcpy(buffer, buffer_, copy_bytes);
  if (copy_bytes != length_)
    memmove(buffer_, buffer_ + copy_bytes, length_ - copy_bytes);
  length_ -= copy_bytes;

  return copy_bytes;
}

int 
Buffer::Increment(int bytes)
{
  if (bytes <= 0)
    return -1;

  if (length_ + bytes > storage_) {
    if (!Regrow())
      return -1;
  }

  length_ += bytes;

  return bytes;
}

int 
Buffer::Decrement(int bytes)
{
  if (bytes > length_) {
    LOG_FAIL("bytes > length_\n");
    return -1;
  }

  if (bytes < length_)
    memmove(buffer_, buffer_ + bytes, length_ - bytes);
  length_ -= bytes;

  return bytes;
}

bool 
Buffer::Regrow(void)
{
  int new_storage = (0 == storage_ ? kDefaultStorage : 2 * storage_);
  buffer_ = (char*)realloc(buffer_, new_storage);
  if (NULL == buffer_) {
    LOG_FAIL("realloc failed\n");
    return false;
  }
  storage_ = new_storage;

  return true;
}
