/*!
  @file           Converter_BackUpPageNoContainer.hpp
  @author         TorstenS
  @author         AlexanderK
  @ingroup        Converter
  @brief          Container which holds all page numbers that belong
                  to a back up
*/

/*
    ========== licence begin  GPL
    Copyright (c) 2001-2005 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    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.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end

*/

#ifndef CONVERTER_BACKUPPAGENOCONTAINER_HPP
#define CONVERTER_BACKUPPAGENOCONTAINER_HPP

/*===========================================================================*
 *  INCLUDES                                                                 *
 **/

#include "DataAccess/Data_Types.hpp"
#include "Converter/Converter_Types.hpp"
#include "Container/Container_Vector.hpp"
#include "Converter/Converter_FlagInfo.hpp"
#include "RunTime/Synchronisation/RTESync_InterlockedCounter.hpp"

/*!
  @class Converter_BackUpPageNoContainer
  @brief          Container which holds all page numbers that belong
                  to a back up
 */

typedef Container_Vector<Converter_FlagInfo::FlagInfoData>      FlagInfoBlocks;

// size of allocation unit: 8kb
#define ALLOCATE_SIZE (1024*8)

class Converter_BackUpPageNoContainer
{

public:

    /*!
    @brief          Deletes container structures; deallocates memory
    @return         none
    */
    void Delete()
    {
        m_FlagInfoBlockAnchorList.Delete();
        while (m_FlagInfoBlocksContainer.GetSize() != 0)
        {
            destroy(m_FlagInfoBlocksContainer[0], m_Allocator);
            m_FlagInfoBlocksContainer.DeleteFront();
        }
        m_FlagInfoBlocksContainer.Delete();
        m_NumUsedFlagInfoBlocks = 0;
        m_NumUsedFlagInfoBlocks = 0;
        m_NumFlagInfoBlocks     = 0;
        m_PageNoCount           = 0;
    }

    /*!
       @brief          Constructor
       @param          Allocator [in] allocator for container resources
       @return         none
    */
    Converter_BackUpPageNoContainer  (SAPDBMem_IRawAllocator&  Allocator)
    :
    m_FlagInfoBlockAnchorList( Allocator ),
    m_FlagInfoBlocksContainer( Allocator ),
    m_Allocator( Allocator )
    {
        Delete();
    }


    /*!
       @brief          Initializes container
       @param          MaxPageNo [in] maximum page number to be stored in the container
       @param          NumFlagInfoBlocks [in]
       @param          NumPageNosPerFlagInfoBlock [in]
       @return         (Converter_ReturnCode) if the memory for the container cannot be allocated
                       the value Converter_MemoryAllocationFailed is returned
                       otherwise Converter_Ok
     */
    Converter_ReturnCode  Initialize (SAPDB_UInt  MaxPageNo,
                                      SAPDB_UInt  NumFlagInfoBlocks,
                                      SAPDB_UInt  NumPageNosPerFlagInfoBlock);

    /*!
    @brief          inserts a page number into the container
    @param          PageNo [in] page number to insert
    @return         (Converter_ReturnCode)  in case the page number is already included
                    the value Converter_DuplicatePageNo is returned otherwise Converter_Ok.

    */
    Converter_ReturnCode Insert( const Data_PageNo  PageNo);

    /*!
    @brief          Checks whether container is empty
    @return         (SAPDB_Bool) true if empty
    */
    SAPDB_Bool IsEmpty() const
    {
        return m_PageNoCount == 0;
    }

    /*!
    @brief          Returns total number of pagenos stored in container
    @return         (SAPDB_UInt) number of pagenos stored in container
    */
    SAPDB_UInt GetPageNoCount() const
    {
        return m_PageNoCount;
    }

    /*!
    @brief          Removes a page number from the container
    @param          PageNo [in] page number to be removed
    @return         (SAPDB_Bool) true if pageno found in container and removed
    */

    SAPDB_Bool Remove ( const Data_PageNo  PageNo);

private: // methods

    /*!
    @brief  Checks whether container is initialized
    @return (SAPDB_Bool) true if initialized
    */
    SAPDB_Bool IsInitialized() const
    {
        return (m_FlagInfoBlockAnchorList.GetSize() > 0) && (m_FlagInfoBlocksContainer.GetSize() > 0) ;
    }
    /*!
           @brief  Calculates the number of the FlagInfoBlock the pageNo belongs too.
                   No validity check is executed!
           @param  pageNo [in] page number to be used for calculation
           @return  (SAPDB_UInt) blockNo
       */

    SAPDB_UInt CalculateFlagInfoBlockNo( const Data_PageNo  pageNo ) const{
        return pageNo/m_NumPageNosPerFlagInfoBlock;
    }
    /*!
        @brief  Calculates the offset in a given FlagInfoBlock, identified
                by the flagInfoBlockNo. No validity check is executed!
        @param  pageNo          [in] page number to be used for calculation
        @param  flagInfoBlockNo [in] identifier of the FlagInfoBlock
        @return (SAPDB_UInt) blockNo
    */

    SAPDB_UInt CalculateFlagInfoBlockOffset(
        const Data_PageNo  pageNo,
        const SAPDB_UInt   flagInfoBlockNo ) const
    {
        return pageNo - flagInfoBlockNo * m_NumPageNosPerFlagInfoBlock;
    }

    SAPDB_UInt CalculateNumFlagInfoContainer(
        const SAPDB_UInt  numFlagInfoBlocks,
        const SAPDB_UInt  sizeOfFlagInfoBlock,
              SAPDB_UInt &blocksPerContainer)
    {
        blocksPerContainer = ALLOCATE_SIZE / (sizeOfFlagInfoBlock * sizeof (Converter_FlagInfo::FlagInfoData));
        if (0 == numFlagInfoBlocks)
        {
            return 0;
        }
        else
        { 
            return (numFlagInfoBlocks - 1) / blocksPerContainer + 1;
        }
    }


private: // members

    /// ...
    Container_Vector<Converter_FlagInfo::FlagInfoData *>    m_FlagInfoBlockAnchorList;
    /// ...
    Container_Vector<FlagInfoBlocks*>                       m_FlagInfoBlocksContainer;
    /// ...
    RTESync_InterlockedCounter<SAPDB_UInt>                  m_PageNoCount;
    /// ...
    SAPDB_UInt                                              m_NumUsedFlagInfoBlocks;
    /// ...
    SAPDB_UInt                                              m_NumFlagInfoBlocks;
    /// ...
    SAPDB_UInt                                              m_NumPageNosPerFlagInfoBlock;
    /// ...
    SAPDB_UInt                                              m_SizeOfFlagInfoBlock;

    /// memory allocation for all FlagInfoBlocks is split into
    /// containers with n FlagInfoBlocks per container to fit the ALLOCATE_SIZE
    SAPDB_UInt  m_BlocksPerContainer;
    
    /// number of FlagInfoBlock container
    SAPDB_UInt  m_NumBlockContainer;

    /// allocator
    SAPDBMem_IRawAllocator &m_Allocator;
};





#endif  /* CONVERTER_BACKUPPAGENOCONTAINER_HPP */

