/*
 * Base class for all news subscribers.
 */

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

NewsSubscriber::NewsSubscriber (CORBA::ORB_ptr orb)
  : orbVar_ (CORBA::ORB::_duplicate (orb))
  , util_ (orb)
  , channelVar_ (0)
  , consumerVar_ (0)
  , proxyVar_ (0)
{
  if (CORBA::is_nil (orbVar_.in ()))
    {
      ACE_ERROR ((LM_ERROR, ACE_TEXT ("Passed a null ORB reference\n")));
      throw TestException ();
    }

  // Obtain a reference to the root POA.
  CORBA::Object_var objVar =
    orbVar_->resolve_initial_references (ACE_TEXT ("RootPOA"));
  PortableServer::POA_var poaVar =
    PortableServer::POA::_narrow (objVar.in ());

  // Obtain a reference to the POA manager and activate it.
  PortableServer::POAManager_var poaManagerVar =
    poaVar->the_POAManager ();
  poaManagerVar->activate ();

  // Create the CORBA object for this subscriber.
  objVar = _this ();
  consumerVar_ =
    CosNotifyComm::StructuredPushConsumer::_narrow (objVar.in ());
}

void
NewsSubscriber::connectToChannel (void)
{
  // Obtain a reference to the channel.
  channelVar_ = util_.getChannel ();

  // Obtain a reference to the default consumer admin.
  CosNotifyChannelAdmin::ConsumerAdmin_var adminVar;
  try
    {
      adminVar = channelVar_->default_consumer_admin ();
      ACE_DEBUG ((LM_INFO, ACE_TEXT ("Obtained default consumer admin\n")));
    }
  catch (const CORBA::Exception &)
    {
      ACE_ERROR ((LM_ERROR, ACE_TEXT ("Failed to obtain default consumer admin\n")));
      throw;
    }

  // Obtain a proxy supplier.
  CosNotifyChannelAdmin::ProxySupplier_var psVar;
  try
    {
      CosNotifyChannelAdmin::ProxyID pid;
      CosNotifyChannelAdmin::ClientType type = CosNotifyChannelAdmin::STRUCTURED_EVENT;

      psVar = adminVar->obtain_notification_push_supplier (type, pid);
      if (CORBA::is_nil (psVar.in ()))
        {
          ACE_ERROR ((LM_ERROR, ACE_TEXT ("Obtained a null proxy supplier\n")));
          throw TestException ();
       }
     }
  catch (const CORBA::Exception &)
    {
      ACE_ERROR ((LM_ERROR, ACE_TEXT ("Failed to obtain a proxy supplier\n")));
      throw;
    }

  // Narrow to a structured proxy push supplier.
  proxyVar_ =
    CosNotifyChannelAdmin::StructuredProxyPushSupplier::_narrow (psVar.in ());
  if (CORBA::is_nil (proxyVar_.in ()))
    {
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("Narrowed to a null structured proxy push supplier\n")));
      throw TestException ();
    }

  // Connect.
  try
    {
      proxyVar_->connect_structured_push_consumer (consumerVar_.in ());
      ACE_DEBUG ((LM_INFO, ACE_TEXT ("Connected consumer to proxy\n")));
    }
  catch (const CORBA::Exception &)
    {
      ACE_ERROR ((LM_ERROR, ACE_TEXT ("Failed to connect consumer to proxy\n")));
      throw;
    }
}

void
NewsSubscriber::setFilter (const char *domainName, const char *typeName, const char *constraint)
{
  if (CORBA::is_nil (proxyVar_.in ()))
    {
      ACE_ERROR ((LM_ERROR, ACE_TEXT ("No proxy push supplier\n")));
      throw TestException ();
    }

  // Obtain a reference to the filter factory.
  CosNotifyFilter::FilterFactory_var factoryVar =
    channelVar_->default_filter_factory ();
  if (CORBA::is_nil (factoryVar.in ()))
    {
      ACE_ERROR ((LM_ERROR, ACE_TEXT ("Cannot get default filter factory\n")));
      throw TestException ();
    }

  try
    {
      const char *grammar = ACE_TEXT ("EXTENDED_TCL");

      // Create the filter.
      CosNotifyFilter::Filter_var filterVar =
        factoryVar->create_filter (grammar);

      // Create the constraint and add it to the filter.
      CosNotification::EventType type;
      type.domain_name = CORBA::string_dup (domainName);
      type.type_name = CORBA::string_dup (typeName);

      CosNotification::EventTypeSeq evts;
      evts.length (1);
      evts[0] = type;

      CosNotifyFilter::ConstraintExp exp;
      exp.event_types = evts;
      exp.constraint_expr = CORBA::string_dup (constraint);

      CosNotifyFilter::ConstraintExpSeq exps;
      exps.length (1);
      exps[0] = exp;

      CosNotifyFilter::ConstraintInfoSeq_var tmp =
        filterVar->add_constraints (exps);

      // Add the filter to the proxy.
      proxyVar_->add_filter (filterVar.in ());
    }
  catch (const CORBA::Exception &)
    {
      ACE_ERROR ((LM_ERROR, ACE_TEXT ("Failed to create/add filter\n")));
      throw;
    }
}

void
NewsSubscriber::disconnect_structured_push_consumer (void)
{
}

void
NewsSubscriber::offer_change (const CosNotification::EventTypeSeq &/*added*/,
                              const CosNotification::EventTypeSeq &/*removed*/)
{
}

void
NewsSubscriber::push_structured_event (const CosNotification::StructuredEvent& event)
{
  char message[60];
  util_.printEvent (event, message);

  ACE_DEBUG ((LM_INFO, ACE_TEXT ("Received message: %s\n"), message));
}
