// Change History
// 03/18/04 AV Development: Add VirtualPeriodCount, VirtualPeriod, VirtualIndexPeriod
// 11/20/03 AV Development: BC6 conversion.

#include <cstdio>
//#include <stdlib>

//#include <string>

#include "drs/drs_type.h"
#include "drs/drs_appl.h"
#include "drs/drs_vect.h"
#include "drs/drs_data.h"
#include "drs/drs_rec.h"
#include "drs/drs_formula.h"

// **************************************************************************
// DRS_Vector Classes
// **************************************************************************

DRS_VectorIndexState::DRS_VectorIndexState( DRS_FilePath sFile, DRS_FileSetting sSection, DRS_Setting BaseSetting)
  : Descr( sFile, sSection, BaseSetting)
{
  BaseSetting += "Normal";
  iNormal = GetPrivateProfileIntA( (LPCSTR) sSection, (LPCSTR) *BaseSetting, 0, (LPCSTR) sFile);
}

// **************************************************************************
// DRS_VectorQuantile
// **************************************************************************
DRS_VectorQuantile::DRS_VectorQuantile( byte *sFile, byte *sSection, DRS_Setting BaseKey)
{
  DRS_FileSetting instr;

  DRS_Setting key = BaseKey;
  key += "Descr";

  GetPrivateProfileStringA( (LPCSTR) sSection, (LPCSTR) *key, "", (LPSTR) instr, sizeof(DRS_FileSetting), (LPSTR) sFile);
  Descr.Extract( instr);

  key = BaseKey;
  key += "State";
  iState = GetPrivateProfileIntA( (LPCSTR) sSection, (LPCSTR) *key, MAX_UINT, (LPCSTR) sFile);
  if( iState == MAX_UINT) throw DRSERR_MissingConfig( *this, sFile, sSection, *key);

  /*
  key = BaseKey;
  key += "Method";
  // AT_Quantile_Index::METHOD_ASC - standard ATSI method
  method = GetPrivateProfileInt( sSection, *key, AT_Quantile_Index::METHOD_ASC, sFile);
  */
  
  key = BaseKey;
  key += "Precision";
  precision = GetPrivateProfileIntA( (LPCSTR) sSection, (LPCSTR) *key, 0, (LPCSTR) sFile);
}

// **************************************************************************
// DRS_VirtualPeriod
// **************************************************************************
void DRS_VirtualPeriodDef::Extract( byte *buf)
{
  UTL_StringClean( buf);

  char *delim = strchr( (char *) buf, ';');
  if( delim)
    {
    *delim = 0;
    delim ++;
    v_len = (uint) std::atoi( (const char*) delim);
    }
  v_offset = (uint) std::atoi( (const char*) buf);
}

// **************************************************************************
// DRS_VectorNode
// **************************************************************************

DRS_VectorNodeReader::DRS_VectorNodeReader( FILE *hFile) : iDim(0), bytesIn(0)
{
  DRS_FileSetting buf;
  //byte buf[(2 * sizeof(T_Caption))+ 3];

  //endoffile or endofsection
  if ( ! fgets( (char*)buf, sizeof(DRS_FileSetting), hFile) || buf[0] == '[')
    return;
   //this will crash at eof
  UTL_StringClean( buf);
  if( !( bytesIn = std::strlen( (const char*) buf)))
    return;

  byte *p;
  for( p = &buf[0]; *p && *p == ' '; p++, iDim++);
  if( *p == '-') //Exclusion for total calc
    {
     isInTotal = false;
     p++;
    }
  Descr.Extract( p);
}

//Vector dimension calculations
//Must be fixed. Used now only for formula to get averages. Won't work anyway.
uint32 DRS_VectorNode::GetVectorCount( DRS_VectorDim const *pVectorDim, uint32 *pVectorIDs) const
{
  //Each dimension is COLLECTIVE or DISPARATE
  //Collective dimensions will sum children.
  //Disparate dimensions assume that the desired child is set in the
  //vector address. Hence, they simple pass the job on to selected child.

  if(! vChildren.size()) return( 1); //Bottom of node hierarchy - 1 item

  uint32 lVectorCount = 0L;

  //If this dim is mapped to child, get child's data
  //Else if child diemension is collective, sum children
  //  Else Child is Disparate, so get preset child's data
  if( pVectorDim->isMappedToChild)
    {
      int32 lMapped = ( pVectorDim->lMappedToChild < 0L) ?
                          (int32) vChildren.size() + pVectorDim->lMappedToChild + 1L :
                          pVectorDim->lMappedToChild;
      uint32 lSave = pVectorIDs[pVectorDim->Dim()];
      pVectorIDs[pVectorDim->Dim()] = lMapped;
      AssertChild( lMapped);
      lVectorCount += vChildren[lMapped]->GetVectorCount( pVectorDim->GetChild(), pVectorIDs);
      pVectorIDs[pVectorDim->Dim()] = lSave;
    }
  else if( (pVectorDim->GetChild())->IsCollective())
    {
      // Cycle elements
      //Compiler bug: cannot create iterator on downcast type.
      for( std::vector< DRS_VectorNode *>::const_iterator iterChildren = vChildren.begin();
           iterChildren != vChildren.end();
           lVectorCount += (*iterChildren++)->GetVectorCount( pVectorDim->GetChild(), pVectorIDs));
      /*
      uint32 lSave = pVectorIDs[pVectorDim->Dim()];
      for( uint i = 0; i < vChildren.size(); i++)
        {
        pVectorIDs[pVectorDim->Dim()] = i;
        lVectorCount += vChildren[i]->GetVectorCount( pVectorDim->GetChild(), pVectorIDs);
        }
      pVectorIDs[pVectorDim->Dim()] = lSave;
      */
    }
  else //Disparate
    {
      AssertChild( pVectorIDs[pVectorDim->Dim()]);
      lVectorCount += vChildren[pVectorIDs[pVectorDim->Dim()]]->GetVectorCount( pVectorDim->GetChild(), pVectorIDs);
    }

  return( lVectorCount);
}

uint32 DRS_VectorNode::AssertChild( uint32 lIndex) const
{
  if( lIndex == NODE_SUM )
    lIndex = 0; //sum nodes have 0 index in node tree.

  return inherited::AssertChild( lIndex );
}

