/****************************************************************************

  module      : Converter_BackUpPageNoContainer.cpp

  -------------------------------------------------------------------------

  responsible : TorstenS

  author:       AlxanderK

  special area: Converter

  description : see .hpp

  see also    :

  copyright:    (c) 2001-2004 SAP AG

  -------------------------------------------------------------------------

    ========== 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


*****************************************************************************/


/*===========================================================================*
 *  MACROS                                                                   *
 *===========================================================================*/

#define ALIGN(LEN) (((((LEN) - 1) >> 1) + 1 ) << 1)

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

#include "Converter/Converter_BackUpPageNoContainer.hpp"
#include "Converter/Converter_Exception.hpp"
#include "Converter/Converter_Messages.hpp"
#include "RunTime/RTE_Message.hpp"

/*===========================================================================*
 *  METHODS OF THE BackUpPageNoContainer CLASS                                           *
 *===========================================================================*/

Converter_ReturnCode
Converter_BackUpPageNoContainer::Insert( const Data_PageNo    PageNo )
{
    /* check current state of the container */
    SAPDBERR_ASSERT_STATE (IsInitialized());

    /* find the flag info which contains the flag to switch on for the given page number */
    const SAPDB_UInt FlagInfoBlockNo = CalculateFlagInfoBlockNo( PageNo );
    const SAPDB_UInt BlockOffset     = CalculateFlagInfoBlockOffset( PageNo, FlagInfoBlockNo );

    Converter_FlagInfo::FlagInfoData *  FlagInfoBlockPtr =  m_FlagInfoBlockAnchorList[FlagInfoBlockNo];

    if (NULL == FlagInfoBlockPtr)
    {
        SAPDBERR_ASSERT_STATE (m_NumUsedFlagInfoBlocks < m_NumFlagInfoBlocks)

        SAPDB_UInt container = m_NumUsedFlagInfoBlocks / m_BlocksPerContainer;
        SAPDB_UInt containerOffset = m_NumUsedFlagInfoBlocks - (container * m_BlocksPerContainer);
        FlagInfoBlockPtr = &((*m_FlagInfoBlocksContainer[ container ])[containerOffset * m_SizeOfFlagInfoBlock ]);
        ++m_NumUsedFlagInfoBlocks;
        m_FlagInfoBlockAnchorList[FlagInfoBlockNo] = FlagInfoBlockPtr;
    }

    Converter_FlagInfo FlagInfo (FlagInfoBlockPtr, BlockOffset);

    /* check that  the page number is not already inserted */
    /* check if the page number is inserted at all */
    if (FlagInfo.FlagIsSet(PageNo))
        return Converter_DuplicatePageNo;

    /* insert the page number */
    FlagInfo.SetFlag(PageNo);

    /* update number of pages in the container */
    m_PageNoCount.Increment();

    return Converter_Ok;
}

/*---------------------------------------------------------------------------*/

Converter_ReturnCode
Converter_BackUpPageNoContainer::Initialize (SAPDB_UInt  MaxPageNo,
        SAPDB_UInt  NumFlagInfoBlocks,
        SAPDB_UInt  NumPageNosPerFlagInfoBlock)
{
    /* check current state of the container */
    SAPDBERR_ASSERT_STATE (! IsInitialized());

    /* prmitive consistency check of  input parameter */
    SAPDBERR_ASSERT_STATE (((MaxPageNo/NumPageNosPerFlagInfoBlock)+1) >= NumFlagInfoBlocks);

    m_NumFlagInfoBlocks          = NumFlagInfoBlocks;
    m_NumPageNosPerFlagInfoBlock = NumPageNosPerFlagInfoBlock;

    /* calulate the number of FlagInfo in a blocj required to accomodate   */
    /* NumPageNosPerFlagInfoBlock page numbers. align the flag info blocks */
    /* to avoid inteferences during the paralell removing of page numbers  */
    m_SizeOfFlagInfoBlock = ALIGN (Converter_FlagInfo::FlagInfoBlockNo(NumPageNosPerFlagInfoBlock) + 1);

    /* check 8 byte alignment of flag info blocks */
    SAPDBERR_ASSERT_STATE (((m_SizeOfFlagInfoBlock * sizeof (Converter_FlagInfo::FlagInfoData)) % 8) == 0);

    m_NumBlockContainer = CalculateNumFlagInfoContainer(m_NumFlagInfoBlocks,  m_SizeOfFlagInfoBlock, m_BlocksPerContainer);

    const SAPDB_UInt allocSize = CalculateFlagInfoBlockNo( MaxPageNo )+ 1;  // anchor

    const bool bOkay1 = m_FlagInfoBlockAnchorList.Resize( allocSize, 0 );
    const bool bOkay2 = m_FlagInfoBlocksContainer.Reserve( m_NumBlockContainer );

    bool bOkay3 = true;
    SAPDB_UInt blocks = m_NumFlagInfoBlocks;
    for (SAPDB_UInt container = 0; (container < m_NumBlockContainer ) && bOkay3; container++)
    {
        SAPDB_UInt allocateBlocks = SAPDB_MIN(blocks, m_BlocksPerContainer);
        FlagInfoBlocks *ptr = new (m_Allocator) FlagInfoBlocks(m_Allocator);
        bOkay3 = (NULL != ptr) && (0 != blocks) ;
        if (bOkay3)
        {
            bOkay3 = ptr->Initialize(allocateBlocks * m_SizeOfFlagInfoBlock, 0);
            blocks -= allocateBlocks;
            bOkay3 &= m_FlagInfoBlocksContainer.InsertEnd(ptr);
        }
    }

    if( ! ( bOkay1 && bOkay2 && bOkay3 ))
    {
        Delete(); // release probably used memory

        Converter_Exception ErrMsg( __CONTEXT__, CONVERTER_NO_MEMORY_FOR_BACKUP_CONTAINER,
                                    SAPDB_ToString(MaxPageNo, _T_d),
                                    SAPDB_ToString(NumFlagInfoBlocks, _T_d ),
                                    SAPDB_ToString( NumPageNosPerFlagInfoBlock, _T_d ));
        RTE_Message (ErrMsg);
        return Converter_MemoryAllocationFailed;
    }
    return Converter_Ok;
}

/*---------------------------------------------------------------------------*/

SAPDB_Bool
Converter_BackUpPageNoContainer::Remove (const Data_PageNo  PageNo)
{
    /* check current state of the container */
    SAPDBERR_ASSERT_STATE (IsInitialized());

    /* find the flag info which contains the flag to switch on for the given page number */
    const SAPDB_UInt FlagInfoBlockNo = CalculateFlagInfoBlockNo( PageNo );
    const SAPDB_UInt BlockOffset     = CalculateFlagInfoBlockOffset( PageNo, FlagInfoBlockNo );

    if( FlagInfoBlockNo >= m_FlagInfoBlockAnchorList.GetSize())
        return false; // given pageNo is out of range

    Converter_FlagInfo::FlagInfoData*  FlagInfoBlockPtr =  m_FlagInfoBlockAnchorList[FlagInfoBlockNo];

    if (NULL == FlagInfoBlockPtr)
        return false;

    Converter_FlagInfo FlagInfo (FlagInfoBlockPtr, BlockOffset);

    /* check if the page number is inserted at all */
    if (!FlagInfo.FlagIsSet(PageNo))
        return false;

    /* remove the page number */
    FlagInfo.DelFlag(PageNo);

    /* update number of pages in the container */
    m_PageNoCount.Decrement();

    return true;
}

/*---------------------------------------------------------------------------*/
