#include "Object_Ref_Table.h"
#include "ORB.h"
#include "Environment.h"
#include "debug.h"
#include "ORB_Constants.h"
#include "ace/OS_NS_string.h"

ACE_RCSID (tao,
           Object_Ref_Table,
           "Object_Ref_Table.cpp,v 1.20 2004/06/18 14:29:36 jwillemsen Exp")

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

TAO_Object_Ref_Table::TAO_Object_Ref_Table (void)
  : table_ (TAO_DEFAULT_OBJECT_REF_TABLE_SIZE)
{
}

TAO_Object_Ref_Table::~TAO_Object_Ref_Table (void)
{
  // Must explicitly call destroy() in the destructor since not all
  // applications will invoke ORB::shutdown() or ORB::destroy().
  this->destroy ();
}

void
TAO_Object_Ref_Table::register_initial_reference (
  const char *id,
  CORBA::Object_ptr obj
  ACE_ENV_ARG_DECL)
{
  if (id == 0 || ACE_OS::strlen (id) == 0)
    {
      ACE_THROW (CORBA::ORB::InvalidName ());
    }
  else if (CORBA::is_nil (obj))
    {
      ACE_THROW (CORBA::BAD_PARAM (CORBA::OMGVMCID | 27,
                                   CORBA::COMPLETED_NO));
    }

  int result = this->bind (id, obj);

  if (result == 1)
    {
      if (TAO_debug_level > 1)
        {
          ACE_ERROR ((LM_ERROR,
                      ACE_TEXT ("(%P|%t) Object_Ref_Table::register_initial_reference:")
                      ACE_TEXT ("  Could not register duplicate object <%s> ")
                      ACE_TEXT ("with the ORB\n"),
                      ACE_TEXT_CHAR_TO_TCHAR (id)));
        }

      ACE_THROW (CORBA::ORB::InvalidName ());
    }

  if (result == -1)
    {
      if (TAO_debug_level > 1)
        ACE_ERROR ((LM_ERROR,
                    ACE_TEXT ("(%P|%t) Object_Ref_Table::register_initial_reference:")
                    ACE_TEXT ("  Could not register object <%s> with ")
                    ACE_TEXT ("the ORB\n"),
                    ACE_TEXT_CHAR_TO_TCHAR (id)));

      ACE_THROW (CORBA::INTERNAL ());
    }
}

CORBA::Object_ptr
TAO_Object_Ref_Table::resolve_initial_references (
  const char *id
  ACE_ENV_ARG_DECL_NOT_USED)
{
  return this->find (id);  // Returns a duplicate.
}

void
TAO_Object_Ref_Table::destroy (void)
{
  for (Iterator i = this->begin ();
       i != this->end ();
       ++i)
    {
      // Deallocate the id.
      CORBA::string_free (const_cast<char *> ((*i).ext_id_));

      // Release the Object.
      CORBA::release ((*i).int_id_);
    }

  this->table_.unbind_all ();
}

TAO_Object_Ref_Table::Iterator
TAO_Object_Ref_Table::begin (void)
{
  return this->table_.begin ();
}

TAO_Object_Ref_Table::Iterator
TAO_Object_Ref_Table::end (void)
{
  return this->table_.end ();
}

size_t
TAO_Object_Ref_Table::current_size (void) const
{
  return this->table_.current_size ();
}

int
TAO_Object_Ref_Table::bind (const char *id,
                            CORBA::Object_ptr obj)
{
  // Make sure that the supplied Object reference is valid,
  // i.e. not nil.
  if (id == 0 || CORBA::is_nil (obj))
    {
      errno = EINVAL;
      return -1;
    };

  CORBA::String_var name = CORBA::string_dup (id);
  CORBA::Object_var object = CORBA::Object::_duplicate (obj);

  int result = this->table_.bind (name.in (),
                                  object.in ());

  if (result == 0)
    {
      // Transfer ownership to the Object Table.
      (void) name._retn ();
      (void) object._retn ();
    }

  return result;
}

CORBA::Object_ptr
TAO_Object_Ref_Table::find (const char *id)
{
  CORBA::Object_ptr found = CORBA::Object::_nil ();

  this->table_.find (id, found);

  return CORBA::Object::_duplicate (found);
}

int
TAO_Object_Ref_Table::unbind (const char *id)
{
  Table::ENTRY *entry = 0;

  int result = this->table_.find (id, entry);

  if (result == 0)
    {
      // Deallocate the external ID and obtain the ORB core pointer
      // before unbinding the entry since the entry is deallocated
      // during the call to unbind().
      CORBA::string_free (const_cast<char *> (entry->ext_id_));
      CORBA::Object_ptr obj = entry->int_id_;

      result = this->table_.unbind (entry);

      if (result != 0)
        return result;

      CORBA::release (obj);
    }

  return result;
}


#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)

template class ACE_Hash_Map_Entry<const char *, CORBA::Object_ptr>;
template class ACE_Hash_Map_Manager_Ex<const char *, CORBA::Object_ptr, ACE_Hash<const char *>, ACE_Equal_To<const char *>, TAO_SYNCH_MUTEX>;
template class ACE_Hash_Map_Iterator_Base_Ex<const char *, CORBA::Object_ptr, ACE_Hash<const char *>, ACE_Equal_To<const char *>, TAO_SYNCH_MUTEX>;
template class ACE_Hash_Map_Iterator_Ex<const char *, CORBA::Object_ptr, ACE_Hash<const char *>, ACE_Equal_To<const char *>, TAO_SYNCH_MUTEX>;
template class ACE_Hash_Map_Reverse_Iterator_Ex<const char *, CORBA::Object_ptr, ACE_Hash<const char *>, ACE_Equal_To<const char *>, TAO_SYNCH_MUTEX>;

#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)

#pragma instantiate ACE_Hash_Map_Entry<const char *, CORBA::Object_ptr>
#pragma instantiate ACE_Hash_Map_Manager_Ex<const char *, CORBA::Object_ptr, ACE_Hash<const char *>, ACE_Equal_To<const char *>, TAO_SYNCH_MUTEX>
#pragma instantiate ACE_Hash_Map_Iterator_Base_Ex<const char *, CORBA::Object_ptr, ACE_Hash<const char *>, ACE_Equal_To<const char *>, TAO_SYNCH_MUTEX>
#pragma instantiate ACE_Hash_Map_Iterator_Ex<const char *, CORBA::Object_ptr, ACE_Hash<const char *>, ACE_Equal_To<const char *>, TAO_SYNCH_MUTEX>
#pragma instantiate ACE_Hash_Map_Reverse_Iterator_Ex<const char *, CORBA::Object_ptr, ACE_Hash<const char *>, ACE_Equal_To<const char *>, TAO_SYNCH_MUTEX>

#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