//Obsolete.
void DRS_VectorNode::GetData( AT_Record const *pRecord, DRS_Vector const *pVector, DRS_VectorDim const *pVectorDim, uint32 pVectorIDs[], DRS_VectorData *pDestVector) const
{
  //Each dimension is COLLECTIVE or DISPARATE
  //Collective dimensions will sum all dimension vectors.
  //Disparate dimensions assume that the desired dimension element is set in the
  //vector address. Hence, they simply pass the job on to the child.

  if(! vChildren.size())
    {
    // Bottom of node hierarchy, add vector and return
    DRS_VectorData RawVector( *pVector);
                                                             //isAvail
    pVector->GetData( pRecord, pVectorIDs, &RawVector, NULL);
    ( *pDestVector) += RawVector;
    return;
    }

  //If this dim is mapped to child, get child's data
  //Else if child diemension is collective, sum children
  //  Else Child is Disparate, so get preset child's data

  if( pVectorDim->isMappedToChild) //Get mapped child
    {
      int32 lMapped = ( pVectorDim->lMappedToChild < 0L) ?
                          (int32) vChildren.size() + pVectorDim->lMappedToChild + 1L :
                          pVectorDim->lMappedToChild;
      uint32 lSave = pVectorIDs[pVectorDim->Dim()];
      pVectorIDs[pVectorDim->Dim()] = lMapped;
      AssertChild( lMapped);
      vChildren[lMapped]->GetData( pRecord, pVector, pVectorDim->GetChild(), pVectorIDs, pDestVector);
      pVectorIDs[pVectorDim->Dim()] = lSave;
    }
  else if( (pVectorDim->GetChild())->isCollective) //Sum children
    {
      // Cycle elements
      //Compiler bug: cannot create iterator on downcast type.
      //std::vector< DRS_TreeNodeContiguous *>::iterator pChild = vChildren.begin();
      uint32 lSave = pVectorIDs[pVectorDim->Dim()];
      for( uint i = 0; i < vChildren.size(); i++)
        {
        if( vChildren[i]->IsInTotal())
          {
          pVectorIDs[pVectorDim->Dim()] = i;
          vChildren[i]->GetData( pRecord, pVector, pVectorDim->GetChild(), pVectorIDs, pDestVector);
          }
        }
      pVectorIDs[pVectorDim->Dim()] = lSave;
    }
  else //Disparate: Get requested child
    {
      AssertChild( pVectorIDs[pVectorDim->Dim()]);
      vChildren[pVectorIDs[pVectorDim->Dim()]]->GetData( pRecord, pVector, pVectorDim->GetChild(), pVectorIDs, pDestVector);
    }
}

/////////////////////////////////////////////////////////////////////////////////////////
//VectorDim
/////////////////////////////////////////////////////////////////////////////////////////
DRS_VectorDim::DRS_VectorDim( DRS_Database const &oDatabase, byte *sSection, uint iID, byte *sFile) :
                                  DRS_TreeDim<DRS_VectorDim>( sSection, iID, sFile)
{
    DRS_FileKey key;

    wsprintfA( (LPSTR) key, "Dim%uIsCollective", iID);
    isCollective = (bool) GetPrivateProfileIntA( (LPCSTR) sSection, (LPCSTR) key, 0, (LPCSTR) sFile);

    if( isCollective)
      {
      wsprintfA( (LPSTR) key, "Dim%uTotalDescr", iID);
      pTotalDescr.reset( new DRS_DescriptorSerialize( sFile, sSection, key));
      }
    wsprintfA( (LPSTR) key, "Dim%uIsMappedToChild", iID);
    if( isMappedToChild = (bool) GetPrivateProfileIntA( (LPCSTR) sSection, (LPCSTR) key, 0, (LPCSTR) sFile))
      {
      wsprintfA( (LPSTR) key, "Dim%uMappedToChild", iID);
      lMappedToChild = UTL_GetPrivateProfileInt( sSection, key, 0L, sFile);
      //Assert element within bounds
      if( (uint)labs(lMappedToChild ) >= MaxLength())
        throw AT_Bounds_Err( *this, key, lMappedToChild);
      }


    //If dim is constant, constant descriptors are in [Dimx]
    wsprintfA( (LPSTR) key, "Dim%uIsConstant", iID);
    if( isConstant = (bool) GetPrivateProfileIntA( (LPCSTR) sSection, (LPCSTR) key, 0, (LPCSTR) sFile))
      {
      wsprintfA( (LPSTR) key, "Dim%uLookupList", iID);
      uint iLookupList = GetPrivateProfileIntA( (LPCSTR) sSection, (LPCSTR) key, -1L, (LPCSTR) sFile);
      if( iLookupList != (uint)-1L)
        {
        //Load from lookup list
        // <appl><db>l<XX>.eng
        T_FilePath fp;
        T_FileName fn;

        wsprintfA( (LPSTR) fn, "%cl%2.2u.eng", oDatabase.Designator(), iLookupList);
        DRS_Application::DataFilePathGet( fn, fp, sizeof(T_FilePath), oDatabase.ParentAppl().INIFile() );

        //Open file
        FILE *hFile = fopen( (char *)fp, "rt");
        if( !hFile)
          throw AT_File_Open_Err( *this, (AT_String)fp);

        try {

        DRS_FileSetting sSetting;

        /* Read size from file? Nah....
        if( ! fgets( sSetting, sizeof(DRS_FileSetting), hFile) )
          throw AT_File_Read_Err( *this, (AT_String) sFile.c_str());
        */

        aaConstDescr = new DRS_DescriptorSerialize[MaxLength()];

        for( uint i = 0; i < MaxLength(); i++)
          {
          if( feof(hFile) )
            throw AT_File_Read_Err( *this, (AT_String) fp);

          sSetting[0] = 0;
          if( ! fgets( (char*)sSetting, sizeof(DRS_FileSetting), hFile) )
             {
             //Don't throw if end of file and have contents.
             if( !(feof(hFile) && std::strlen((const char*) sSetting) ) )
               throw AT_File_Read_Err( *this, (AT_String) fp);
             }
          if( std::strlen( (const char*) sSetting ) > (sizeof(DRS_FileSetting) - 5))
            {
            throw AT_Unexpected_Err;
            }
          if( ! aaConstDescr[i].Extract( sSetting))
            throw AT_File_Read_Err( *this, (AT_String) fp);
          }
        }
        catch( AT_Error &err)
          {
          fclose( hFile);
          throw;
          }
        }
      else
        {
        //Load from config file
        aaConstDescr = new DRS_DescriptorSerialize[MaxLength()];
        for( uint i = 0; i < MaxLength(); i++)
          {
          unsigned char buf[128];

          wsprintfA( (LPSTR) key, "Dim%uNodeDescr%u", iID, i);

          GetPrivateProfileStringA( (LPSTR) sSection, (LPCSTR) key, "", (LPSTR) buf, 128, (LPCSTR) sFile);

          if( ! std::strlen((const char*) buf)) throw DRSERR_MissingConfig( *this, sFile, sSection, key);

          if( ! aaConstDescr[i].Extract(buf)) throw DRSERR_MissingConfig( *this, sFile, sSection, key);
          }
        }
      }

}

