/*
 * Utility class for the naming service bank example.
 */

#include "Util.h"
#include "Common/ObjectAdapter.h"

Util::Util (CORBA::ORB_ptr orb)
  : orbVar_ (CORBA::ORB::_duplicate (orb))
  , rootPoaVar_ (0)
  , rootCtxVar_ (0)
  , accMgrCtxVar_ (0)
  , accountsCtxVar_ (0)
{
  // Get a reference to the root POA.
  CORBA::Object_var objVar =
    orbVar_->resolve_initial_references (ACE_TEXT ("RootPOA"));
  rootPoaVar_ = PortableServer::POA::_narrow (objVar.in ());
  if (CORBA::is_nil (rootPoaVar_.in ()))
    {
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("ERROR: Nil reference\n")));
      throw TestException ();
    }

  // Get a reference to the root context.
  objVar = orbVar_->resolve_initial_references (ACE_TEXT ("NameService"));
  rootCtxVar_ = CosNaming::NamingContextExt::_narrow (objVar.in ());
  if (CORBA::is_nil (rootCtxVar_.in ()))
    {
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("ERROR: Nil reference\n")));
      throw TestException ();
    }
}

PortableServer::POA_ptr
Util::getRootPOA (void)
{
  return PortableServer::POA::_duplicate (rootPoaVar_.in ());
}

void
Util::buildNameGraph (void)
{
  ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Building name service graph\n")));

  CosNaming::NamingContextExt_var rootNamingCtx = getRootNamingCtx ();
  CosNaming::NamingContext_var plainRootVar =
    CosNaming::NamingContext::_narrow (rootNamingCtx.in ());
  CosNaming::NamingContext_var acmeCtxVar =
    myBindContext (plainRootVar.in (), ACE_TEXT ("ACME_Bank"));
  accMgrCtxVar_ = myBindContext (acmeCtxVar.in (), ACE_TEXT ("AccountManager"));
  accountsCtxVar_ = myBindContext (acmeCtxVar.in (), ACE_TEXT ("Accounts"));
}

Bank::AccountManager_ptr
Util::getAccManagerObject (void)
{
  CosNaming::NamingContextExt_var rootNamingCtx = getRootNamingCtx ();
  CORBA::Object_var objVar =
    rootNamingCtx->resolve_str (ACE_TEXT ("ACME_Bank/AccountManager/AccountManagerServer"));

  if (CORBA::is_nil (objVar.in ()))
    {
      ACE_ERROR_RETURN ((LM_ERROR,
                         ACE_TEXT ("ERROR: AccountManager is null\n")),
                        0);
    }

  Bank::AccountManager_var accManagerVar =
    Bank::AccountManager::_narrow (objVar.in ());

  if (CORBA::is_nil (accManagerVar.in ()))
    {
      ACE_ERROR_RETURN ((LM_ERROR,
                         ACE_TEXT ("ERROR: AccountManager is null\n")),
                        0);
    }

  return accManagerVar._retn ();
}

void
Util::bindAccountManager (CORBA::Object_ptr obj)
{
  CosNaming::NamingContextExt_var rootNamingCtx = getRootNamingCtx ();
  CosNaming::Name_var nameVar =
    rootNamingCtx->to_name (ACE_TEXT ("AccountManagerServer"));
  CosNaming::NamingContext_var accManagerCtx = getAccManagerCtx ();
  accManagerCtx->rebind (nameVar.in (), obj);

  ACE_DEBUG ((LM_DEBUG,
              ACE_TEXT ("Successfully bound account manager to name service\n")));
}

void
Util::addAccount (const char *name, CORBA::Object_ptr obj)
{
  Bank::Account_var accountVar = getAccount (name);

  if (CORBA::is_nil (accountVar.in ()))
    {
      CosNaming::NamingContextExt_var rootNamingCtx = getRootNamingCtx ();
      CosNaming::Name_var accNameVar = rootNamingCtx->to_name (name);
      CosNaming::NamingContext_var accountsCtx = getAccountsCtx ();
      accountsCtx->rebind (accNameVar.in (), obj);
    }
}

Bank::Account_ptr
Util::getAccount (const char *name)
{
  CosNaming::Name accName;
  accName.length (1);
  accName[0].id = CORBA::string_dup (name);

  try
    {
      CosNaming::NamingContext_var accountsCtx = getAccountsCtx ();
      CORBA::Object_var objVar = accountsCtx->resolve (accName);
      Bank::Account_var accountVar = Bank::Account::_narrow (objVar.in ());
      if (CORBA::is_nil (accountVar.in ()))
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             ACE_TEXT ("ERROR: Nil reference\n")),
                            0);
        }

      return accountVar._retn ();
    }
  catch (const CosNaming::NamingContext::NotFound &)
    {
      return 0;
    }
}

CosNaming::NamingContext_ptr
Util::getAccManagerCtx (void)
{
  CORBA::Object_var objVar;

  if (CORBA::is_nil (accMgrCtxVar_.in ()))
    {
      CosNaming::NamingContextExt_var rootNamingCtx = getRootNamingCtx ();
      CORBA::Object_var objVar =
        rootNamingCtx->resolve_str (ACE_TEXT ("ACME_Bank/AccountManager"));
      accMgrCtxVar_ = CosNaming::NamingContext::_narrow (objVar.in ());
      if (CORBA::is_nil (accMgrCtxVar_.in ()))
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             ACE_TEXT ("ERROR: Nil reference\n")),
                            0);
        }
    }

  return CosNaming::NamingContext::_duplicate (accMgrCtxVar_.in ());
}

CosNaming::NamingContext_ptr
Util::getAccountsCtx (void)
{
  if (CORBA::is_nil (accountsCtxVar_.in ()))
    {
      CosNaming::NamingContextExt_var rootNamingCtx = getRootNamingCtx ();
      CORBA::Object_var objVar =
        rootNamingCtx->resolve_str (ACE_TEXT ("ACME_Bank/Accounts"));
      accountsCtxVar_ = CosNaming::NamingContext::_narrow (objVar.in ());
      if (CORBA::is_nil (accountsCtxVar_.in ()))
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             ACE_TEXT ("ERROR: Nil reference\n")),
                            0);
        }
    }

  return CosNaming::NamingContext::_duplicate (accountsCtxVar_.in ());
}

CosNaming::NamingContextExt_ptr
Util::getRootNamingCtx (void)
{
  return CosNaming::NamingContextExt::_duplicate (rootCtxVar_.in ());
}

CosNaming::NamingContext_ptr
Util::myBindContext (CosNaming::NamingContext_ptr parentCtx,
                     const char *ctxName)
{
  CosNaming::NamingContextExt_var rootNamingCtx = getRootNamingCtx ();
  CosNaming::Name_var nameVar = rootNamingCtx->to_name (ctxName);

  CosNaming::NamingContext_var ctxVar;
  try
    {
      ctxVar = parentCtx->bind_new_context (nameVar.in ());
    }
  catch (const CosNaming::NamingContext::AlreadyBound &)
    {
      ctxVar = parentCtx->new_context ();
      parentCtx->rebind_context (nameVar.in (), ctxVar.in ());
    }

  return ctxVar._retn ();
}
