/**
 * \file BGDNetBuffer.cpp
 * \brief Реализация классов Buffer, InputBuffer и OutputBuffer
 */

#include "BGDNetPch.h"

#include "BGDNetBuffer.h"

#include <assert.h>
#include <nwerror.h>
#include "BGDNetContext.h"

namespace BGDNet
{

Buffer::Buffer( const Context& ctx, size_t sz ) throw(Exception) :
  m_ctx(ctx)
{
  m_pBuf = 0;
  NWDSCCODE err = NWDSAllocBuf(sz, &m_pBuf);
  if( SUCCESS != err)
    throw Exception(err);
}

Buffer::~Buffer( void )
{
  if( m_pBuf )
    NWDSFreeBuf(m_pBuf);
}

const Context& Buffer::ctx( void ) const
{
  return m_ctx;
}

Buf_T* Buffer::buf( void )
{
  return m_pBuf;
}

const Buf_T* Buffer::buf( void ) const
{
  return m_pBuf;
}




InputBuffer::InputBuffer( const Context& ctx, nuint32 op, size_t sz )
  throw(Exception) :
    Buffer(ctx, sz)
{
  NWDSCCODE err = NWDSInitBuf(ctx, op, buf());
  if (SUCCESS != err)
    throw Exception(err);
}

void InputBuffer::putAttrName( const char* name )
{
  NWDSCCODE err = NWDSPutAttrName(ctx(), buf(), const_cast<char*>(name));
  if (SUCCESS != err)
    throw Exception(err);
}




OutputBuffer::OutputBuffer( const Context& ctx, size_t sz ) throw(Exception) :
  Buffer(ctx, sz)
{
}

int OutputBuffer::objCount( void )
  throw(Exception)
{
  nuint32 n;
  NWDSCCODE err = NWDSGetObjectCount(ctx(), buf(), &n);
  if (SUCCESS != err)
    throw Exception(err);
  return n;
}

String OutputBuffer::objName( String* pBaseClass )
  throw(Exception)
{
  char objectName[MAX_DN_CHARS + 1];
  Object_Info_T objectInfo;
  nuint32 attrCount;
  NWDSCCODE err = NWDSGetObjectName(
    ctx(),
    buf(),
    objectName,
    &attrCount,
    &objectInfo);
  if (SUCCESS != err)
    throw Exception(err);
  assert(!attrCount);
  if (pBaseClass)
    *pBaseClass = objectInfo.baseClass;
  return String(objectName);
}

String OutputBuffer::objNameAndDSIInfo( char** ppInfo )
  throw(Exception)
{
  char objectName[MAX_DN_CHARS + 1];
  nuint32 attrCount;
  NWDSCCODE err = NWDSGetObjectNameAndInfo(
    ctx(),
    buf(),
    objectName,
    &attrCount,
    ppInfo);
  if (SUCCESS != err)
    throw Exception(err);
  assert(!attrCount);
  return String(objectName);
}

int OutputBuffer::attrCount( void )
  throw(Exception)
{
  nuint32 n;
  NWDSCCODE err = NWDSGetAttrCount(ctx(), buf(), &n);
  if (SUCCESS != err)
    throw Exception(err);
  return n;
}

String OutputBuffer::getAttr( NDSAttrValues* pValues )
{
  pValues->clear();

  char attrName[MAX_SCHEMA_NAME_CHARS + 1];
  nuint32 attrValCount = 0;
  nuint32 syntaxID = 0;
  
  // 1) Получаем имя атрибута и количество значений:
  NWDSCCODE err = NWDSGetAttrName(
    ctx(),
    buf(),
    attrName,
    &attrValCount,
    &syntaxID);
  if (SUCCESS != err)
    throw Exception(err);

  // 2) По очереди получаем все значения:
  while (attrValCount--)
  {
    // Добавляем в конец контейнера "чистый" элемент:
    pValues->add(NDSAttrVal());
    
    // 2.1) Получаем размер значения:
    nuint32 attrValSize = 0;
    err = NWDSComputeAttrValSize(ctx(), buf(), syntaxID, &attrValSize);
    if (SUCCESS != err)
      throw Exception(err);
    
    // 2.2) Изменяем размер добавленного "чистого" элемента:
    pValues->back().resize(attrValSize);

    // 2.3) Получаем значение атрибута:
    err = NWDSGetAttrVal(ctx(), buf(), syntaxID, &pValues->back().front());
    if (SUCCESS != err)
      throw Exception(err);
  }

  return String(attrName);
}

} // namespace BGDNet