DRS_Descriptor const & DRS_VectorDim::NodeDescr( DRS_Vector const &rVector, uint i) const
{

  if( i == (uint) -1L)
    {
    if( ! IsCollective()) throw AT_Logic_Err( *this, "Total requested for disparate dimension.");
    AT_Assert( pTotalDescr.get(), *this, "Total descr");
    return( *pTotalDescr);
    }

  //Skip contained total
  DRS_VectorDim const & daddy = rVector.Dim(Depth()-1);

  if(   IsCollective()
        && daddy.IsMappedToChild()
        && (i >= daddy.MappedToChild()))
             {
              ++i;
             }

  if( ! aaConstDescr.get() || ( i >= MaxLength()))
    throw AT_Bounds_Err( *this, "Constant node", i);

  return aaConstDescr[i];
}

// **************************************************************************
// DRS_Vector
// **************************************************************************
DRS_Vector::DRS_Vector(uint iVectorIDnew, DRS_Database const &rParent, byte *sFile)
                        : rDatabase( rParent),
                          iVectorID(iVectorIDnew),
                          Periods(0), iPeriodCount(0),
                          VirtualPeriods(0), iVirtualPeriodCount(0),
                          pIndexPeriods(0), iIndexPeriodCount(0),
                          iVIndexPeriodCount(0),
                          m_iDataPrecision(0),
                          m_iIndexPrecision(0),                          
                          iFormulaCount(0),
                          lDatabaseVectorAddress(0), iDatabaseVectorDepth(0)
{
  uint i;
  DRS_FileSetting sSetting;
  DRS_FileKey key, section;

  ///////////////////////////////////////////////////////
  //Read Vector Definitions stored in Vectordef 'V'
  ///////////////////////////////////////////////////////
  wsprintfA( (LPSTR) section, "Vector%i", iVectorID);

  //DRS_Vector mapping to Database vector
  if( iDatabaseVectorDepth = GetPrivateProfileIntA( (LPSTR) section, "DatabaseVectorDepth", 0, (LPCSTR) sFile))
    {
    lDatabaseVectorAddress = new uint32[iDatabaseVectorDepth];
    for( uint i = 0; i < iDatabaseVectorDepth; i++)
      {
  if( iDatabaseVectorDepth = GetPrivateProfileIntA( (LPSTR) section, "DatabaseVectorDepth", 0, (LPCSTR) sFile))
      wsprintfA( (LPSTR) key, "DatabaseVectorAddress%u", i);
      lDatabaseVectorAddress[i] = UTL_GetPrivateProfileInt( section, key, 0L, sFile);
      }
    }

  iIndexFileIDBase = GetPrivateProfileIntA( (LPCSTR) section, "IndexFileIDBase", MAX_INT, (LPCSTR) sFile);
  if( iIndexFileIDBase == MAX_INT)
    throw DRSERR_MissingConfig( *this, sFile, section, "IndexFileIDBase");

  //IF IndexFileIDBase is -1, IndexListMapLevel MUST be -1.
  if( iIndexFileIDBase < 0) iIndexListMapLevel = -1;
  else
    {
    iIndexListMapLevel = GetPrivateProfileIntA( (LPCSTR) section, "IndexListMapLevel", MAX_INT, (LPCSTR) sFile);
    if( iIndexListMapLevel == MAX_INT)
      throw DRSERR_MissingConfig( *this, sFile, section, "IndexListMapLevel");
    }

  ///////////////////////////////////////////////////////
  //Read Vector Data Precision stored in Vectordef 'V'
  ///////////////////////////////////////////////////////
  m_iDataPrecision = GetPrivateProfileIntA( (LPCSTR) section, "DatabaseVectorDataPrecision", 0, (LPCSTR) sFile);
  if (!m_iDataPrecision)
    // AV Add support for old VV parameter
    m_iDataPrecision = GetPrivateProfileIntA( (LPCSTR) section, "DatabaseVectorPrecision", 0, (LPCSTR) sFile);

  ///////////////////////////////////////////////////////
  //Read Vector Index Precision stored in Vectordef 'V'
  ///////////////////////////////////////////////////////
  m_iIndexPrecision = GetPrivateProfileIntA( (LPCSTR) section, "DatabaseVectorIndexPrecision", 0, (LPCSTR) sFile);

  ////////////////////////////////////////////////////////////////////////////////////////////////
  //Vector dimensions
  ////////////////////////////////////////////////////////////////////////////////////////////////
  //Create vector dims and add to hierarchy
  uint iDepth = GetPrivateProfileIntA( (LPCSTR) section, "Depth", -1, (LPCSTR) sFile);
  if( iDepth == (uint) -1)
    throw DRSERR_MissingConfig( *this, (AT_String) sFile, (AT_String) section, (AT_String) "Depth");
  if( (iDepth + iDatabaseVectorDepth) > (rDatabase.VectorDepth()))
    throw AT_Bounds_Err( *this, "Depth", iDepth);

  for( i = 0; i <= iDepth; i++)
    AttachDim( new DRS_VectorDim( rDatabase, section, i, sFile));

  ////////////////////////////////////////////////////////////////////////////////////////////////
  //Vector periods
  ////////////////////////////////////////////////////////////////////////////////////////////////

  //TO_DO Read period count. Vector can any number of periods <= VectorLength() of database
  Periods = new DRS_DescriptorSerialize[iPeriodCount = rDatabase.VectorLength()];
  for( i = 0; i < iPeriodCount; i++)
    {
    wsprintfA( (LPSTR) key, "Period%u", i);
    GetPrivateProfileStringA( (LPCSTR) section, (LPCSTR) key, "", (LPSTR) sSetting, sizeof(DRS_FileSetting), (LPCSTR) sFile);
    Periods[i].Extract( sSetting);
    }

  ////////////////////////////////////////////////////////////////////////////////////////////////
  //Virtual periods
  //Periods not contained in the data, but calculated, e.g. roll-ups ( Quarters)
  ////////////////////////////////////////////////////////////////////////////////////////////////
  iVirtualPeriodCount = GetPrivateProfileIntA( (LPCSTR) section, "VirtualPeriodCount", -1, (LPCSTR) sFile);
  if( iVirtualPeriodCount == (uint) -1) //Error
    throw DRSERR_MissingConfig( *this, sFile, section, "VirtualPeriodCount");

  if( iVirtualPeriodCount)
    {
    //byte key[32];
    //byte buf[128];

    VirtualPeriods = new DRS_VirtualPeriod[iVirtualPeriodCount];
    for( i = 0; i < iVirtualPeriodCount; i++)
      {
      wsprintfA( (LPSTR) key, "VirtualPeriod%u", i);
      GetPrivateProfileStringA( (LPCSTR) section, (LPCSTR) key, "", (LPSTR) sSetting, sizeof(DRS_FileSetting), (LPCSTR) sFile);
      VirtualPeriods[i].Descriptor.Extract( sSetting);

      wsprintfA( (LPSTR) key, "VirtualPeriodDef%u", i);
      GetPrivateProfileStringA( (LPCSTR) section, (LPCSTR) key, "", (LPSTR) sSetting, sizeof(DRS_FileSetting), (LPCSTR) sFile);
      VirtualPeriods[i].PeriodDef.Extract( sSetting);
      }
    }

  ////////////////////////////////////////////////////////////////////////////////////////////////
  //Index periods
  //IFF not all data periods are indexed.
  ////////////////////////////////////////////////////////////////////////////////////////////////
  iIndexPeriodCount = GetPrivateProfileIntA( (LPCSTR) section, "IndexPeriodCount", 0, (LPCSTR) sFile);
  iVIndexPeriodCount = 0;
  if( iIndexPeriodCount)
    {
    pIndexPeriods = new uint[iIndexPeriodCount];
    for( i = 0; i < iIndexPeriodCount; i++)
      {
      wsprintfA( (LPSTR) key, "IndexPeriod%u", i);
      if( (pIndexPeriods[i] = GetPrivateProfileIntA( (LPCSTR) section, (LPCSTR) key, MAX_UINT, (LPCSTR) sFile)) == MAX_UINT)
        throw DRSERR_MissingConfig( *this, sFile, section, key);
      if( pIndexPeriods[i] >= iPeriodCount + iVirtualPeriodCount)
        throw AT_Bounds_Err( *this, key, pIndexPeriods[i]);
      if(pIndexPeriods[i] >= iPeriodCount)
          ++iVIndexPeriodCount;
      }
    }

  ////////////////////////////////////////////////////////////////////////////////////////////////
  //DRS_VectorNodes
  //Read [VectorDescription<x>] and create DRS_VectorNode hierarchy
  ////////////////////////////////////////////////////////////////////////////////////////////////
  //Create vector nodes and attach to hierarchy
  FILE *hVFile = fopen( (char*)sFile, "rt");
  if( !hVFile)
    throw AT_File_Open_Err( *this, (AT_String)sFile);

  //Skip to start of node descriptors
  wsprintfA( (LPSTR) section, "[VectorDescription%i]", iVectorID);
  while( !feof(hVFile) && fgets( (char*)sSetting, sizeof(DRS_FileSetting), hVFile) && memcmp( (void*)sSetting, (void*) section, std::strlen((const char*) section)));
  if( feof(hVFile)) //Error
    {
    fclose(hVFile);
    throw DRSERR_MissingConfig( *this, sFile, section, 0);
    }

  bool isDone  = false;
  while( !isDone)
    {
    //read til fail : AT_Contructor_Err
    try
      {
      DRS_VectorNodeReader NewNode(hVFile);
      if (!NewNode)
        isDone = true;
      else
        AttachNode( new DRS_VectorNode( NewNode), NewNode.Dim());
      }
    catch( AT_Error &err)
      {
      //clean up and rethrow
      fclose(hVFile);
      throw;
      }
    }
  fclose(hVFile);

  ////////////////////////////////////////////////////////////////////////////////////////////////
  //Vector formulas & quantiles
  //NOTE: these MUST be loaded LAST. Depends on vector dims and periods.
  ////////////////////////////////////////////////////////////////////////////////////////////////
  wsprintfA( (LPSTR) section, "Vector%i", iVectorID);

  iIndexStateCount = GetPrivateProfileIntA( (LPCSTR) section, "IndexStateCount", 0, (LPCSTR) sFile);
  //For now, create blank state if no states.
  //TO_DO: 0 states means not indexed.
  if( !iIndexStateCount)
    {
    //Create blank index state: vector val
    ++iIndexStateCount;
    aaIndexStates = new auto_ptr< DRS_VectorIndexState>[iIndexStateCount];
    aaIndexStates[0].reset( new DRS_VectorIndexState());
    }
  else
    {
    aaIndexStates = new auto_ptr< DRS_VectorIndexState>[iIndexStateCount];
    for( i = 0; i < iIndexStateCount; i++)
      {
      DRS_Setting oSetting( "IndexState");
      oSetting += i;
      aaIndexStates[i].reset( new DRS_VectorIndexState( sFile, section, oSetting));
      }
    }
  //Quantile count
  iQuantileCount = GetPrivateProfileIntA( (LPCSTR) section, "QuantileCount", 0, (LPCSTR) sFile);
  if( iQuantileCount)
    {
    aaQuantiles = new auto_ptr<DRS_VectorQuantile> [iQuantileCount];
    for( i = 0; i < iQuantileCount; i++)
      {
      DRS_Setting setting = "Quantile";
      setting += i;
      aaQuantiles[i].reset( new DRS_VectorQuantile( sFile, section, setting));
      if( aaQuantiles[i].get()->State() >= iIndexStateCount)
        throw AT_Bounds_Err( *this, "QuantileState", aaQuantiles[i].get()->State());
      }
    }

  iFormulaCount = GetPrivateProfileIntA( (LPCSTR) section, "FormulaCount", 0, (LPCSTR) sFile);
  //aaFormulas = new auto_ptr<DRS_Formula> [max( 1U, iFormulaCount)];
  aaFormulas = new DRS_Formula* [max( 1U, iFormulaCount)];
  if( iFormulaCount == 0) //If no formulas, default to single vector val formula
  {
    //auto_ptr<DRS_Formula> p(new DRS_Formula( *this));
    //aaFormulas[0] = p; //Creates VectorVal root node.
    aaFormulas[0] = new DRS_Formula( *this);
    iFormulaCount = 1;
  }
  else
  {
    uint invalidCnt = 0;
    for( i = 0; i < iFormulaCount; i++)
    {
      //auto_ptr<DRS_Formula> p(new DRS_Formula( *this, i, section, sFile));
      //aaFormulas[i] = p;
      DRS_Formula *p = new DRS_Formula( *this, i, section, sFile);
      if (p->isValid())
        aaFormulas[i - invalidCnt] = p;
      else
        ++invalidCnt;
    }

    iFormulaCount -= invalidCnt;
  }
}

