/*
 * A simple mail server.
 */

#include "MailServerImpl.h"
#include <orbsvcs/Shutdown_Utilities.h>

class Service_Shutdown_Functor : public Shutdown_Functor
{
public:
  Service_Shutdown_Functor (CORBA::ORB_ptr orb)
    : orb_ (CORBA::ORB::_duplicate (orb))
  {
  }

  void operator() (int which_signal)
  {
    ACE_DEBUG ((LM_DEBUG,
                ACE_TEXT ("shutting down on signal %d\n"),
                which_signal));
    (void) this->orb_->shutdown ();
  }

private:
  CORBA::ORB_var orb_;
};

/*
 * @func Constructs a MailServerImpl object
 * @parm | orbVar | a reference to the ORB
 * @parm | pUtil | a reference to the channel utility
 * @rdesc
 */
MailServerImpl::MailServerImpl (CORBA::ORB_ptr orb, ChannelUtil &util)
  : orbVar_ (CORBA::ORB::_duplicate (orb))
  , util_ (util)
{
  // Obtain a reference to a transient POA.
  ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Obtaining default transient POA\n")));
  PortableServer::POA_var poaVar = util_.getDefaultTransientPoa ();

  // Create the mail server CORBA object.
  PortableServer::ObjectId_var oidVar = poaVar->activate_object (this);
  CORBA::Object_var objVar = poaVar->id_to_reference (oidVar.in ());

  // Write out the mail server's IOR.
  util_.writeIOR (ACE_TEXT ("MailServer.ior"), objVar.in ());
}

/*
 * @func Creates an account (mailbox) for a user
 * @parm | name | the user name for the account
 * @rdesc AccountExists is thrown if an account with the name already exists
 */
void
MailServerImpl::createAccount (const char *name)
{
  MailBoxImpl *pMailBox = 0;

  ACE_NEW_THROW_EX (pMailBox,
                    MailBoxImpl (orbVar_.in (), util_, name),
                    CORBA::NO_MEMORY ());
  PortableServer::ServantBase_var holder (pMailBox);
  servants_.push_back (holder);

  pMailBox->init ();
}

/*
 * @func Deletes an account (mailbox) for a user
 * @parm | name | the user name for the account
 * @rdesc NoSuchAccount is thrown if an account with the name does not exist
 */
void
MailServerImpl::deleteAccount (const char *name)
{
  ACE_CString filename = ACE_CString (name) + ACE_TEXT (".ior");
  if (!util_.fileExists (filename.c_str ()))
    {
      throw Mail::NoSuchAccount ();
    }

  CORBA::Object_var objVar = util_.readIOR (filename.c_str ());
  Mail::MailBox_var mailBoxVar = Mail::MailBox::_narrow (objVar.in ());
  mailBoxVar->destroy ();
}

int
main (int argc, char **argv)
{
  try
    {
      // Initialise the ORB reference.
      ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Creating ORB reference\n")));
      CORBA::ORB_var orbVar = CORBA::ORB_init (argc, argv);
      if (CORBA::is_nil (orbVar.in ()))
        {
          ACE_ERROR_RETURN ((LM_ERROR,
                             ACE_TEXT ("Could not create the ORB\n")),
                            1);
        }

      // Cleaning guard.
      Service_Shutdown_Functor killer (orbVar.in ());
      Service_Shutdown kill_contractor (killer);

      // Obtain a reference to the channel utility.
      ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Creating channel utility\n")));
      ChannelUtil util (orbVar.in ());

      // Create the mail server.
      ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Creating mail server\n")));
      MailServerImpl *pMailServerImpl = 0;
      ACE_NEW_THROW_EX (pMailServerImpl,
                        MailServerImpl (orbVar.in (), util),
                        CORBA::NO_MEMORY ());
      PortableServer::ServantBase_var holder (pMailServerImpl);

      // Handle incoming requests.
      ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Waiting for incoming requests\n")));
      orbVar->run ();

      // Clean up and exit.
      orbVar->destroy ();
    }
  catch (const CORBA::Exception &ex)
    {
      ex._tao_print_exception (ACE_TEXT ("ERROR: Exception in MailServerImpl.cpp:"));
      return 1;
    }

  return 0;
}
