// -*- C++ -*-
// $Id: default_client.cpp 93686 2011-03-31 12:12:12Z johnnyw $

#include "tao/default_client.h"
#include "tao/Wait_On_Read.h"
#include "tao/Wait_On_Reactor.h"
#include "tao/Wait_On_Leader_Follower.h"
#include "tao/Wait_On_LF_No_Upcall.h"
#include "tao/Exclusive_TMS.h"
#include "tao/Muxed_TMS.h"
#include "tao/Blocked_Connect_Strategy.h"
#include "tao/Reactive_Connect_Strategy.h"
#include "tao/LF_Connect_Strategy.h"
#include "tao/orbconf.h"

#include "ace/Lock_Adapter_T.h"
#include "ace/Recursive_Thread_Mutex.h"

#include "ace/OS_NS_strings.h"
#include "ace/OS_NS_string.h"

TAO_BEGIN_VERSIONED_NAMESPACE_DECL

TAO_Default_Client_Strategy_Factory::TAO_Default_Client_Strategy_Factory (void)
  : transport_mux_strategy_ (TAO_MUXED_TMS)
  , wait_strategy_ (TAO_WAIT_ON_LEADER_FOLLOWER)
  , connect_strategy_ (TAO_LEADER_FOLLOWER_CONNECT)
  , rd_table_size_ (TAO_RD_TABLE_SIZE)
  , muxed_strategy_lock_type_ (TAO_THREAD_LOCK)
  , use_cleanup_options_ (false)
{
  // Use single thread client connection handler
#if defined (TAO_USE_ST_CLIENT_CONNECTION_HANDLER)
  this->wait_strategy_ = TAO_WAIT_ON_REACTOR;
#elif defined (TAO_USE_WAIT_ON_LF_NO_UPCALL)
  this->wait_strategy_ = TAO_WAIT_ON_LF_NO_UPCALL;
#else
  this->wait_strategy_ = TAO_WAIT_ON_LEADER_FOLLOWER;
#endif /* TAO_USE_ST_CLIENT_CONNECTION_HANDLER */

#if TAO_USE_MUXED_TRANSPORT_MUX_STRATEGY == 1
  this->transport_mux_strategy_ = TAO_MUXED_TMS;
#else
  this->transport_mux_strategy_ = TAO_EXCLUSIVE_TMS;
#endif /* TAO_USE_MUXED_TRANSPORT_MUX_STRATEGY */

  // @todo: will be changed when other strategies are implemented.
  this->connect_strategy_ = TAO_LEADER_FOLLOWER_CONNECT;
}

TAO_Default_Client_Strategy_Factory::~TAO_Default_Client_Strategy_Factory (void)
{
}

int
TAO_Default_Client_Strategy_Factory::init (int argc, ACE_TCHAR* argv[])
{
  return this->parse_args (argc, argv);
}