DRS_Vector::~DRS_Vector()
{
  for (uint f = 0; f < iFormulaCount; ++f)
    delete aaFormulas[f];
  delete [] aaFormulas;
  
  delete [] pIndexPeriods;
  delete [] Periods;
  delete [] VirtualPeriods;
}

DRS_Descriptor const &  DRS_Vector::NodeDescr( uint32 *addrNode, uint iDepth) const
{
  //if collective and -1, return "Total"
  //Else get node's descr.

  if( ! iDepth) return Node( 0, addrNode).Descriptor();

  if( Dim(iDepth).IsConstant() || (addrNode[iDepth - 1] == NODE_SUM) )
    {
    return( Dim(iDepth).NodeDescr( *this, addrNode[iDepth - 1]));
    }
  else
    {
    //Skip contained total
    DRS_VectorDim const & me = Dim(iDepth);
    DRS_VectorDim const & daddy = Dim(iDepth-1);

    if(    me.IsCollective()
        && daddy.IsMappedToChild()
        && (addrNode[iDepth - 1] >= daddy.MappedToChild()))
             {
              ++addrNode[iDepth - 1];
              DRS_Descriptor const &d = Node( iDepth, addrNode).Descriptor();
              --addrNode[iDepth - 1];
              return d;
             }
    else
      return Node( iDepth, addrNode).Descriptor();
    }
}

