/*!
 * \file    OMS_ClassIdEntry.hpp
 * \author  IvanS, MarkusSi, PeterG
 * \brief   OMS ClassIdEntry.
 */
/*

    ========== licence begin  GPL
    Copyright (c) 2002-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_CLASSIDENTRY_HPP
#define __OMS_CLASSIDENTRY_HPP

#include "Oms/OMS_ClassIdEntryDef.hpp"
#include "Oms/OMS_ContextDef.hpp"
#include "Oms/OMS_Globals.hpp"
#include "Oms/OMS_ClassInfo.hpp"
#include "Oms/OMS_ContainerInfo.hpp"
#include "Oms/OMS_CacheMissEntry.hpp"
#include "Oms/OMS_SessionDef.hpp"    

inline OMS_ClassIdEntry::~OMS_ClassIdEntry()
{
}

inline void* OMS_ClassIdEntry::operator new (size_t sz, OMS_Context* context)
{
  return context->allocate(sz);
}

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

#if defined(OMS_PLACEMENT_DELETE)
inline void OMS_ClassIdEntry::operator delete (void* p, OMS_Context* context)
{
  context->deallocate(p);
}
#endif

/*----------------------------------------------------------------------*/
/// Check whether key is already registered as a cache miss     
inline bool OMS_ClassIdEntry::IsCacheMiss(const unsigned char *key)
{ 
  m_cacheMissCmp->setKey(key, GetKeyDesc().GetLen());    
  return m_cacheMiss.Find(m_cacheMissCmp) != NULL ? true : false;
}

/*----------------------------------------------------------------------*/
/// Delete specified entry from the cache miss structure           
inline void OMS_ClassIdEntry::DeleteCacheMiss(const unsigned char *key, OMS_Context* pContext)
{
  m_cacheMissCmp->setKey(key, GetKeyDesc().GetLen());  
  
  // Find pointer to the node in the AVL-Tree
  OMS_CacheMissEntry*const* pCacheMissEntry = m_cacheMiss.Find(m_cacheMissCmp); 
  OMS_CacheMissEntry*       pDelEntry       = const_cast<OMS_CacheMissEntry*>(*pCacheMissEntry);

  // Delete the node in the AVL-Tree
  tgg00_BasisError rc = m_cacheMiss.Delete(m_cacheMissCmp);
  if (e_ok != rc) {
    // Object does not existent is the structure
    OMS_Globals::Throw(DbpError (DbpError::DB_ERROR, rc, "OMS_ClassIdEntry::DeleteCacheMiss", __MY_FILE__, __LINE__)); 
  }

  // Delete the cache miss entry 
  pDelEntry->deleteSelf(pContext);
}

/*----------------------------------------------------------------------*/
/// Insert entry into the cache miss structure 
inline void OMS_ClassIdEntry::InsertCacheMiss(const unsigned char *key,
                                              OMS_Context* pContext)
{
  // Create object for cache miss structure
  OMS_CacheMissEntry* pCacheMiss 
    = new (GetKeyDesc().GetLen(),pContext) OMS_CacheMissEntry (key, GetKeyDesc().GetLen());  

  tgg00_BasisError rc 
    = m_cacheMiss.Insert(const_cast<OMS_CacheMissEntry*>(pCacheMiss));
  if (e_ok != rc) {
    // Object is already existent is the structure
    OMS_Globals::Throw(DbpError (DbpError::DB_ERROR, rc, "OMS_ClassIdEntry::InsertCacheMiss", __MY_FILE__, __LINE__)); 
  }
}

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


inline int OMS_ClassIdEntry::Compare(const unsigned char* l, const unsigned char* r) 
{
  int cmp = memcmp (l, r, GetKeyDesc().GetLen());  
  if (0 != cmp) {
    if (cmp > 0) {
      return 1;
    }
    else {
      return -1;
    }
  }
  else {
    return 0;
  }
}

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