int
TAO_Default_Client_Strategy_Factory::parse_args (int argc, ACE_TCHAR* argv[])
{
  ACE_TRACE ("TAO_Default_Client_Strategy_Factory::parse_args");

  int curarg;

  for (curarg = 0; curarg < argc && argv[curarg]; ++curarg)
    {
      if (ACE_OS::strcasecmp (argv[curarg],
                              ACE_TEXT("-ORBClientConnectionHandler")) == 0
          ||
          ACE_OS::strcasecmp (argv[curarg],
                              ACE_TEXT("-ORBWaitStrategy")) == 0)
        {
          curarg++;
          if (curarg < argc)
            {
              ACE_TCHAR* name = argv[curarg];

              if (ACE_OS::strcasecmp (name,
                                      ACE_TEXT("MT")) == 0)
                this->wait_strategy_ = TAO_WAIT_ON_LEADER_FOLLOWER;
              else if (ACE_OS::strcasecmp (name,
                                           ACE_TEXT("ST")) == 0)
                this->wait_strategy_ = TAO_WAIT_ON_REACTOR;
              else if (ACE_OS::strcasecmp (name,
                                           ACE_TEXT("RW")) == 0)
                this->wait_strategy_ = TAO_WAIT_ON_READ;
              else if (ACE_OS::strcasecmp (name,
                                           ACE_TEXT("MT_NOUPCALL")) == 0)
                this->wait_strategy_ = TAO_WAIT_ON_LF_NO_UPCALL;
              else
                this->report_option_value_error (ACE_TEXT("-ORBClientConnectionHandler"), name);
            }
        }
      else if (ACE_OS::strcasecmp (argv[curarg],
                                   ACE_TEXT("-ORBTransportMuxStrategy")) == 0)
        {
          curarg++;
          if (curarg < argc)
            {
              ACE_TCHAR* name = argv[curarg];

              if (ACE_OS::strcasecmp (name,
                                      ACE_TEXT("MUXED")) == 0)
                this->transport_mux_strategy_ = TAO_MUXED_TMS;
              else if (ACE_OS::strcasecmp (name,
                                           ACE_TEXT("EXCLUSIVE")) == 0)
                this->transport_mux_strategy_ = TAO_EXCLUSIVE_TMS;
              else
                this->report_option_value_error (ACE_TEXT("-ORBTransportMuxStrategy"), name);
            }
        }
      else if (ACE_OS::strcasecmp (argv[curarg],
                                   ACE_TEXT("-ORBTransportMuxStrategyLock")) == 0)
        {
          curarg++;
          if (curarg < argc)
            {
              ACE_TCHAR* name = argv[curarg];

              if (ACE_OS::strcasecmp (name,
                                      ACE_TEXT("null")) == 0)
                this->muxed_strategy_lock_type_ = TAO_NULL_LOCK;
              else if (ACE_OS::strcasecmp (name,
                                           ACE_TEXT("thread")) == 0)
                this->muxed_strategy_lock_type_ = TAO_THREAD_LOCK;
              else
                this->report_option_value_error (ACE_TEXT("-ORBTransportMuxStrategyLock"), name);
            }
        }
      else if (ACE_OS::strcasecmp (argv[curarg],
                                   ACE_TEXT("-ORBConnectStrategy")) == 0)
        {
          curarg++;
          if (curarg < argc)
            {
              ACE_TCHAR* name = argv[curarg];

              if (ACE_OS::strcasecmp (name,
                                      ACE_TEXT("Blocked")) == 0)
                this->connect_strategy_ = TAO_BLOCKED_CONNECT;
              else if (ACE_OS::strcasecmp (name,
                                           ACE_TEXT("Reactive")) == 0)
                this->connect_strategy_ = TAO_REACTIVE_CONNECT;
              else if (ACE_OS::strcasecmp (name,
                                           ACE_TEXT("LF")) == 0)
                this->connect_strategy_ = TAO_LEADER_FOLLOWER_CONNECT;
              else
                this->report_option_value_error (ACE_TEXT("-ORBConnectStrategy"), name);
            }
        }
      else if (ACE_OS::strcasecmp (argv[curarg],
                                   ACE_TEXT("-ORBReplyDispatcherTableSize")) == 0)
        {
          curarg++;
          if (curarg < argc)
            {
              this->rd_table_size_ = ACE_OS::atoi (argv[curarg]);
            }
        }
      else if (ACE_OS::strcmp (argv[curarg],
                               ACE_TEXT("-ORBConnectionHandlerCleanup")) == 0)
         {
           curarg++;
           if (curarg < argc)
             {
               ACE_TCHAR* name = argv[curarg];

               if (ACE_OS::strcmp (name, ACE_TEXT("0")) == 0 ||
                   ACE_OS::strcasecmp (name, ACE_TEXT("false")) == 0)
                 this->use_cleanup_options_ = false;
               else if (ACE_OS::strcmp (name, ACE_TEXT("1")) == 0 ||
                        ACE_OS::strcasecmp (name, ACE_TEXT("true")) == 0)
                 this->use_cleanup_options_ = true;
               else
                 this->report_option_value_error (ACE_TEXT("-ORBConnectionHandlerCleanup"), name);
             }
         }
      else if (ACE_OS::strncmp (argv[curarg], ACE_TEXT("-ORB"), 4) == 0)
        {
          // Can we assume there is an argument after the option?
          // curarg++;
          ACE_ERROR ((LM_ERROR,
                      "Client_Strategy_Factory - "
                      "unknown option <%s>\n",
                      argv[curarg]));
        }
      else
        {
          ACE_DEBUG ((LM_DEBUG,
                      "Client_Strategy_Factory - "
                      "ignoring option <%s>\n",
                      argv[curarg]));
        }
    }
  return 0;
}

/// Create the correct client transport muxing strategy.
TAO_Transport_Mux_Strategy *
TAO_Default_Client_Strategy_Factory::create_transport_mux_strategy (TAO_Transport *transport)
{
  TAO_Transport_Mux_Strategy *tms = 0;

  switch (this->transport_mux_strategy_)
    {
      case TAO_MUXED_TMS:
      {
        ACE_NEW_RETURN (tms,
                        TAO_Muxed_TMS (transport),
                        0);
        break;
      }
      case TAO_EXCLUSIVE_TMS:
      {
        ACE_NEW_RETURN (tms,
                        TAO_Exclusive_TMS (transport),
                        0);
        break;
      }
    }

  return tms;
}