uint DRS_Vector::NodeCount( uint iDepth, VectorAddress *addrVector, bool isIncludeTotal) const
{
  if( iDepth == 0) return(1);

  DRS_VectorDim const &dim = Dim(iDepth);

  if( dim.IsConstant())
    //return no total contained in data
    return ! isIncludeTotal && dim.IsCollective() && Dim(iDepth - 1).IsMappedToChild() ?

                  dim.MaxLength() - 1 :
                  dim.MaxLength();

  else
    {
    //return no total contained in data
    AT_Assert( Node( iDepth - 1, (uint32*) addrVector).ChildCount(), *this, "NodeCount")
    return ! isIncludeTotal && dim.IsCollective() && Dim(iDepth - 1).IsMappedToChild() ?

      Node( iDepth - 1, (uint32*) addrVector).ChildCount() - 1 :
      Node( iDepth - 1, (uint32*) addrVector).ChildCount();
    }
}

void DRS_VectorDim::NextDim( DRS_Vector const &rVector,
                              VectorAddress addrSelector[],
                              VectorAddress addrVector[],
                              AT_Record const *pRecord,
                              DRS_VectorData *pDestVector,
                              bool *pIsAvail ) const
{

        if( GetChild() )
          {
          //Node
          GetChild()->GetData( rVector, addrSelector, addrVector, pRecord, pDestVector, pIsAvail );
          }
        else
          {
          //Leaf
          rVector.GetData( pRecord, (uint32*) addrVector, pDestVector, pIsAvail);
          }
}
void DRS_VectorDim::BumpDim( DRS_Vector const &rVector, VectorAddress addrVector[]) const
{
  AT_Assert( Depth(), *this, "Bump0");

  if( addrVector[Depth() - 1] == NODE_SUM) return;

      if(    IsCollective()
          && rVector.Dim(Depth()-1).IsMappedToChild()
          && (addrVector[Depth()-1] >= rVector.Dim(Depth()-1).MappedToChild()))

              ++addrVector[Depth() - 1];
}
void DRS_VectorDim::UnbumpDim( DRS_Vector const &rVector, VectorAddress addrVector[]) const
{
  AT_Assert( Depth(), *this, "UnbumpDim0");

  if( addrVector[Depth() - 1] == NODE_SUM) return;

      if(    IsCollective()
          && rVector.Dim(Depth()-1).IsMappedToChild()
          && (addrVector[Depth()-1] >= rVector.Dim(Depth()-1).MappedToChild()))

              --addrVector[Depth() - 1];
}

void DRS_VectorDim::GetData(  DRS_Vector const &rVector,
                              VectorAddress addrSelector[],
                              VectorAddress addrVector[],
                              AT_Record const *pRecord,
                              DRS_VectorData *pDestVector,
                              bool *pIsAvail ) const
{
  //No root.
  AT_Assert( Dim(), *this, "GetData()");

  uint iDim = Dim();
  if( addrSelector[iDim - 1] == NODE_SUM)
    {
    AT_Assert( IsCollective(), *this, "Sum requested for disparate dim.");

    //if mapped to child get sibling.
    if( rVector.Dim(iDim-1).IsMappedToChild() )
      {
      addrVector[iDim-1] = rVector.Dim(iDim-1).MappedToChild();
      NextDim( rVector, addrSelector, addrVector, pRecord, pDestVector, pIsAvail );
      }
    else
      {
      //Sum nodes
      uint iNodeCount = rVector.NodeCount( iDim, addrVector); //, true);
      for( uint i = 0; i < iNodeCount; i++)
        {
        addrVector[iDim-1] = i;
        BumpDim( rVector, addrVector);
        NextDim( rVector, addrSelector, addrVector, pRecord, pDestVector, pIsAvail );
        }
      }

    }
  else
    {
      addrVector[iDim-1] = addrSelector[iDim -1];

      //Bump sum held in data
      BumpDim( rVector, addrVector);

      NextDim( rVector, addrSelector, addrVector, pRecord, pDestVector, pIsAvail );

      UnbumpDim( rVector, addrVector);
    }
}

