/*!
  @file           Log_ActionObject.hpp
  @ingroup        ActionHandling
  @author         UweH
  @brief          defines class Log_ActionObject

\if EMIT_LICENCE
    ========== licence begin  GPL
    Copyright (c) 2000-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

\endif
*/



#ifndef Log_ActionObject_H
#define Log_ActionObject_H

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

#include "ggg00.h"  // tgg00_TransContext, tgg00_FileId
#include "ggg92.h"  // tgg92_KernelOid, tgg92_ObjHeader

#include "SAPDBCommon/SAPDB_Types.hpp"
#include "SAPDBCommon/ErrorsAndMessages/SAPDBErr_Assertions.hpp"
#include "SAPDBCommon/MemoryManagement/SAPDBMem_NewDestroy.hpp"

#include "DataAccess/Data_PageSplitSpace.hpp"
#include "DataAccess/Data_ISplitSpace.hpp"

#include "Logging/Log_Types.hpp"
#include "Logging/Log_IAction.hpp"

/*===========================================================================*
 *  DEFINES                                                                  *
 *===========================================================================*/

class Log_AfterImage;
class Log_BeforeImage;

/*===========================================================================*
 *  MACROS                                                                   *
 *===========================================================================*/
/*===========================================================================*
 *  EXTERNAL VARIABLES                                                       *
 *===========================================================================*/
/*===========================================================================*
 *  CLASSES, STRUCTURES, TYPES, UNIONS ...                                   *
 *===========================================================================*/

/*!
   @brief          Handle for manipulating OMS objects.
 */


class Log_ActionObject : public Log_IAction
{

public:

    /// constructor
    Log_ActionObject ()
    : m_pKey       (NULL),
      m_pBody      (NULL),
      m_pAllocator (NULL),
      m_Head()
    {}
    
    /// destructor
    ~Log_ActionObject ()
    {
        if ( NULL != m_pAllocator )
        {
            if ( NULL != m_pBody )
            {
                destroy (m_pBody,*m_pAllocator);
            }
            if ( NULL != m_pKey )
            // PTS 1136035 mb 2005-06-08
            {
                destroy (m_pKey,*m_pAllocator);
            }
        }
    }
    
    /// Initialize the new action
    void InitNew (const tgg00_FileId    &fileid,
                  const tgg92_KernelOid &oid,
                  const tgg91_PageRef   &version,
                  SAPDB_Int4             keySize,
                  SAPDB_Byte            *pKey)
    {
        m_Type           = Log_NewObject;
        m_Head.fileno    = fileid.fileObjFileNo_gg00();
        m_Head.oid()     = oid;
        m_Head.keySize   = keySize;
        //memcpy (m_Head.version, &version, sizeof(m_Head.version));
        m_Head.version() = version;
        m_pKey           = pKey;
    }

    /// This is used to write.
    void InitDelete (tgg00_ObjFileNo        fileno,
                     const tgg92_KernelOid &oid,
                     const tgg91_PageRef   &version)
    {
        m_Type           = Log_DeleteObject;
        m_Head.fileno    = fileno;
        m_Head.oid()     = oid;
        //memcpy (m_Head.version, &version, sizeof(m_Head.version));
        m_Head.version() = version;
    }

    /// This is used to write.
    void InitInsUpd (Log_ActionType         actiontype,
                     const tgg00_FileId    &fileid,
                     const tgg92_KernelOid &oid,
                     const tgg91_PageRef   &version,
                     SAPDB_Int4             keySize,
                     SAPDB_Int4             bodySize,
                     SAPDB_Byte            *pBody)
    {
        m_Type           = actiontype;
        m_Head.fileno    = fileid.fileObjFileNo_gg00();
        m_Head.oid()     = oid;
        //memcpy (m_Head.version, &version, sizeof(m_Head.version));
        m_Head.version() = version;
        m_Head.bodySize  = bodySize - keySize;
        m_pBody          = pBody;
    }
    
    /// this has at least to be copied in one step
    static SAPDB_UInt GetMinimalLengthToCopyEntry()
    {
        return sizeof (Head);
    }

    /// return the minimum length for creating a persistent entry
    virtual SAPDB_UInt GetMinimalPersistentLength() const
    {
        return GetMinimalLengthToCopyEntry();
    }

    /// Get the length of the action
    virtual SAPDB_UInt GetPersistentLength() const
    {
        if ( m_Head.bodySize > 0 )
            return GetMinimalPersistentLength() + Data_PageSplitSpace::AlignRecordSize (m_Head.bodySize);
        else
            return GetMinimalPersistentLength() + Data_PageSplitSpace::AlignRecordSize (m_Head.keySize);
    }