ACE_Lock *
TAO_Default_Client_Strategy_Factory::create_transport_mux_strategy_lock (void)
{
  ACE_Lock *the_lock = 0;

  switch (this->muxed_strategy_lock_type_)
    {
      case TAO_NULL_LOCK:
        {
          ACE_NEW_RETURN (the_lock,
                          ACE_Lock_Adapter<ACE_SYNCH_NULL_MUTEX> (),
                          0);
          break;
        }
      case TAO_THREAD_LOCK:
        {
          ACE_NEW_RETURN (the_lock,
                          ACE_Lock_Adapter<TAO_SYNCH_RECURSIVE_MUTEX> (),
                          0);
          break;
        }
    }

  return the_lock;
}

int
TAO_Default_Client_Strategy_Factory::reply_dispatcher_table_size (void) const
{
  return this->rd_table_size_;
}

TAO_Wait_Strategy *
TAO_Default_Client_Strategy_Factory::create_wait_strategy (TAO_Transport *transport)
{
  TAO_Wait_Strategy *ws = 0;

/*
 * Hook to customize the wait strategy object when the concrete wait strategy
 * object is known a priori.
 */
//@@ WAIT_STRATEGY_SPL_COMMENT_HOOK_START
  switch (this->wait_strategy_)
    {
      case TAO_WAIT_ON_LEADER_FOLLOWER :
        {
          ACE_NEW_RETURN (ws,
                          TAO_Wait_On_Leader_Follower (transport),
                          0);
          break;
        }
      case TAO_WAIT_ON_REACTOR:
        {
          ACE_NEW_RETURN (ws,
                          TAO_Wait_On_Reactor (transport),
                          0);
          break;
        }
      case TAO_WAIT_ON_READ:
        {
          ACE_NEW_RETURN (ws,
                          TAO_Wait_On_Read (transport),
                          0);
          break;
        }
      case TAO_WAIT_ON_LF_NO_UPCALL:
        {
          ACE_NEW_RETURN (ws,
                          TAO::Wait_On_LF_No_Upcall (transport),
                          0);
          break;
        }
    }
//@@ WAIT_STRATEGY_SPL_COMMENT_HOOK_END

  return ws;
}

TAO_Client_Strategy_Factory::Connect_Strategy
TAO_Default_Client_Strategy_Factory::connect_strategy (void) const
{
  return this->connect_strategy_;
}

TAO_Connect_Strategy *
TAO_Default_Client_Strategy_Factory::create_connect_strategy (TAO_ORB_Core *orb_core)
{
  TAO_Connect_Strategy *cs = 0;

  switch (this->connect_strategy_)
    {
      case TAO_BLOCKED_CONNECT:
        {
          ACE_NEW_RETURN (cs,
                          TAO_Blocked_Connect_Strategy (orb_core),
                          0);
          break;
        }
      case TAO_REACTIVE_CONNECT:
        {
          ACE_NEW_RETURN (cs,
                          TAO_Reactive_Connect_Strategy (orb_core),
                          0);
          break;
        }
      case TAO_LEADER_FOLLOWER_CONNECT :
        {
          ACE_NEW_RETURN (cs,
                          TAO_LF_Connect_Strategy (orb_core),
                          0);
          break;
        }
    }

  return cs;
}


int
TAO_Default_Client_Strategy_Factory::allow_callback (void)
{
  return (this->wait_strategy_ != TAO_WAIT_ON_READ);
}

void
TAO_Default_Client_Strategy_Factory::report_option_value_error (
                                 const ACE_TCHAR* option_name,
                                 const ACE_TCHAR* option_value)
{
  ACE_DEBUG((LM_DEBUG,
             ACE_TEXT ("Client_Strategy_Factory - unknown argument")
             ACE_TEXT (" <%s> for <%s>\n"),
             option_value, option_name));
}

bool
TAO_Default_Client_Strategy_Factory::use_cleanup_options (void) const
{
  return this->use_cleanup_options_;
}

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

ACE_STATIC_SVC_DEFINE (TAO_Default_Client_Strategy_Factory,
                       ACE_TEXT ("Client_Strategy_Factory"),
                       ACE_SVC_OBJ_T,
                       &ACE_SVC_NAME (TAO_Default_Client_Strategy_Factory),
                       ACE_Service_Type::DELETE_THIS | ACE_Service_Type::DELETE_OBJ,
                       0)
ACE_FACTORY_DEFINE (TAO, TAO_Default_Client_Strategy_Factory)

TAO_END_VERSIONED_NAMESPACE_DECL