// get database vector address
inline void  DRS_Vector::SetVectorIds( uint32 *IDs, const uint32 *addrVector) const
{
  uint addrEnd = iDatabaseVectorDepth + Depth();
  AT_Assert( addrEnd <= rDatabase.VectorDepth(), *this, "Address under/overflow." );

  memcpy( &IDs[0], lDatabaseVectorAddress.get(), iDatabaseVectorDepth * sizeof(uint32));
  memcpy( &IDs[iDatabaseVectorDepth], addrVector, Depth() * sizeof(uint32));
  memset( &IDs[addrEnd], 0, (rDatabase.VectorDepth() - addrEnd) * sizeof(uint32));
}

//To get data, leaf dim calls vector.
//Vector calls dim an passes at-record.
//Dim at leaf calls vector with AT_Record.
//Sums contents to dest
void DRS_Vector::GetData( AT_Record const *pRecord,
                          uint32* addrVector,
                          DRS_VectorData* pSumDest,
                          bool *pIsAvail)
                        const
{
  DRS_VectorData Dest( *this);

  auto_array<uint32> IDs( new uint32[rDatabase.VectorDepth()]);
  SetVectorIds(IDs.get(), addrVector);

  //Load vector and compute Virtual elements.                       //iVectorType
  if( Dest.LoadFromATVector( pRecord, IDs.get()))
    //Not avail, do nothing
    {
    if( pIsAvail) *pIsAvail = true;
    ( *pSumDest) += Dest;
    }

}

//Gets vector by selector. -1 total else child excluding total
void DRS_Vector::GetData( DRS_RecordSet *pRecordSet,
                          uint32* addrSelector,
                          DRS_VectorData *pDestVector,
                          bool *pIsAvail)
                        const
{

  /***************************************************************************
  A DRS_Vector is attached at a node of the parent database's vector.
  The AT_Database has one and only one vector (PS).
  A vector stores it's address in the parent database's vector as its
  lParentVectorIDs[].
  When requesting a vector from the AT_Database (through a DRS_Record), it must
  map in its address within the parent database.
  ***************************************************************************/
  //lDatabaseVectorAddress[];
  //iDatabaseVectorDepth;

  if( pIsAvail) *pIsAvail = false;

  if( ! Depth()) //No address, so go strigth to data
    {
    GetData( pRecordSet->Record( rDatabase.ID()), addrSelector, pDestVector, pIsAvail);
    return;
    }

  //Allocate traversal address.
  uint32 * addrVector = new uint32[Depth()];
  memcpy( addrVector, addrSelector, Depth() * sizeof(uint32));

  pDestVector->Clear();

  //Dim processes address recursively, adds
  Dim(1).GetData( *this, (VectorAddress*) addrSelector, (VectorAddress*) addrVector, pRecordSet->Record( rDatabase.ID()), pDestVector, pIsAvail);


  delete [] addrVector;
}

//Get ordinal occurence, assuming this vector
void DRS_Vector::GetData( DRS_RecordSet *pRecord, uint iOccurrence, DRS_VectorData *pData) const
{
  pData->LoadFromATVector( pRecord->Record( rDatabase.ID()), (uint32) iOccurrence);
}

DRS_VectorQuantile const & DRS_Vector::VectorQuantile( uint iQuantileID) const
{
  if( iQuantileID >= iQuantileCount) throw AT_Bounds_Err( *this, "VectorQuantile", iQuantileID);
  return *(aaQuantiles[iQuantileID].get());
}

DRS_Descriptor const & DRS_Vector::Period( uint iPeriod) const
{
  if( iPeriod >= iPeriodCount + iVirtualPeriodCount) throw AT_Bounds_Err( *this, "Period", iPeriod);
  if( iPeriod >= iPeriodCount) return( VirtualPeriods[iPeriod-iPeriodCount].Descriptor);
  else return( Periods[iPeriod].Descriptor());
}

DRS_Descriptor const & DRS_Vector::IndexPeriod( uint iPeriod) const
{
  if( iPeriod >= (iIndexPeriodCount ? iIndexPeriodCount : iPeriodCount + iVirtualPeriodCount)) throw AT_Bounds_Err( *this, "Index period", iPeriod);

  if( iIndexPeriodCount) iPeriod = pIndexPeriods[iPeriod];

  if( iPeriod >= iPeriodCount) return( VirtualPeriods[iPeriod-iPeriodCount].Descriptor);
  else return( Periods[iPeriod].Descriptor());
}

DRS_Descriptor const & DRS_Vector::VirtualPeriod( uint iPeriod) const
{
  if( iPeriod >= VirtualPeriodCount()) throw AT_Bounds_Err( *this, "Virtual Period", iPeriod);
  return( VirtualPeriods[iPeriod].Descriptor);
}

DRS_Descriptor const & DRS_Vector::VirtualIndexPeriod( uint iPeriod) const
{
  if( iPeriod >= VirtualIndexPeriodCount()) throw AT_Bounds_Err( *this, "Virtual Index period", iPeriod);

  if( iIndexPeriodCount)
    {
    uint offset = iIndexPeriodCount - VirtualIndexPeriodCount();
    iPeriod = pIndexPeriods[offset + iPeriod];
    if( iPeriod < iPeriodCount) throw AT_Bounds_Err( *this, "Virtual Index period. Data Period", iPeriod);
    iPeriod -= iPeriodCount;
    }
    
return VirtualPeriods[iPeriod].Descriptor;
}

uint DRS_Vector::IndexPeriodToDataPeriod( uint iIndexPeriod) const
{
  if( iIndexPeriodCount)
    {
    if( iIndexPeriod >= iIndexPeriodCount) throw AT_Bounds_Err( *this, "Index period", iIndexPeriod);
    return(pIndexPeriods[iIndexPeriod]);
    }
  else
    return iIndexPeriod;
}