inline void OMS_ClassIdEntry::DeleteSelf(OMS_Context* pContext) 
{
  // Delete complete structure for new version objects / cached keys 
  VersionDelIndex(false, pContext);

  // PTS 1117571
  // Delete complete structure of the cache misses
  if (UseCachedKeys()){
    DropCacheMisses(pContext);
    if (m_cacheMissCmp != NULL){
      m_cacheMissCmp->deleteSelf(pContext);
      m_cacheMissCmp = NULL;
    }
  }
  
  // release reference to global container dictionary 
  OMS_Globals::DetachContainerInfo(pContext->LcSink(), GetContainerInfoPtr());
  // destroy self
  pContext->deallocate(this);
}

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

inline const OMS_ClassInfo* OMS_ClassIdEntry::GetClassInfoPtr() const 
{
  return GetContainerInfoPtr()->GetClassInfoPtr();
}

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

inline OMS_ContainerInfo* OMS_ClassIdEntry::GetContainerInfoPtr() const 
{
  if (m_containerInfo->m_eyeCatcher != 0xabcdabcd){
    pasbool     *pToCancel;
    tsp00_TaskId taskId;
    OMS_Session *pSession;

    IliveCacheSink *pSink = OMS_Globals::GetCurrentLcSink();
    pSink->GetDefaultContext(reinterpret_cast<void**>(&pSession), &pToCancel, taskId);

    // Remove entry out of the local container directory and delete it
    pSession->m_context->m_containerDir.HashDelete_Slow(const_cast<OMS_ClassIdEntry*>(this));
    pSession->m_context->deallocate(const_cast<OMS_ClassIdEntry*>(this));

    char buf[128];
    sprintf (buf, "Eye-Catcher has wrong value : %#X", m_containerInfo->m_eyeCatcher);
    DbpBase b(pSink);
    b.dbpOpError(buf);
    OMS_Globals::Throw(DbpError (DbpError::DB_ERROR, e_unknown_guid, buf, __MY_FILE__, __LINE__)); 
  }

  return m_containerInfo;
}

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

inline tsp00_Uint4 OMS_ClassIdEntry::GetContainerHandle() const {
  return GetContainerInfoPtr()->GetContainerHandle();
}

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

inline OmsContainerNo OMS_ClassIdEntry::GetContainerNo() const {
  return GetContainerInfoPtr()->m_ContainerNo;
}

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

inline tgg00_FileId& OMS_ClassIdEntry::GetFileId() const { 
  return GetContainerInfoPtr()->m_ContainerId;
}

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

inline const ClassIDRef OMS_ClassIdEntry::GetGuid() const {
  return GetContainerInfoPtr()->GetGuid();
}


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

inline int OMS_ClassIdEntry::GetKeyLen() const {         
  return GetContainerInfoPtr()->GetKeyDesc().GetLen();      
}

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


inline const OMS_KeyDesc& OMS_ClassIdEntry::GetKeyDesc() const { // PTS 1122540
  return GetContainerInfoPtr()->GetKeyDesc();
}

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

inline unsigned char* OMS_ClassIdEntry::GetKeyPtr(OmsObjectContainer* p) {
  return (((unsigned char*) &p->m_pobj) 
         + sizeof (void*)             /* vtblptr */ 
         + GetKeyDesc().GetPos()      /* key */ 
         - 1);
}

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

inline tsp00_Int4 OMS_ClassIdEntry::GetObjectSize() const {
  return GetContainerInfoPtr()->GetObjectSize();
}

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

inline tsp00_Int4 OMS_ClassIdEntry::GetPersistentSize() const {
  return (tsp00_Int4) GetContainerInfoPtr()->m_PersistentSize;
}

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

inline OmsContainerNo OMS_ClassIdEntry::GetSchema() const {
  return GetContainerInfoPtr()->m_schema;
}

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

inline void* OMS_ClassIdEntry::GetVirtualTablePtr() const {
   return GetContainerInfoPtr()->GetVirtualTablePtr();
}

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

