/*!
 * \file    OMS_Oid.hpp
 * \author  IvanS, MarkusSi, PeterG
 * \brief   OID of the persistent class
 */

/*

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



*/

#ifndef __OMS_OID_HPP
#define __OMS_OID_HPP

#include "livecachetypes.h" // nocheck
#include "Oms/OMS_AFX.h"
#include "Oms/OMS_GUID.hpp"

/* PTS 1115295 FF 2002-04-19 */
// TODO
//#ifdef KERNEL
//#undef AFX_EXT_CLASS
//#define AFX_EXT_CLASS
//#endif

class OmsExternalOid;
class OmsHandle;

/*-----------------------------------------------------------------------------*/
/// Defines an OID of the persistent class T.
struct AFX_EXT_CLASS OmsObjectId : public OmsTypeOid
{
public:
  /*-----------------------------------------------------------------------------*/
  /// Defines the "smaller than" operator for OIDs.
  /*!
  ** Defines the "smaller than" operator for OIDs. The statement that an OID is smaller 
  ** than another must not be understood as having semantic meaning. This operator has 
  ** been provided merely to enable sorting to be carried out according to OIDs.
  */
  inline bool operator< ( const OmsObjectId&r ) const;

  /*-----------------------------------------------------------------------------*/
  /// Defines the "smaller than or equal" operator for OIDs
  /*!
  ** Defines the "smaller than or equal" operator for OIDs. The statement that an OID  
  ** is smaller or equal than another must not be understood as having semantic meaning. 
  ** This operator has been provided merely to enable sorting to be carried out according 
  ** to OIDs.
  */
  inline bool operator<=( const OmsObjectId&r ) const;

  /*-----------------------------------------------------------------------------*/
  /// Defines the equality of two OIDs.
  inline bool operator==( const OmsObjectId&r ) const;

  /*-----------------------------------------------------------------------------*/
  /// Defines the inequality of two OIDs.
  inline bool operator!=( const OmsObjectId&r ) const;

  /*-----------------------------------------------------------------------------*/
  /// Provides true for the NULL OID; otherwise, false;
  inline bool operator! () const; 

  /*-----------------------------------------------------------------------------*/
  /// Provides true for the NULL OID; otherwise, false;
  inline operator bool  () const; 

  inline unsigned int   getPno() const;
  inline int            getPagePos() const;
  inline int            getGeneration() const;
  inline unsigned long  omsHashValue() const;                  /* PTS 1125318 */
  inline unsigned long  omsHashValue(unsigned long upb) const; /* PTS 1103189 */
  inline int            Compare(const OmsObjectId &oid1, const OmsObjectId &oid2);

protected:
  inline OmsObjectId();
  inline void operator= (const OmsExternalOid&r);
  inline OmsObjectId(OmsTypeUInt4 p, unsigned short pp, unsigned short g);

private:
  friend class OmsObjByClsIterBase;
  friend class OmsHandle;
  friend class DbpError;

  inline void setNil();

#ifdef  OMS_IMPLEMENTATION
  // OMS implementation-specific stuff:
  friend class OMS_Context;
  friend class OMS_VarObjContainer;    // PTS 1121449
  friend class OMS_VarObjChunk;
  friend class OMS_VarObjInfoNode;
  friend class OMS_BeforeImageListDumpInfo;
  friend class OMS_Globals;
  friend class OMS_OidHashDumpInfo;
  friend class OMS_Session;
  friend class OMS_BasisKeyIterBase;
  friend class OMS_KernelKeyIter;
  friend class OMS_UnloadedVersionKeyIter;
  friend class OMS_KernelClsIter;
  friend class OMS_OidHash;  // PTS 1125361

  inline void setPno(OmsTypeUInt4 p);
  /// Increments the generation counter of the oid
  inline void operator++();                                      // PTS 1125361
  /// Returns true if the oid is equal except for the generation
  inline bool equalExceptGeneration(const OmsObjectId &oid) const; // PTS 1125361
  /// Returns true if the oid is equal except for the generation and the generation differs exactly by one
  inline bool isDirectPredOf(const OmsObjectId &oid) const;        // PTS 1125361 
#endif
};