uint DRS_Vector::DataPeriodToIndexPeriod( uint iDataPeriod) const
{
  if( iIndexPeriodCount)
    {
    for( uint i = 0; i < iIndexPeriodCount; ++i)
      if( pIndexPeriods[i] == iDataPeriod)
        return(i);
    return MAX_UINT; //No match
    }
  else
    return iDataPeriod;

}

DRS_Descriptor const & DRS_Vector::IndexStateDescr( uint iState) const
{
  //A vector presents both states and quantiles as states.

  if( iState >= (iIndexStateCount + iQuantileCount)) throw AT_Bounds_Err( *this, (AT_String)"Index State", iState);

  if( iState >= iIndexStateCount)
    {
    iState -= iIndexStateCount;
    return aaQuantiles[iState].get()->Descriptor();
    }
  return aaIndexStates[iState].get()->Descriptor();
}

DRS_Formula const & DRS_Vector::Formula( uint iFormula) const
{
  if( iFormula >= iFormulaCount) throw AT_Bounds_Err( *this, (AT_String)"Formula", iFormula);
  //return( *aaFormulas[iFormula].get());
  return( *aaFormulas[iFormula]);
}

const uint32 * DRS_Vector::IndexAddress(uint32 addrVector[]) const
{
  static std::vector<uint32> addr(Depth());
  if(addr.size() < Depth())
    addr.resize(Depth());

  memcpy( (void*) &addr.front(), addrVector, Depth() * sizeof( uint32));

  //Convert -1's to addressable item
  for( uint i = 1; i <= Depth(); i++)
    {
    if( addr[i-1] == NODE_SUM)
      {
      AT_Assert( Dim(i).IsCollective(), *this, "Total requested for disparate dim.");

      //
      if( Dim(i-1).IsMappedToChild() )
        addr[i-1] = Dim(i-1).MappedToChild();
      else
        //OOPS! If we're not mapped to child, we still need to know where the index is!
        //We'll assume that total is always 0.
        addr[i-1] = 0L;
      }
    else
      Dim(i).BumpDim( *this, (VectorAddress*) &addr.front());

    AT_Assert( !(addr[i-1] == (uint32)-1L), *this, "Total requested for disparate dim.");
    }

  return &addr.front();
}

DRS_Index * DRS_Vector::IndexOpen( uint32 addrVector[], uint iVectorState, uint iPeriod, uint prefPrec) const
{
  const uint32 * addr = IndexAddress( addrVector);
  DRS_Database * db = (DRS_Database *)&ParentDatabase();
  
  if( iVectorState >= iIndexStateCount)
    {
    iVectorState -= iIndexStateCount; //iVectorState becomes QuantileID.
    if( iVectorState >= iQuantileCount)
      throw AT_Bounds_Err( *this, "Quantile", iVectorState);
    int iIndexFileID = IndexFileID(addr);

    uint indexID = IndexID( addr, VectorQuantile(iVectorState).State(), iPeriod);

    std::auto_ptr<DRS_IntegerIndex> idx;
    // rounded quantiles
    if (VectorQuantile(iVectorState).Precision() < m_iIndexPrecision)
      idx.reset(new DRS_RoundIndex( db->IndexOpen( iVectorID, iIndexFileID, indexID),
                                    DRS_IndexDefInteger( Normal(VectorQuantile(iVectorState).State()),
                                                         0,                           //Width
                                                         m_iIndexPrecision),          //Index Precision
                                    VectorQuantile(iVectorState).Precision()));
    else
      idx.reset(new DRS_IntegerIndex(db->IndexOpen( iVectorID, iIndexFileID, indexID),
                                     DRS_IndexDefInteger( Normal(VectorQuantile(iVectorState).State()),
                                                          0,                           //Width
                                                          m_iIndexPrecision)));

    return new DRS_QuantileIndex(*idx,
                                 *idx, 
                                 db->Quantile( iIndexFileID, iVectorState),
                                 indexID);
    }


  //IMS: Vector indexes have 0s stored.
  //#define IMS_KLUDGE
  #ifdef IMS_KLUDGE
  return new DRS_IntegerIndex( db->IndexOpen( iVectorID, IndexFileID(addr),
                                                    IndexID( addr, iVectorState, iPeriod)),
                               DRS_IndexDefInteger( Normal(iVectorState),
                                                    0,                          //Width
                                                    m_iPrecision));             //Precision
  #else
  if (prefPrec < m_iIndexPrecision)
    return new DRS_RoundIndex( db->IndexOpen( iVectorID, IndexFileID(addr),
                                                    IndexID( addr, iVectorState, iPeriod)),
                                 DRS_IndexDefInteger( Normal(iVectorState),
                                                      0,                           //Width
                                                      m_iIndexPrecision),          //Index Precision
                                 prefPrec);                                        //Preffered Precision

  else
    return new DRS_IntegerIndex( db->IndexOpen( iVectorID, IndexFileID(addr),
                                                      IndexID( addr, iVectorState, iPeriod)),
                                 DRS_IndexDefInteger( Normal(iVectorState),
                                                      0,                           //Width
                                                      m_iIndexPrecision));         //Precision
  #endif
}

int DRS_Vector::IndexFileID( const uint32 VectorAddress[]) const
{
  if( iIndexFileIDBase == -1) return iIndexFileIDBase;

  int iIndexFileID = iIndexFileIDBase;
  if( iIndexListMapLevel > 0)
    {
    //Calculate index files preceding requested node.
    uint iIndexListOffset = 0;
    for( int iLevel = 1; iLevel < iIndexListMapLevel; ++iLevel)
      {
      uint iIndexFilesPerLevel = 1;
      for( int j = iLevel + 1; j <= iIndexListMapLevel; ++j)
        iIndexFilesPerLevel *= Dim(j).MaxLength();
      iIndexListOffset += VectorAddress[iLevel-1] * iIndexFilesPerLevel;
      }
    iIndexFileID += (iIndexListOffset + VectorAddress[ iIndexListMapLevel-1]);
    }
  return iIndexFileID;
}

