#include <tao/corba.h>
#include <tao/PortableServer/PortableServer.h>
#include <ace/streams.h>

#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>

#include "ObjectAdapter.h"

ObjectAdapter::ObjectAdapter (CORBA::ORB_ptr orb,
                              const CORBA::Boolean agent)
  : orbVar_ (CORBA::ORB::_duplicate (orb)),
    agent_ (agent),
    poaName_ (ACE_TEXT ("thisPOA")),
    rootPoaVar_ (0),
    thisPoaVar_ (0),
    poaManagerVar_ (0),
    managerIdVar_ (0)
{
  initialiseRootPOA ();
}

ObjectAdapter::ObjectAdapter (CORBA::ORB_ptr orb,
                              const char *poaName,
                              const CORBA::Boolean agent)
  : orbVar_ (CORBA::ORB::_duplicate (orb)),
    agent_ (agent),
    poaName_ (poaName),
    rootPoaVar_ (0),
    thisPoaVar_ (0),
    poaManagerVar_ (0),
    managerIdVar_ (0)
{
  initialiseRootPOA ();
}

void
ObjectAdapter::initialiseRootPOA (void)
{
   CORBA::Object_var objVar =
     orbVar_->resolve_initial_references (ACE_TEXT ("RootPOA"));
   rootPoaVar_ = PortableServer::POA::_narrow (objVar.in ());
   poaManagerVar_ = rootPoaVar_->the_POAManager ();
   poaManagerVar_->activate ();
}

void
ObjectAdapter::createTransient (PortableServer::ServantBase *pImpl)
{
  if (pImpl == 0)
    {
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("ERROR: Null implementation passed to createTransient ()\n")));
      throw TestException ();
    }

  // Create a transient POA.
  create (0);

  // Activate the transient object reference.
  addServantToAdapter (pImpl, ACE_TEXT ("thisServer"), 0);
}

void
ObjectAdapter::createPersistent (PortableServer::ServantBase *pImpl)
{
  if (pImpl == 0)
    {
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("ERROR: Null implementation passed to createPersistent ()\n")));
      throw TestException ();
    }

  // Create a persistent POA.
  create (1);

  // Activate the persistent object reference.
  addServantToAdapter (pImpl, ACE_TEXT ("thisServer"), 1);
}

void
ObjectAdapter::create (CORBA::Boolean persistent)
{
  // Create policies.
  CORBA::PolicyList policies;
  if (persistent)
    {
      policies.length (3);
      policies[0] =
        rootPoaVar_->create_lifespan_policy (PortableServer::PERSISTENT);
      policies[1] =
        rootPoaVar_->create_id_assignment_policy (PortableServer::USER_ID);
      policies[2] =
        rootPoaVar_->create_implicit_activation_policy (PortableServer::NO_IMPLICIT_ACTIVATION);
      ACE_DEBUG ((LM_INFO, ACE_TEXT ("INFO: created persistent policies\n")));
    }
  else
    {
      policies.length (1);
      policies[0] =
        rootPoaVar_->create_lifespan_policy (PortableServer::TRANSIENT);
      ACE_DEBUG ((LM_INFO, ACE_TEXT ("INFO: created transient policy\n")));
    }

  // Create a child POA with the right policies.
  try
    {
      thisPoaVar_ =
        rootPoaVar_->create_POA (poaName_.c_str (),
                                 poaManagerVar_.in (),
                                 policies);
    }
  catch (const CORBA::Exception &ex)
    {
      ex._tao_print_exception (ACE_TEXT ("ERROR: failed to create POA\n"));
      throw;
    }
}

void
ObjectAdapter::createTransient (void)
{
  create (0);
}

void
ObjectAdapter::createPersistent (void)
{
  create (1);
}

PortableServer::POA_ptr
ObjectAdapter::getPOA (void) const
{
  return PortableServer::POA::_duplicate (thisPoaVar_.in ());
}

char *
ObjectAdapter::getPoaName (void) const
{
  return CORBA::string_dup (poaName_.c_str ());
}

void
ObjectAdapter::addServantToAdapter (PortableServer::ServantBase *pImpl,
                                    const char *name,
                                    CORBA::Boolean persistent)
{
  if (persistent == 1)
    {
      try
        {
          // Create an ID for the persistent object, and activate it.
          PortableServer::ObjectId_var serverIdVar =
            PortableServer::string_to_ObjectId (name);

          PortableServer::POA_var poaVar = getPOA ();

          poaVar->activate_object_with_id (serverIdVar.in (), pImpl);
        }
      catch (const CORBA::Exception &ex)
        {
          ex._tao_print_exception (ACE_TEXT ("ERROR: Failed to activate persistent servant\n"));
          throw;
        }
    }
  else
    {
      // Allow the system to create an ID for the transient object, and activate it.
      try
        {
          PortableServer::POA_var poaVar = getPOA ();

          PortableServer::ObjectId_var serverIdVar =
            poaVar->activate_object (pImpl);
        }
      catch (const CORBA::Exception &ex)
        {
          ex._tao_print_exception (ACE_TEXT ("ERROR: Failed to activate transient servant\n"));
          throw;
        }
    }
}

void
ObjectAdapter::activateManager (void)
{
  PortableServer::POAManager_var manager =
    thisPoaVar_->the_POAManager ();
  manager->activate ();
}


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

TestException::TestException (void)
  : CORBA::UserException ("IDL:prismtech.com/OF/TestException:1.0",
                          "TestException")
{
}

TestException*
TestException::_downcast (CORBA::Exception *ex)
{
  return dynamic_cast <TestException*> (ex);
}

CORBA::Exception *
TestException::_tao_duplicate (void) const
{
  CORBA::Exception *result = 0;
  ACE_NEW_RETURN (result,
                  TestException (*this),
                  0);
  return result;
}

void
TestException::_raise (void) const
{
  throw *this;
}

void
TestException::_tao_encode (TAO_OutputCDR &cdr) const
{
  if (cdr << this->_rep_id ())
    {
      return;
    }

  throw ::CORBA::MARSHAL ();
}

void
TestException::_tao_decode (TAO_InputCDR &)
{
}