class OmsExternalOid : public OmsObjectId
{
public:
  OmsExternalOid() {}
  OmsExternalOid( const OmsObjectId&r ) : OmsObjectId(r) {}
  OmsExternalOid( const OmsTypeOid&r  ) : OmsObjectId(r.pno, r.pagePos, r.generation) {}
  OmsExternalOid( const OmsTypeByte* r) 
  { 
    OmsTypeByte* pDest = reinterpret_cast<OmsTypeByte*>(this);
    *pDest++ = *r++;
    *pDest++ = *r++;
    *pDest++ = *r++;
    *pDest++ = *r++;
    *pDest++ = *r++;
    *pDest++ = *r++;
    *pDest++ = *r++;
    *pDest   = *r;
  }
  void omsCopyTo( OmsTypeByte* pDest ) 
  {  
    OmsTypeByte* pSource = reinterpret_cast<OmsTypeByte*>(this);
    *pDest++ = *pSource++;
    *pDest++ = *pSource++;
    *pDest++ = *pSource++;
    *pDest++ = *pSource++;
    *pDest++ = *pSource++;
    *pDest++ = *pSource++;
    *pDest++ = *pSource++;
    *pDest   = *pSource;
  }
private:
};



#define OMS_NIL_OBJ_PAGE_NO  2147483647
#define OMS_NIL_OBJ_PAGE_POS 0
#define OMS_NIL_OBJ_VERSION  0

#define OMS_VERSION_OBJ_PAGE_NO OMS_NIL_OBJ_PAGE_NO

inline OmsObjectId::OmsObjectId()
{
  pno        = OMS_NIL_OBJ_PAGE_NO;
  pagePos    = OMS_NIL_OBJ_PAGE_POS;
  generation = OMS_NIL_OBJ_VERSION;
}

inline bool OmsObjectId::operator< ( const OmsObjectId&r ) const
{
#ifdef LIVECACHE_INTGUIDS
  if (pno < r.pno) {
    return true;
  }
  if (pno > r.pno) {
    return false;
  }
  return *((&pno) + 1) < *((&r.pno) + 1);
#else
  register unsigned char* pThis = (unsigned char*) this;
  register unsigned char* pR    = (unsigned char*) &r;

  for (int ix = 0; ix < sizeof(r) - 1; ++ix)
  {
    if (*pThis != *pR)
    {
      break;
    }
    else
    {
      ++pThis;
      ++pR;
    }
  }
  return (*pThis < *pR); 
#endif
}

inline int OmsObjectId::Compare(const OmsObjectId &oid1, const OmsObjectId &oid2)
{
  if (oid1 < oid2){
    return -1;
  }
  else if (oid2 < oid1){
    return 1;
  }
  else {
    return 0;
  }
}


inline bool OmsObjectId::operator<=( const OmsObjectId&r ) const
{
#ifdef LIVECACHE_INTGUIDS
  if (pno < r.pno) {
    return true;
  }
  if (pno > r.pno) {
    return false;
  }
  return *((&pno) + 1) <= *((&r.pno) + 1);
#else
  register unsigned char* pThis = (unsigned char*) this;
  register unsigned char* pR    = (unsigned char*) &r;

  for (int ix = 0; ix < sizeof(r) - 1; ++ix)
  {
    if (*pThis != *pR)
    {
      break;
    }
    else
    {
      ++pThis;
      ++pR;
    }
  }
  return (*pThis <= *pR);
#endif
}

inline bool OmsObjectId::operator==( const OmsObjectId&r ) const 
{ 
  return ((pno == r.pno) && (pagePos == r.pagePos) && (generation == r.generation)); 
}

inline bool OmsObjectId::operator!=( const OmsObjectId&r ) const
{
  return ((pno != r.pno) || (pagePos != r.pagePos) || (generation != r.generation)); 
}

inline OmsObjectId::OmsObjectId(OmsTypeUInt4 p, unsigned short pp, unsigned short g)
{ 
  pno        = p;
  pagePos    = pp;
  generation = g;
}

inline void OmsObjectId::operator= (const OmsExternalOid&r) 
{
  pno        = r.pno;
  pagePos    = r.pagePos;
  generation = r.generation;
}

inline bool OmsObjectId::operator! () const 
{
  return ((OMS_NIL_OBJ_PAGE_NO==pno) && (OMS_NIL_OBJ_PAGE_POS==pagePos) && (OMS_NIL_OBJ_VERSION==generation));
}