uint DRS_Vector::IndexID( const uint32 addrVector[], uint iState, uint iPeriod) const
{
  if( iState >= iIndexStateCount) throw AT_Bounds_Err( *this, "State", iState);

  uint ttl_periods = iIndexPeriodCount ? iIndexPeriodCount : iPeriodCount + iVirtualPeriodCount;

  uint indexes_per_leaf = max(1U, iIndexStateCount) * ttl_periods;
  uint iDimCount = DimCount();

  //Preceding leafs
  uint lIndexID = 0;
  for( int i = iDimCount - 2; i >= (iIndexListMapLevel >= 0 ? iIndexListMapLevel : 0); --i)
    {
    uint32 idx_count_per_dim;
    idx_count_per_dim = indexes_per_leaf;
    for( uint j = i + 1; j <= iDimCount - 2; ++j)
      idx_count_per_dim *= Dim(j+1).MaxLength();
    lIndexID += addrVector[i] * idx_count_per_dim;
    }

  //Add current leaf offsets
  lIndexID += ( iState * ttl_periods);
  lIndexID += iPeriod;

  return lIndexID;
}

uint DRS_Vector::IndexFileCount() const
{
  //Adds IndexListIDs OR IndexIDs as appropriate

  if( iIndexListMapLevel < 0) return 0;

  int iIndexFileCount = 1;
  for( int i = 0; i <= iIndexListMapLevel; i++)
    iIndexFileCount *= Dim(i).MaxLength();

  return iIndexFileCount;
}

uint DRS_Vector::IndexCount() const
{
    uint iCount = (iIndexPeriodCount ? iIndexPeriodCount : iPeriodCount + iVirtualPeriodCount) * max( 1U, iIndexStateCount);
    for( uint i = DimCount() - 1; i > 0; --i)
      iCount *= Dim(i).MaxLength();

    return iCount;
}

int /*_USERENTRY*/ comp_uint( const void *elem1, const void *elem2)
{
  return ( (int)(* (uint *) elem1 - * (uint *) elem2));
}

//Get address of vector for ordinal vector occurrence: Reports
void DRS_Vector::GetVectorAddress( DRS_RecordSet & oRecord, uint iRecordVector, uint32 *addrVector) const
{
  auto_array<uint32> addrDBVector( new uint32[rDatabase.VectorDepth()]);

  oRecord.Record( rDatabase.ID())->getVector( 0, addrDBVector.get(), iRecordVector);


  //ASSUMED that this ordinal vector is an occurrence from this vector.
  memcpy( &addrVector[0], &addrDBVector[iDatabaseVectorDepth], Depth() * sizeof(uint));

}

void DRS_Vector::VectorOccurrences( DRS_RecordSet & oRecordSet,
                                    std::vector<uint> * pvOccs,
                                    VectorAddress const addrVector[]) const
{

  //Get occurrences (ordinal vector numbers in record) and cycle occurrences, adding nodes.
  auto_array<uint32> addrDBVector( new uint32[rDatabase.VectorDepth()]);

  SetVectorIds(addrDBVector.get(), (uint32*) addrVector);

  uint pOccurrences[100];

  AT_Record const *pRec = oRecordSet.Record( rDatabase.ID());

  uint count;
  uint start = 0;
  for( ; count = pRec->getVectorList( pOccurrences, start, 100, (uint *) addrDBVector.get()); start += count)
    {
    for( uint i = 0; i < count; i++)
      pvOccs->push_back( pOccurrences[i]);
    if( count < 100) break;
    }

}

void DRS_Vector::NodeOccurrences( DRS_RecordSet *pRecordSet,
                                  uint32 addr[],
                                  uint16 iDepth,
                                  bool isUnique,
                                  std::vector<uint> *pOccs) const
{
  auto_array<uint32> addrDBVector( new uint32[rDatabase.VectorDepth()]);

  SetVectorIds(addrDBVector.get(), addr);

  static std::vector<uint> vnos;
  AT_Record const *pRec = pRecordSet->Record( rDatabase.ID());

  uint arrnos[100];
  uint count;
  uint start = 0;
  for( ; count = pRec->getVectorList( arrnos, start, 100, (uint *) addrDBVector.get()); start += count)
    {
    for( uint i = 0; i < count; i++)
      if( start + i >= vnos.size())
        vnos.push_back( arrnos[i]);
      else
        vnos[start + i] = arrnos[i];

    if( count < 100)
      {
      count += start;
      break;
      }
    }
  if( count >= vnos.size())
    vnos.push_back( MAXUINT);
  else
    vnos[count] = MAXUINT;

  //vnos is vector of ordinal vector numbers.
  //Get each address and pull node ids.
  std::vector<uint> vAdds;
  for( std::vector<uint>::const_iterator iter = vnos.begin(); (iter < vnos.end()) && (uint32) *iter != MAXUINT; iter++)
    {
    pRec->getVector( 0, addrDBVector.get(), (uint32) *iter);
    //If collective, total contained, and this is total, ignore.
    if( ! ( Dim(iDepth).IsCollective() &&
            Dim(iDepth-1).IsMappedToChild() &&
            ( addrDBVector[iDatabaseVectorDepth + iDepth - 1] == Dim(iDepth-1).MappedToChild() ) ) )
      vAdds.push_back(addrDBVector[iDatabaseVectorDepth + iDepth - 1]);
    }

  //sort && deduplicate.
  //Ordering of IDs is NOT guaranteed.
  auto_array<uint> arrNodes( new uint[vAdds.size()]);
  for( uint i = 0; i < vAdds.size(); i++)
    if( Dim(iDepth).IsCollective() &&
        Dim(iDepth-1).IsMappedToChild() )
      arrNodes[i] = vAdds[i] - 1;
    else
      arrNodes[i] = vAdds[i];
      
  qsort( arrNodes.get(), vAdds.size(), sizeof( uint), comp_uint );

  for( uint i = 0; i < vAdds.size(); i++)
    {
    if( !i || ( arrNodes[i] != arrNodes[i-1] ) )
      pOccs->push_back(arrNodes[i]);
    }
}

uint DRS_Vector::Normal(uint state) const
{
    return state < iIndexStateCount ?
                            aaIndexStates[state]->Normal() : 0;
}

uint DRS_Vector::GetDataSize() const
{
    return DRS_VectorData::GetDataSize();
}

uint DRS_Vector::GetDataTextSize() const
{
    return DRS_VectorData::GetDataTextSize();
}