inline bool OMS_ClassIdEntry::IsDerivedClassOf(const ClassIDRef guid) const {
  return GetContainerInfoPtr()->m_clsInfo->IsDerivedClassOf(guid);
}

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

inline bool OMS_ClassIdEntry::IsKeyedObject() const {  
  //return  m_containerInfo->m_clsInfo->IsKeyedObject();
  return  GetContainerInfoPtr()->GetKeyDesc().IsKeyed();
}

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

inline bool OMS_ClassIdEntry::IsVarObject() {
  return GetContainerInfoPtr()->m_clsInfo->IsVarObject();
}

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

inline bool OMS_ClassIdEntry::UseCachedKeys() const {  
  return m_useCachedKeys;
}

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

tgg00_BasisError OMS_ClassIdEntry::VersionAddKey(OmsObjectContainer* p, OMS_Context* pContext, bool noThrowIfExist) 
{
  const char* msg = "OMS_ClassIdEntry::VersionAddKey";

  tgg00_BasisError rc;
  rc = m_index.Insert(GetKeyPtr(p));
  if (rc != e_ok && (noThrowIfExist == false || rc != e_duplicate_key)){
    OMS_Globals::Throw(DbpError (DbpError::DB_ERROR, rc, "OMS_ClassIdEntry::VersionAddKey", __MY_FILE__, __LINE__)); 
  }

  OMS_DETAIL_TRACE(omsTrKey, pContext->m_session->m_lcSink, msg 
                       << " Insert Object " << p->m_oid
                       << " RC: " << rc);

  return rc;
}

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

void OMS_ClassIdEntry::VersionDelKey(OmsObjectContainer* p, OMS_Context* pContext) 
{
  const char* msg = "OMS_ClassIdEntry::VersionDelKey";

  tgg00_BasisError    rc    = 0;
  OmsObjectContainer* found = NULL;

  bool check = false;

  if (check){
    // Check that the object frame, to which the entry with the given key in the tree
    // is pointing to, is the same as the given object frame
    found = VersionFindKey(GetKeyPtr(p));
  }

  if (!check || (found && found == p)){
    rc = m_index.Delete(GetKeyPtr(p));

    OMS_DETAIL_TRACE(omsTrKey, pContext->m_session->m_lcSink, msg 
                       << " Delete Object " << p->m_oid
                       << " RC: " << rc);
  }
  else if (check && found && found != p) {
    OMS_DETAIL_TRACE(omsTrKey, pContext->m_session->m_lcSink, msg 
                       << " Object " << p->m_oid << " not deleted as tree is pointing to other object");
  }
}

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

OmsObjectContainer* OMS_ClassIdEntry::VersionFindKey(const unsigned char* k) {
  unsigned char* const* p = m_index.Find(CONST_CAST(unsigned char*, k));
    
  return p != NULL ? VersionGetInfoFromNode(p) : NULL;
}

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

void OMS_ClassIdEntry::VersionReplaceOrAddKeyContainerPtr(OmsObjectContainer* pObj, OMS_Context* pContext)
{
  const char* msg = "OMS_ClassIdEntry::VersionDelKey";

  unsigned char* const* p = m_index.Find(GetKeyPtr(pObj));
  if (NULL != p)
  {
    *CONST_CAST(unsigned char**, p) = GetKeyPtr(pObj);
    OMS_DETAIL_TRACE(omsTrKey, pContext->m_session->m_lcSink, msg 
                       << " Object changed " << pObj->m_oid);
  }
  else
  {
     VersionAddKey(pObj, pContext);
  }
}

/*----------------------------------------------------------------------*/
// Returns the user-data (pointer to a object-container) from a node of 
// the version/cached-key search structure 
OmsObjectContainer* OMS_ClassIdEntry::VersionGetInfoFromNode(const unsigned char* const* p) {
    return REINTERPRET_CAST(OmsObjectContainer*, 
                 CONST_CAST(unsigned char*, (*p) 
                                            + GetKeyDesc().GetLen()
                                            - GetObjectSize()));
}

#endif  // __OMS_CLASSIDENTRY_HPP