inline OmsObjectId::operator bool () const 
{ 
  return ((OMS_NIL_OBJ_PAGE_NO!=pno) || (OMS_NIL_OBJ_PAGE_POS!=pagePos) || (OMS_NIL_OBJ_VERSION!=generation));
}

inline unsigned int OmsObjectId::getPno() const 
{
  return pno;
}

#ifdef  OMS_IMPLEMENTATION
inline void OmsObjectId::setPno(OmsTypeUInt4 p)
{
  pno = p;
}

inline void OmsObjectId::operator++()  // PTS 1125361
{
  // Only ONE byte is used for the generation in the kernel, although two bytes
  // are reserved in the oid, so the maximal allowed range is [0..255]
  // Attention: The value 0x00 is no valid generation.
  if (generation == 0xff){
    generation = 1;
  }
  else { 
    generation++;
  }
}

inline bool OmsObjectId::equalExceptGeneration(const OmsObjectId &oid) const  // PTS 1125361
{
  return (pno == oid.pno && pagePos == oid.pagePos);
}

inline bool OmsObjectId::isDirectPredOf(const OmsObjectId &oid) const        // PTS 1125361 
{
  // Only ONE byte is used for the generation in the kernel, although two bytes
  // are reserved in the oid, so the maximal allowed range is [0..255]
  // Attention: The value 0x00 is no valid generation.
  if (equalExceptGeneration(oid)){
    if (generation == 0xff){
      return (oid.getGeneration() == 1);
    }
    else{
      return (generation+1 == oid.getGeneration());
    }
  }
  else {
    return false;
  }
}
#endif

inline void OmsObjectId::setNil()
{
  pno = OMS_NIL_OBJ_PAGE_NO;
  pagePos = OMS_NIL_OBJ_PAGE_POS;
  generation = OMS_NIL_OBJ_VERSION;
}

inline int OmsObjectId::getPagePos() const 
{
  return pagePos;
}

inline int OmsObjectId::getGeneration() const 
{
  return generation;
}

/* PTS 1125318 */
inline unsigned long OmsObjectId::omsHashValue() const
{
  if (pno == OMS_VERSION_OBJ_PAGE_NO){  
    // Version OID: pno is a constant therefore not relevant for hash value computation
    return (pagePos ^ (((long)generation) << 16));
  }
  else {  
    // normal OID: all oids with the same pno and pagePos should have the same
    // hash-value. This is needed for the oid-hash, to ensure, that these objects
    // are placed in the same bucket-chain.
    return (pno ^ (((long)pno) << 7) ^ (pno >> 7) ^ (pagePos >> 3) ^ (((long)pagePos) << 9));
  }
}

/* PTS 1103189 */
inline unsigned long OmsObjectId::omsHashValue(unsigned long upb) const 
{ 
  /* changed with PTS 1125318 */
  return (omsHashValue() % upb);
}

// forward declaration
struct OmsVarOid;

/*---------------------------------------------------------------------------*/
/// Interface for the enumeration of OID's
/*!
** This interface defines methods for the enumeration of OID's which e.g. be
** stored in arrays, chained lists,...
**
** \since 7.4.3  PTS 1115027
*/
class AFX_EXT_CLASS OmsIOidReadIterator   
{
public:
  /*---------------------------------------------------------------------------*/
  /// Resets the enumeration, so that the next access will return the first oid again
  virtual void omsReset() = 0;

  /*---------------------------------------------------------------------------*/
  /// Returns the current oid
  virtual const OmsObjectId& omsGet() const = 0;

  /*---------------------------------------------------------------------------*/
  /// Increments to the next oid
  virtual void operator++ () = 0;

  /*---------------------------------------------------------------------------*/
  /// Return true if omsGet() wourd return a valid oid; otherwise false.
  virtual operator bool () const = 0;
};


/*---------------------------------------------------------------------------*/
/// Interface to collect OID's
/*!
** This interface defines a method to insert OID's e.g. into arrays, 
** chained lists,...
**
** \since 7.4.3  PTS 1115027
*/
class AFX_EXT_CLASS OmsIOidAppender   
{
public:
  /*---------------------------------------------------------------------------*/
  /// Appends the oid and returns whether the action have been executed successfully
  virtual bool omsAppend(const OmsObjectId& currOid) = 0;
}; 

#endif  // __OMS_OID_HPP