// Change History
// 01/03/03 AV Development: Add CreateVector function
// 01/03/03 AV Development: Use AT_Num64 for result values
// 11/19/03 AV Development: Merge Production version 14
// 10/29/03 AV Production: 64 bit conversion

#include "drs/drs_data.h"
#include "drs/drs_formula.h"

//rounding function
#include "base/at_utls.h"

// **************************************************************************
// DRS_VectorDataElem implementation
// **************************************************************************
DRS_VectorDataElem DRS_VectorDataElem::FormulaResult::Compute( uint *piPresMult) const
{
  DRS_VectorDataElem res = pFormulaNode->Compute( *pVectorData, iItem, lRecNum);
  *piPresMult = res.GetPrecisionMult();
  return res;
}

DRS_VectorDataElem::DRS_VectorDataElem( DRS_VectorDataElem const &rFormulaResult)
  : m_iValue( rFormulaResult.m_iValue),
    m_iMaxPrecisionMult( rFormulaResult.m_iMaxPrecisionMult),
    m_FRValue( rFormulaResult.m_FRValue)
{
}

DRS_VectorDataElem & DRS_VectorDataElem::operator= ( DRS_VectorDataElem const &rhs)
{
  m_iValue = rhs.m_iValue;
  m_iMaxPrecisionMult = rhs.m_iMaxPrecisionMult;
  m_FRValue = rhs.m_FRValue;

  return *this;
}

DRS_VectorDataElem &DRS_VectorDataElem::ResetDataElem( AT_Num64 iValue, uint iMaxPrecisionMult)
{
  m_iValue = iValue;
  m_iMaxPrecisionMult = iMaxPrecisionMult;
  memset( &m_FRValue, 0, sizeof( FormulaResult));

  return *this;
}

void DRS_VectorDataElem::SetFormulaNode( const DRS_FormulaNode *pParentFormula,
                                         const DRS_VectorData *pParentData,
                                         uint iParentItem,
                                         uint32 lRecordNum)
{
    m_FRValue.iItem = iParentItem;
    m_FRValue.pVectorData = pParentData;
    m_FRValue.lRecNum = lRecordNum;
    m_FRValue.pFormulaNode = pParentFormula;
}

DRS_VectorDataElem DRS_VectorDataElem::operator+ ( DRS_VectorDataElem const &rhs) const
{
  return DRS_VectorDataElem( GetRawValue() + rhs.GetRawValue(), m_iMaxPrecisionMult );
}

DRS_VectorDataElem DRS_VectorDataElem::operator- ( DRS_VectorDataElem const &rhs) const
{
  return DRS_VectorDataElem( GetRawValue() - rhs.GetRawValue(), m_iMaxPrecisionMult );
}

DRS_VectorDataElem DRS_VectorDataElem::operator* ( DRS_VectorDataElem const &rhs) const
{
  return DRS_VectorDataElem( GetRawValue() * rhs.GetRawValue(), m_iMaxPrecisionMult );
}

DRS_VectorDataElem DRS_VectorDataElem::operator/ ( DRS_VectorDataElem const &rhs) const
{
  RealValue res = ( ( RealValue)GetRawValue() / rhs.GetRawValue()) * m_iMaxPrecisionMult;
  return DRS_VectorDataElem( std_round( res, 1), m_iMaxPrecisionMult );
}

bool DRS_VectorDataElem::operator !() const
{
  return !GetRawValue();
}

AT_Num64 DRS_VectorDataElem::GetRawValue() const
{
  uint *piPresMult = const_cast<uint*> ( &m_iMaxPrecisionMult);

  return m_FRValue.pFormulaNode ? m_FRValue.Compute( piPresMult).GetRawValue() :
                                  m_iValue;
}

AT_Num64 DRS_VectorDataElem::GetIntValue() const
{
  return GetRawValue() / m_iMaxPrecisionMult;
}

RealValue DRS_VectorDataElem::GetRealValue() const
{
  return ( ( RealValue)GetRawValue()) / m_iMaxPrecisionMult;
}