    /// The Space must be initialized with the value given by GetPersistentLength().
    virtual void WritePersistentFormat (Data_SplitSpaceWriter &Writer,
                                        bool                  &isOK) const;

    /// all internal components are initialized with the reader
    virtual void ReadPersistentFormat (Data_SplitSpaceReader  &Reader,
                                       SAPDBMem_IRawAllocator &Allocator,
                                       bool                   &isOK);
    ///  action is written to the trace file
    virtual void WriteToTrace (const char * Title) const;

    /// The action is re-done.
    void Redo (tgg00_TransContext   &Trans,
               const Log_AfterImage &AfterImage);

    /// The action is rollbacked.
    void Undo (tgg00_TransContext    &Trans,
               const Log_BeforeImage &BeforeImage,
               Data_PageNo            pageno,
               Data_PageOffset        offset);

    /// the ObjectID is returned
    tgg92_KernelOid& GetOid()
    {
        return m_Head.oid();
    }

    /// the ObjectID is returned
    tgg92_KernelOid GetOid() const
    {
        return m_Head.const_oid();
    }

    /// the file-number is returned
    tgg00_ObjFileNo GetFileNo() const
    {
        return m_Head.fileno;
    }

    /// the size of the body of the action is returned
    SAPDB_UInt2 GetBodySize() const
    {
        return m_Head.bodySize;
    }

    /// returns the size of the key
    SAPDB_UInt2 GetKeySize() const
    {
        return m_Head.keySize;
    }

    /// returns the version
    const tgg91_PageRef& GetVersion()
    {
        return m_Head.version();
    }

    /// returns a pointer to the key-values
    const SAPDB_Byte* GetKey() const
    {
        return m_pKey;
    }

    /// returns a pointer to the body
    const SAPDB_Byte* GetBody() const
    {
        return m_pBody;
    }

    /// The image must be the pointer to a persistent format of this action.
    static void ExtractOid ( const SAPDB_Byte  *image,
		                     SAPDB_UInt         imagelength,
							 tgg92_KernelOid   &oid )
    {
        SAPDBERR_ASSERT_ARGUMENT( imagelength >= sizeof(Head) );
		const Head *pHead = reinterpret_cast <const Head*> (image);
		oid = pHead->const_oid();
    }

public: // must be public for the struct definition (on HP)

    /// object version
    typedef SAPDB_Byte PersistentObjVersion [sizeof(tgg91_PageRef)];

    /// object-id
    typedef SAPDB_Byte PersistentOid [sizeof(tgg92_KernelOid)];

private:

    /// the size of the alignment
    SAPDB_UInt GetAlignmentLength() const
    {        
        SAPDB_UInt length = GetPersistentLength();
        
        if ( m_Head.bodySize > 0 )
            return length - GetMinimalPersistentLength() - m_Head.bodySize;
        else
            return length - GetMinimalPersistentLength() - m_Head.keySize;
    }

private:

    /// the Head of an Log_Action: Written into undo/redo-files
    /// (totally 28 bytes long)
    struct Head
    {
        PersistentOid        poid;     ///< 8 bytes
        tgg00_ObjFileNo      fileno;   ///< 4 bytes
        SAPDB_UInt2          bodySize; ///< 2 bytes
        SAPDB_UInt2          keySize;  ///< 2 bytes
        PersistentObjVersion pversion; ///< 6 bytes
        SAPDB_UInt2          filler;   ///< 2 bytes

        /// initializes the head
        Head()
        {
            oid().gg92SetNil();
            fileno    = 0;
            bodySize  = 0;
            keySize   = 0;
            version().gg91SetNilRef();
            filler    = 0;
        }

        /// returns the object-id
        tgg92_KernelOid& oid()
        {
            return *(reinterpret_cast<tgg92_KernelOid*>(poid));
        }
        
        /// returns the object-id
        tgg92_KernelOid const_oid() const
        {
            return *(reinterpret_cast<const tgg92_KernelOid*>(poid));
        }

        /// returns the action
        tgg91_PageRef& version()
        {
            return *(reinterpret_cast<tgg91_PageRef*>(pversion));
        }
    };                        

    /// the in-memory used head
    Head m_Head;

    /// a pointer to the key
    SAPDB_Byte *m_pKey;

    /// a pointer to the body of the entry
    SAPDB_Byte *m_pBody;

    /// an allocator used for dynamic memory allocation
    SAPDBMem_IRawAllocator* m_pAllocator;
};


#endif  /* Log_ActionObject_H */