RealValue DRS_VectorDataElem::GetRealValueAtPrecision( uint iPrecision ) const
{
  RealValue real_val = GetRealValue();
  uint iPrecisionMult = pow10<uint>(iPrecision );

  if( iPrecisionMult >= m_iMaxPrecisionMult)
    return real_val;
  else
    return std_round( real_val, iPrecisionMult);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
//DRS_Data
//Storage objects for each data type.
//
//  Data vectors
//  Data fields
////////////////////////////////////////////////////////////////////////////////////////////////////////

//Allocate storage
DRS_VectorData::DRS_VectorData( DRS_Vector const &rVector) :
  m_pData(NULL),
  m_pVector(&rVector),
  m_elem( 0, rVector.DataPrecisionMult())
{
  CreateVector();
  Clear();
};
//Create from record
DRS_VectorData::DRS_VectorData( DRS_RecordSet &rRecord, DRS_Vector const &rVector, uint iOccurrence) :
  m_pData(NULL),
  m_pVector(&rVector)
{
  CreateVector();
  Clear();
  LoadFromATVector( rRecord, ( uint32)iOccurrence);
}
//Copy
DRS_VectorData::DRS_VectorData( DRS_VectorData const &rDataVector) :
  m_pData(NULL),
  m_pVector(rDataVector.m_pVector)
{
  CreateVector();
  CopyData(rDataVector.m_pData);
};

bool DRS_VectorData::LoadFromATVector( const AT_Record *pRecord, uint32 *ids)
{
  if( !pRecord->getVector( m_pData, ids) )
    {
    Clear();
    return false;
    }

  return true;
}

bool DRS_VectorData::LoadFromATVector( const AT_Record *pRecord, uint32 iOccurrence)
{
  if( !pRecord->getVector( m_pData, 0, iOccurrence) )
    {
    Clear();
    return false;
    }

  return true;
}

bool DRS_VectorData::LoadFromDRSVector( DRS_RecordSet &rRecordSet, uint32 *ids)
{
  bool res;
  // clear vector data
  Clear();
  // get data
  m_pVector->GetData( &rRecordSet, ids, this, &res);

  return res;
}

inline void DRS_VectorData::CopyData(AT_Num * src)
{
  memcpy( m_pData, src, m_pVector->iPeriodCount * sizeof(AT_Num));
}

inline void DRS_VectorData::CreateVector()
{
    if(!m_pVector)
        return;
    if(m_pData)
        delete [] m_pData;
    m_pData = new AT_Num [m_pVector->iPeriodCount];
}

DRS_VectorData const & DRS_VectorData::operator=( DRS_VectorData const&rhs)
{
  if( m_pVector != rhs.m_pVector )
    {
    m_pVector = rhs.m_pVector;
    CreateVector();
    }

  CopyData(rhs.m_pData);

  return *this;
}

DRS_VectorData const & DRS_VectorData::operator+= (DRS_VectorData const &rhs)
{
  for( uint i = min( m_pVector->iPeriodCount, rhs.m_pVector->iPeriodCount); i > 0; i--)
    m_pData[i-1] += rhs.m_pData[i-1];
  return *this;
}

DRS_VectorDataElem &DRS_VectorData::GetDataElement( uint iElem) const
{
  if( iElem < m_pVector->iPeriodCount)
    return m_elem.ResetDataElem( m_pData[iElem], m_pVector->DataPrecisionMult());
  else //Virtual element
    {
    //Compute virtual vector element: Only summation for now
    DRS_VirtualPeriodDef &oPeriodDef = m_pVector->VirtualPeriods[iElem - m_pVector->iPeriodCount].PeriodDef;
    AT_Num64 val = 0;
    for( uint j = oPeriodDef.Offset(); j < oPeriodDef.Offset() + oPeriodDef.Length(); j++)
      val = val + m_pData[j];

    return m_elem.ResetDataElem( val, m_pVector->DataPrecisionMult());
    }
}

void DRS_VectorData::GetData( DRS_VectorDataElem* pVectorElems[]) const
{
  for( uint i = 0; i < m_pVector->PeriodCount(); ++i)
    *pVectorElems[i] = GetDataElement( i);
}

// **************************************************************************
// DRS_FieldData implementation
// **************************************************************************
DRS_FieldData::DRS_FieldData( DRS_FieldData const &rCopy)
  : pDataField( & rCopy.DataField()), buf(0), buflen(rCopy.datalen), datalen(rCopy.datalen)
{
  buf = new byte[datalen];
  memcpy( buf, rCopy.buf, datalen);
}

DRS_FieldData const & DRS_FieldData::operator=( DRS_FieldData const &rCopy)
{
  pDataField = & rCopy.DataField();
  datalen = rCopy.datalen;
  if( datalen > buflen)
    {
    delete [] buf;
    buf = new byte[buflen = datalen];
    }
  memcpy( buf, rCopy.buf, datalen);
  return( *this);
}


void DRS_FieldData::Get( byte *sDest, uint iLen) const
{
  memcpy( sDest, buf, min(iLen, datalen));
  if( datalen < iLen) sDest[datalen] = 0;
}

void DRS_FieldData::operator<< ( DRS_RecordSet &rRec)
{
  //Load field data from record
  if( (datalen = pDataField->FieldLen( &rRec, 0, 0)) >= buflen)
    {
    delete [] buf;
    buf = new byte[buflen = datalen + 1];
    }

  //TO_DO Assuming 1st fld occ for now and first state.
  pDataField->FieldData( &rRec, 0, 0, buf, buflen);
}



